MD5加密算法解析

2023-11-09

背景:网上看了几篇关于MD5加密算法的文章,有些地方不太明白,就去看了维基百科上的英文介绍,逻辑很清晰,所以整理出来。

1、 简介

MD5即Message-Digest Algorithm 5,在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2、MD3和MD4发展而来。

MD5将任意长度的“字节串”变换成一个128bit的消息摘要,并且它是一个不可逆的字符串变换算法,典型应用是对一段信息串 (Message)产生所谓的指纹 (fingerprint),以防止被“篡改”。

2、MD5算法逻辑

(1)、消息补位:

对于任意长度的消息,首先需要对消息添加位数,使消息总长度为512位的整数倍。在消息后添加位的方法是第一个添加位是1,其余都是0,使消息长度对512取模得448。然后将真正消息的长度(没有添加位以前的消息长度)对264取模后以64位表示,附加于前面已添加过位的消息后,此时的消息长度正好是512位的倍数。消息补位是必须要有的操作。

(2)、消息分块:

经过添加位数处理的消息,其长度正好为512位的整数倍,然后按512位的长度进行分块,可以划分成m块消息,我们用x1,x2,…,xm表示这些块消息。

对于512位的消息块,将其再分成16个字符串,每个字符串为32位(用十六进制表示),我们使用M[k](k= 0, 1,……15)来表示这16个字符串。

(3)、初始化变量:

初始化变量a、b、c、d对应的十六进制表示为:

a = 0x67452301

b = 0xefcdab89

c = 0x98badcfe

d = 0x10325476

(4)、需要用到的常量(十六进制)

K[i]为232 × abs(sin(i + 1)) 的整数部分,其中i的单位是弧度。

K[ 0.. 3] := { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee }
K[ 4.. 7] := { 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 }
K[ 8..11] := { 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be }
K[12..15] := { 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 }
K[16..19] := { 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa }
K[20..23] := { 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 }
K[24..27] := { 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed }
K[28..31] := { 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a }
K[32..35] := { 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c }
K[36..39] := { 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 }
K[40..43] := { 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 }
K[44..47] := { 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 }
K[48..51] := { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 }
K[52..55] := { 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 }
K[56..59] := { 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 }
K[60..63] := { 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }

另外还需要常量s[i]:

s[ 0..15] := { 7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22 }
s[16..31] := { 5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20 }
s[32..47] := { 4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23 }
s[48..63] := { 6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21 }

(5)、需要使用的函数:

⊕,∧,∨,¬分别代表异或,与,或,非运算。

(6)、循环加密过程:

对于每一个消息块都有4轮的运算,每一轮包括16次(一共64次),最后产生128位摘要。开始时,初始值为abcd,而在每次处理完单个消息块后,此哈希值将被得到的新哈希值替换,用于下一个消息块的计算。最后一个哈希值等于MD5的输出摘要。

对于每一个消息块,循环加密过程中首先要初始化链接变量A、B、C、D:

接下来进行4轮,共64次的运算,每轮用到的函数F和M的下标g不同:

第一轮:0≤i≤15

F=F

g=i

第二轮:16≤i≤31

F=G

g=(5i+1) mod 16

第三轮:32≤i≤47

F=H

g=(3i+5) mod 16

第四轮:48≤i≤63

F=I

g=7i mod 16

最后,经过4轮操作之后,还要进行加法运算,

a≔a+A

b≔b+B

c≔c+C

d≔d+D

新得到的abcd用作下一个消息块计算的初始值,直到最后一个消息块计算完成输出的abcd,即为经过MD5计算输出的摘要。

循环过程如下图:

(7)、轮内计算过程:

MD5的4轮,共64次的运算使用同一个操作程序,如下:

可以表示为:

F≔F+A+K[i]+M[g]

A≔D

D≔C

C≔B

B≔B + F<<<s[i]

3、维基百科上的伪代码

// : All variables are unsigned 32 bit and wrap modulo 2^32 when calculating
var int s[64], K[64]
var int i

// s specifies the per-round shift amounts (计算过程中会用到位移,移多少位看s[i])
s[ 0..15] := { 7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22 }
s[16..31] := { 5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20 }
s[32..47] := { 4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23 }
s[48..63] := { 6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21 }

// Use binary integer part of the sines of integers (Radians) as constants:
for i from 0 to 63 do
    K[i] := floor(2^32 × abs(sin(i + 1))) (K[i]取这个公式的整数部分,下面已经给出)
end for
// (Or just use the following precomputed table):
K[ 0.. 3] := { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee }
K[ 4.. 7] := { 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 }
K[ 8..11] := { 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be }
K[12..15] := { 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 }
K[16..19] := { 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa }
K[20..23] := { 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 }
K[24..27] := { 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed }
K[28..31] := { 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a }
K[32..35] := { 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c }
K[36..39] := { 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 }
K[40..43] := { 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 }
K[44..47] := { 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 }
K[48..51] := { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 }
K[52..55] := { 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 }
K[56..59] := { 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 }
K[60..63] := { 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }

// Initialize variables:(初始化变量)
var int a0 := 0x67452301   // A
var int b0 := 0xefcdab89   // B
var int c0 := 0x98badcfe   // C
var int d0 := 0x10325476   // D
(消息补位)
// Pre-processing: adding a single 1 bit
append "1" bit to message (补1个1)    
 // Notice: the input bytes are considered as bit strings,
 //  where the first bit is the most significant bit of the byte.

// Pre-processing: padding with zeros(补0,直到消息长度mod 512 = 448)
append "0" bit until message length in bits ≡ 448 (mod 512)

// Notice: the two padding steps above are implemented in a simpler way
 //  in implementations that only work with complete bytes: append 0x80
 //  and pad with 0x00 bytes so that the message length in bytes ≡ 56 (mod 64).

append original length in bits mod 264 to message(补上原始消息长度mod 2^64后的结果,以64位表示)
(对每一个512位的消息块做如下运算)
// Process the message in successive 512-bit chunks:
for each 512-bit chunk of padded message do
    break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15(每个消息块分成16个32位的words)
    // Initialize hash value for this chunk:(初始化变量ABCD)
    var int A := a0
    var int B := b0
    var int C := c0
    var int D := d0
    // Main loop:
    for i from 0 to 63 do(共64次运算)
        var int F, g
        if 0 ≤ i ≤ 15 then(第一轮,函数F,变量g)
            F := (B and C) or ((not B) and D)
            g := i
        else if 16 ≤ i ≤ 31 then(第二轮,函数F,变量g)
            F := (D and B) or ((not D) and C)
            g := (5×i + 1) mod 16
        else if 32 ≤ i ≤ 47 then(第三轮,函数F,变量g)
            F := B xor C xor D
            g := (3×i + 5) mod 16
        else if 48 ≤ i ≤ 63 then(第四轮,函数F,变量g)
            F := C xor (B or (not D))
            g := (7×i) mod 16
        // Be wary of the below definitions of a,b,c,d(ABCD经过如下变换得到新的值)
        F := F + A + K[i] + M[g]  // M[g] must be a 32-bit block
        A := D
        D := C
        C := B
        B := B + leftrotate(F, s[i])(leftrotate(F,s[i])表示F循环左移s[i]位)
    end for
    // Add this chunk's hash to result so far:(64次运算后,A,B,C,D分别加上最初的a0,b0,c0,d0成为新的a0,b0,c0,d0,用作下一个消息块的初始变量)
    a0 := a0 + A
    b0 := b0 + B
    c0 := c0 + C
    d0 := d0 + D
end for
(最后一个消息块运算的结果即为MD5输出的摘要)
var char digest[16] := a0 append b0 append c0 append d0 // (Output is in little-endian)

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MD5加密算法解析 的相关文章

随机推荐

  • 2023美赛C题保姆级思路及代码 wordle

    C题思路 C题是数据挖掘题 通过分析wordle的游戏机制 挖掘不同单词所对应的得分情况对其难度的影响 这道题的难度主要是如何提取不同单词难度的特征 相对来说反而是最好实现的 完整解题思路将持续更新 大家也可持续关注 或者移步B站查看完整解
  • 2010流行语

    2010年的岁尾 记者试图遴选出本年度的十大网络流行语 但总觉得很 纠结 且 鸭梨山大 因为对于一日千里的网络流行语发展速度而言 其实 神马都是浮云 或许明天甚至下一秒更 给力 的词汇就会冒出来 因此 我们作出了一个非常艰难的决定 只做盘点
  • 技术管理-概要设计评审指南

    最近一段时间 工作的重点转移到了技术管理 主要是编写概要设计模板和概要设计评审上 在这个过程中 发现有必要对概要设计评审的工作做一个简单指南编写 由此整理了一个PPT 下面列出愿与大家分享
  • Ubuntu下安装并配置FastDFS

    FastDFS是一个开源的轻量级分布式文件系统 它对文件进行管理 功能包括 文件存储 文件同步 文件访问 文件上传 文件下载 等 解决了大容量存储和负载均衡的问题 特别适合以文件为载体的在线服务 如相册网站 视频网站等等 FastDFS的项
  • Hap中Activity 配置界面控件选项修改

    首先看看这块区域怎么出来的看看在edito html 是遍历节点的属性 获取到对应的html页面拼上 看看属性在哪里定义的 stencilset zh CN json 一个审批模版的配置 同时再把审批模版属性加入人工任务节点 做法 在 st
  • logging.file和logging.path【java 日志 logback、log4j】

    1 logging file的优先级高于logging path 即两个同时写上时 只使用logging file 2 logging path 生成的日志名为spring log 3 logging path home java pro
  • Android JNI 生成头文件以及cpp详细步骤

    Step1 创建java native 类和方法 public class BeautyNative static System loadLibrary beautyNative lib 加载动态库 libdemojni so 初始化上下文
  • 5.基本统计方法-分类变量的组间比较

    目录 1 分类变量的统计描述 绘制列联表 1 1 查看数据框的基本信息 1 2 频数和频率统计描述 1 3 四格表的绘制 1 4 多维列联表绘制 2 独立二分类定性变量比较 3 配对的两组二分类变量比较 配对卡方 4 独立多组多分类定性变量
  • CyberRT API文档链接

    https cyber rt readthedocs io en latest CyberRT API for Developers html
  • 利用DateFormat、Date、Calendar等类 对含有时间的字符串进行提取和计算

    在时间提取方面我用了三种方法 最开始使用的是正则表达式 很简洁 之后使用的是Date类中的方法 但这种方法都已过时 最后使用的是Calendar类的方法 我推荐使用正则表达式 简洁实用 package cn hanfeng example1
  • 安装Ubuntu Linux系统时硬盘分区最合理的方法

    无论是安装Windows还是Linux操作系统 硬盘分区都是整个系统安装过程中最为棘手的环节 网上的一些Ubuntu Linux安装教程一般都是自动分区 给初学者带来很大的不便 下面我就根据多年来在装系统的经验谈谈安装Ubuntu Linu
  • 关于mfc中的调出来控制台使用

    解决方案资源管理器 gt 工程项目右键 属性 gt 配置属性 gt 生成事件 gt 生成后事件 gt 命令行 gt 添入 editbin SUBSYSTEM CONSOLE OUTDIR ProjectName exe 就可以调出来控制台使
  • Unity 3D 三维模型简介||

    Unity 3D 三维模型简介 三维模型是用三维建模软件建造的立体模型 也是构成 Unity 3D 场景的基础元素 Unity 3D 几乎支持所有主流格式的三维模型 如 FBX 文件和 OBJ 文件等 开发者可以将三维建模软件导出的模型文件
  • dstat裸机LInux安装

    因为dstat是采用python写的 所以机器上需要有python2 7版本 并且需要six包 所以下载三个上述的包到Linux 1 dstat 0 7 4 orig tar gz 2 six 1 16 0 tar gz 3 Python
  • dell笔记本怎么开启虚拟化_笔记本电脑玩游戏卡顿怎么办?开启“卓越性能”模式告别卡顿...

    Windows 10更新到1803之后 一些朋友可能发现 以往电源管理模式有标准 节能和高性能 现在只剩下一个标准了 当然我们也可以通过一些简单操作将这些电源模式找回来 比如通过Windows移动中心 但微软的用意可能是不需要用户进行手动干
  • md文档自动上传图片

    Typora设置图片自动上传图床教程 终于可以快乐的写markdown文档啦 先上效果 1 准备 注意软件不要随便无脑装 找一个固定装软件的目录 方便管理 安装 Typora 一个贼好用的md文件编写软件 传送门 安装 Picgo 图片上传
  • CNN的可视化

    前言 前文中已经实现了SimpleConvNet类 本文将通过把卷积层可视化 去了解在CNN层中到底实现了怎样的处理 第一层权重的可视化 例如 假设第1层的卷积层的权重的形状是 30 1 5 5 即30个大小为5 5 通道为1的滤波器 滤波
  • llvm 常见命令

    llvm作为一套成熟的编译体系 提供了很多命令用于不同阶段的使用 通过这些命令的组合使用 可以将一个完整的编译过程 拆分成多个步骤 llvm as 将IR文件编译为二进制文件 默认生成后缀名为 bc的文件 也可以使用 o指定输出 llvm
  • react+ts+antd创建项目流程

    基于nodejs和vite的安装 ant design官网地址 组件总览 Ant Design gitee io 操作流程 用vite创建项目 npm init vite latest 安装依赖 npm i 安装路由 npm i react
  • MD5加密算法解析

    背景 网上看了几篇关于MD5加密算法的文章 有些地方不太明白 就去看了维基百科上的英文介绍 逻辑很清晰 所以整理出来 1 简介 MD5即Message Digest Algorithm 5 在90年代初由MIT的计算机科学实验室和RSA D