摘要算法之MD5介绍及OpenSSL中MD5常用函数使用举例

MD5(Message-DigestAlgorithm 5)是计算机中广泛使用的杂凑算法之一。主要可以实现将数据运算后转换为一串固定值,其前身主要有MD2、MD3和MD4算法。MD2算法在1989年由Rivest设计开发,后来由Rogier和Chauvaud发现如果忽略了校验将和MD2产生冲突。为了加强算法的安全性,Rivest在1990年又开发出MD4算法,随后由Denboer和Bosselaers以及其他人很快的发现了攻击MD4版本中第一步和第三步的漏洞,于是MD4就此被淘汰了。1991年Rivest在原有MD4算法的基础上开发出技术更成熟的MD5算法。

MD5算法是一个被广泛使用的称为信息摘要的摘要算法,其主要过程包括了对字符串的填充(Padding)、分段摘要(Digesting)和最终摘要的输出(Outputting)三个步骤。其中填充是指首先需要对信息进行填充,使其字节长度对512求余得到结果为448.填充是在信息的后面填充一个1和无数个0,直到满足上面的长度条件时停止。在填充完成后,再往后面附加一个以64位二进制表示填充前信息的长度,使现在的信息字节长度等于N*512+448+64=(N+1)*512,这样长度恰好可以被512整除满足后面处理中对信息长度可以划分为N+1个完整分组的要求。

摘要算法的两个重要评价指标是摘要强度和速度。摘要强度是指算法抵抗各种攻击的能力,而加密速度就是摘要产生的速度。通常摘要强度和摘要处理速度是一对互斥的参数,即强度越大不可避免的会增加摘要产生的时间即降低摘要产生的速度。而在摘要强度一定的情况下加密速度在实现中可以使用各种优化技术最大限度地发挥算法速度的潜力。

MD5算法的应用领域非常广泛,包括数据加密、数据校验、数字签名等。在Linux系统中,主要应用MD5对明文进行加密,在文件的上传和下载中为了校验文件是否被改动过,需要提供文件的MD5散列值,而在数字签名中先要利用MD5计算报文摘要。

MD5算法是迭代型Hash函数结构,输入一个任意长度的信息,将输出128比特的消息摘要。算法的核心为分段摘要过程,即图1中所示的由A、B、C、D到经过摘要运算处理过后的结果A、B、C、D的过程。

其算法实现过程:

(1)、补位:MD5算法中首先对信息加以填充,让其位数满足对512求余后等于448.即填充后的消息长度等于512的某倍数减掉 64,即使原来消息值得长度满足条件也需要进行填充,长度填充的方式是在信息的末尾添加一个1和无数个0,直至满足条件为止.

(2)、补明文长度:通过第一步补位后,将预留的64比特信息来表示消息在被填充前的长度,并附加在信息之后,使其总长度变成512的整数被,这样方便后面对信息的分组。如果某消息的原始长度超出2^64,则以2^64进行取模。

通过以上两步执行完之后,可以对消息进行分组,每组长度均为512比特,而每组值又可表示为16个32比特的字。

(3)、初始化:算法中采用128比特的缓冲区存放中间结果以及最终的hash值,缓冲区利用4个32比特的寄存器(A,B,C,D)充当,对MD5种四个32位的链接变量(Chaining Variable)进行初始化,分别为:state[0]=0x67452301, state[1]=0xefcdab89, state[2]=0x98badcfe,state[3]=0x10325476

(4)、输入:将4个链接变量的值复制到另外四个变量中。a=state[0], b=state[1], c=state[2], d=state[3],由这四个新变量及每个分割后的512位的子消息组作为算法的输入值,进入到算法的四轮循环,而循环次数则由消息分组后的数目决定。

(5)、运算:算法的主循环中包括4轮,每一轮都要执行16次操作。而每次操作就是对a,b,c,d四个变量中的其中3个做一次非线性的函数运算,接着将结果加上第4个变量,以及一个子分组和一个常数(常数来自常数表,该常数表共有64个元素,第i个常数即为2^32*abs(sin(i))),再将整个结果左循环移动一个不定的数,最后再加上a,b,c或d中之一,这个结果取代变量a,b,c或d,见图1和图2.

图 1  MD5 处理流程

图2 MD5分段摘要函数处理流程

其中m[i],表示子消息组的第i个分组,i为0--15;T[j]表示该步的常数。

(6)、输出:当消息的N个分组均被处理完成后,最后的压缩函数将输出一个128位的散列值,即为消息摘要。

利用Hash函数可以将任意长度的消息压缩转换为固定长度的hash值,俗称消息摘要或数字指纹,可以直接用于数据的完整性检测。

MD2, MD4, andMD5 are cryptographic hash functions with a 128 bit output.

1.      MD5(): compute the MD5 messagedigest of the B<n> bytes at B<d> and place it in B<md> (whichmust have space for MD5_DIGEST_LENGTH == 16 bytes of output). If B<md> isNULL, the digest is placed in a static array.

The following functions may be used if the message isnot completely stored in memory:

2.      MD5_Init(): initializes aB<MD5_CTX> structure.

3.      MD5_Update(): can be calledrepeatedly with chunks of the message to be hashed (B<len> bytes atB<data>).

4.     MD5_Final():places the message digest in B<md>, which must have space for MD5_DIGEST_LENGTH== 16 bytes of output, and erases the B<MD5_CTX>.

以下是测试代码:

cryptotest.h:

#ifndef _CRYPTOTEST_H_
#define _CRYPTOTEST_H_

#include <string>

using namespace std;

typedef enum {
	GENERAL = 0,
	ECB,
	CBC,
	CFB,
	OFB,
	TRIPLE_ECB,
	TRIPLE_CBC
}CRYPTO_MODE;

string DES_Encrypt(const string cleartext, const string key, CRYPTO_MODE mode);
string DES_Decrypt(const string ciphertext, const string key, CRYPTO_MODE mode);

string RC4_Encrypt(const string cleartext, const string key);
string RC4_Decrypt(const string ciphertext, const string key);

string MD5_Digest(const string cleartext);

#endif //_CRYPTOTEST_H_

md5test.cpp:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <iomanip>
#include <stdlib.h>
#include <openssl/md5.h>

#include "cryptotest.h"

using namespace std;

string MD5_Digest(const string cleartext)
{
	string strDigest;
	unsigned char tmp[16] = {0};

#if 0
	MD5((const unsigned char*)cleartext.c_str(), cleartext.length(), tmp);
#else
	MD5_CTX c;
	MD5_Init(&c);
	MD5_Update(&c, cleartext.c_str(), cleartext.length());
	MD5_Final(tmp, &c);
#endif

	char* tmp1 = new char[32 + 1];
	memset(tmp1, 0, 32 + 1);

	for(int i = 0; i < 16; i++)
		sprintf(&(tmp1[i*2]), "%02x", tmp[i]);
		//cout<<hex<<setw(2)<<setfill(‘0‘)<<(int)tmp[i]; 

	strDigest = (char*)tmp1;

	delete [] tmp1;

	return strDigest;
}

main.cpp:

#include "stdafx.h"
#include "cryptotest.h"
#include "TestMemory.h"
#include <iostream>
#include <string>

using namespace std;

void test_MD5()
{
	string strSrc[7] = {"", "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz",
						"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
						"12345678901234567890123456789012345678901234567890123456789012345678901234567890"};

	string strDigest[7] = {"d41d8cd98f00b204e9800998ecf8427e",
						  "0cc175b9c0f1b6a831c399e269772661",
						  "900150983cd24fb0d6963f7d28e17f72",
						  "f96b697d7cb7938d525a2f31aaf161d0",
						  "c3fcd3d76192e4007dfb496cca67e13b",
						  "d174ab98d277d9f5a5611c2c9f419d9f",
						  "57edf4a22be3c955ac49da2e2107b67a"};

	for (int i = 0; i < 7; i++) {
		string str = MD5_Digest(strSrc[i]);
		cout<<str<<endl;

		if (strcmp(strDigest[i].c_str(), str.c_str()) != 0)
			cout<<"i = "<<i<<" MD5 error!"<<endl;
	}
}

int main(int argc, char* argv[])
{
	test_MD5();

	cout<<"ok!!!"<<endl;

	return 0;
}

MD5理论摘自:

1.      《基于简化MD5摘要技术快照差分算法的研究》

2.      《基于MD5改进算法的安全教师博客系统设计及开发》

时间: 2024-08-02 16:11:31

摘要算法之MD5介绍及OpenSSL中MD5常用函数使用举例的相关文章

对称加密算法之RC4介绍及OpenSSL中RC4常用函数使用举例

RC4是一种对称密码算法,它属于对称密码算法中的序列密码(streamcipher,也称为流密码),它是可变密钥长度,面向字节操作的流密码. RC4是流密码streamcipher中的一种,为序列密码.RC4加密算法是Ron Rivest在1987年设计出的密钥长度可变的加密算法簇.起初该算法是商业机密,直到1994年,它才公诸于众.由于RC4具有算法简单,运算速度快,软硬件实现都十分容易等优点,使其在一些协议和标准里得到了广泛应用. 流密码也属于对称密码,但与分组加密算法不同的是,流密码不对明

非对称加密算法之RSA介绍及OpenSSL中RSA常用函数使用举例

RSA算法,在1977年由Ron Rivest.Adi Shamirh和LenAdleman,在美国的麻省理工学院开发完成.这个算法的名字,来源于三位开发者的名字.RSA已经成为公钥数据加密标准. RSA属于公开密钥密码体制.公开密钥体制就是产生两把密钥,一把用于加密,一把用于解密,而且不能根据算法和其中的一把密钥,而去推出另外的一把密钥.在使用的时候,将公钥公开,对方用公开的公钥加密数据后,将密文发回,然后用另一把私钥进行解密,从而还原出明文. RSA算法的数学基础是数论中的素数相关性质.RS

socket编程之三:socket网络编程中的常用函数

这节本来打算先给出常用函数介绍,再给两个代码实例,写着写着发现越来越长,决定把代码放在下一节. 本节内容持续更新...... 1 socket()函数 原型: int socket(int domain, int type, int protocol); 描述: 类似打开一个文件,返回一个socket描述符,唯一标识一个socket,后面相应的操作都是这用这个socket描述符. 参数: domain:协议族,常用的协议族有AF_INET.AF_INET6.AF_LOCAL.AF_ROUTE等:

头文件algorithm中的常用函数

头文件algorithm中的常用函数 一.非修改性序列操作(12个) 循环         对序列中的每个元素执行某操作         for_each() 查找         在序列中找出某个值的第一次出现的位置         find() 在序列中找出符合某谓词的第一个元素     find_if() 在序列中找出一子序列的最后一次出现的位置         find_end() 在序列中找出第一次出现指定值集中之值的位置     find_first_of() 在序列中找出相邻的一对

numpy函数库中一些常用函数的记录

numpy函数库中一些常用函数的记录 最近才开始接触python,python中为我们提供了大量的库,不太熟悉,因此在<机器学习实战>的学习中,对遇到的一些函数的用法进行记录. (1)mat( ) numpy函数库中存在两种不同的数据类型(矩阵matrix和数组array),都可以用于处理行列表示的数字元素.虽然他们看起来很相似,但是在这两个数据类型上执行相同的数学运算可以得到不同的结果,其中numpy函数库中matrix与MATLAB中matrices等价. 调用mat( )函数可以将数组转

MATLAB中的常用函数

MATLAB中的常用函数 1. 特殊变量与常数 主题词 意义 主题词 意义 ans 计算结果的变量名 computer 确定运行的计算机 eps 浮点相对精度 Inf 无穷大 I 虚数单位 inputname 输入参数名 NaN 非数 nargin 输入参数个数 nargout 输出参数的数目 pi 圆周率 nargoutchk 有效的输出参数数目 realmax 最大正浮点数 realmin 最小正浮点数 varargin   实际输入的参量 varargout 实际返回的参量     2.

oracle中的常用函数

oracle中的常用函数 1. 字符串常用函数 函数名 说明 concat 用来连接字符串的函数,只能连接两个字符串.如果想连接多个字符串可以使用"||"符号 initcap 把每个单词的首字母大写. instr(‘母字符串’,‘子字符串’) 母字符串:被查找的字符串.子字符串:要查找的字符串. 如果有第三个参数,代表从第几个字符开始查找. 第四个参数代表查询第几次出现的字符串的下标,默认是1. 查询不到返回0 select instr('410106199012132018','19

php中的常用函数

先声明一下,copy来的,各位看官请勿吐槽,我是留给自己回顾和补充知识点用的. PHP数据类型包括8种 相对应的判断函数有: is_bool(),is_int(),is_integer(),is_long()(同样是判断整型),is_real()(同样是判断浮点型),is_float(),is_string(),is_array(),is_object(),is_null()用来检测变量是否为 NULL 其他常用函数 array_values() 函数可以返回数组中所有的值并给其建立数字索引 <

Makefile 中的常用函数

1.$(subset <from>,<to>,<text>) 名称:字符串替换 功能:把字符串<text>中得<from>字符串替换成<to> 返回值:返回被替换过后的字符串 示例: $(subst ee,EE,feet on the street) 把"feet on the street"中的"ee"替换成"EE",返回结果是"fEEt on the strEE