Created
February 24, 2022 03:30
-
-
Save xjoker/ea48535adadc32749a7b63bec84b8815 to your computer and use it in GitHub Desktop.
MD5算法逻辑学习
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
namespace ConsoleApp11 | |
{ | |
internal class Program | |
{ | |
private static uint A = 0x67452301; | |
private static uint B = 0xefcdab89; | |
private static uint C = 0x98badcfe; | |
private static uint D = 0x10325476; | |
// 基础 S 表,每一轮的位移数量 | |
private static readonly int[] STable = new int[64] | |
{ | |
0x07, 0x0c, 0x11, 0x16,0x07, 0x0c, 0x11, 0x16,0x07, 0x0c, 0x11, 0x16,0x07, 0x0c, 0x11, 0x16, | |
0x05, 0x09, 0x0e, 0x14,0x05, 0x09, 0x0e, 0x14,0x05, 0x09, 0x0e, 0x14,0x05, 0x09, 0x0e, 0x14, | |
0x04, 0x0b, 0x10, 0x17,0x04, 0x0b, 0x10, 0x17,0x04, 0x0b, 0x10, 0x17,0x04, 0x0b, 0x10, 0x17, | |
0x06, 0x0a, 0x0f, 0x15,0x06, 0x0a, 0x0f, 0x15,0x06, 0x0a, 0x0f, 0x15,0x06, 0x0a, 0x0f, 0x15, | |
}; | |
private static readonly List<uint> TTable = new(); | |
private static void Main() | |
{ | |
string testStr = "The quick brown fox jumps over the lazy dog"; | |
// 初始化 T 表 总计64个 | |
for (int i = 1; i < 65; i++) | |
{ | |
// floor(2^32 × abs (sin(i + 1))) | |
var v = Math.Abs(Math.Sin(i)) * Math.Pow(2, 32); | |
TTable.Add((uint)v); | |
} | |
// 输入字符串转为Byte | |
var inValue = Encoding.UTF8.GetBytes(testStr).ToArray(); | |
// 输入的长度 | |
long inValueLength = inValue.Length; | |
// 将数据按照64byte(512bit)拆分 | |
int startIndex = 0; | |
while (startIndex <= inValueLength - 64) | |
{ | |
byte[] working = new byte[64]; | |
Array.Copy(inValue, startIndex, working, 0, 64); | |
GetHashBlock(working); | |
startIndex += 64; | |
} | |
// 最终方法处理剩余小于64位的数据 | |
var output = GetHashFinalBlock(inValue, startIndex, inValueLength); | |
string result = BitConverter.ToString(output).Replace("-", string.Empty); | |
Console.WriteLine(result.ToLower() == "9e107d9d372bb6826bd81d3542a419d6" ? "Success" : "Error"); | |
Console.ReadLine(); | |
} | |
/// <summary> | |
/// 计算最终的块 | |
/// </summary> | |
/// <param name="inValue"></param> | |
/// <param name="startIndex"></param> | |
/// <param name="len"></param> | |
/// <returns></returns> | |
private static byte[] GetHashFinalBlock(byte[] inValue, int startIndex, long len) | |
{ | |
byte[] working = new byte[64]; | |
byte[] length = BitConverter.GetBytes(len * 8);//转换为bit | |
int leftSize = inValue.Length - startIndex;//剩余长度 | |
//拷贝到暂存byte | |
Array.Copy(inValue, startIndex, working, 0, leftSize); | |
// 数据末尾增加 1bit | |
// 0x80 = 10000000 HEX | |
working[leftSize] = 0x80; | |
// 如果长度小于56,则足够在末尾存储长度 | |
if (leftSize < 56) | |
{ | |
// 将长度填充到末尾,64位的末尾8位作为长度存储 | |
// C#中需要将长度转为 long | |
Array.Copy(length, 0, working, 56, 8); | |
GetHashBlock(working); | |
} | |
else//如果剩余长度大于56,则需要填充新区块来存储长度 | |
{ | |
GetHashBlock(working); | |
//清空working | |
working = new byte[64]; | |
// 将长度填充到末尾,64位的末尾8位作为长度存储 | |
Array.Copy(length, 0, working, 56, 8); | |
GetHashBlock(working); | |
} | |
// 组合A B C D 的结果输出 | |
byte[] output = new byte[16]; | |
Array.Copy(BitConverter.GetBytes(A), 0, output, 0, 4); | |
Array.Copy(BitConverter.GetBytes(B), 0, output, 4, 4); | |
Array.Copy(BitConverter.GetBytes(C), 0, output, 8, 4); | |
Array.Copy(BitConverter.GetBytes(D), 0, output, 12, 4); | |
return output; | |
} | |
/// <summary> | |
/// 块计算 | |
/// </summary> | |
/// <param name="inValue"></param> | |
private static void GetHashBlock(byte[] inValue) | |
{ | |
var v1 = A; | |
var v2 = B; | |
var v3 = C; | |
var v4 = D; | |
// 转换为uint | |
uint[] result = new uint[16]; | |
for (int i = 0; i < 16; i++) | |
{ | |
result[i] = (uint)inValue[i * 4 + 0] << 0; | |
result[i] += (uint)inValue[i * 4 + 1] << 8; | |
result[i] += (uint)inValue[i * 4 + 2] << 16; | |
result[i] += (uint)inValue[i * 4 + 3] << 24; | |
} | |
for (int i = 0; i < 64; i++) | |
{ | |
v1 = Round(v1, v2, v3, v4, result, STable[i], TTable[i], i); | |
i++; | |
v4 = Round(v4, v1, v2, v3, result, STable[i], TTable[i], i); | |
i++; | |
v3 = Round(v3, v4, v1, v2, result, STable[i], TTable[i], i); | |
i++; | |
v2 = Round(v2, v3, v4, v1, result, STable[i], TTable[i], i); | |
} | |
A = unchecked(v1 + A); | |
B = unchecked(v2 + B); | |
C = unchecked(v3 + C); | |
D = unchecked(v4 + D); | |
} | |
/// <summary> | |
/// 线性函数计算 | |
/// </summary> | |
/// <param name="a">魔数A</param> | |
/// <param name="b">魔数B</param> | |
/// <param name="c">魔数C</param> | |
/// <param name="d">魔数D</param> | |
/// <param name="xArray">16个待处理对象</param> | |
/// <param name="s">s表内数字</param> | |
/// <param name="t">t表内数字</param> | |
/// <param name="round">循环次数</param> | |
/// <returns></returns> | |
private static uint Round(uint a, uint b, uint c, uint d, uint[] xArray, int s, uint t, int round) | |
{ | |
if (round < 16) | |
return unchecked(b + LeftRotate((a + ((b & c) | ((b ^ 0xFFFFFFFF) & d)) + xArray[round] + t), s)); | |
if (round < 32) | |
return unchecked(b + LeftRotate((a + ((b & d) | (c & (d ^ 0xFFFFFFFF))) + xArray[(5 * round + 1) % 16] + t), s)); | |
if (round < 48) | |
return unchecked(b + LeftRotate((a + (b ^ c ^ d) + xArray[(3 * round + 5) % 16] + t), s)); | |
return unchecked(b + LeftRotate((a + (c ^ (b | (d ^ 0xFFFFFFFF))) + xArray[(7 * round) % 16] + t), s)); | |
} | |
/// <summary> | |
/// 左旋转 | |
/// </summary> | |
/// <param name="i"></param> | |
/// <param name="s"></param> | |
/// <returns></returns> | |
private static uint LeftRotate(uint i, int s) | |
{ | |
/* | |
* 假设 i = 100 s=2 | |
* | |
* (i << s) | |
* 100 的二进制 0110 0100 | |
* 左移 2 位,相当于末尾补2个0 | |
* 0001 1001 0000 | |
* | |
* (i >> (32 - s)) | |
* | |
* 32-2=30 | |
* 100 右移 30位 | |
* 结果直接为0 | |
* | |
* 400 -> 0001 1001 0000 | |
* 0 -> 0000 0000 0000 | |
* 或运算后 | |
* 0001 1001 0000 | |
* | |
* 结果400 | |
* | |
*/ | |
return ((i << s) | (i >> (32 - s))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment