MD5算法加密的过程

开发 前端 算法
MD5 是一种算法, MD5 中的 MD 代表 Message Digest, 也即信息摘要.至于数字 5, 则因它是从更早的 MD4 算法改进而来, 因此得名 MD5.

 

什么是 MD5

MD5 是一种算法, MD5 中的 MD 代表 Message Digest, 也即信息摘要.

至于数字 5, 则因它是从更早的 MD4 算法改进而来, 因此得名 MD5.

所以 MD5 即是信息摘要算法第五版.

什么是信息摘要算法

那什么又是信息摘要算法呢? 它本质上就是一个哈希函数(hash function).

又叫散列函数.

那什么又是哈希函数呢? 它是指这样一种函数: 它能把任意大小的数据映射(map)为一个固定大小的值.

A hash function is any function that can be used to map data of arbitrary size to fixed-size values.

哈希函数所返回的这个值称为哈希值(hash value), 又称为哈希码(hash codes), 或直接简称为哈希(hash).

具体例子

单纯地这样去讲会比较抽象, 因此这里引入具体例子来说明, 以 Java 为例, 可以这样去计算 MD5:

  1. public void rawMd5() throws NoSuchAlgorithmException { 
  2.     byte[] bytes = "hello".getBytes(StandardCharsets.UTF_8); 
  3.     MessageDigest md = MessageDigest.getInstance("MD5"); 
  4.     byte[] md5 = md.digest(bytes); 

注: 因为摘要计算的输入是一个字节数组, 如果要计算字符串的摘要值, 则要转成某种编码的字节数组, 为保持一致, 应始终显式使用同一种编码, 比如 utf-8.

从以上代码中也不难看出, 一个 MD5 函数的输入和输出都是字节数组 byte[].

而代码中不能直接体现的一点则是: 输入可以是任意大小的字节数组, 输出则是固定大小的字节数组.

对于 MD5 算法而言, 这个输出值是一个固定大小为 16 字节的数组, 然后因为每个字节(byte)有 8 个位(bit), 所以最终的输出值是一个 16 × 8 = 128 位的二进制数. MD5 的值就是一个 128 位的二进制大整数.

比如下面就是一个具体的 MD5 的值, 以原始的 128 位二进制形式表示: 10001000100100011001000111110000100011111000000111010010110010101100010111101010000110011011110000111011111101111101100110111110

这个 MD5 值实际是对我的网站域名 xiaogd.net 作摘要的结果.

这个值的二进制形式实在是长得不要不要的, 所以一般会转换为十六进制形式, 共 16 组具体为: 88 91 91 f0 8f 81 d2 ca c5 ea 19 bc 3b f7 d9 be. 依然还是很长, 但比二进制好多了.

随便说一句, IPv6 的地址也是 128 bit 的, 所以也是像这般变态的长, 写成 16 进制也还是很长, 压根记不住...

最后通常还会去掉空格写成一个紧凑的 32 个字符的字符串的形式: 889191f08f81d2cac5ea19bc3bf7d9be, 也即是我们最常见到的 MD5 值的形式.

但请不要误解, MD5 的值并不是一个字符串, 更不是什么字母都能出现在里边的.

术语和符合

本文中一个“字”是32位,一个“字节”是8位。

我们定义x_i代表“x减去I".如果减数是一个表达式,则用括号括住,如:x_{i+1}。同样我们用^代表求幂,这样x^i则代表x的i次幂。“+”代表“字”之间的相加,X<<< s代表X左移s位,not(X)表示对X进行按位补运算,X v Y表示按位或。X xor Y表示按位异或,XY表示按位与。

 MD5算法描述

我们假设有一个b位长的信息作为输入,然后我们算出他的摘要信息。b是一个非负整数,b有可能是0,不需要一定是8的倍数,可能会非常得大。我们将输入信息描绘如下:

m_0 m_1 .. m_{b-1}

接下来的五步我们来算出它的摘要。

1、 填充

我们将输入信息填充到长度对512取余对于448。无论输入信息的长度多少,填充总是会发生的,即使本身的长度就已经满足模512对于448的情况下。

过程如下:

在输入信息后添加一个“1”位,其余添加“0”位使得输入信息长度满足对512取余对于448。总的来说,至少添加一位,至多添加512位。

举个例子:66

2、 补充数据长度

将输入信息b用64位表示并添加到填充的数据之后,如果b大于2^64的话,则只取低64位。

至此,我们的处理结果刚好是512的倍数,等效的,也是16字的倍数,我们用M[0...N-1]来表示这个结果,其中N是16的倍数。

3、 初始化MD缓冲区

用一个四字的缓冲区(A,B,C,D)来计算消息摘要,这里的A,B,C,D每一个都是一个32位的寄存器。这些寄存器的初始值如下,用16进制表示的,低位字节优先。

  1. word A: 01 23 45 67 
  2. word B: 89 ab dc ed 
  3. word C: fe dc ba 98 
  4. word D: 76 54 32 10 

4、 处理消息

我们首先需要定义四个辅助函数。

  1. F(X,Y,Z) = XY v not(X) Z 
  2. G(X,Y,Z) = XZ v Y not(Z) 
  3. H(X,Y,Z) = X xor Y xor Z 
  4. I(X,Y,Z) = Y xor (X v not(Z)) 

对于函数F来说,在每一位上F函数就像是一个选择器:if X then Y else Z。

这一步需要一个64长度的表格T[1...64],由sin函数构造而成。T[i]是4294967296次运行abs(sin(i))的结果,以此类推即可。

我们需要进行一下处理

  1. /* 处理原数据. */ 
  2. For i = 0 to N/16-1 do 
  3. /* 将数据赋值给X. */ 
  4. For j = 0 to 15 do 
  5. Set X[j] to M[i*16+j]. 
  6. end /* 结束对j的循环 */ 
  7. /* 把A保存位AA B保存为BB C保存为CC D保存位DD */ 
  8. AA = A 
  9. BB = B 
  10. CC = C 
  11. DD = D 
  12. /* 第一轮操作 */ 
  13. /* [abcd k s i] 表示如下操作 
  14. a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 
  15. [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] 
  16. [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] 
  17. [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] 
  18. [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16] 
  19. /* 第二轮操作 */ 
  20. /* [abcd k s i] 表示如下操作 
  21. a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 
  22. [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] 
  23. [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] 
  24. [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] 
  25. [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32] 
  26. /* 第三轮操作 */ 
  27. /* [abcd k s t] 表示如下操作 
  28. a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 
  29. [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] 
  30. [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] 
  31. [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] 
  32. [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48] 
  33. /* 第四轮操作 */ 
  34. /* [abcd k s t] 表示如下操作 
  35. a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 
  36. [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] 
  37. [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] 
  38. [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] 
  39. [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64] 
  40. A = A + AA 
  41. B = B + BB 
  42. C = C + CC 
  43. D = D + DD 
  44. end /* 结束对i的循环 */ 

5、 输出

上一步输出最终的结果A,B,C,D。我们从A的低位字节开,到D的高位字节结束,每一个都是32位,最终拼接的结果就是4*32 = 128位,这就是MD5结算的结果。

 

责任编辑:姜华 来源: 今日头条
相关推荐

2016-12-15 09:26:53

MD5加密

2009-06-06 18:57:47

MD5加密类Java Bean

2022-10-18 22:21:51

2015-03-23 11:21:08

2009-06-30 10:05:24

MD5加密JSP源码

2020-02-25 16:30:36

MD5是不是加密

2022-11-09 08:24:39

2009-10-26 14:06:03

2021-06-07 10:00:41

MD5算法加密

2011-12-28 13:14:39

2021-02-19 11:55:36

C语言MD5加密

2009-09-09 18:35:07

C# 加密MD5和SHA1

2009-07-24 15:58:20

ASP.NET MD5ASP.NET SHA

2009-07-28 16:39:16

VB.NET的MD5加

2016-12-19 15:50:36

2010-01-06 09:54:30

.NET Framew

2021-12-06 18:16:14

SQLCRCMD5

2022-10-19 07:35:28

2010-06-25 16:19:17

2012-09-20 15:45:09

点赞
收藏

51CTO技术栈公众号