id="c_n9"width="1920"height="990"style="position: fixed; top: 0px; left: 0px; z-index: -1; opacity: 0.5;">

md5

MD5

简介

MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16个字符(BYTES))的散列值(hash value),用于确保信息传输完整一致。

1996年后被证实存在弱点,可以被加以破解,对于需要高度安全性的资料,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞攻击,因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。

实现过程

md5强化

首先将消息扩充为512bit(64byte)的整数倍。填充规则为:

在要处理的信息x的二进制表示之后先填入一个1,然后再添加若干个0(不超过511bit),使得message digest的bit长度是512的整数倍少64bit,最后再最低的64bit中填入消息x的比特长度的二进制表示。

以上是密码学教科书中的md5强化的方法。

那么很容易得到填充的模式是这样的。

image-20230304131742601但是当你这样去填充的过程中,你会发现消息的bit长度的填充会存在一些问题。

譬如有这样的一个message digest ”abc“,其 bit长度为24,16进制表示为0x18;那么我们以人的思维去填充那么必然是这样的0 0 0 0 0 0 0 18 ,但是这样是错误的。因为这根本就不是真正的填充方式。


在关于md5 hash函数的rfc文档中有这么几句:

  • In this document a "word" is a 32-bit quantity and a "byte" is an eight-bit quantity. A sequence of bits can be interpreted in a natural manner as a sequence of bytes, where each consecutive group of eight bits is interpreted as a byte with the high-order (mostsignificant) bit of each byte listed first. Similarly, a sequence of bytes can be interpreted as a sequence of 32-bit words, where each consecutive group of four bytes is interpreted as a word with the low-order (least significant) byte given first.
  • A 64-bit representation of b (the length of the message before the padding bits were added) is appended to the result of the previous step. In the unlikely event that b is greater than 2^64, then only the low-order 64 bits of b are used. (These bits are appended as two 32-bit words and appended low-order word first in accordance with the previous conventions.)

那么就很明显了,在md5的计算中的,其word是从低字节到高字节的(其实这里也就是跨字节的小端序,至于为什么这里要采用小端序的方式来填充bit长度,其实我不是很清楚,就我个人的理解应该是为了后面步骤中的将512bit的block划分为多个32bit的block,因为在md5中其他的跨字节常量在计算机中存的都是小端序,此处采用小端序的顺序来存储方便后续的计算)

故真正的填充顺序为(上个例子) -> 18 0 0 0 0 0 0 0

以上表示填充方式了,简单的说一下就是先填充1bit,然后疯狂的添加0bit,直到$len(message\ digest) \mod 64 = 56 $即可开始填充比特长度。

md5 MainLoop

首先将message digest中的一个512bit的block划分为多个32bit的block;具体的方式如下:

首先在md5中存在初始量A, B, C, D;其长度均为32bit,以计算机小端序的眼光来看的话,那么其存储的顺序为a[0], a[1], a[2], a[3](a[0]为低有效位);那么在对应的md5的计算中a[0]必然对应一位message digest中的值,当然也就是每个32bit block的最前面的1 byte。但是这是在memory中,所以转化为正常的数字表示,那么32bit block也就需要reverse一下,以32bit中的最后一位为最高位,第一位为最低位。故转化式子为\(m[3] << 24 + m[2] << 16 + m[1] << 8 + m[0]\) (m为32bit block)。

接下来就是4 * 16/圈的循环了。当然在这之前需要一些function&constant;

\[F(x, y, z) = (x \wedge y) \vee (\overline{x} \wedge z) \]

\[G(x,y,z) = (x \wedge z)\vee(y \wedge \overline{z}) \]

\[H(x, y, z) = x \oplus y \oplus z \]

\[I(x, y, z) = y \oplus (x \vee \overline{z}) \]

\[A_0 = 0x67452301, B_0 = 0xefcdab89, C_0 = 0x98badcfe, D_0 = 0x10325476 \]

\[64轮常数:k[i] = 2 ^ {32} * abs(sin(i + 1)) \]

自此,便可以开始进行64轮操作了

// A, B, C, D 为常量
var (
	ra, rb, rc, rd int
    // 循环左移的长度
    r [64]int = [64]int{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
                       }
)
ra, rb, rc, rd = A, B, C, D

func MainLoop(w []uint32) {
    var f, g uint32
    a, b, c, d = ra, rb, rc, rd
    for i := 0; i < 64; i++ {
        switch {
        case i < 16:
            f, g = F(b, c, d), i
        case i < 32:
            f, g = G(b, c, d), (5 * i + 1) % 16
        case i < 48:
            f, g = H(b, c, d), (3 * i + 5) % 16
        default:
            f, g = I(b, c, d), (7 * i) % 16
        }
        temp := d
        d = c
        c = b
        b = leftrotate((a + f + k[i] + w[g]), r[i]) + b
        a = temp
    }
    ra, rb, rc, rd = ra + a, rb + b, rc + c, rd + d
}

func leftrotate(a, n uint32) uint32 {
    return (a >> (32 - n) | a << n)
}

如此循环完所有的512 bit block便可以计算出对应的MD5散列值,就是\(ra, rb, rc, rd\)在内存中的按小端序排列的值,写一个格式化函数即可实现。

参考文献

posted @ 2023-03-04 15:20  hellozmc  阅读(29)  评论(0编辑  收藏  举报