Wednesday, March 5, 2008

Convert Hex String to Byte Array and Vice-Versa

If you've dealt with legacy encryption schemes across multiple platforms, you know what a chore it can be to deal with the various encoding options, the character sets, etc. Sure, Microsoft provides various short-cuts for converting hex strings to/from byte arrays (BitConverter, Encoding.ASCII.GetBytes, etc) that seem to sometimes work depending on the details of what you're doing and the systems involved.. but time and again I wind up going back to an old tried-and-true method shown below.


/// <summary>
/// Convert string to byte_array
/// </summary>
/// <param name="strInput">
private byte[] String_To_Bytes(string strInput)
{
// i variable used to hold position in string
int i = 0;
// x variable used to hold byte array element position
int x = 0;
// allocate byte array based on half of string length
byte[] bytes = new byte[(strInput.Length) / 2];
// loop through the string - 2 bytes at a time converting
// it to decimal equivalent and store in byte array
while (strInput.Length > i + 1)
{
long lngDecimal = Convert.ToInt32(strInput.Substring(i, 2), 16);
bytes[x] = Convert.ToByte(lngDecimal);
i = i + 2;
++x;
}
// return the finished byte array of decimal values
return bytes;
}

/// <summary>
/// Convert byte_array to string
/// </summary>
/// <param name="bytes_Input">
private string Bytes_To_String(byte[] bytes_Input)
{
// convert the byte array back to a true string
string strTemp = "";
for (int x = 0; x <= bytes_Input.GetUpperBound(0); x++)
{
int number = int.Parse(bytes_Input[x].ToString());
strTemp += number.ToString("X").PadLeft(2, '0');
}
// return the finished string of hex values
return strTemp;
}

This allows you, for example, to go from a string value of say "A5B2FFD0" back and forth between the equivalent byte array { 0xA5, 0xB2, 0xFF, 0xD0 }.

14 comments:

  1. Your String_to_bytes is more or less reasonable, although it can be toned up a bit:

    private byte[] String_To_Bytes2(string strInput)
    {
    // allocate byte array based on half of string length
    int numBytes = (strInput.Length) / 2;
    byte[] bytes = new byte[numBytes];

    // loop through the string - 2 bytes at a time converting it to decimal equivalent and store in byte array
    // x variable used to hold byte array element position
    for(int x=0; x<numBytes; ++x)
    {
    bytes[x] = Convert.ToByte(strInput.Substring(x*2, 2), 16);
    }

    // return the finished byte array of decimal values
    return bytes;
    }

    Bytes_To_String on the other hand, is more of a mess:

    // convert the byte array back to a true string
    private string Bytes_To_String2(byte[] bytes_Input)
    {
    StringBuilder strTemp = new StringBuilder(bytes_Input.Length *2);
    foreach(byte b in bytes_Input)
    {
    strTemp.Append(b.ToString("X02"));
    }
    return strTemp.ToString();
    }

    ReplyDelete
  2. james-
    nice job on the cleanup. that code is several years old and definitely needed to be cleaned up. thanks-

    ReplyDelete
  3. anyone know how to do it in VB.Net?

    ReplyDelete
  4. It should really be pretty trivial to port to vb.net. Although I sometimes have mixed results, you can probably even use one of the online code converters like this one to get you started:
    http://www.developerfusion.com/tools/convert/csharp-to-vb/

    good luck-

    ReplyDelete
  5. Thanks, this was a real help!

    ReplyDelete
  6. byte[] byteBuffer = new byte[7];
    string x = "1938641353225F";
    string[] bx = new string[x.Length / 2];
    for (int i = 0; i < x.Length; i += 2)
    {
    bx[i / 2] = x.Substring(i, 2);

    byteBuffer[i/2] = Convert.ToByte(bx[i / 2]);
    }

    I try the above code, and wants the string to be in Byte Array, not String Array.
    It does not seem to be able to put 5F into that Byte Array, please advise.

    ReplyDelete
  7. Anonymous-

    I'm not sure why you wouldn't just use the code shown, but if you want to do it your own way I believe you'll need to specify that you're dealing with base-16 numbers.

    Change your last line
    FROM:
    byteBuffer[i/2] = Convert.ToByte(bx[i / 2]);
    TO:
    byteBuffer[i/2] = Convert.ToByte(bx[i / 2], 16);

    good luck-

    ReplyDelete
  8. All the above code, including your suggestion of byteBuffer[i/2] = Convert.ToByte(bx[i / 2], 16);
    gives the byteBuffer in terms of decimal values, i.e,
    byteBuffer[0]=25;
    byteBuffer[1]=56;
    byteBuffer[2]=100;
    byteBuffer[3]=19;
    byteBuffer[4]=83;
    byteBuffer[5]=34;
    byteBuffer[6]=95;

    What I want my byteBuffer of Byte Array type is of HEX-DECIMAL values, i.e.
    byteBuffer[0]=19;
    byteBuffer[1]=38;
    byteBuffer[2]=64;
    byteBuffer[3]=13;
    byteBuffer[4]=53;
    byteBuffer[5]=22;
    byteBuffer[6]=5F;

    I hope my explanation is clear.

    ReplyDelete
  9. >> gives the byteBuffer in terms of decimal values, i.e,
    >> What I want my byteBuffer of Byte Array type is of HEX-DECIMAL values, i.e.

    The statements are meaningless. The contents of byteBuffer are values -- they aren't decimal value or hexadecimal values -- just values. When printed, these values can be displayed as decimal or Hexadecimal (or octal or binary or ASCII or whatever you choose).

    ReplyDelete
  10. I understand now, thanks a lot

    ReplyDelete
  11. Fantastic - I've been looking for something like this in order to pass a timestamp value (held in the C# class as a string) into a SQL database...

    ReplyDelete
  12. Hi guys,
    I can recommend a pretty good online tool to convert ascii to binary
    I think this is a good link to complement this post :)
    David

    ReplyDelete
  13. how can you do this in vbscript? please help.

    ReplyDelete