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》的更多相关文章

  1. 2.Java 加解密技术系列之 MD5

    Java 加解密技术系列之 MD5 序 背景 正文 结束语 序 上一篇文章中,介绍了最基础的编码方式 — — BASE64,也简单的提了一下编码的原理.这篇文章继续加解密的系列,当然也是介绍比较基础的 ...

  2. 常用校验算法CRC、MD5、SHA_转

    1.算法概述 数据摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名.数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密.数据摘要算法也被称为哈希(H ...

  3. 简答一波 HashMap 常见八股面试题 —— 算法系列(2)

    请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注 ...

  4. JAVA算法系列 冒泡排序

    java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...

  5. JAVA算法系列 快速排序

    java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...

  6. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  7. 三白话经典算法系列 Shell排序实现

    山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...

  8. 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 ...

  9. 【C#实现漫画算法系列】-判断 2 的乘方

    微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...

  10. 玩转算法系列--图论精讲 面试升职必备(Java版)

    第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...

随机推荐

  1. Epic - Desirable Number

    A number is called 'desirable' if all thedigits are strictly ascending eg: 159 as 1<5<9. You k ...

  2. THE ONE THING PEOPLE WILL MASSIVELY OVERPAY FOR (有一个东西人们是愿意出高价购买的)

    THE ONE THING PEOPLE WILL MASSIVELY OVERPAY FOR有一个东西人们是愿意出高价购买的 by GARY VAYNERCHUK 点此直达湾区日报简评 I don' ...

  3. 【测试】trunc和round的区别

    trunc是截断:round是四舍五入:下面通过一个例子具体看一下trunc和round的不同 SQL),trunc() from dual; TRUNC() TRUNC() ------------ ...

  4. noi2010 能量采集

    2005: [Noi2010]能量采集 Time Limit: 10 Sec  Memory Limit: 552 MB Submit: 3068  Solved: 1820 [Submit][Sta ...

  5. Java之注解

    package com.demo.test; import java.lang.annotation.Documented; import java.lang.annotation.ElementTy ...

  6. gerrit 调试smtp email

  7. 【Linux】inode_针对MySQL读写操作在系统层的进一步学习【转】

    转自http://www.cnblogs.com/itech/archive/2012/05/15/2502284.html 一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘 ...

  8. vs 异常处理

    解决方法: 4.0 删除 C:/Windows/Microsoft.NET/Framework/v4.0.30319/Temporary ASP.NET Files 2..0 删除 C:/WINDOW ...

  9. ERR: Failed to complete setup of assembly (hr = 0x8007000b). Probing terminated.

    这个问题, 估计是由于  在 64位系统上运行 C#.net 项目的问题. 试试,将项目 生成属性 中的 平台改成  X86  编译重新发布试试

  10. 移动端rem自适应布局关键代码

    function resi() { var html = document.querySelector("html"); var wW = document.body.client ...