Search code examples
c#qr-codepublic-keytlv

Public key format is not correct inside TLV QR tag using C#


I have a code will decodebase64 the public key and then add it in QR TLV code, but when I add it in QR code the format is different than in PHP, and not same as I need it!

the Decoded64 Public key in C#:

0V0*�H�=+�
Ba���L;�-z�_g&���u�$��½k9�-��տ�.��A�ڇ)�1��_�B�x�i�;��'�

the what I need it like this:

X0V0*H=+�
B�a`L;-z_g&u$½k9-տ.Aڇ)1_Bxi;'

my C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace tlvgenerator
{
    class Program
    {
        static void Main(string[] args)
        {
            static string Base64Decode(string base64EncodedData)
            {
                var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
                return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
            }
            string base64 = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYYMMoOaFYAhMO/steotfZyavr6p11SSl wsK9azmsLY7b1b+FLhqMArhB2dqHKboxqKNfvkKDePhpqjui5hcn0Q==";
            Console.WriteLine("Encoded String = " + base64);
            var original = Base64Decode(base64);

            byte[] bytes = Encoding.Default.GetBytes(original);
            original = Encoding.UTF8.GetString(bytes);

            Console.WriteLine("Decoded String = " + original);

            string SallerName = gethexstring(1, "Bobs Records"); //Tag1
            string VATReg = gethexstring(2, "310122393500003"); //Tag2
            string DateTimeStr = gethexstring(3, "2022-04-25 15:30:00"); //Tage3
            string TotalAmt = gethexstring(4, "10000.00"); //Tag4
            string VatAmt = gethexstring(5, "150.00"); //Tag5
            string PK = gethexstring(6, original); //Tag6


            string decString = SallerName + VATReg + DateTimeStr + TotalAmt + VatAmt + PK;
            Console.WriteLine(decString);
            Console.WriteLine(HexToBase64(decString));
            Console.Read();


        }
        static string gethexstring(Int32 TagNo, string TagValue)
        {
            string StrTagNo = String.Format("0{0:X}", TagNo);
            String TagNoVal = StrTagNo.Substring(StrTagNo.Length - 2, 2);

            string StrTagValue_Length = String.Format("0{0:X}", TagValue.Length);
            String TagValue_LengthVal = StrTagValue_Length.Substring(StrTagValue_Length.Length - 2, 2);

            string decString = TagValue;
            byte[] bytes = Encoding.Default.GetBytes(decString);
            string hexString = BitConverter.ToString(bytes);
            hexString = TagNoVal + TagValue_LengthVal + hexString.Replace("-", "");

            return hexString;
        }

        static string gethexDec(Int32 TagValue)
        {
            string hxint = String.Format("0{0:X}", TagValue);
            return hxint.Substring(hxint.Length - 2, 2);

        }
        public static string HexToBase64(string strInput)
        {
            try
            {
                var bytes = new byte[strInput.Length / 2];
                for (var i = 0; i < bytes.Length; i++)
                {
                    bytes[i] = Convert.ToByte(strInput.Substring(i * 2, 2), 16);
                }
                return Convert.ToBase64String(bytes);
            }
            catch (Exception)
            {
                return "-1";
            }
        }

        private string StringToHex(string hexstring)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char t in hexstring)
            {
                //Note: X for upper, x for lower case letters
                sb.Append(Convert.ToInt32(t).ToString("x"));
            }
            return sb.ToString();
        }
    }
}

the QR output which is not same I want it:

AQxCb2JzIFJlY29yZHMCDzMxMDEyMjM5MzUwMDAwMwMTMjAyMi0wNC0yNSAxNTozMDowMAQIMTAwMDAuMDAFBjE1MC4wMAZUMFYwEAYHKu+/vUjvv709AgEGBSvvv70EAAoDQgAEYe+/vQzvv73vv71gCEw777+9LXrvv71fZybvv73vv73vv71177+9JO+/ve+/vcK9aznvv70t77+977+91b/vv70uGu+/vQLvv71B77+92ocp77+9Me+/ve+/vV/vv71C77+9eO+/vWnvv70777+977+9Fyfvv70=

the correct expected QR code like in PHP:

AQxCb2JzIFJlY29yZHMCDzMxMDEyMjM5MzUwMDAwMwMTMjAyMi0wNC0yNSAxNTozMDowMAQIMTAwMDAuMDAFBjE1MC4wMAZYMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYYMMoOaFYAhMO/steotfZyavr6p11SSlwsK9azmsLY7b1b+FLhqMArhB2dqHKboxqKNfvkKDePhpqjui5hcn0Q==

What is the wrong in C# code and how can I solve the issue? I thought was from UTF8 but it's not!


Solution

  • MFY...cn0Q== is a DER encoded public EC key in X.509/SPKI format after Base64 encoding. This is corrupted during UTF8 encoding in Base64Decode(), which is shown in the replacement characters 0xEFBFBD of the result.
    Also the use of the default encoding in Encoding.Default should be avoided, instead the encoding should be specified concretely.

    A possible fix is:

    string base64 = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYYMMoOaFYAhMO/steotfZyavr6p11SSlwsK9azmsLY7b1b+FLhqMArhB2dqHKboxqKNfvkKDePhpqjui5hcn0Q==";
    
    string sallerName = GetHexString(1, Encoding.UTF8.GetBytes("Bobs Records"));            //Tag1
    string vatReg = GetHexString(2, Encoding.UTF8.GetBytes("310122393500003"));             //Tag2
    string dateTimeStr = GetHexString(3, Encoding.UTF8.GetBytes("2022-04-25 15:30:00"));    //Tag3
    string totalAmt = GetHexString(4, Encoding.UTF8.GetBytes("10000.00"));                  //Tag4
    string vatAmt = GetHexString(5, Encoding.UTF8.GetBytes("150.00"));                      //Tag5
    string pk = GetHexString(6, Convert.FromBase64String(base64));                          //Tag6
    
    string decString = sallerName + vatReg + dateTimeStr + totalAmt + vatAmt + pk;
    
    Console.WriteLine(HexToBase64(decString));
    

    with

    static string GetHexString(int tagNo, byte[] tagValue)
    {
        string strTagNo = string.Format("0{0:X}", tagNo);
        string tagNoVal = strTagNo.Substring(strTagNo.Length - 2, 2);
    
        string strTagValueLength = string.Format("0{0:X}", tagValue.Length);
        string tagValueLengthVal = strTagValueLength.Substring(strTagValueLength.Length - 2, 2);
    
        return tagNoVal + tagValueLengthVal + BitConverter.ToString(tagValue).Replace("-", "");
    }
    

    Here in GetHexString() the encoding was moved outside, so that the method can be used for all tags independently of the input encoding.

    This fix gives the expected result.