How to convert a byte array (MD5 hash) into a string (36 chars)?
NickName:Kees C. Bakker Ask DateTime:2011-09-13T15:47:13

How to convert a byte array (MD5 hash) into a string (36 chars)?

I've got a byte array that was created using a hash function. I would like to convert this array into a string. So far so good, it will give me hexadecimal string.

Now I would like to use something different than hexadecimal characters, I would like to encode the byte array with these 36 characters: [a-z][0-9].

How would I go about?

Edit: the reason I would to do this, is because I would like to have a smaller string, than a hexadecimal string.

Copyright Notice:Content Author:「Kees C. Bakker」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/7398465/how-to-convert-a-byte-array-md5-hash-into-a-string-36-chars

Answers
erikH 2011-09-13T08:07:34

If you want a shorter string and can accept [a-zA-Z0-9] and + and / then look at Convert.ToBase64String ",


xanatos 2011-09-13T08:14:17

Using BigInteger (needs the System.Numerics reference)\n\nUsing BigInteger (needs the System.Numerics reference)\n\nconst string chars = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n\n// The result is padded with chars[0] to make the string length\n// (int)Math.Ceiling(bytes.Length * 8 / Math.Log(chars.Length, 2))\n// (so that for any value [0...0]-[255...255] of bytes the resulting\n// string will have same length)\npublic static string ToBaseN(byte[] bytes, string chars, bool littleEndian = true, int len = -1)\n{\n if (bytes.Length == 0 || len == 0)\n {\n return String.Empty;\n }\n\n // BigInteger saves in the last byte the sign. > 7F negative, \n // <= 7F positive. \n // If we have a \"negative\" number, we will prepend a 0 byte.\n byte[] bytes2;\n\n if (littleEndian)\n {\n if (bytes[bytes.Length - 1] <= 0x7F)\n {\n bytes2 = bytes;\n }\n else\n {\n // Note that Array.Resize doesn't modify the original array,\n // but creates a copy and sets the passed reference to the\n // new array\n bytes2 = bytes;\n Array.Resize(ref bytes2, bytes.Length + 1);\n }\n }\n else\n {\n bytes2 = new byte[bytes[0] > 0x7F ? bytes.Length + 1 : bytes.Length];\n\n // We copy and reverse the array\n for (int i = bytes.Length - 1, j = 0; i >= 0; i--, j++)\n {\n bytes2[j] = bytes[i];\n }\n }\n\n BigInteger bi = new BigInteger(bytes2);\n\n // A little optimization. We will do many divisions based on \n // chars.Length .\n BigInteger length = chars.Length;\n\n // We pre-calc the length of the string. We know the bits of \n // \"information\" of a byte are 8. Using Log2 we calc the bits of \n // information of our new base. \n if (len == -1)\n {\n len = (int)Math.Ceiling(bytes.Length * 8 / Math.Log(chars.Length, 2));\n }\n\n // We will build our string on a char[]\n var chs = new char[len];\n int chsIndex = 0;\n\n while (bi > 0)\n {\n BigInteger remainder;\n bi = BigInteger.DivRem(bi, length, out remainder);\n\n chs[littleEndian ? chsIndex : len - chsIndex - 1] = chars[(int)remainder];\n chsIndex++;\n\n if (chsIndex < 0)\n {\n if (bi > 0)\n {\n throw new OverflowException();\n }\n }\n }\n\n // We append the zeros that we skipped at the beginning\n if (littleEndian)\n {\n while (chsIndex < len)\n {\n chs[chsIndex] = chars[0];\n chsIndex++;\n }\n }\n else\n {\n while (chsIndex < len)\n {\n chs[len - chsIndex - 1] = chars[0];\n chsIndex++;\n }\n }\n\n return new string(chs);\n}\n\npublic static byte[] FromBaseN(string str, string chars, bool littleEndian = true, int len = -1)\n{\n if (str.Length == 0 || len == 0)\n {\n return new byte[0];\n }\n\n // This should be the maximum length of the byte[] array. It's \n // the opposite of the one used in ToBaseN.\n // Note that it can be passed as a parameter\n if (len == -1)\n {\n len = (int)Math.Ceiling(str.Length * Math.Log(chars.Length, 2) / 8);\n }\n\n BigInteger bi = BigInteger.Zero;\n BigInteger length2 = chars.Length;\n BigInteger mult = BigInteger.One;\n\n for (int j = 0; j < str.Length; j++)\n {\n int ix = chars.IndexOf(littleEndian ? str[j] : str[str.Length - j - 1]);\n\n // We didn't find the character\n if (ix == -1)\n {\n throw new ArgumentOutOfRangeException();\n }\n\n bi += ix * mult;\n\n mult *= length2;\n }\n\n var bytes = bi.ToByteArray();\n\n int len2 = bytes.Length;\n\n // BigInteger adds a 0 byte for positive numbers that have the\n // last byte > 0x7F\n if (len2 >= 2 && bytes[len2 - 1] == 0)\n {\n len2--;\n }\n\n int len3 = Math.Min(len, len2);\n\n byte[] bytes2;\n\n if (littleEndian)\n {\n if (len == bytes.Length)\n {\n bytes2 = bytes;\n }\n else\n {\n bytes2 = new byte[len];\n Array.Copy(bytes, bytes2, len3);\n }\n }\n else\n {\n bytes2 = new byte[len];\n\n for (int i = 0; i < len3; i++)\n {\n bytes2[len - i - 1] = bytes[i];\n }\n }\n\n for (int i = len3; i < len2; i++)\n {\n if (bytes[i] != 0)\n {\n throw new OverflowException();\n }\n }\n\n return bytes2;\n}\n\n\nBe aware that they are REALLY slow! REALLY REALLY slow! (2 minutes for 100k). To speed them up you would probably need to rewrite the division/mod operation so that they work directly on a buffer, instead of each time recreating the scratch pads as it's done by BigInteger. And it would still be SLOW. The problem is that the time needed to encode the first byte is O(n) where n is the length of the byte array (this because all the array needs to be divided by 36). Unless you want to work with blocks of 5 bytes and lose some bits. Each symbol of Base36 carries around 5.169925001 bits. So 8 of these symbols would carry 41.35940001 bits. Very near 40 bytes.\n\nNote that these methods can work both in little-endian mode and in big-endian mode. The endianness of the input and of the output is the same. Both methods accept a len parameter. You can use it to trim excess 0 (zeroes). Note that if you try to make an output too much small to contain the input, an OverflowException will be thrown.",


Samich 2011-09-13T07:55:30

System.Text.Encoding enc = System.Text.Encoding.ASCII;\nstring myString = enc.GetString(myByteArray);\n\n\nYou can play with what encoding you need:\n\nSystem.Text.ASCIIEncoding,\nSystem.Text.UnicodeEncoding,\nSystem.Text.UTF7Encoding,\nSystem.Text.UTF8Encoding\n\n\nTo match the requrements [a-z][0-9] you can use it:\n\nByte[] bytes = new Byte[] { 200, 180, 34 };\nstring result = String.Join(\"a\", bytes.Select(x => x.ToString()).ToArray());\n\n\nYou will have string representation of bytes with char separator. To convert back you will need to split, and convert the string[] to byte[] using the same approach with .Select().",


C.Evenhuis 2011-09-13T08:09:07

Usually a power of 2 is used - that way one character maps to a fixed number of bits. An alphabet of 32 bits for instance would map to 5 bits. The only challenge in that case is how to deserialize variable-length strings.\n\nFor 36 bits you could treat the data as a large number, and then:\n\n\ndivide by 36\nadd the remainder as character to your result \nrepeat until the division results in 0\n\n\nEasier said than done perhaps.",


Jon 2011-09-13T08:14:51

I adapted my arbitrary-length base conversion function from this answer to C#:\n\nstatic string BaseConvert(string number, int fromBase, int toBase)\n{\n var digits = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n var length = number.Length;\n var result = string.Empty;\n\n var nibbles = number.Select(c => digits.IndexOf(c)).ToList();\n int newlen;\n do {\n var value = 0;\n newlen = 0;\n\n for (var i = 0; i < length; ++i) {\n value = value * fromBase + nibbles[i];\n if (value >= toBase) {\n if (newlen == nibbles.Count) {\n nibbles.Add(0);\n }\n nibbles[newlen++] = value / toBase;\n value %= toBase;\n }\n else if (newlen > 0) {\n if (newlen == nibbles.Count) {\n nibbles.Add(0);\n }\n nibbles[newlen++] = 0;\n }\n }\n length = newlen;\n result = digits[value] + result; //\n }\n while (newlen != 0);\n\n return result;\n}\n\n\nAs it's coming from PHP it might not be too idiomatic C#, there are also no parameter validity checks. However, you can feed it a hex-encoded string and it will work just fine with\n\nvar result = BaseConvert(hexEncoded, 16, 36);\n\n\nIt's not exactly what you asked for, but encoding the byte[] into hex is trivial.\n\nSee it in action.",


kornman00 2012-12-29T05:37:05

Earlier tonight I came across a codereview question revolving around the same algorithm being discussed here. See: https://codereview.stackexchange.com/questions/14084/base-36-encoding-of-a-byte-array/\n\nI provided a improved implementation of one of its earlier answers (both use BigInteger). See: https://codereview.stackexchange.com/a/20014/20654. The solution takes a byte[] and returns a Base36 string. Both the original and mine include simple benchmark information.\n\nFor completeness, the following is the method to decode a byte[] from an string. I'll include the encode function from the link above as well. See the text after this code block for some simple benchmark info for decoding.\n\nconst int kByteBitCount= 8; // number of bits in a byte\n// constants that we use in FromBase36String and ToBase36String\nconst string kBase36Digits= \"0123456789abcdefghijklmnopqrstuvwxyz\";\nstatic readonly double kBase36CharsLengthDivisor= Math.Log(kBase36Digits.Length, 2);\nstatic readonly BigInteger kBigInt36= new BigInteger(36);\n\n// assumes the input 'chars' is in big-endian ordering, MSB->LSB\nstatic byte[] FromBase36String(string chars)\n{\n var bi= new BigInteger();\n for (int x= 0; x < chars.Length; x++)\n {\n int i= kBase36Digits.IndexOf(chars[x]);\n if (i < 0) return null; // invalid character\n bi *= kBigInt36;\n bi += i;\n }\n\n return bi.ToByteArray();\n}\n\n// characters returned are in big-endian ordering, MSB->LSB\nstatic string ToBase36String(byte[] bytes)\n{\n // Estimate the result's length so we don't waste time realloc'ing\n int result_length= (int)\n Math.Ceiling(bytes.Length * kByteBitCount / kBase36CharsLengthDivisor);\n // We use a List so we don't have to CopyTo a StringBuilder's characters\n // to a char[], only to then Array.Reverse it later\n var result= new System.Collections.Generic.List<char>(result_length);\n\n var dividend= new BigInteger(bytes);\n // IsZero's computation is less complex than evaluating \"dividend > 0\"\n // which invokes BigInteger.CompareTo(BigInteger)\n while (!dividend.IsZero)\n {\n BigInteger remainder;\n dividend= BigInteger.DivRem(dividend, kBigInt36, out remainder);\n int digit_index= Math.Abs((int)remainder);\n result.Add(kBase36Digits[digit_index]);\n }\n\n // orientate the characters in big-endian ordering\n result.Reverse();\n // ToArray will also trim the excess chars used in length prediction\n return new string(result.ToArray());\n}\n\n\n\"A test 1234. Made slightly larger!\" encodes to Base64 as \"165kkoorqxin775ct82ist5ysteekll7kaqlcnnu6mfe7ag7e63b5\"\n\nTo decode that Base36 string 1,000,000 times takes 12.6558909 seconds on my machine (I used the same build and machine conditions as provided in my answer on codereview)\n\nYou mentioned that you were dealing with a byte[] for the MD5 hash, rather than a hexadecimal string representation of it, so I think this solution provide the least overhead for you.",


More about “How to convert a byte array (MD5 hash) into a string (36 chars)?” related questions

How to convert a byte array (MD5 hash) into a string (36 chars)?

I've got a byte array that was created using a hash function. I would like to convert this array into a string. So far so good, it will give me hexadecimal string. Now I would like to use something

Show Detail

Convert Base64 encoded md5 to a readable String

I have a password stored in ldap as md5 hash: {MD5}3CydFlqyl/4AB5cY5ZmdEA== By the looks of it, it's base64 encoded. How can i convert byte array received from ldap to a nice readable md5-hash-style

Show Detail

Convert an byte array to MD5 Hash in react native

I have a system in C# which receives a password and this password is encrypted into a MD5 Hash using this function. I had read a lot of posts and suggestion, but I couldn't create the MD5 byte arra...

Show Detail

How to Convert md5 hash to a string?

How to convert Md5Hash values to string.. i have convert string values to hash.. i have used the to method to convert MD5Hash to string ` public static string ConvertStringtoMD5(string strword) ...

Show Detail

Converting a md5 hash byte array to a string

How can I convert the hashed result, which is a byte array, to a string? byte[] bytePassword = Encoding.UTF8.GetBytes(password); using (MD5 md5 = MD5.Create()) { byte[] byteHashedPassword = md5.

Show Detail

md5 hash or crc32 which one to use in this case

I need a hash that can be represented in less than 26 chars Md5 produces 32 chars long string , if convert it to base 36 how good will it be, I am need of hash not for cryptography but rather for

Show Detail

Java: convert byte[] to base36 String

I'm a bit lost. For a project, I need to convert the output of a hash-function (SHA256) - which is a byte array - to a String using base 36. So In the end, I want to convert the (Hex-String

Show Detail

How to send MD5 hash of empty byte array?

I need to send a request from PHP to a C# WEB API. As part of the authentication it requires an MD5 hash of an empty byte array. How can I generate an MD5 hash of an empty byte array on PHP? I wou...

Show Detail

How to turn a MD5 Hash to a String?

I want to turn an MD5 Hash to a string: public String MD5ToString(String plain) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(plain.

Show Detail

Random generated string to md5 hash

I created a random string. First, I'd like to display the string and after that, I'd like to convert it to a MD5 hash. Can someone help me? I tried a lot but I can't get the right solution. Here i...

Show Detail