OpenSSL源码分析—MD4算法实现
来源:互联网 发布:开淘宝需要多少资金 编辑:程序博客网 时间:2024/04/30 12:31
作为Hash算法之一的MD4算法曾经是风靡一时的Hash算法,随着时间的推移,MD4算法已经渐渐地落后,目前已经被MD5和SHA系列算法给代替。作为一个压缩算法,碰撞是不可避免的,我国著名学者王小云成功地找到了在可接受时间内有效地算出MD4算法的碰撞值,成为世界上密码学界的翘楚。
笔者这次将分析OpenSSL的源码中MD4部分,作为分析OpenSSL中Hash函数部分的第一站,虽然OpenSSL自从0.98版本开始也支持MD2,但由于MD2算法太古老,分析的价值不大,所以就从MD4开始。
1.MD4算法流程:
步骤1:附加填充比特。对消息进行填充,使得消息的长度模512运算为448,即,填充后的消息长度mod512 = 448,即填充后的消息长度加64则为512的正倍数。
填充的比特串的最高位为1,其余各位均为0。
将填充前的消息长度mod2 ^64后,填充到最后64个比特位上,使得填充后的消息长度为512的整数倍。
步骤2:将填充后的消息M按512比特长度进行分块(假设为M1,M2,M3,...,Mn),准备作为输入在压缩函数中进行运算。
步骤3:初始化MD4的缓存,给寄存器设置初值。MD4使用一个128bit的缓存来存储Hash函数的中间及最终的摘要。该缓存可看作4个32bit的寄存器(A,B,C,D),它们被初始化为以下值
A = 0x67452301
B = 0xefcbab89
C = 0x98badcfe
D = 0x10325476
步骤4:对n个消息分组进行n+1次压缩函数迭代,每次迭代后产生一个链接终极变量Hi,在进行下一次迭代得到Hi+1
即:Hi+1= C(Hi,Mi)
步骤5:n个消息分组处理完后,最后一个连接变量Hn的值即作为消息摘要。MD4的摘要为最后4个32bit寄存器的值组成一个128bit的十六进制字。
至于MD4的压缩函数是怎么样,就不详细说明了,接下来直接分析OpenSSL中的源码。
2.MD4算法源码:
OpenSSL中MD4算法的源码在crypto/md4文档中。在平时调用时,我们可以简单地直接使用函数
MD4(unsignedchar* in,unsignedchar* out,size_tlen)
打开查看函数MD4的实现,主要分为三个子函数来实现,分别是MD4_Init、MD4_Update和MD4_Final,以及数据结构MD4_CTX。在OpenSSL中,大部分的Hash函数都是由这三个子函数实现的,在OpenSSL的md32_common.h头文件中,巧妙地运用了宏定义来实现一些可重用的代码,降低了代码量。
1.数据结构MD4_CTX
来看看MD4_CTX的定义
typedefstruct MD4state_st { MD4_LONGA,B,C,D; MD4_LONGNl,Nh; MD4_LONGdata[MD4_LBLOCK]; unsignedint num; }MD4_CTX;
明显ABCD是寄存器,存放初始值和每一轮的中间值,Nl和Nh分别是数据长度的低32位和高32位,而data应该是存放当前块512bit的数据(16*32bit),而num是存放长度信息的。
2.函数MD4_Init
初始化函数MD4_Init的实现在md4_dgst.c文件中的fips_md_init(MD4)函数中,在crypto.h头文件中有一个巧妙的宏是这样写的
555行中#definefips_md_init(alg)fips_md_init_ctx(alg,alg)572行中#definefips_md_init_ctx(alg,cx)\intalg##_Init(cx##_CTX*c)
MD4_Init函数主要是初始化MD4_CTX;变量,把MD4_CTX变量全部置0,然后赋予四个寄存器初值。
3.MD4_Update函数
MD4_Update是用于对已经初始化好的MD4_CTX函数进行压缩。算法并没有马上对数据进行填充,而是直接对数据先进行压缩,把数据填充留到了MD4_Final函数中。在压缩过程中使用到md4_block_data_order函数,该函数就是算法的压缩函数。在使用md4_block_data_order函数时,函数直接把没填充的数据进行压缩,但只压缩能够组成512bit的数据块,剩余的尾部数据会和后面填充进来的数据在MD4_Final函数中进行最后一次压缩。
4.MD4_Final函数
MD4_Final函数的作用是对数据先进行填充,然后在对剩余的数据进行最后一次压缩,并把压缩的结果转成unsignedchar型的数组便于输出。
这次对OpenSSL中的MD4函数的粗略分析到此结束,最后贴上笔者抠出来的能够独立openssl库编译的MD4代码。
#include <stdio.h> #include <string.h> #define DATA_ORDER_IS_LITTLE_ENDIAN #define MD4_LONG unsigned long #define MD4_CBLOCK64 #define MD4_LBLOCK(MD4_CBLOCK/4) #define MD4_DIGEST_LENGTH 16 #define INIT_DATA_A (unsigned long)0x67452301L #define INIT_DATA_B (unsigned long)0xefcdab89L #define INIT_DATA_C (unsigned long)0x98badcfeL #define INIT_DATA_D (unsigned long)0x10325476L #defineHASH_MAKE_STRING(c,s)do {\ unsigned long ll;\ ll=(c)->A; (void)HOST_l2c(ll,(s));\ ll=(c)->B; (void)HOST_l2c(ll,(s));\ ll=(c)->C; (void)HOST_l2c(ll,(s));\ ll=(c)->D; (void)HOST_l2c(ll,(s));\ } while (0) #define MD32_REG_T long #define HOST_c2l(c,l)(l =(((unsigned long)(*((c)++))) ),\ l|=(((unsigned long)(*((c)++)))<< 8),\ l|=(((unsigned long)(*((c)++)))<<16),\ l|=(((unsigned long)(*((c)++)))<<24)) #define HOST_l2c(l,c)(*((c)++)=(unsigned char)(((l) )&0xff),\ *((c)++)=(unsigned char)(((l)>> 8)&0xff),\ *((c)++)=(unsigned char)(((l)>>16)&0xff),\ *((c)++)=(unsigned char)(((l)>>24)&0xff),\ l) #defineF(b,c,d)((((c) ^ (d)) & (b)) ^ (d)) #define G(b,c,d)(((b) & (c)) | ((b) & (d)) | ((c) & (d))) #defineH(b,c,d)((b) ^ (c) ^ (d)) #define R0(a,b,c,d,k,s,t) { \ a+=((k)+(t)+F((b),(c),(d))); \ a=ROTATE(a,s); }; #define R1(a,b,c,d,k,s,t) { \ a+=((k)+(t)+G((b),(c),(d))); \ a=ROTATE(a,s); };\ #define R2(a,b,c,d,k,s,t) { \ a+=((k)+(t)+H((b),(c),(d))); \ a=ROTATE(a,s); }; #define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) typedef struct MD4state_st { MD4_LONG A,B,C,D; MD4_LONG Nl,Nh; MD4_LONG data[MD4_LBLOCK]; unsigned int num; }MD4_CTX; int MD4_Init(MD4_CTX *c){ memset (c,0,sizeof(*c)); c->A=INIT_DATA_A; c->B=INIT_DATA_B; c->C=INIT_DATA_C; c->D=INIT_DATA_D; return 1; } void md4_block_data_order(MD4_CTX *c, const void *data_, size_t num){ const unsigned char *data=data_; register unsigned MD32_REG_T A,B,C,D,l; #ifndef MD32_XARRAY /* See comment in crypto/sha/sha_locl.h for details. */ unsigned MD32_REG_TXX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9,XX10,XX11,XX12,XX13,XX14,XX15; # define X(i)XX##i #else MD4_LONG XX[MD4_LBLOCK]; # define X(i)XX[i] #endif A=c->A; B=c->B; C=c->C; D=c->D; for (;num--;){ (void)HOST_c2l(data,l); X( 0)=l; (void)HOST_c2l(data,l); X( 1)=l; /* Round 0 */ R0(A,B,C,D,X( 0), 3,0);(void)HOST_c2l(data,l); X( 2)=l; R0(D,A,B,C,X( 1), 7,0);(void)HOST_c2l(data,l); X( 3)=l; R0(C,D,A,B,X( 2),11,0);(void)HOST_c2l(data,l); X( 4)=l; R0(B,C,D,A,X( 3),19,0);(void)HOST_c2l(data,l); X( 5)=l; R0(A,B,C,D,X( 4), 3,0);(void)HOST_c2l(data,l); X( 6)=l; R0(D,A,B,C,X( 5), 7,0);(void)HOST_c2l(data,l); X( 7)=l; R0(C,D,A,B,X( 6),11,0);(void)HOST_c2l(data,l); X( 8)=l; R0(B,C,D,A,X( 7),19,0);(void)HOST_c2l(data,l); X( 9)=l; R0(A,B,C,D,X( 8), 3,0);(void)HOST_c2l(data,l); X(10)=l; R0(D,A,B,C,X( 9), 7,0);(void)HOST_c2l(data,l); X(11)=l; R0(C,D,A,B,X(10),11,0);(void)HOST_c2l(data,l); X(12)=l; R0(B,C,D,A,X(11),19,0);(void)HOST_c2l(data,l); X(13)=l; R0(A,B,C,D,X(12), 3,0);(void)HOST_c2l(data,l); X(14)=l; R0(D,A,B,C,X(13), 7,0);(void)HOST_c2l(data,l); X(15)=l; R0(C,D,A,B,X(14),11,0); R0(B,C,D,A,X(15),19,0); /* Round 1 */ R1(A,B,C,D,X( 0), 3,0x5A827999L); R1(D,A,B,C,X( 4), 5,0x5A827999L); R1(C,D,A,B,X( 8), 9,0x5A827999L); R1(B,C,D,A,X(12),13,0x5A827999L); R1(A,B,C,D,X( 1), 3,0x5A827999L); R1(D,A,B,C,X( 5), 5,0x5A827999L); R1(C,D,A,B,X( 9), 9,0x5A827999L); R1(B,C,D,A,X(13),13,0x5A827999L); R1(A,B,C,D,X( 2), 3,0x5A827999L); R1(D,A,B,C,X( 6), 5,0x5A827999L); R1(C,D,A,B,X(10), 9,0x5A827999L); R1(B,C,D,A,X(14),13,0x5A827999L); R1(A,B,C,D,X( 3), 3,0x5A827999L); R1(D,A,B,C,X( 7), 5,0x5A827999L); R1(C,D,A,B,X(11), 9,0x5A827999L); R1(B,C,D,A,X(15),13,0x5A827999L); /* Round 2 */ R2(A,B,C,D,X( 0), 3,0x6ED9EBA1L); R2(D,A,B,C,X( 8), 9,0x6ED9EBA1L); R2(C,D,A,B,X( 4),11,0x6ED9EBA1L); R2(B,C,D,A,X(12),15,0x6ED9EBA1L); R2(A,B,C,D,X( 2), 3,0x6ED9EBA1L); R2(D,A,B,C,X(10), 9,0x6ED9EBA1L); R2(C,D,A,B,X( 6),11,0x6ED9EBA1L); R2(B,C,D,A,X(14),15,0x6ED9EBA1L); R2(A,B,C,D,X( 1), 3,0x6ED9EBA1L); R2(D,A,B,C,X( 9), 9,0x6ED9EBA1L); R2(C,D,A,B,X( 5),11,0x6ED9EBA1L); R2(B,C,D,A,X(13),15,0x6ED9EBA1L); R2(A,B,C,D,X( 3), 3,0x6ED9EBA1L); R2(D,A,B,C,X(11), 9,0x6ED9EBA1L); R2(C,D,A,B,X( 7),11,0x6ED9EBA1L); R2(B,C,D,A,X(15),15,0x6ED9EBA1L); A = c->A += A; B = c->B += B; C = c->C += C; D = c->D += D; } } int MD4_Update(MD4_CTX *c, const void *data_, size_t len){ const unsigned char *data=data_; unsigned char *p; MD4_LONG l; size_t n; if (len==0) return 1; l=(c->Nl+(((MD4_LONG)len)<<3))&0xffffffffUL; if (l < c->Nl) c->Nh++; c->Nh+=(MD4_LONG)(len>>29); c->Nl=l; n = c->num; if (n != 0){ p=(unsigned char *)c->data; if (len >= MD4_CBLOCK || len+n >= MD4_CBLOCK){ memcpy (p+n,data,MD4_CBLOCK-n); md4_block_data_order(c,p,1); n = MD4_CBLOCK-n; data += n; len -= n; c->num = 0; memset (p,0,MD4_CBLOCK);/* keep it zeroed */ } else{ memcpy (p+n,data,len); c->num += (unsigned int)len; return 1; } } n = len/MD4_CBLOCK; if (n > 0){ md4_block_data_order(c,data,n); n *= MD4_CBLOCK; data += n; len -= n; } if (len != 0){ p = (unsigned char *)c->data; c->num = (unsigned int)len; memcpy(p,data,len); } return 1; } int MD4_Final(unsigned char *md, MD4_CTX *c){ unsigned char *p = (unsigned char *)c->data; size_t n = c->num; p[n] = 0x80; /* there is always room for one */ n++; if (n > (MD4_CBLOCK-8)){ memset(p+n,0,MD4_CBLOCK-n); n=0; md4_block_data_order(c,p,1); } memset (p+n,0,MD4_CBLOCK-8-n); p += MD4_CBLOCK-8; #if defined(DATA_ORDER_IS_BIG_ENDIAN) (void)HOST_l2c(c->Nh,p); (void)HOST_l2c(c->Nl,p); #elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) (void)HOST_l2c(c->Nl,p); (void)HOST_l2c(c->Nh,p); #endif p -= MD4_CBLOCK; md4_block_data_order(c,p,1); c->num=0; memset (p,0,MD4_CBLOCK); #ifndef HASH_MAKE_STRING #error "HASH_MAKE_STRING must be defined!" #else HASH_MAKE_STRING(c,md); #endif return 1; } unsigned char *MD4(const unsigned char *d, size_t n, unsigned char *md){ MD4_CTX c; static unsigned char m[MD4_DIGEST_LENGTH]; if (md == NULL) md=m; if (!MD4_Init(&c)) return NULL; MD4_Update(&c,d,n); MD4_Final(md,&c); //OPENSSL_cleanse(&c,sizeof(c)); return(md); } int main(){ unsigned char in[]="12345678987"; unsigned char out[20]; size_t n; int i; n = strlen((const char*)in); MD4(in,n,out); printf("\n\nMD4 digest result :\n"); for(i=0;i<16;i++) printf("%x ",out[i]); printf("\n"); }参考文献:
[1]胡鑫,MD4差分攻击自动搜索差分路径算法研究[CP],2009-07-05
- OpenSSL源码分析—MD4算法实现
- MD4 算法代码实现
- Rsync源码——md4
- OpenSSL源码分析之MD5算法
- OpenSSL源码分析之SHA0算法
- MD4加密java算法
- openssl——sha256算法源码
- OpenSSL 中 RSA 加密解密实现源码分析
- ECC算法分析--openssl的实现以及其调用流程
- ECC算法分析--openssl的实现以及其调用流程 .
- MD4
- 【OpenSSL】heartbleed漏洞源码分析
- Mahhout实现的算法、源码包分析
- Mahhout实现的算法、源码包分析
- openssl中dh算法实现
- 消息摘要算法-bouncy castle支持的MD4算法扩展
- 用OpenSSL实现RSA算法加密(转)
- 一些算法的MapReduce实现——1 TB数据排序源码分析
- .net +xml实现url重写
- c++对合数的简单应用
- java 构建器的调用顺序
- Github开源Android组件资源整理(四) ImageView, ProgressBar,TextView
- 1590 - IP Networks
- OpenSSL源码分析—MD4算法实现
- SQL小技巧
- java枚举使用详解
- Android之launcher学习(三)
- 项目开发经验分享—漂亮的弹出框效果
- 多柱汉诺塔最优算法设计探究
- github开源Android组件资源整理(五)ScrollView, TimeView, TipView, FlipView, ColorPickView
- GLib双向链表
- SSH的一些简单理解