Monday, 3. November 2008 23:37
Creating MD5 hashes of strings can be useful for example when storing passwords. There is only one gotcha when trying to store the generated MD5 hash to a text file. During conversion from an MD5 hash, which is a byte array, to a string some crucial information might get lost.
Check out the following example, it will create an MD5 hash of a string and then display the hash as a hex value:
$inputString1 = “Hello World”
$inputString2 = “PowerShell is kinda cool
”
$cryptoServiceProvider = [System.Security.Cryptography.MD5CryptoServiceProvider];
$hashAlgorithm = new-object $cryptoServiceProvider
$hashByteArray1 = $hashAlgorithm.ComputeHash($([Char[]]$inputString1));
$hashByteArray2 = $hashAlgorithm.ComputeHash($([Char[]]$inputString2));
foreach ($byte in $hashByteArray1) { $result1 += “{0:X}” -f $byte }
foreach ($byte in $hashByteArray2) { $result2 += “{0:X}” -f $byte }
Write-Host $result1
Write-Host $result2
When you run the script above you will see that is has generated two MD5 hashes with different lengths:
B1A8DB164E075415B7A99BE72E3FE5
D7E0714B5CE93382EBDD80E02C375
As long as you keep comparing the MD5 hashes using the same script, you will probably never run into any problems. However, when you want to compare these hashes to MD5 hashes generated by another tool you will definitely get false negatives and you may even get false positives (oops).
A simple solution to this problem is shown below:
$inputString1 = “Hello World”
$inputString2 = “PowerShell is kinda cool
”
$cryptoServiceProvider = [System.Security.Cryptography.MD5CryptoServiceProvider];
$hashAlgorithm = new-object $cryptoServiceProvider
$hashByteArray1 = $hashAlgorithm.ComputeHash($([Char[]]$inputString1));
$hashByteArray2 = $hashAlgorithm.ComputeHash($([Char[]]$inputString2));
foreach ($byte in $hashByteArray1) { if ($byte -lt 16) {$result1 += “0{0:X}” -f $byte } else { $result1 += “{0:X}” -f $byte }}
foreach ($byte in $hashByteArray2) { if ($byte -lt 16) {$result2 += “0{0:X}” -f $byte } else { $result2 += “{0:X}” -f $byte }}
Write-Host $result1
Write-Host $result2
This script adds a “0″ in front of each byte with a value less than 16 (0x0F). The result is:
B10A8DB164E0754105B7A99BE72E3FE5
D7E0714B5CE933820EBD0D80E002C375
As you can see, this second script result in two MD5 hashes of equal length. When comparing the first script(blue) to the second(red) it becomes more clear:
D7 E0 71 4B 5C E9 33 82 E BD D 80 E0 2 C3 75
D7 E0 71 4B 5C E9 33 82 0E BD 0D 80 E0 02 C3 75
B1 A 8D B1 64 E0 75 41 5 B7 A9 9B E7 2E 3F E5
B1 0A 8D B1 64 E0 75 41 05 B7 A9 9B E7 2E 3F E5
UPDATE (Thanks Arnout):
$inputString1 = “Hello World”
$inputString2 = “PowerShell is kinda cool
”
$cryptoServiceProvider = [System.Security.Cryptography.MD5CryptoServiceProvider];
$hashAlgorithm = new-object $cryptoServiceProvider
$hashByteArray1 = $hashAlgorithm.ComputeHash([Char[]]$inputString1);
$hashByteArray2 = $hashAlgorithm.ComputeHash([Char[]]$inputString2);
foreach ($byte in $hashByteArray1) { $result1 += “{0:X2}” -f $byte}
foreach ($byte in $hashByteArray2) { $result2 += “{0:X2}” -f $byte }
Write-Host $result1
Write-Host $result2