学习笔记-C语言实现MD5加密算法

来源:互联网 发布:获取json的key和value 编辑:程序博客网 时间:2024/05/16 15:41

参考了不知道哪一位前辈的主体构思,暂时不知道改怎么描述,网上资料一大堆,实际看起来还是云里雾里,而现在想对做出来的东西做一个整理,发现还是找不到一个好的头绪,代码先贴出来:

头文件:CMD5.h

int MD5_32(char** szOut, char* szBuff, int iLen);
int MD5_16(char** szOut, char* szBuff, int iLen);


CMD5.cpp

#include <memory.h>
#include <stdlib.h>
#include "CMD5.h"

const int DIGEST32_LEN = 16;
const int DIGEST16_LEN = 8;

const unsigned int g_nTable[4][16] = {
{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}
};//四轮循环中每16步的累加基数

const int g_nMove[4][16] = {
{7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22},
{5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20},
{4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23},
{6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21}
};//四轮循环中每16步的LROTATE位数

const unsigned int g_nMagNum[4] = {0x67452301,0xefcdab89,0x98badcfe,0x10325476};//四个初始幻数

//四轮循环的操作
#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))) 

#define LROTATE(X, n) ((X << n) | (X >> (32 - n))) //整数X向左循环移n位,将高位移至低位
#define RROTATE(t, a, b, c, d) {\
t = d;\
d = c;\
c = b;\
b = a;\
a = t;\
}//数组元素向右循环移一个位置

#define FGHI(t, a, b, c, d, n) {\
a = LROTATE(a, n);\
a += b;\
RROTATE(t, a, b, c, d);\
}//四轮循环中的算法流程

//填充需要加密的信息,使信息长度(以Byte为单位)取64模运算时余数是56字节
//余数为[0,56)时,填充满56字节;当余数为56时,填充64字节
//填充内容的第一个字节最高位为1、其余位为0,其余字节均为0
//剩余8字节填充的是信息的原始长度,即信息填充前的长度,单位为Bit
static int FillBuff(char** szOut, char* szBuff, int iLen)
{
char* szAppend;
int iMod = iLen % 64, iFill;
unsigned __int64 iNum = iLen * 8;
if(iMod < 56)
{
iFill = 56 - iMod;
}
else if(iMod == 56)
{
iFill = 64;
}
else
{
iFill = 64 - iMod + 56;
}
szAppend = calloc(iFill, 1);
*szOut = calloc(iLen + iFill + 8, 1);
szAppend[0] = (char)0x80;
memcpy(*szOut, szBuff, iLen);//复制原信息
memcpy(*szOut + iLen, szAppend, iFill);//填充字节使 %64 余数为56
memcpy(*szOut + iLen + iFill, &iNum, 8);//填充原信息Bit长度
free(szAppend);
return iLen + iFill + 8;
}

//数组拷贝
static void cpy(const unsigned int src[], unsigned int dest[], int len)
{
while(--len >= 0)
{
dest[len] = src[len];
}
}

//将加密后的字节流转换成16进制整数的字符串形式
static void FormatStr(char** szOut, char* szBuff, int iLen)
{
unsigned char ch;
int i = 0, j = 0;
*szOut = calloc(iLen * 2 + 1, 1);
for(; i < iLen; i++)//每个字节是8Bit,刚好是2位16进制
{
ch = (unsigned char)((szBuff[i] >> 4) & 0x0f);//第一位
(*szOut)[j++] = (unsigned char)(ch < 0x0a ? ('0' + ch) : ('A' + (ch - 0x0a)));
ch = (unsigned char)(szBuff[i] & 0x0f);//第二位
(*szOut)[j++] = (unsigned char)(ch < 0x0a ? ('0' + ch) : ('A' + (ch - 0x0a)));
}
}

//算法主体都在这函数里头了
//32位MD5加密,得到的是密文字节流
//返回密文字节数
static int Digest32(char** szOut, char* szBuff, int iLen)
{
char* szData;
int iGroup;
unsigned int g_nState[4]/*保存密文摘要状态作为最后返回*/, g_nTemp[4]/*上一组的密文摘要状态*/, iTemp;


cpy(g_nMagNum, g_nState, 4);//以幻数初始化密文摘要状态
iLen = FillBuff(&szData, szBuff, iLen);


for(iGroup = 0; iGroup < iLen; iGroup += 64)//每64字节为一组
{
int iRound = 0, i = 0, j = 0;
cpy(g_nState, g_nTemp, 4);//临时记录上一组的密文摘要状态


for(j = 0;j < 16; j++)
{
i = j;
g_nTemp[0] += F(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
FGHI(iTemp, g_nTemp[0], g_nTemp[1], g_nTemp[2], g_nTemp[3], g_nMove[iRound][j]);
}
iRound++;
for(j = 0;j < 16; j++)
{
i=(1+5*j)%16;
g_nTemp[0] += G(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
FGHI(iTemp, g_nTemp[0], g_nTemp[1], g_nTemp[2], g_nTemp[3], g_nMove[iRound][j]);
}
iRound++;
for(j = 0;j < 16; j++)
{
i=(5+3*j)%16;
g_nTemp[0] += H(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
FGHI(iTemp, g_nTemp[0], g_nTemp[1], g_nTemp[2], g_nTemp[3], g_nMove[iRound][j]);
}
iRound++;
for(j = 0;j < 16; j++)
{
i=(7*j)%16;
g_nTemp[0] += I(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
FGHI(iTemp, g_nTemp[0], g_nTemp[1], g_nTemp[2], g_nTemp[3], g_nMove[iRound][j]);
}

g_nState[0]+=g_nTemp[0];
g_nState[1]+=g_nTemp[1];
g_nState[2]+=g_nTemp[2];
g_nState[3]+=g_nTemp[3];
//和上边儿是一样的,感觉这样看思路比较清晰
//for(;iRound < 4; iRound++)//4轮循环
//{
// for(j = 0;j < 16; j++)//每轮16步
// {
// switch(iRound)
// {
// case 0://第一轮
// i = j;
// g_nTemp[0] += F(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
// break;
// case 1://第二轮
// i=(1+5*j)%16;
// g_nTemp[0] += G(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
// break;
// case 2://第三轮
// i=(5+3*j)%16;
// g_nTemp[0] += H(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
// break;
// case 3://第四轮
// i=(7*j)%16;
// g_nTemp[0] += I(g_nTemp[1],g_nTemp[2],g_nTemp[3])+*(unsigned int*)(szData+iGroup+i*4)+g_nTable[iRound][j];
// break;
// }
// FGHI(iTemp, g_nTemp[0], g_nTemp[1], g_nTemp[2], g_nTemp[3], g_nMove[iRound][j]);
// }
//}
////四轮循环结束后累加密文摘要状态
//g_nState[0]+=g_nTemp[0];
//g_nState[1]+=g_nTemp[1];
//g_nState[2]+=g_nTemp[2];
//g_nState[3]+=g_nTemp[3];
}
free(szData);


*szOut = calloc(DIGEST32_LEN, 1);
memcpy(*szOut, g_nState, DIGEST32_LEN);//保存最终密文摘要信息
return DIGEST32_LEN;
}

//16位MD5加密,得到的是加密字节流
static int Digest16(char** szOut, char* szBuff, int iLen)
{
char* szTemp;
Digest32(&szTemp, szBuff, iLen);
*szOut = calloc(DIGEST16_LEN, 1);
memcpy(*szOut, szTemp + DIGEST16_LEN / 2, DIGEST16_LEN);
free(szTemp);
return DIGEST16_LEN;
}

//32位MD5加密,得到的是密文的16进制整数字符串形式
//返回密文字符数
//char**的意图是调用时不必关心事先的内存分配,调用完记得free
int MD5_32(char** szOut, char* szBuff, int iLen)
{
char* szTemp;
Digest32(&szTemp, szBuff, iLen);
FormatStr(szOut, szTemp, DIGEST32_LEN);
free(szTemp);
return DIGEST32_LEN * 2;
}

//16位MD5加密,得到的是密文的16进制整数字符串形式
int MD5_16(char** szOut, char* szBuff, int iLen)
{
char* szTemp;
Digest16(&szTemp, szBuff, iLen);
FormatStr(szOut, szTemp, DIGEST16_LEN);
free(szTemp);
return DIGEST16_LEN * 2;
}


调用示例,含有中文的字符串一般先转为UTF8编码,反正参考网上的工具是这样子的:

#include <windows.h>
#include <stdio.h>
#include "CMD5.h"

char* szTest = "我也就试试hehe";
int main()
{
char* szOut;
char szBuff[128] = {0};
wchar_t w[128] = {0};
int i1 , i2; 
memcpy(szBuff, szTest, lstrlenA(szTest));
i1 = MultiByteToWideChar(CP_ACP, 0, szBuff, lstrlenA(szBuff), w, 128);
i2 = WideCharToMultiByte(CP_UTF8, 0, w, i1, szBuff, 128, NULL, FALSE);


MD5_32(&szOut, szBuff, i2);
printf(szOut);
free(szOut);

MD5_16(&szOut, szBuff, i2);
printf("\n");
printf(szOut);
free(szOut);

getchar();
return 0;
}

0 0
原创粉丝点击