开发者

Is there a hash algorithm that produces a hash size of 64 bits in C#?

I need to produce a Hash value based off of a variable length string that I can store within a field no longer than 16 (due to vendor requirements).

I am concatenating together several strings that are being passed through a C# script transformation in order to calculate the Hash. I am constrained by the vendor's file specification in that the ou开发者_如何学编程tput of the hash cannot be any longer than 16 characters.

Does anyone have any suggestions? As an example the string conversion of the MD5 algorithm (128-bits) has a hex-encoded length of 32 characters.


The cryptographic has functions are designed such that you may truncate the output to some size and the truncated hash function remains a secure cryptographic hash function. For example, if you take the first 128 bits (16 bytes) of the output of SHA-512 applied to some input, then the first 128 bits are a cryptographic hash as strong as any other 128-bits cryptographic hash.

The solution is to choose some cryptographic hash function - SHA-256, SHA-384, and SHA-512 are good choices - and truncate the output to 128 bits (16 bytes).

--EDIT--

Based on the comment that the hash value must, when encoded to ASCII, fit within 16 ASCI characters, the solution is

  • first, to choose some cryptographic hash function (the SHA-2 family includes SHA-256, SHA-384, and SHA-512)
  • then, to truncate the output of the chosen hash function to 96 bits (12 bytes) - that is, keep the first 12 bytes of the hash function output and discard the remaining bytes
  • then, to base-64-encode the truncated output to 16 ASCII characters (128 bits)
  • yielding effectively a 96-bit-strong cryptographic hash.


You can easily use an MD5 hash for this, but you will have to alter the way it is stored. An MD5 is 128-bits, which is typically displayed as 32 4-bit (hexadecimal) values. A standard char is 8 bits, however, so 16 characters is exactly enough to store the value of an MD5 hash.

To convert it, try the following:

String hash32 = "d41d8cd98f00b204e9800998ecf8427e"
String hash16 = ""

for(int i = 0; i < 32; i+=2)
{
  uint high = Convert.ToUInt32(hash32[i], 16);
  uint low = Convert.ToUInt32(hash32[i+1], 16);
  char c = (char) ((high << 4) | low);

  hash16 += c;
}


Any comments about this code? Seems works well...

var p = new MD5CryptoServiceProvider();
var dic = new Dictionary<long, string>();

for (var i = 0; i < 10000000; i++)
{
    if (i%25000 == 0)
        Console.WriteLine("{0:n0}", i);

    var h = p.ComputeHash(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
    var b = BitConverter.ToInt64(h, 0);

    // "b" is hashed Int64

    if (!dic.ContainsKey(b))
        dic.Add(i, null);
    else
        throw new Exception("Oops!");
}


I've noticed this question is relatively old, but I'm sure someone will find this answer to it valuable.

My suggestion would be to use Blake2b which has the ability to use 8 bit through 512 bits. If no key size is used, the default value is used "512" in this case. Blake2s default value 256 bits.

        // BLAKE2b
        // using System.Data.HashFunction;
        //
        // String message to use.
        string str = "The quick brown fox jumps over the lazy dog";
        // Initialize
        System.Data.HashFunction.Blake2B Blake2B = new System.Data.HashFunction.Blake2B();
        // Get string hash bytes; create 64 bit hash.
        var HashBytes = Blake2B.ComputeHash(str, 64);
        // Convert bytes to string and remove the dashes.
        string hexString = BitConverter.ToString(HashBytes).Replace("-", string.Empty);
        // Display results.
        MessageBox.Show(hexString);
        /*
         * "The quick brown fox jumps over the lazy dog" produces a hash value of
         * "A8ADD4BDDDFD93E4877D2746E62817B116364A1FA7BC148D95090BC7333B3673F82401CF7AA2E4CB1ECD90296E3F14CB5413F8ED77BE73045B13914CDCD6A918"
         * and "2FD0F3FB3BD58455" hash for 64 bits.
         */

Hope this helps!


If you have 16 bytes storing a 128bit number is not an issue. Store the 128bit value as a 16byte value instead of a 32 character string that stored the 16 byte value as HEX.

As a note I have used GUID/UUID fields in databases to store MD5 hashes. While no longer cryptographically secure, 128bit MD5 hashes are fine for Checksums (and is much better than 64 bits.)

var result = MD5.Create().ComputeHash(new byte[] { 0 });

Console.WriteLine(result.Length);
Console.WriteLine(Convert.ToBase64String(result));
Console.WriteLine(result.Aggregate(new StringBuilder(),
                                    (sb, v) => sb.Append(v.ToString("x2"))));

//16
//k7iFrf4NoInN9jSQT9WfcQ==
//93b885adfe0da089cdf634904fd59f71

File.WriteAllBytes("tempfile.dat", result);

var input = File.ReadAllBytes("tempfile.dat");

Console.WriteLine(input.Length);
Console.WriteLine(Convert.ToBase64String(input));
Console.WriteLine(input.Aggregate(new StringBuilder(), 
                                    (sb, v) => sb.Append(v.ToString("x2"))));

//16
//k7iFrf4NoInN9jSQT9WfcQ==
//93b885adfe0da089cdf634904fd59f71

Note that I don't show the file content because there is a good chance that it will contain "unprintable" characters.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜