3

I have the below .NET code to convert a string to Base64 encoding by first converting it to byte array. I tried different answers on Stack Overflow to convert the string in byte array and then use btoa() function for base64 encoding in JavaScript. But, I'm not getting the exact encoded value as shared below.

For string value,

BBFDC43D-4890-4558-BB89-50D802014A97

I need Base64 encoding as,

PcT9u5BIWEW7iVDYAgFKlw==

.NET code:

String str = "BBFDC43D-4890-4558-BB89-50D802014A97"
Guid guid = new Guid(str);
Console.WriteLine(guid);    // bbfdc43d-4890-4558-bb89-50d802014a97
Byte[] bytes = guid.ToByteArray();
Console.WriteLine(bytes);   // System.Byte[]
String s = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
Console.WriteLine(s);   // PcT9u5BIWEW7iVDYAgFKlw==

Currently, I tried with the below code, which is not producing the desired result:

function strToUtf8Bytes(str) {
  const utf8 = [];
  for (let ii = 0; ii < str.length; ii++) {
    let charCode = str.charCodeAt(ii);
    if (charCode < 0x80) utf8.push(charCode);
    else if (charCode < 0x800) {
      utf8.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));
    } else if (charCode < 0xd800 || charCode >= 0xe000) {
      utf8.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
    } else {
      ii++;
      // Surrogate pair:
      // UTF-16 encodes 0x10000-0x10FFFF by subtracting 0x10000 and
      // splitting the 20 bits of 0x0-0xFFFFF into two halves
      charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (str.charCodeAt(ii) & 0x3ff));
      utf8.push(
        0xf0 | (charCode >> 18),
        0x80 | ((charCode >> 12) & 0x3f),
        0x80 | ((charCode >> 6) & 0x3f),
        0x80 | (charCode & 0x3f),
      );
    }
  }
  return utf8;
}

const str = "BBFDC43D-4890-4558-BB89-50D802014A97";
const strByteArr = strToUtf8Bytes(str);
const strBase64 = btoa(strByteArr);
// NjYsNjYsNzAsNjgsNjcsNTIsNTEsNjgsNDUsNTIsNTYsNTcsNDgsNDUsNTIsNTMsNTMsNTYsNDUsNjYsNjYsNTYsNTcsNDUsNTMsNDgsNjgsNTYsNDgsNTAsNDgsNDksNTIsNjUsNTcsNTU=
Himanshu Aggarwal
  • 1,803
  • 2
  • 24
  • 36
  • Could you also provide the JS code you use? – Patrick Mar 26 '19 at 11:40
  • maybe dupplicate from: https://stackoverflow.com/questions/246801/how-can-you-encode-a-string-to-base64-in-javascript – LeBigCat Mar 26 '19 at 11:45
  • This is not the duplicate of that question because I'm using btoa() to encode but I'm concerned about the byte array here. – Himanshu Aggarwal Mar 26 '19 at 11:51
  • 1
    Are you sure that PcT9u5BIWEW7iVDYAgFKlw== is the base64 representation of the string BBFDC43D-4890-4558-BB89-50D802014A97 – John Mar 26 '19 at 11:51
  • Why are using Guid? The byte array you're getting is not the string converted to byte array, but it is the hex values represented by the guid converted do dec – Magnetron Mar 26 '19 at 11:52
  • @John. The base64 is formed from the byte array of that string, as you can see in the code. This is what I tried on my code. And is working fine on the current system on .NET – Himanshu Aggarwal Mar 26 '19 at 11:52
  • @Patrick I used the JS function shared in this answer and all other answers in the same question: https://stackoverflow.com/a/51904484/1488014 – Himanshu Aggarwal Mar 26 '19 at 11:53
  • @HimanshuAggarwal it was my understanding that a base64 representation of data would be longer given that you are unable to encode as many possible values with a single character – John Mar 26 '19 at 11:55
  • @Magnetron This is the current code in .NET. I need to replicate this functionality on JS. That is why, I have no other option. – Himanshu Aggarwal Mar 26 '19 at 11:55
  • 1
    You should post your javascript code. And again, as I said before, your code is not converting that string to base64, it's taking that string as a bunch of hex values, converting it to base 10, and then encoding the resulting byte array to base 64 – Magnetron Mar 26 '19 at 11:59
  • Also, from [Guid.GetByteArray](https://learn.microsoft.com/en-us/dotnet/api/system.guid.tobytearray?view=netframework-4.7.2#remarks): _Note that the order of bytes in the returned byte array is different from the string representation of a Guid value. The order of the beginning four-byte group and the next two two-byte groups is reversed, whereas the order of the last two-byte group and the closing six-byte group is the same._ – Magnetron Mar 26 '19 at 12:01
  • @Magnetron, I posted my current JS code in the answer. – Himanshu Aggarwal Mar 26 '19 at 12:11

3 Answers3

4

Your problem is caused by the following:

  • btoa() is using ASCII encoding
  • guid.ToByteArray(); does not use ASCII encoding

If you modify your C# code like this:

String str = "BBFDC43D-4890-4558-BB89-50D802014A97";
//Guid guid = new Guid(str);
//Console.WriteLine(guid);
// bbfdc43d-4890-4558-bb89-50d802014a97
//Byte[] bytes = guid.ToByteArray();
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);
//Console.WriteLine(bytes);   // System.Byte[]
String s = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
Console.WriteLine(s);

You will get the following output:

QkJGREM0M0QtNDg5MC00NTU4LUJCODktNTBEODAyMDE0QTk3

Which will be the same string as the one returned from the btoa() function:

var rawString = "BBFDC43D-4890-4558-BB89-50D802014A97";
var b64encoded = btoa(rawString);
console.log(b64encoded);

Output:

QkJGREM0M0QtNDg5MC00NTU4LUJCODktNTBEODAyMDE0QTk3

UPDATE - Since you can't modify the C# code

You should adapt your Javascript code by combining Piotr's answer and this SO answer

function guidToBytes(guid) {
    var bytes = [];
    guid.split('-').map((number, index) => {
        var bytesInChar = index < 3 ? number.match(/.{1,2}/g).reverse() : number.match(/.{1,2}/g);
        bytesInChar.map((byte) => { bytes.push(parseInt(byte, 16)); })
    });
    return bytes;
}

function arrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary);
}

var str = "BBFDC43D-4890-4558-BB89-50D802014A97";
var guidBytes = guidToBytes(str);
var b64encoded = arrayBufferToBase64(guidBytes);
console.log(b64encoded);

Output:

PcT9u5BIWEW7iVDYAgFKlw==
Marko Papic
  • 1,846
  • 10
  • 23
2

The problem with your code is representation of Guid. In C# code you are converting "BBFDC43D-4890-4558-BB89-50D802014A97" into UUID which is a 128-bit number. In JavaScript code, you are doing something else. You iterate through the string and calculate a byte array of a string. They are simply not equal. Now you have to options

  1. Implement proper guid conversion in JS (this may help: https://gist.github.com/daboxu/4f1dd0a254326ac2361f8e78f89e97ae)
  2. In C# calculate byte array in the same way as in JS
Piotr Stapp
  • 19,392
  • 11
  • 68
  • 116
1

Your string is a hexadecimal value, which you use to create a GUID. Then you convert the GUID into a byte array with:

Byte[] bytes = guid.ToByteArray();

The GUID is a 16-byte value which can be represented as a hexadecimal value. When you convert this GUID into a byte array, you will get the 16 bytes of the value, not the byte representation of the hexadecimal value.

In the provided JavaScript function you are doing something else: You are converting the string directly to a byte array.

In C# you do the equivalent with an Encoding:

String str = "BBFDC43D-4890-4558-BB89-50D802014A97";
Byte[] bytes = Encoding.UTF8.GetBytes(str);
Sefe
  • 13,731
  • 5
  • 42
  • 55