网络安全 | C语言实现MD5信息摘要算法

算法不难,只是要注意大端小端,以及使用合适的数据结构。很久没用过C语言了,网上有一篇花式位运算的,我实在学不来,不过合理使用unsigned int (32位)和 unsigned char(8位)还是能方便很多的,还有就是#define 常量的用处(比如#define F(b, c, d) ((b & c) | (~b & d))),之前没这么运用过,发现还挺好用的。


MD5概述

MD5 即 Message-Digest Algorithm 5 (信息-摘要算法 5)

  • MD4 (1990)、MD5(1992, RFC 1321) 由 Ron Rivest 发明,是广泛 使用的 Hash 算法,用于确保信息传输的完整性和一致性。

  • MD5 使用 little-endian (小端模式),输入任意不定长度信息,以 512-bit 进行分组,生成四个32-bit 数据,最后联合输出固定 128-bit 的信息摘要。

  • MD5 算法的基本过程为:填充、分块、缓冲区初始化、循环压 缩、得出结果。

  • MD5 不是足够安全的。 Hans Dobbertin 在1996年找到了两个不同的 512-bit 块,它们 在 MD5 计算下产生相同的 hash 值。

    至今还没有真正找到两个不同的消息,它们的 MD5 的 hash 值相等。


MD5基本流程

网络安全 | C语言实现MD5信息摘要算法_第1张图片

网络安全 | C语言实现MD5信息摘要算法_第2张图片


算法逻辑

填充 padding
  • 在长度为 K bits 的原始消息数据尾部填充长度为 P bits 的标识
    100…0,1≤P≤ 512 (即至少要填充1个bit),使得填充后的消息位
    数为:K + P = 448 (mod 512).
  • 再向上述填充好的消息尾部附加 K 值的低64位 (即 K mod 264),
    最后得到一个长度位数为 K + P + 64 = 0 (mod 512) 的消息。(注意,长度位数需是8的倍数,不足就补0,得到这个长度之后,直接加在后面,剩下的位数都是0,具体可以参考MD5填充时的算法)
分块

把填充后的消息结果分割为 L 个 512-bit 分组:Y0, Y1, …, YL-1。
分组结果也可表示成 N 个32-bit 字 M0, M1, …, MN-1,N = L*16。

初始化

初始化一个128-bit 的 MD 缓冲区,记为 CVq,表示成4个32-bit寄存器 (A, B, C, D);CV0 = IV。迭代在 MD 缓冲区进行,最后一步的128-bit 输出即为算法结果。

寄存器 (A, B, C, D) 置16进制初值作为初始向量 IV,并采用小端存储 (little-endian) 的存储结构:
• A = 0x67452301
• B = 0xEFCDAB89
• C = 0x98BADCFE
• D = 0x10325476
网络安全 | C语言实现MD5信息摘要算法_第3张图片

Little-Endian 将低位字节排放在内存的低地址端,高位字节 排放在内存的高地址端。相反 Big-Endian 将高位字节排放
在内存的低地址端,低位字节排放在内存的高地址端。存 储结构与 CPU 体系结构和语言编译器有关。PowerPC 系列 采用 Big
Endian 方式存储数据,而 Intel x86系列则采用 Little Endian 方式存储。

总控流程

以512-bit 消息分组为单位,每一分组 Yq (q = 0, 1, …, L-1) 经过4
个循环的压缩算法,表示为:
CV0 = IV
CVi = HMD5(CVi-1 , Yi)
输出结果:MD = CVL .

MD5 压缩函数 HMD5

• HMD5 从 CV 输入128位,从消息分组输入512位,完成4轮循环后,输出128位,用于下一轮输入的 CV 值。
• 每轮循环分别固定不同的生成函数 F, G, H, I,结合指定的 T 表元素 T[] 和消息分组的不同部分 X[] 做16次迭代运算,生成下一轮循环的输入。
• 4轮循环总共有64次迭代运算。4轮循环中使用的生成函数(轮函数) g 是一个32位非线性逻辑函数,在相应各轮的定义如下:
网络安全 | C语言实现MD5信息摘要算法_第4张图片

每轮循环中的一次迭代运算逻辑

(1) 对 A 迭代:a = b + ((a + g(b, c, d) + X[k] + T[i]) << (2) 缓冲区 (A, B, C, D) 作循环轮换:
(B, C, D, A) <— (A, B, C, D) (就是(B, C, D, A)变成(A, B, C, D))

说明
◌ a, b, c, d : MD 缓冲区 (A, B, C, D) 的当前值。
◌ g : 轮函数 (F, G, H, I 中的一个)。
◌ << ◌ X[k] : 当前处理消息分组的第 k 个 (k =0…15) 32位字,即 Mq16+k。
◌ T[i] : T 表的第 i 个元素,32位字;T 表总共有64个元素,也 称为加法常数。
◌ + : 模 2^32 加法。 每轮循环中的一次迭代运算逻辑

网络安全 | C语言实现MD5信息摘要算法_第5张图片

各轮循环中第 i 次迭代 (i = 1…16) 使用的 X[k] 的确定
设 j = i -1:
◌ 第1轮迭代:k = j.
• 顺序使用 X[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15]
◌ 第2轮迭代:k = (1 + 5j) mod 16.
• 顺序使用 X[1, 6,11, 0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12]
◌ 第3轮迭代:k = (5 + 3j) mod 16.
• 顺序使用 X[5, 8,11,14, 1, 4, 7,10,13, 0, 3, 6, 9,12,15, 2]
◌ 第4轮迭代:k = 7j mod 16.
• 顺序使用 X[0, 7,14, 5,12, 3,10, 1, 8,15, 6,13, 4,11, 2, 9]

T 表的生成
◌ T[i] = int(2^32 * |sin(i)|) • int 取整函数,sin 正弦函数,以 i 作为弧度输入。

各次迭代运算采用的左循环移位的 s 值:
s[ 1…16] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22 }
s[17…32] = { 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20 }
s[33…48] = { 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23 }
s[49…64] = { 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 }


C语言代码

从文件读入任意长度的信息,得出结果。这份代码还是比较粗糙的,主要是不太熟悉位运算,其实有些转换是不必要的。不过个人认为写成这样可能会比较好理解hhh 有不止一个地方要进行大小端转换,我也不知道为啥要转来转去的,反正转了结果才正确。

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <math.h>

/*-----------------------------------------*/
// 轮函数,迭代函数

#define F(b, c, d) ((b & c) | (~b & d))
#define G(b, c, d) ((b & d) | (c & ~d))
#define H(b, c, d) (b ^ c ^ d)
#define I(b, c, d) (c ^ (b | ~d))
#define CLS(a, s) ((a << s) | (a >> (32 - s)))
#define iteration(a, b, c, d, g, x, t, s) {
   \
    switch(g) {
   \
        case 0:\
            a += F(b, c, d) + x + t;\
            break;\
        case 1:\
            a += G(b, c, d) + x + t;\
            break;\
        case 2:\
            a += H(b, c, d) + x + t;\
            break;\
        case 3:\
            a += I(b, c, d) + x + t;\
            break;\
    }\
    a = CLS(a, s);\
    a += b;\
}

/*-----------------------------------------*/
// 表

int x[64] = {
   
    0, 1, 2, 3, 4, 

你可能感兴趣的:(web安全)