C#: How to generate short MD5 code?
Solution 1
I like @RichieHindle's answer. However, if you're interested in losing fewer bits of fidelity (and thereby decreasing the risk of collisions), you could take the 128 bit value returned by the MD5 Hash, and encode it using ASCII85 (also known as Base85 encoding), instead of a hexadecimal-based encoding. This will give you the whole hash in 20 bytes (which is more than you wanted, but you could chop 2 bytes off, resulting in much less loss than removing 14 of the 32 bytes you'd get using hex encoding).
Edit: Prashant says 20 characters is close enough, and asked for sample code:
After obtaining the MD5 hash from the MD5.ComputeHash call, you can use Jeff Atwood's ASCII85 encoder:
MD5 m = MD5.Create();
byte[] hash = m.ComputeHash(System.Text.Encoding.ASCII.GetBytes("23"));
Ascii85 encoder = new Ascii85();
encoder.EnforceMarks = false;
string hash85 = encoder.Encode(hash);
Console.Out.WriteLine(hash85);
Yields
2ebDPFFZsD?&,r1fX\$,
so you can just use hash85
. The encoder.EnforceMarks
makes sure that the encoding doesn't include some typical prefix and suffixes that are associated with ASCII85.
Solution 2
You can just take as much of the MD5 hash as you need, and throw the rest away. All the bits have equal value, so there's no difference between doing that and using some hashing algorithm that natively produces fewer bits.
(If you're doing this for security reasons, remember that fewer bits makes hashes easier to crack, regardless of the algorithm. Even outside of security applications, fewer bits increase the risk of collisions. Also bear in mind that MD5 is relative insecure these days - SHA-1 or SHA-2 are considered more secure.)
Solution 3
MD5 always creates a 128 Bit Hash.
Other smaller Hashtypes (taken from Wikipedia)
Fowler-Noll-Vo hash function (32, 64, 128, 256, 512, or 1024 bits)
Jenkins hash function (32 bits)
MurmurHash (32 or 64 bits)
Pearson hashing (8 bits)
But remember hash collisions
Solution 4
I wouldn't use a hash function if you want to be able to map the result back to its original value without collisions.
If your aim is to turn a small decimal number into a long obfuscated string, just invent some mapping algorithm and encode the result with zBase32 or similar.
public string Obfuscate(long x)
{
return ToZBase32(BitConverter.GetBytes(x * 63498398L));
}
public long Deobfuscate(string x)
{
return BitConverter.ToInt64(FromZBase32(x)) / 63498398L;
}
23
gets encoded to "gmuyaiayyyyyy"
. (63498398 chosen by fair dice roll.)
Solution 5
Use FVNHash - http://www.codeproject.com/KB/security/FnvHash.aspx
You can set the length of your hash, do not use it for security reasons.
Comments
-
djmzfKnm almost 2 years
When I am encrypting
23
using MD5 encryption I am getting37693cfc748049e45d87b8c7d8b9aacd
this 32-character long string which will always be static for 23.I want the same kind of mechanism but that should generate 18 or less (like:
122ff1e4883358b6
) characters long string instead 32.How I can do that in C#, is there any shorter version of MD5 in c#??
-
Michael Madsen almost 15 yearsMD5 is not encryption, it is a hashing algorithm. There is a big difference between the two; most importantly, hashing cannot be reversed, unlike encryption, because multiple inputs will give the same output.
-
Marc Stober almost 15 yearsHi, Prashant. I see your new comment about using the string in a URL. I can think of a few approaches to make this work again, but maybe we'd be able to give an answer that fits your problem if you expanded on what kinds of inputs you expect to have, exactly why you're making an MD5 hash, and what you want to accomplish with the URL in the end. That way we can short-circuit any objections you may have with new solutions, or maybe even just suggest another approach, like @tvanfosson's Perfect Hash Function idea.
-
djmzfKnm over 14 yearsHi @Blair: Actually there is nothing special in making URL's like this, I am just inspired by GMAIL message URL's they are making them like:
http://mail.google.com/mail/?shva=1#inbox/14461a1185905642
and this is good because on logged in user can view there messages, in the same way in my app also only logged in users are allowed to perform any activity. So instead of giving URL like:http://examle.com/mail/18/
I wantto make them likehttp://examle.com/mail/14461a1185905642/
. -
djmzfKnm over 14 years... That's why I require some good of encryption function or technique which will not fail in any way and will produce output like google doing, no special chars only numbers and letters.
-
-
Feidex almost 15 yearsSHA-1 creates a 160 Bit hash.
-
Thomas Owens almost 15 yearsWouldn't this increase the chances of collision, though? I'm not expert in cryptography, but it just seems like a bad idea to be throwing away portions of a hash and still expect it to maintain its properties.
-
djmzfKnm almost 15 yearsI thought the same, just fetch first 18 chars from MD5
37693cfc748049e45d87b8c7d8b9aacd
but can't the fist 18 characters in an MD5 be the same for other string?? -
mmx almost 15 yearsThomas: Well, it will happen in any case. A shorter hash inherently has a higher chance for collisions.
-
Thomas Owens almost 15 yearsMehrdad: Yes, MD5 has collisions, but I still think it's sufficient for non-critical passwords, file duplicate verification, etc. The only thing you don't want to do is increase the collisions by taking subsets of the output, since that's making a known problem even more visible.
-
tvanfosson almost 15 yearsIf the values are always smaller than the hash size, you can easily create a hash that won't have collisions. Collisions are only inherent when the size of the data is larger than the size of the hash because then every possible input cannot map one-to-one onto a different hash value.
-
Anwar Chandra almost 15 yearsbecause MD5 is one-way hash algorithm, we don't need to consider how to 'unhash' it back. But the problem is: how to make sure that the first 18 character always unique?
-
tvanfosson almost 15 yearsOverflow? Might want to convert to a long (or if they're always positive, to unsigned) or you will either lose some range or have some mis-mapped values.
-
Nick Johnson almost 15 yearsYou can't make it always unique - it's a hash, by definition it has collisions. The shorter you make it, the more likely a collision is.
-
djmzfKnm almost 15 yearsOk, this is fine, but the output contains special chars (? , & etc) but I want to pass this has string in URL as parameter so that on the next page I can decrypt it and show the output to the user, something like gmail is doing
mail.google.com/mail/?zx=1xjighs8u7ewc&shva=1#inbox/1230e772c539f5e3
. If I'll pass ? or & in url then that will create problem. Can't we remove the special chars from final output to generate output something like "1230f774c459b5f3" (without special characters ??