我正在尝试在C#中编写自己的MD5哈希算法实现。我已经得到了我的算法来生成哈希,但它与我期望的那个不匹配。例如,当我散列字符串“test”时:
ff9dc1ed49568b10c3c6e09053ea4317 -- my implementation's result
098f6bcd4621d373cade4e832627b4f6 -- expected result
我的代码如下:
public class general
{
public static string numToBinary(int charCode, int idealLength)
{
string toReturn = Convert.ToString(charCode, 2);
int numAdd = idealLength - toReturn.Length;
for (int i = 0; i < numAdd; i++)
{
toReturn = "0" + toReturn;
}
return toReturn;
}
public static string padZero(string str, int numZeroes)
{
for (int i = 0; i < numZeroes; i++)
{
str += "0";
}
return str;
}
public static string padZeroLeft(string str, int numZeroes)
{
string reversed = (string)str.Reverse();
reversed = padZero(reversed, numZeroes);
return (string)reversed.Reverse();
}
public static string[] getChunks(string totalString, int chunkLength)
{
int numOfChunks;
numOfChunks = totalString.Length / chunkLength;
string[] chunks = new string[numOfChunks]; //Create a new array to hold the chunks
string currentChunk;
for (int i = 1; i <= numOfChunks; i++)
{
currentChunk = totalString.Substring(i * chunkLength - (chunkLength), chunkLength);
chunks[i - 1] = currentChunk;
}
return chunks;
}
public static uint F(uint nB, uint nC, uint nD)
{
uint toReturn = (nB & nC) | ((~nB) & nD);
return toReturn;
}
public static uint G(uint nB, uint nC, uint nD)
{
uint toReturn = (nD & nB) | ((~nD) & nC);
return toReturn;
}
public static uint H(uint nB, uint nC, uint nD)
{
uint toReturn = (nB ^ nC ^ nD);
return toReturn;
}
public static uint I(uint nB, uint nC, uint nD)
{
uint toReturn = nC ^ (nB | (~nD));
return toReturn;
}
public static uint circularLeftShift(uint original, int shiftAmount) //Bitwise circular left shift
{
uint newNum = (original << shiftAmount) | (original >> (32 - shiftAmount));
return newNum;
}
public static string makeUniformLength(string bits, int length)
{
int toAdd = length - bits.Length;
bits = reverseString(bits);
bits = padZero(bits, toAdd);
bits = reverseString(bits);
return bits;
}
public static string reverseString(string str)
{
char[] chars = str.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}
class Program
{
static void Main(string[] args)
{
int[] s = { //Create array to specify per-round shift amounts
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
};
uint[] k = new uint[64]; //Create array with 64 unsigned integers
Console.Write("Please enter a string to hash: ");
string message;
message = Console.ReadLine();
string msgFinal = "";
byte[] messageBytes;
messageBytes = Encoding.ASCII.GetBytes(message);
for (int i = 0; i < messageBytes.Length; i++) //Form string for all the values
{
msgFinal = msgFinal + general.numToBinary(messageBytes[i], 8);
}
//Console.WriteLine(msgFinal);
for (int i = 0; i < 64; i++)
{
k[i] = (uint)Math.Floor(Math.Pow(2, 32) * Math.Abs(Math.Sin(i + 1)));
Console.Write(Convert.ToString(k[i], 16) + "; ");
}
uint a0 = 0x67452301;
uint b0 = 0xefcdab89;
uint c0 = 0x98badcfe;
uint d0 = 0x10325476;
msgFinal += "1"; //Append 1 to the message
int over448 = (msgFinal.Length) % 448;
int zeroesToAdd = 448 - over448;
msgFinal = general.padZero(msgFinal, zeroesToAdd); // Pad the end of the message with enough zeroes to bring it to a multiple of 448
Console.WriteLine("len: " + msgFinal.Length);
int originalLength = message.Length * 8;
//ulong toAdd = (ulong)originalLength % ()Math.Pow(2, 64);
uint toAdd = (uint)originalLength;
string toAddStr = Convert.ToString(toAdd, 2);
Console.WriteLine("existing length: " + toAddStr.Length);
Console.WriteLine("adding: " + (64 - toAddStr.Length));
string toAddSecondary = general.padZero("", 64 - toAddStr.Length);
toAddStr = toAddSecondary + toAddStr;
Console.WriteLine(toAddStr);
Console.WriteLine("Length of toadd: " + toAddStr.Length);
msgFinal += toAddStr;
string[] msgChunks = general.getChunks(msgFinal, 512);
string[] subChunks;
uint A, B, C, D;
uint dTemp;
uint F = 0;
uint g = 0;
Console.WriteLine(msgFinal);
Console.WriteLine(msgFinal.Length);
foreach (string chunk in msgChunks)
{
subChunks = general.getChunks(chunk, 32);
A = a0;
B = b0;
C = c0;
D = d0;
for (int i = 0; i < 64; i++)
{
if (i >= 0 && i <= 15) {
F = general.F(B, C, D);
g = (uint)i;
} else if (i >= 16 && i <= 31)
{
F = general.G(B, C, D);
g = (uint)((5 * i + 1) % 16);
} else if (i >= 32 && i <= 47)
{
F = general.H(B, C, D);
g = (uint)((3 * i + 5) % 16);
} else if (i >= 48 && i <= 63)
{
F = general.I(B, C, D);
g = (uint)((7 * i) % 16);
}
dTemp = D;
D = C;
C = B;
B = B + general.circularLeftShift((A + F + k[i] + Convert.ToUInt32(subChunks[g], 2)), s[i]);
A = dTemp;
}
a0 = a0 + A;
b0 = b0 + B;
c0 = c0 + C;
d0 = d0 + D;
}
string aF, bF, cF, dF;
aF = Convert.ToString(a0, 16);
bF = Convert.ToString(b0, 16);
cF = Convert.ToString(c0, 16);
dF = Convert.ToString(d0, 16);
string final = aF + bF + cF + dF;
Console.WriteLine(final);
Console.ReadLine();
}
}