MD5算法——C++实现
MD5算法原理
MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要。
具体实现可参考博客
https://blog.csdn.net/sinat_27933301/article/details/79538169
和官方标准RFC1321
https://tools.ietf.org/html/rfc1321
算法实现
一些常量的定义
//定义循环右移函数
#define RPTATE_SHIFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
//定义F,G,H,I函数
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
//定义寄存器word A,B,C,D
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
//strBaye的长度
unsigned int strlength = 0;
//A,B,C,D的临时变量
int tempA = 0, tempB = 0, tempC = 0, tempD = 0;
//定义k数组,用于压缩函数
const unsigned int k[] = {
0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821,
0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 };
//用数组存储向左位移数,方便操作
//每一行 表示一轮的左位移数 , 根据 RFC 1321的标准参数来做
const unsigned int s[] = { 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 };
//用于转换16进制
const char str16[] = "0123456789abcdef";
这些定义包括标准里的 A,B,C,D word, F,G,H,I函数, 用于压缩参数的常量值, 这些先定义下来,方便后面写程序,防止出错

主要函数getMD5Code
此暗示通过传入一个字符串,返回对此字符串进行MD4处理得到的摘要字符串ik, 这是一个主要的流程。
首先初始化最终的变量A,B,C,D, 然后进行填充操作, 进行压缩操作, 最后转换为16进制哈希值。
string getMD5Code(string source) {
//初始化
tempA = A;
tempB = B;
tempC = C;
tempD = D;
//把string变成二进制, 同时附加填充位
unsigned int *strByte = padding(source);
// 对于i = 0到N / 16-1 将块i复制到X.
// 对于j = 0到15做
// 将X [j]设置为M [i * 16 + j]。
// 进行压缩函数操作
for (int i = 0; i<strlength / 16; i++) {
unsigned int num[16];
for (int j = 0; j<16; j++) {
num[j] = strByte[i * 16 + j];
}
MD5compress(num);
}
//把得到的摘要2进制变成16进制字符串输出
return changeToHex(tempA).append(changeToHex(tempB)).append(changeToHex(tempC)).append(changeToHex(tempD));
}
填充函数padding
填充函数
处理后应满足bits≡448(mod512), 填充方式为先加一个1,其它位补零,最后加上64位的原来长度
unsigned int* padding(string str) {
//以512位,64个字节为一组, num表示组数, 利用整数相除直接得到组数
unsigned int num = ((str.length() + 8) / 64) + 1;
//对于一组需要16个整数来存储 16*4=64, strByte表示此字符串的2进制表示(这里用int数组表示)
unsigned int *strByte = new unsigned int[num * 16];
//初始化字符串的长度(长度是16*组数)
strlength = num * 16;
//初始化 strByte数组
for (unsigned int i = 0; i < num * 16; i++) {
strByte[i] = 0;
}
//一个整数存储四个字节,一个unsigned int对应4个字节,保存4个字符信息
for (unsigned int i = 0; i <str.length(); i++) {
strByte[i / 4] |= (str[i]) << ((i % 4) * 8);
}
//尾部添加1 一个unsigned int保存4个字符信息,所以用128左移
strByte[str.length() / 4] |= 0x80 << (((str.length() % 4)) * 8);
/*
*添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位
*/
strByte[num * 16 - 2] = str.length() * 8;
return strByte;
}
压缩函数
按照RFC 1321的标准 进行一共64次压缩运算, 因为每一次的参数是固定的, 所以可以提前输入参数, 这里我是k数组来存储这些参数

//MD5 压缩函数 Hmd5
void MD5compress(unsigned int M[]) {
int f = 0, g = 0;
int a = tempA, b = tempB, c = tempC, d = tempD;
/*第1轮迭代:
*X[j] , j = 1..16.
*第2轮迭代:
*X[p2(j)], p2(j) = (1 + 5j) mod 16, j = 1..16.
*第3轮迭代:
*X[p3(j)], p3(j) = (5 + 3j) mod 16, j = 1..16.
*第2轮迭代:
*X[p4(j)], p4(j) = 7j mod 16, j = 1..16*/
for (int i = 0; i < 64; i++) {
if (i<16) {
f = F(b, c, d);
g = i;
}
else if (i<32) {
f = G(b, c, d);
g = (5 * i + 1) % 16;
}
else if (i<48) {
f = H(b, c, d);
g = (3 * i + 5) % 16;
}
else {
f = I(b, c, d);
g = (7 * i) % 16;
}
//每次循环使用相同的迭代逻辑和 4*16 次运算的预设参数表, 也就是前面的k表
unsigned int tmp = d;
d = c;
c = b;
b = b + RPTATE_SHIFT((a + f + k[i] + M[g]), s[i]);
a = tmp;
}
tempA = a + tempA;
tempB = b + tempB;
tempC = c + tempC;
tempD = d + tempD;
}
进制转换函数
把数字变为2进制 以字符串输出
string changeToHex(int num) {
int b;
string tmp;
string str = "";
for (int i = 0; i<4; i++) {
tmp = "";
b = ((num >> i * 8) % (1 << 8)) & 0xff; //逆序处理每个字节
for (int j = 0; j < 2; j++) {
tmp.insert(0, 1, str16[b % 16]);
b = b / 16;
}
str += tmp;
}
return str;
}
测试函数
验证函数,通过RFC 1321给的标准输入输出来判断

int main() {
//这是 RFC 1321的标准测试输入和输出, 用来验证此MD5算法的正确性
string input[7] = {
"",
"a",
"abc",
"message digest",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"12345678901234567890123456789012345678901234567890123456789012345678901234567890"};
string expect[7] = {
"d41d8cd98f00b204e9800998ecf8427e", "0cc175b9c0f1b6a831c399e269772661",
"900150983cd24fb0d6963f7d28e17f72", "f96b697d7cb7938d525a2f31aaf161d0",
"c3fcd3d76192e4007dfb496cca67e13b", "d174ab98d277d9f5a5611c2c9f419d9f",
"57edf4a22be3c955ac49da2e2107b67a"};
for (int i = 0; i < 7; i++) {
cout << "--------------------------------" << endl;
cout << "测试 " << i + 1 << ":" << endl;
cout << "原消息: " << input[i] << endl;
cout << "MD5标准输出: " << expect[i] << endl;
string digest = getMD5Code(input[i]);
cout << "MD5输出: " << digest << endl;
}
}
测试结果
可看到和标准输出是相同的, 证明此MD5算法正确。

源码传送门
https://github.com/wangjiwu/implement-MD5-in-C-
参考文档
MD5加密算法原理及实现
https://www.cnblogs.com/hjgods/p/3998570.htmlThe MD5 Message-Digest Algorithm
https://tools.ietf.org/html/rfc1321
MD5算法——C++实现的更多相关文章
- md5算法
md5算法 不可逆的:原文-->密文.用系统的API可以实现: 123456 ---密文 1987 ----密文: 算法步骤: 1.用每个byte去和11111111做与运算并且得到的是int类 ...
- MD5算法 简介
MD5(单向散列算法)的全称是Message-Digest Algorithm 5(信息-摘要算法),经MD2.MD3和MD4发展而来.MD5算法的使用不需要支付任何版权费用. MD5功能 l 输入任 ...
- md5算法原理一窥(其一)
首先,需要了解的事,md5并不是传说中的加密算法,只是一种散列算法.其加密的算法并不是我们说所的那样固定不变,只是一种映射的关系. 所以解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD ...
- Java利用MessageDigest提供的MD5算法加密字符串或文件
MD5是常用的加密算法,也经常用于校验信息完整,如文件的完整性.用术语讲,MD5是一种消息摘要算法(Message Digest Algorithm).另外还有一种常用的消息摘要算法SHA1.如果想了 ...
- python学习笔记(MD5算法)
博主最近进度停滞了 对web开发理解欠缺好多内容 今天整理下MD5算法,这个涉及到mysql数据库存储用户表密码字段的时候 一般是带有加密的 # -*- coding: utf-8 -*- impor ...
- 在MAC平台下编译Ngnix ,由于MD5算法不能编译通过 解决办法
近期想学习Ngnix 代码,前些日子,对”自己下手狠一次“, 买了MAC 本. 所以想在Mac 上编译,是必须的,不然对不起自己的内心. 不巧遇到了MD5算法编译的问题 src/core/ngx_cr ...
- MD5算法步骤详解
转自MD5算法步骤详解 之前要写一个MD5程序,但是从网络上看到的资料基本上一样,只是讲了一个大概.经过我自己的实践,我决定写一个心得,给需要实现MD5,但又不要求很高深的编程知识的童鞋参考.不多说了 ...
- Java 实现Md5算法
package other; import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;/* * ...
- MD5算法【计算文件和字符串的MD5值】
1. MD5算法是一种散列(hash)算法(摘要算法,指纹算法),不是一种加密算法(易错).任何长度的任意内容都可以用MD5计算出散列值.MD5的前身:MD2.MD3.MD4.介绍工具:CalcMD5 ...
- 经常使用MD5算法代码
经常使用的MD5算法代码日期: 2014年8月4日作者: 铁锚 MD5,全称为 Message Digest Algorithm 5(消息摘要算法第五版).详情请參考 维基百科:MD5 MD5加密后 ...
随机推荐
- 题解 CF1354D 【Multiset】
考试拿到题,一看,这不是权值线段树吗? 思路 使用线段树每个节点维护该区间内元素出现次数. 根据题目,对于加入.删除元素,我们可以单点修改(\(+1\).\(-1\)),对于输出,我们可 随便 遍历找 ...
- 代码Verify简介
序 对于开发者而言,编译代码和提交代码是必不可少的流程,同一个需求反复提交的情况也时常出现,那么怎么避免这种情况,且保证代码的质量,这就是Verify CI的目标.Verify表示认证验证的意思,结合 ...
- 关于C#反射(转载)
反射的用途: (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例. (2)使用Module了解包含模块的程序集以及模块中 ...
- Linux内存大页设置
实际环境中,遇到3次由于内存大页设置参数不合理或者错误,导致系统内存不足,或者数据库内存不足的问题. 按照如下方式,推荐设置大页参考下发设置! 参考HugePages on Oracle Linux ...
- Java 并发实践 — ConcurrentHashMap 与 CAS
转载 http://www.importnew.com/26035.html 最近在做接口限流时涉及到了一个有意思问题,牵扯出了关于concurrentHashMap的一些用法,以及CAS的一些概念. ...
- CSS3选择器用法小结
1.*通配符选择器 eg:*{margin:0;padding:0;} 2.#id选择符 ID选择器是CSS中效率最高的选择器,使用的时候要保证ID的唯一性 eg:#div{width:960px;m ...
- BUUCTF-Web Easy Calc
要素察觉 打开calc.php发现源码 过滤了很多字符.题目一开始提示了有waf,最后通过eval实现计算功能.考虑利用该函数读取flag文件,先尝试弹个phpinfo 被waf拦截,在num参数前面 ...
- Zookeeper集群部署及报错分析
安装 下载压缩包 解压 修改zoo.cfg文件 创建myid文件 启动 自启动配置 有时间再补hhh 报错处理 很荣幸的遇到了大部分报错,日志再zookeeper目录的bin下的zookeeper.o ...
- animate动画基础
定义: animate() 方法执行 CSS 属性集的自定义动画. 1.该方法通过CSS样式将元素从一个状态改变为另一个状态.CSS属性值是逐渐改变的,这样就可以创建动画效果. 2.只有数字值可创建动 ...
- Docker引言,由来,思想
引言 我本地运行没问题啊? 环境不一致? 哪个哥们又写死循环了?,怎么这么卡? 在多用户操作系统下,会相互影响 淘宝在双11的时候,用户量暴增 运维成果过高的问题 学习一门技术,学习安装成本高 关于安 ...