算法系列9《MD5》
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。
将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。
MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。
对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。总体流程如下图所示,表示第i个分组,每次的运算都由前一轮的128位结果值和第i块512bit值进行运算。初始的128位值为初试链接变量,这些参数用于第一轮的运算,以大端字节序来表示,他们分别为:A=0x01234567,B=0x89ABCDEF,C=0xFEDCBA98,D=0x76543210。
C++代码实现
1. 《MD5.h》
#pragma once /* POINTER defines a generic pointer type */
typedef unsigned char *POINTER; /* UINT2 defines a two byte word */
typedef unsigned short int UINT2; /* UINT4 defines a four byte word */
typedef unsigned long int UINT4; class cMd5
{
private:
unsigned int m_Content[16];
unsigned int m_ContentLen;
unsigned int m_TotalLen;
static unsigned int m_T[64];
unsigned int m_A, m_B, m_C, m_D; private:
inline void FF(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s);
inline void GG(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s);
inline void HH(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s);
inline void II(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s);
inline unsigned int roateLeft(unsigned int a, unsigned int c);
void transform(); /* MD5 context. */
typedef struct _MD5_CTX{
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* bit ,2^64(Low before) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX; void MD5Init (MD5_CTX *);
void MD5Update (MD5_CTX *, unsigned char *, unsigned int);
void MD5Final (unsigned char [16], MD5_CTX *);
void MD5String(char *string, long buflen, char digest[]); static void MD5Transform (UINT4 [4], unsigned char [64]);
static void Encode (unsigned char *, UINT4 *, unsigned int);
static void Decode (UINT4 *, unsigned char *, unsigned int);
static void MD5_memcpy (POINTER, POINTER, unsigned int);
static void MD5_memset (POINTER, int, unsigned int); public:
cMd5();
virtual ~cMd5();
//initialize
void beginCal();
//Show that no longer input data, will add a filling
void endCal();
//Is initialized, input data, in endCal call before, can continue to add data
void addData(unsigned char* data, unsigned int size);
//End after operation, get the code
unsigned char* getCode();
void clearMemoryHelper(char* p);
};
2. 《MD5.CPP》
#include "stdafx.h"
#include "Md5.h"
#include <string.h>
#include <stdio.h> unsigned int cMd5::m_T[64] = {
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
}; cMd5::cMd5()
{ }
cMd5::~cMd5()
{ } void cMd5::FF(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s)
{
a = b + roateLeft(a + ((b & c) | ((~b) & d)) + m_Content[k] + m_T[i], s);
}
void cMd5::GG(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s)
{
a = b + roateLeft(a + ((b & d) | (c & (~d))) + m_Content[k] + m_T[i], s);
}
void cMd5::HH(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s)
{
a = b + roateLeft(a + (b ^ c ^ d) + m_Content[k] + m_T[i], s);
}
void cMd5::II(unsigned int& a, unsigned int b, unsigned int c, unsigned int d, int k, int i, int s)
{
a = b + roateLeft(a + (c ^ (b | (~d))) + m_Content[k] + m_T[i], s);
}
unsigned int cMd5::roateLeft(unsigned int a, unsigned int c)
{
return ( (a << c) | (a >> (32-c)) );
}
void cMd5::transform()
{
unsigned int AA, BB, CC, DD;
AA = m_A;
BB = m_B;
CC = m_C;
DD = m_D;
//1 round
FF(AA, BB, CC, DD, 0, 0, 7);
FF(DD, AA, BB, CC, 1, 1, 12);
FF(CC, DD, AA, BB, 2, 2, 17);
FF(BB, CC, DD, AA, 3, 3, 22);
FF(AA, BB, CC, DD, 4, 4, 7);
FF(DD, AA, BB, CC, 5, 5, 12);
FF(CC, DD, AA, BB, 6, 6, 17);
FF(BB, CC, DD, AA, 7, 7, 22);
FF(AA, BB, CC, DD, 8, 8, 7);
FF(DD, AA, BB, CC, 9, 9, 12);
FF(CC, DD, AA, BB, 10, 10, 17);
FF(BB, CC, DD, AA, 11, 11, 22);
FF(AA, BB, CC, DD, 12, 12, 7);
FF(DD, AA, BB, CC, 13, 13, 12);
FF(CC, DD, AA, BB, 14, 14, 17);
FF(BB, CC, DD, AA, 15, 15, 22);
//2 round
GG(AA, BB, CC, DD, 1, 16, 5);
GG(DD, AA, BB, CC, 6, 17, 9);
GG(CC, DD, AA, BB, 11, 18, 14);
GG(BB, CC, DD, AA, 0, 19, 20);
GG(AA, BB, CC, DD, 5, 20, 5);
GG(DD, AA, BB, CC, 10, 21, 9);
GG(CC, DD, AA, BB, 15, 22, 14);
GG(BB, CC, DD, AA, 4, 23, 20);
GG(AA, BB, CC, DD, 9, 24, 5);
GG(DD, AA, BB, CC, 14, 25, 9);
GG(CC, DD, AA, BB, 3, 26, 14);
GG(BB, CC, DD, AA, 8, 27, 20);
GG(AA, BB, CC, DD, 13, 28, 5);
GG(DD, AA, BB, CC, 2, 29, 9);
GG(CC, DD, AA, BB, 7, 30, 14);
GG(BB, CC, DD, AA, 12, 31, 20);
//3 round
HH(AA, BB, CC, DD, 5, 32, 4);
HH(DD, AA, BB, CC, 8, 33, 11);
HH(CC, DD, AA, BB, 11, 34, 16);
HH(BB, CC, DD, AA, 14, 35, 23);
HH(AA, BB, CC, DD, 1, 36, 4);
HH(DD, AA, BB, CC, 4, 37, 11);
HH(CC, DD, AA, BB, 7, 38, 16);
HH(BB, CC, DD, AA, 10, 39, 23);
HH(AA, BB, CC, DD, 13, 40, 4);
HH(DD, AA, BB, CC, 0, 41, 11);
HH(CC, DD, AA, BB, 3, 42, 16);
HH(BB, CC, DD, AA, 6, 43, 23);
HH(AA, BB, CC, DD, 9, 44, 4);
HH(DD, AA, BB, CC, 12, 45, 11);
HH(CC, DD, AA, BB, 15, 46, 16);
HH(BB, CC, DD, AA, 2, 47, 23);
//4 round
II(AA, BB, CC, DD, 0, 48, 6);
II(DD, AA, BB, CC, 7, 49, 10);
II(CC, DD, AA, BB, 14, 50, 15);
II(BB, CC, DD, AA, 5, 51, 21);
II(AA, BB, CC, DD, 12, 52, 6);
II(DD, AA, BB, CC, 3, 53, 10);
II(CC, DD, AA, BB, 10, 54, 15);
II(BB, CC, DD, AA, 1, 55, 21);
II(AA, BB, CC, DD, 8, 56, 6);
II(DD, AA, BB, CC, 15, 57, 10);
II(CC, DD, AA, BB, 6, 58, 15);
II(BB, CC, DD, AA, 13, 59, 21);
II(AA, BB, CC, DD, 4, 60, 6);
II(DD, AA, BB, CC, 11, 61, 10);
II(CC, DD, AA, BB, 2, 62, 15);
II(BB, CC, DD, AA, 9, 63, 21);
m_A = m_A + AA;
m_B = m_B + BB;
m_C = m_C + CC;
m_D = m_D + DD;
}
//initialize
void cMd5::beginCal()
{
memset(m_Content, 0, 64);
m_ContentLen = 0;
m_TotalLen = 0;
m_A = 0x67452301;
m_B = 0xEFCDAB89;
m_C = 0x98BADCFE;
m_D = 0x10325476;
}
void cMd5::endCal()
{
memset((char*)m_Content + m_ContentLen, 0x80, 1);
if (m_ContentLen < 56){
memset((char*)m_Content + m_ContentLen + 1, 0, 55 - m_ContentLen);
}
else{
memset((char*)m_Content + m_ContentLen + 1, 0, 63 - m_ContentLen);
transform();
memset((char*)m_Content, 0, 56);
}
unsigned int h, l;
h = 0;
l = m_TotalLen;
h |= ((l & 0x80000000) >> 31);
h <<= 1;
l <<= 1;
h |= ((l & 0x80000000) >> 31);
h <<= 1;
l <<= 1;
h |= ((l & 0x80000000) >> 31);
h <<= 1;
l <<= 1;
memcpy(m_Content + 14, &l, 4);
memcpy(m_Content + 15, &h, 4);
transform();
}
void cMd5::addData(unsigned char* data, unsigned int size)
{
unsigned int i = 0;
unsigned int remain = 64 - m_ContentLen;
if (remain > size)
remain = size;
memcpy(((char*)m_Content) + m_ContentLen, data, remain);
i += remain;
m_ContentLen += remain;
m_TotalLen += remain;
if (m_ContentLen < 64)
return;
transform();
while (i + 64 <= size)
{
memcpy(m_Content, data + i, 64);
transform();
i += 64;
m_TotalLen += 64;
}
m_ContentLen = size - i;
m_TotalLen += m_ContentLen;
memcpy(m_Content, data + i, m_ContentLen);
}
unsigned char* cMd5::getCode()
{
unsigned char * code = new unsigned char[16];
memcpy(code, &m_A, 4);
memcpy(code + 4, &m_B, 4);
memcpy(code + 8, &m_C, 4);
memcpy(code + 12, &m_D, 4);
return code;
}
void cMd5::clearMemoryHelper(char* p)
{
delete []p;
}
文/yanxin8原创,获取更多信息请访问http://yanxin8.com/278.html
算法系列9《MD5》的更多相关文章
- 2.Java 加解密技术系列之 MD5
Java 加解密技术系列之 MD5 序 背景 正文 结束语 序 上一篇文章中,介绍了最基础的编码方式 — — BASE64,也简单的提了一下编码的原理.这篇文章继续加解密的系列,当然也是介绍比较基础的 ...
- 常用校验算法CRC、MD5、SHA_转
1.算法概述 数据摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名.数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密.数据摘要算法也被称为哈希(H ...
- 简答一波 HashMap 常见八股面试题 —— 算法系列(2)
请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注 ...
- JAVA算法系列 冒泡排序
java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...
- JAVA算法系列 快速排序
java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- 三白话经典算法系列 Shell排序实现
山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...
- Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fix 算法系列补充.docx Atiitt 兼容性提示的艺术 attilax总结.docx Atitit 应用程序容器化总结 v2 s66.docx Atitit file cms api
Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fi ...
- 【C#实现漫画算法系列】-判断 2 的乘方
微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...
- 玩转算法系列--图论精讲 面试升职必备(Java版)
第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...
随机推荐
- 初探接口测试框架--python系列6
点击标题下「蓝色微信名」可快速关注 坚持的是分享,搬运的是知识,图的是大家的进步,没有收费的培训,没有虚度的吹水,喜欢就关注.转发(免费帮助更多伙伴)等来交流,想了解的知识请留言,给你带来更多价值,是 ...
- matlab 小波变换
MATLAB小波变换指令及其功能介绍 1 一维小波变换的 Matlab 实现 (1) dwt函数 功能:一维离散小波变换 格式:[cA,cD]=dwt(X,'wname') [cA,cD]=dwt(X ...
- eclipse 弹出智能提示、代码自动换行
在eclipse 中编写java 程序时,为了快速查找变量或搜索方法调用,在智能窗口的帮助下,程序的编写速度会更快,但eclipse 默认下并不弹出智能窗口,这就需要自己进行配置,设置的步骤如下: 打 ...
- 洛谷P2725 邮票 Stamps
P2725 邮票 Stamps 37通过 224提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交 讨论 题解 最新讨论 为什么RE?在codevs上AC的. 题目背景 给一组 ...
- Android书籍资源汇总
之前一直在Linux下使用C++做服务器端的开发工作,对Android关于移动方面的开发了解较少,现将android开发方面的书籍与资源整理如下,方便后续的查阅. 19本Android开发书籍 7本A ...
- vyos (一) 基础配置
http://www.lowefamily.com.au/2015/11/29/using-a-vyos-router-with-hyper-v/1/ http://thomasvochten.com ...
- 【缓存】.net中Cache管理操作
隐藏行号 复制代码 ? 这是一段程序代码. using System; using System.Web; using System.Web.Caching; using System.Collect ...
- div模拟下拉框
1.模拟下拉框.点击文本框在文本框下面显示一个层divList,点击divList以外的任何地方,关闭divList层 document.body.onclick = function (e) { e ...
- 【风马一族_php】PHP与Mysql建立连接
让php发出 Hi作为基础 http://www.cnblogs.com/sows/p/5990157.html 配置apache ../apache/conf/httpd.conf 创建p ...
- BochsDebug
Bochs User Manual Chapter 8. Tips and Techniques 8.12. Using Bochs internal debugger Note, if yo ...