Skip to content

Instantly share code, notes, and snippets.

@xjoker
Created February 24, 2022 03:30
Show Gist options
  • Save xjoker/ea48535adadc32749a7b63bec84b8815 to your computer and use it in GitHub Desktop.
Save xjoker/ea48535adadc32749a7b63bec84b8815 to your computer and use it in GitHub Desktop.
MD5算法逻辑学习
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