ido talker
ido talker

Reputation: 33

Converting String to Byte Array and vice versa

Converting a string to a byte array and then changing back will sometimes wont return the same string:

RandomNumberGenerator gen = new RNGCryptoServiceProvider();
byte[] randomBytes = new byte[32];
gen.GetBytes(randomBytes);

In some cases (or any kind of encoding other than unicode):

randomBytes != Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(randomBytes));

I'd like to know how to do this method and get the same result for sure. Thanks in advance

Upvotes: 3

Views: 415

Answers (2)

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

Arbitrary byte array does not necessary encodes a valid Unicode string (see https://en.wikipedia.org/wiki/UTF-16 for details), e.g.

  byte[] before = new byte[] { 0xA6, 0xDD };
  byte[] after = Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(before));

  if (!before.SequenceEqual(after))
    Console.Write(string.Join(Environment.NewLine,
      $"before: {string.Join(" ", before.Select(b => b.ToString("x2")))}",
      $"after:  {string.Join(" ", after.Select(b => b.ToString("x2")))}"));

Outcome:

before: a6 dd
after:  fd ff

If you want to generate these strings you can modify your code into

while (true) {
  using (RandomNumberGenerator gen = new RNGCryptoServiceProvider()) {
    byte[] randomBytes = new byte[32];
    gen.GetBytes(randomBytes);

    byte[] after = Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(randomBytes));

    if (!randomBytes.SequenceEqual(after)) {
      Console.Write(string.Join(" ", randomBytes) + 
                    Environment.NewLine + 
                    string.Join(" ", after));

      break;
    }
  }
}

Possible outcome:

166 8 99 175 188 233 240 219 64 143 26 87 157 209 205 219 27 169 239 67 99 170 172 226 254 56 168 168 64 222 178 15
166 8 99 175 188 233 253 255 64 143 26 87 157 209 253 255 27 169 239 67 99 170 172 226 254 56 168 168 253 255 178 15
                     ^
                     Difference

Please, note that we should compare arrays with SequenceEqual.

If you want to encode an array, you can do it with a help of string.Join:

byte[] array = ...

// Something like "166 8 99 175 188 233 240 219 ... 64 222 178 15"
string encoded = string.Join(" ", array);

byte[] back = encoded
  .Split(' ')
  .Select(item => byte.Parse(item))
  .ToArray();

Upvotes: 1

usr
usr

Reputation: 171178

Probably, you are not looking for a text encoding but a serialization format. Text encodings are meant for text. The bytes you are processing are random bytes.

Does Base64 (Convert.ToBase64String) work for you?

You could also jam the bytes into chars (new string(myBytes.Select(b => (char)b).ToArray())). This will produce unreadable strings that are prone to being mangled by other systems. Likely not the right path.

Upvotes: 2

Related Questions