MD5算法介绍及实现

md5的全称是message-digest algorithm 5(信息-摘要算法),在90年代初由mit laboratory for computer science和rsa data security inc的ronald l. rivest开发出来,经md2、md3和md4发展而来。它的作用是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数)。不管是md2、md4还是md5,它们都需要获得一个随机长度的信息并产生一个128位的信息摘要。虽然这些算法的结构或多或少有些相似,但md2的设计与md4和md5完全不同,那是因为md2是为8位机器做过设计优化的,而md4和md5却是面向32位的电脑。这三个算法的描述和c语言源代码在internet rfcs 1321中有详细的描述( http://www.ietf.org/rfc/rfc1321.txt ),这是一份最权威的文档,由ronald l. rivest在1992年8月向ieft提交。

rivest在1989年开发出md2算法。在这个算法中,首先对信息进行数据补位,使信息的字节长度是16的倍数。然后,以一个16位的检验和追加到信息末尾。并且根据这个新产生的信息计算出散列值。后来,rogier和chauvaud发现如果忽略了检验和将产生md2冲突。md2算法的加密后结果是唯一的--既没有重复。

为了加强算法的安全性,rivest在1990年又开发出md4算法。md4算法同样需要填补信息以确保信息的字节长度加上448后能被512整除(信息字节长度mod 512 = 448)。然后,一个以64位二进制表示的信息的最初长度被添加进来。信息被处理成512位damg?rd/merkle迭代结构的区块,而且每个区块要通过三个不同步骤的处理。den boer和bosselaers以及其他人很快的发现了攻击md4版本中第一步和第三步的漏洞。dobbertin向大家演示了如何利用一部普通的个人电脑在几分钟内找到md4完整版本中的冲突(这个冲突实际上是一种漏洞,它将导致对不同的内容进行加密却可能得到相同的加密后结果)。毫无疑问,md4就此被淘汰掉了。

尽管md4算法在安全上有个这么大的漏洞,但它对在其后才被开发出来的好几种信息安全加密算法的出现却有着不可忽视的引导作用。除了md5以外,其中比较有名的还有sha-1、ripe-md以及haval等。

一年以后,即1991年,rivest开发出技术上更为趋近成熟的md5算法。它在md4的基础上增加了"安全-带子"(safety-belts)的概念。虽然md5比md4稍微慢一些,但却更为安全。这个算法很明显的由四个和md4设计有少许不同的步骤组成。在md5算法中,信息-摘要的大小和填充的必要条件与md4完全相同。den boer和bosselaers曾发现md5算法中的假冲突(pseudo-collisions),但除此之外就没有其他被发现的加密后结果了。

van oorschot和wiener曾经考虑过一个在散列中暴力搜寻冲突的函数(brute-force hash function),而且他们猜测一个被设计专门用来搜索md5冲突的机器(这台机器在1994年的制造成本大约是一百万美元)可以平均每24天就找到一个冲突。但单从1991年到2001年这10年间,竟没有出现替代md5算法的md6或被叫做其他什么名字的新算法这一点,我们就可以看出这个瑕疵并没有太多的影响md5的安全性。上面所有这些都不足以成为md5的在实际应用中的问题。并且,由于md5算法的使用不需要支付任何版权费用的,所以在一般的情况下(非绝密应用领域。但即便是应用在绝密领域内,md5也不失为一种非常优秀的中间技术),md5怎么都应该算得上是非常安全的了。

2004年8月17日的美国加州圣巴巴拉的国际密码学会议(Crypto’2004)上,来自中国山东大学的王小云教授做了破译MD5、HAVAL-128、 MD4和RIPEMD算法的报告,公布了MD系列算法的破解结果。宣告了固若金汤的世界通行密码标准MD5的堡垒轰然倒塌,引发了密码学界的轩然大波。

MD5破解工程权威网站
http://www.md5crk.com/ 是为了公开征集专门针对MD5的攻击而设立的,网站于2004年8月17日宣布:“中国研究人员发现了完整MD5算法的碰撞;Wang, Feng, Lai与Yu公布了MD5、MD4、HAVAL-128、RIPEMD-128几个 Hash函数的碰撞。这是近年来密码学领域最具实质性的研究进展。使用他们的技术,在数个小时内就可以找到MD5碰撞。……由于这个里程碑式的发现,MD5CRK项目将在随后48小时内结束”。

用的是哈希函数,在计算机网络中应用较多的不可逆加密算法有RSA公司发明的MD5算法和由美国国家技术标准研究所建议的安全散列算法SHA.
算法的应用

  MD5的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被篡改。比如,在UNIX下有很多软件在下载的时候都有一个文件名相同,文件扩展名为.md5的文件,在这个文件中通常只有一行文本,大致结构如:

   MD5 (tanajiya.tar.gz) = 0ca175b9c0f726a831d895e269332461

  这就是tanajiya.tar.gz文件的数字签名。MD5将整个文件当作一个大文本信息,通过其不可逆的字符串变换算法,产生了这个唯一的MD5信息摘要。如果在以后传播这个文件的过程中,无论文件的内容发生了任何形式的改变(包括人为修改或者下载过程中线路不稳定引起的传输错误等),只要你对这个文件重新计算MD5时就会发现信息摘要不相同,由此可以确定你得到的只是一个不正确的文件。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的"抵赖",这就是所谓的数字签名应用。

  MD5还广泛用于加密和解密技术上。比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。

  正是因为这个原因,现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字典"的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 Bytes),同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘阵列,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。这种加密技术被广泛的应用于UNIX系统中,这也是为什么UNIX系统比一般操作系统更为坚固一个重要原因。

  算法描述

  对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

  在MD5算法中,首先需要对信息进行填充,使其字节长度对512求余的结果等于448。因此,信息的字节长度(Bits Length)将被扩展至N*512+448,即N*64+56个字节(Bytes),N为一个正整数。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后,在在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,现在的信息字节长度=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。

  MD5中有四个32位被称作链接变量(Chaining Variable)的整数参数,他们分别为:A=0x01234567,B=0x89abcdef,C=0xfedcba98,D=0x76543210。

  当设置好这四个链接变量后,就开始进入算法的四轮循环运算。循环的次数是信息中512位信息分组的数目。

  将上面四个链接变量复制到另外四个变量中:A到a,B到b,C到c,D到d。

  主循环有四轮(MD4只有三轮),每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数。再将所得结果向右环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之一。
以一下是每次操作中用到的四个非线性函数(每轮一个)。

   F(X,Y,Z) =(X&Y)|((~X)&Z)
   G(X,Y,Z) =(X&Z)|(Y&(~Z))
   H(X,Y,Z) =X^Y^Z
   I(X,Y,Z)=Y^(X|(~Z))
   (&是与,|是或,~是非,^是异或)

  这四个函数的说明:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。
F是一个逐位运算的函数。即,如果X,那么Y,否则Z。函数H是逐位奇偶操作符。
============================= 头文件Security.h ===============================================

/*
使用方法:

char Md5Buffer[33];
CSecurity Security;
Security.MD5("a string",Md5Buffer);

执行完成之后Md5Buffer中即存储了由"a string"计算得到的MD5值

*/


//  下列 ifdef 块是创建使从 DLL 导出更简单的
//  宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 SECURITY_EXPORTS
//  符号编译的。在使用此 DLL 的
//  任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将 
//  SECURITY_API 函数视为是从此 DLL 导入的,而此 DLL 则将用此宏定义的
//  符号视为是被导出的。

// 在使用该类的地方包含本文件即可
#ifdef SECURITY_EXPORTS
#define  SECURITY_API __declspec(dllexport)
#else
#define  SECURITY_API __declspec(dllimport)
#endif

/* 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; 

#define  PROTO_LIST(list) list 

/* MD5 context. */  
typedef 
struct  _MD5_CTX 

        UINT4 state[
4]; /* state (ABCD) */ 
        UINT4 count[
2]; /* number of bits, modulo 2^64 (lsb first) */ 
        unsigned 
char buffer[64]; /* input buffer */ 
}
 MD5_CTX; 

static  unsigned  char  PADDING[ 64 ] =  
        
0x80000000000000000000000
                
00000000000000000000000
                
0000000000000000000 
}
;
/* Constants for MD5Transform routine. 
*/
 
#define  S11 7 
#define  S12 12 
#define  S13 17 
#define  S14 22 
#define  S21 5 
#define  S22 9 
#define  S23 14 
#define  S24 20 
#define  S31 4 
#define  S32 11 
#define  S33 16 
#define  S34 23 
#define  S41 6 
#define  S42 10 
#define  S43 15 
#define  S44 21 

/* F, G, H and I are basic MD5 functions. 
*/
 
#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))) 

/* ROTATE_LEFT rotates x left n bits. 
*/
 
#define  ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 
Rotation is separate from addition to prevent recomputation. 
*/
 
#define  FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac);(a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 
#define  GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 
#define  HH(a, b, c, d, x, s, ac) {  (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 
#define  II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 

#define  TEST_BLOCK_LEN 1000 
#define  TEST_BLOCK_COUNT 1000 

//  此类是从 Security.dll 导出的
class  SECURITY_API CSecurity 
{
public:
        CSecurity(
void);
        
void CSecurity::MD5( const char *string ,char *lpMD5StringBuffer ) ; 
private:
         
void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); 
         
void MD5_memcpy PROTO_LIST ((POINTER, POINTER, size_t)); 
         
void MD5_memset PROTO_LIST ((POINTER, int, size_t)); 
         
void MD5Init PROTO_LIST ((MD5_CTX *)); 
         
void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, size_t)); 
         
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); 
         
void MDTimeTrial PROTO_LIST ((void)); 
         
void StringAddOne PROTO_LIST ((char *)); 
         
void Encode PROTO_LIST ((unsigned char *, UINT4 *, size_t)); 
         
void Decode PROTO_LIST ((UINT4 *, unsigned char *, size_t)); 
}
;
=============================== Security.cpp ====================================================

//  Security.cpp : 定义 DLL 应用程序的入口点。
//

#include 
" stdafx.h "

#include
< stdio.h >  
#include
< stdlib.h >  
#include
< string .h >  
#include
< math.h >  
#include
< ctype.h >  

#include 
" Security.h "

BOOL APIENTRY DllMain( HANDLE hModule, 
                                          DWORD  ul_reason_for_call, 
                                          LPVOID lpReserved
                                          )
{
        
switch (ul_reason_for_call)
        
{
        
case DLL_PROCESS_ATTACH:
        
case DLL_THREAD_ATTACH:
        
case DLL_THREAD_DETACH:
        
case DLL_PROCESS_DETACH:
                
break;
        }

    
return TRUE;
}



//  这是已导出类的构造函数。
//  有关类定义的信息,请参阅 Security.h
CSecurity::CSecurity()

        
return
}



/* 
MD5 initialization. Begins an MD5 operation, writing a new context. 
*/
 
void  CSecurity::MD5Init( MD5_CTX  * context ) 

        context
->count[0= context->count[1= 0
        
/* 
        Load magic initialization constants. 
        
*/
 
        context
->state[0= 0x67452301
        context
->state[1= 0xefcdab89
        context
->state[2= 0x98badcfe
        context
->state[3= 0x10325476
}
 

/* 
MD5 block update operation. Continues an MD5 message-digest 
operation, processing another message block, and updating the 
context. 
*/
 
void  CSecurity::MD5Update( 
                                          MD5_CTX 
* context,  /* context */  
                                          unsigned 
char   * input,  /* input block */  
                                          size_t inputLen 
/* length of input block */  
                                          ) 

        size_t i, index, partLen; 
        
        
/* Compute number of bytes mod 64 */ 
        index 
= (size_t)((context->count[0>> 3& 0x3F); 
        
        
/* Update number of bits */ 
        
if ((context->count[0+= ((UINT4)inputLen << 3)) 
                
< ((UINT4)inputLen << 3)) 
                context
->count[1]++
        context
->count[1+= ((UINT4)inputLen >> 29); 
        
        partLen 
= 64 - index; 
        
        
/* Transform as many times as possible. */ 
        
if (inputLen >= partLen) 
                MD5_memcpy 
                        ((POINTER)
&context->buffer[index], (POINTER)input, partLen); 
                MD5Transform (context
->state, context->buffer); 
                
                
for (i = partLen; i + 63 < inputLen; i += 64
                        MD5Transform (context
->state, &input); 
                
                index 
= 0
        }
 
        
else 
                i 
= 0
        
        
/* Buffer remaining input */ 
        MD5_memcpy 
                ((POINTER)
&context->buffer[index], (POINTER)&input, 
                inputLen
-i); 
}
 

/* 
MD5 finalization. Ends an MD5 message-digest operation, writing the 
the message digest and zeroizing the context. 
*/
 
void  CSecurity::MD5Final( 
                                         unsigned 
char  digest[ 16 ],  /* message digest */  
                                         MD5_CTX 
* context  /* context */  
                                         ) 

        unsigned 
char bits[8]; 
        size_t index, padLen; 
        
        
/* Save number of bits */ 
        Encode (bits, context
->count, 8); 
        
        
/* Pad out to 56 mod 64. */ 
        index 
= (size_t)((context->count[0>> 3& 0x3f); 
        padLen 
= (index < 56? (56 - index) : (120 - index); 
        MD5Update (context, PADDING, padLen); 
        
        
/* Append length (before padding) */ 
        MD5Update (context, bits, 
8); 
        
        
/* Store state in digest */ 
        Encode (digest, context
->state, 16); 
        
        
/* Zeroize sensitive information. */ 
        MD5_memset ((POINTER)context, 
0sizeof (*context)); 
}
 

/* 
MD5 basic transformation. Transforms state based on block. 
*/
 
void  CSecurity::MD5Transform( 
                                                 UINT4 state[
4 ], 
                                                 unsigned 
char  block[ 64
                                                 ) 

        UINT4 a 
= state[0], b = state[1], c = state[2], d = state[3], x[16]; 
        
        Decode (x, block, 
64); 
        
        
/* Round 1 */ 
        FF (a, b, c, d, x[ 
0], S11, 0xd76aa478); /* 1 */ 
        FF (d, a, b, c, x[ 
1], S12, 0xe8c7b756); /* 2 */ 
        FF (c, d, a, b, x[ 
2], S13, 0x242070db); /* 3 */ 
        FF (b, c, d, a, x[ 
3], S14, 0xc1bdceee); /* 4 */ 
        FF (a, b, c, d, x[ 
4], S11, 0xf57c0faf); /* 5 */ 
        FF (d, a, b, c, x[ 
5], S12, 0x4787c62a); /* 6 */ 
        FF (c, d, a, b, x[ 
6], S13, 0xa8304613); /* 7 */ 
        FF (b, c, d, a, x[ 
7], S14, 0xfd469501); /* 8 */ 
        FF (a, b, c, d, x[ 
8], S11, 0x698098d8); /* 9 */ 
        FF (d, a, b, c, x[ 
9], S12, 0x8b44f7af); /* 10 */ 
        FF (c, d, a, b, x[
10], S13, 0xffff5bb1); /* 11 */ 
        FF (b, c, d, a, x[
11], S14, 0x895cd7be); /* 12 */ 
        FF (a, b, c, d, x[
12], S11, 0x6b901122); /* 13 */ 
        FF (d, a, b, c, x[
13], S12, 0xfd987193); /* 14 */ 
        FF (c, d, a, b, x[
14], S13, 0xa679438e); /* 15 */ 
        FF (b, c, d, a, x[
15], S14, 0x49b40821); /* 16 */ 
        
        
/* Round 2 */ 
        GG (a, b, c, d, x[ 
1], S21, 0xf61e2562); /* 17 */ 
        GG (d, a, b, c, x[ 
6], S22, 0xc040b340); /* 18 */ 
        GG (c, d, a, b, x[
11], S23, 0x265e5a51); /* 19 */ 
        GG (b, c, d, a, x[ 
0], S24, 0xe9b6c7aa); /* 20 */ 
        GG (a, b, c, d, x[ 
5], S21, 0xd62f105d); /* 21 */ 
        GG (d, a, b, c, x[
10], S22, 0x2441453); /* 22 */ 
        GG (c, d, a, b, x[
15], S23, 0xd8a1e681); /* 23 */ 
        GG (b, c, d, a, x[ 
4], S24, 0xe7d3fbc8); /* 24 */ 
        GG (a, b, c, d, x[ 
9], S21, 0x21e1cde6); /* 25 */ 
        GG (d, a, b, c, x[
14], S22, 0xc33707d6); /* 26 */ 
        GG (c, d, a, b, x[ 
3], S23, 0xf4d50d87); /* 27 */ 
        GG (b, c, d, a, x[ 
8], S24, 0x455a14ed); /* 28 */ 
        GG (a, b, c, d, x[
13], S21, 0xa9e3e905); /* 29 */ 
        GG (d, a, b, c, x[ 
2], S22, 0xfcefa3f8); /* 30 */ 
        GG (c, d, a, b, x[ 
7], S23, 0x676f02d9); /* 31 */ 
        GG (b, c, d, a, x[
12], S24, 0x8d2a4c8a); /* 32 */ 
        
        
/* Round 3 */ 
        HH (a, b, c, d, x[ 
5], S31, 0xfffa3942); /* 33 */ 
        HH (d, a, b, c, x[ 
8], S32, 0x8771f681); /* 34 */ 
        HH (c, d, a, b, x[
11], S33, 0x6d9d6122); /* 35 */ 
        HH (b, c, d, a, x[
14], S34, 0xfde5380c); /* 36 */ 
        HH (a, b, c, d, x[ 
1], S31, 0xa4beea44); /* 37 */ 
        HH (d, a, b, c, x[ 
4], S32, 0x4bdecfa9); /* 38 */ 
        HH (c, d, a, b, x[ 
7], S33, 0xf6bb4b60); /* 39 */ 
        HH (b, c, d, a, x[
10], S34, 0xbebfbc70); /* 40 */ 
        HH (a, b, c, d, x[
13], S31, 0x289b7ec6); /* 41 */ 
        HH (d, a, b, c, x[ 
0], S32, 0xeaa127fa); /* 42 */ 
        HH (c, d, a, b, x[ 
3], S33, 0xd4ef3085); /* 43 */ 
        HH (b, c, d, a, x[ 
6], S34, 0x4881d05); /* 44 */ 
        HH (a, b, c, d, x[ 
9], S31, 0xd9d4d039); /* 45 */ 
        HH (d, a, b, c, x[
12], S32, 0xe6db99e5); /* 46 */ 
        HH (c, d, a, b, x[
15], S33, 0x1fa27cf8); /* 47 */ 
        HH (b, c, d, a, x[ 
2], S34, 0xc4ac5665); /* 48 */ 
        
        
/* Round 4 */ 
        II (a, b, c, d, x[ 
0], S41, 0xf4292244); /* 49 */ 
        II (d, a, b, c, x[ 
7], S42, 0x432aff97); /* 50 */ 
        II (c, d, a, b, x[
14], S43, 0xab9423a7); /* 51 */ 
        II (b, c, d, a, x[ 
5], S44, 0xfc93a039); /* 52 */ 
        II (a, b, c, d, x[
12], S41, 0x655b59c3); /* 53 */ 
        II (d, a, b, c, x[ 
3], S42, 0x8f0ccc92); /* 54 */ 
        II (c, d, a, b, x[
10], S43, 0xffeff47d); /* 55 */ 
        II (b, c, d, a, x[ 
1], S44, 0x85845dd1); /* 56 */ 
        II (a, b, c, d, x[ 
8], S41, 0x6fa87e4f); /* 57 */ 
        II (d, a, b, c, x[
15], S42, 0xfe2ce6e0); /* 58 */ 
        II (c, d, a, b, x[ 
6], S43, 0xa3014314); /* 59 */ 
        II (b, c, d, a, x[
13], S44, 0x4e0811a1); /* 60 */ 
        II (a, b, c, d, x[ 
4], S41, 0xf7537e82); /* 61 */ 
        II (d, a, b, c, x[
11], S42, 0xbd3af235); /* 62 */ 
        II (c, d, a, b, x[ 
2], S43, 0x2ad7d2bb); /* 63 */ 
        II (b, c, d, a, x[ 
9], S44, 0xeb86d391); /* 64 */ 
        
        state[
0+= a; 
        state[
1+= b; 
        state[
2+= c; 
        state[
3+= d; 
        
        
/* Zeroize sensitive information. */ 
        MD5_memset ((POINTER)x, 
0sizeof (x)); 
}
 

/* 
Encodes input (UINT4) into output (unsigned char). 
Assumes len is a multiple of 4. 
*/
 
void  CSecurity::Encode( 
                                   unsigned 
char   * output, 
                                   UINT4 
* input, 
                                   size_t len 
                                   ) 

        size_t i, j; 
        
        
for (i = 0, j = 0; j < len; i++, j += 4
                output[j] 
= (unsigned char)(input & 0xff); 
                output[j
+1= (unsigned char)((input >> 8& 0xff); 
                output[j
+2= (unsigned char)((input >> 16& 0xff); 
                output[j
+3= (unsigned char)((input >> 24& 0xff); 
        }
 
}
 

/* 
Decodes input (unsigned char) into output (UINT4). 
Assumes len is a multiple of 4. 
*/
 
void  CSecurity::Decode( 
                                   UINT4 
* output, 
                                   unsigned 
char   * input, 
                                   size_t len 
                                   ) 

        size_t i, j; 
        
        
for (i = 0, j = 0; j < len; i++, j += 4
                output 
= ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8| 
                (((UINT4)input[j
+2]) << 16| (((UINT4)input[j+3]) << 24); 
}
 

/* 
Note: Replace "for loop" with standard memcpy if possible. 
*/
 
void  CSecurity::MD5_memcpy( 
                                           POINTER output, 
                                           POINTER input, 
                                           size_t len 
                                           ) 

        size_t i; 
        
        
for (i = 0; i < len; i++
                output 
= input; 
}
 

/* 
Note: Replace "for loop" with standard memset if possible. 
*/
 
void  CSecurity::MD5_memset( 
                                           POINTER output, 
                                           
int  value, 
                                           size_t len 
                                           ) 

        size_t i; 
        
        
for (i = 0; i < len; i++
                ((
char *)output) = (char)value; 
}
 

/* 
Digests a string and prints the result. 
*/
 
void  CSecurity::MD5(  const   char   * string  , char   * lpMD5StringBuffer ) 

        MD5_CTX context; 
        unsigned 
char digest[16]; 
        
/*char output1[33]; */
        
static char output[33]={""}
        
/*size_t*/size_t len = strlen (string); 
        
int i; 
        
        MD5Init( 
&context); 
        MD5Update( 
&context, (unsigned char*)string, len ); 
        MD5Final( digest, 
&context ); 
        
        
for (i = 0; i < 16; i++
        

                sprintf(
&(lpMD5StringBuffer[2*i]),"%02x",(unsigned char)digest); 
                sprintf(
&(lpMD5StringBuffer[2*i+1]),"%02x",(unsigned char)(digest<<4)); 
        }
 
        
for(i=0;i<32;i++
        

                output
=lpMD5StringBuffer; 
        }
 
}
 

/* 
get the string add one. 
*/
 
void  CSecurity::StringAddOne(  char   *  orstring ) 

        size_t len; 
        size_t i,n; 
        
        len 
= strlen(orstring); 
        n 
= len - 1
        
for(i = n; i >= 0; i--
        

                
if(orstring=='9'
                

                        orstring 
= 'A'
                        
break
                }
 
                
else if(orstring=='Z'
                

                        orstring
='a'
                        
break
                }
 
                
else if(orstring=='z'
                

                        orstring
='0'
                        
continue
                }
 
                
else 
                        orstring 
+= 1
                
break
        }
 
}
 
============================= stdafx.h =====================================
//  stdafx.h : 标准系统包含文件的包含文件,
//  或是常用但不常更改的项目特定的包含文件
//

#pragma  once

// 导出
#define  SECURITY_EXPORTS

#define  WIN32_LEAN_AND_MEAN                 //  从 Windows 头中排除极少使用的资料
//  Windows 头文件:
#include  < windows.h >

//  TODO: 在此处引用程序要求的附加头文件
============================ stdafx.cpp ========================================

//  stdafx.cpp : 只包括标准包含文件的源文件
//  Security.pch 将成为预编译头
//  stdafx.obj 将包含预编译类型信息

#include 
" stdafx.h "

//  TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用
=====================================================================
 以上程序使用命令:@cl /GD /LD Security.cpp stdafx.cpp 编译即可
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值