MD5

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef unsigned char UC;
typedef unsigned int UI;
typedef unsigned long long ULL;
#define maxn 500005
//定义MD5中的4个非线性函数F、G、H、I
#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)))

//循环左移n位
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

//填充的字节常量
UC PADDING[64]={0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

//常量T
UI T[4][16]={
    {0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821},
    {0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x2441453,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}
};

//每轮迭代中M的下标
UI P[4][16]={
    {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
    {1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12},
    {5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2},
    {0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9}
};

//每轮移位量
UI S[4][4]={
    {7,12,17,22},
    {5,9,14,20},
    {4,11,16,23},
    {6,10,15,21}
};

//每轮寄存器代换编号
UI ID[4][4]={
    {0,1,2,3},
    {3,0,1,2},
    {2,3,0,1},
    {1,2,3,0}
};

struct MD5
{
    UI reg[4];    //4个32位寄存器
    UI len[2];   //消息原始长度64位,即最大为2^64bit
    UC buf[64];   //存放消息64*8=512bit
    MD5(){        //构造函数,初始化寄存器
        len[0]=len[1]=0;
        reg[0]=0x67452301;
        reg[1]=0xefcdab89;
        reg[2]=0x98badcfe;
        reg[3]=0x10325476;
    }
};

//函数g
void FunctionG(UI &a,UI b,UI c,UI d,UI m,UI t,UI s,int flag)
{
    if(flag==0) a=b+ROTATE_LEFT((a+F(b,c,d)+m+t),s);
    if(flag==1) a=b+ROTATE_LEFT((a+G(b,c,d)+m+t),s);
    if(flag==2) a=b+ROTATE_LEFT((a+H(b,c,d)+m+t),s);
    if(flag==3) a=b+ROTATE_LEFT((a+I(b,c,d)+m+t),s);
}

//4字节的整数input转储到长度为length的char型数组output中,
void ItoC(UI *input,UC *output,UI length)
{
    UI i,j;
    for(i=0,j=0;j<length;++i,j+=4)
    {
        output[j]=(UC)(input[i]&0xff);
        output[j+1]=(UC)((input[i]>>8)&0xff);
        output[j+2]=(UC)((input[i]>>16)&0xff);
        output[j+3]=(UC)((input[i]>>24)&0xff);
    }
}

//char转int
void CtoI(UC *input,UI *output,UI length)
{
    UI i,j;
    for(i=0,j=0;j<length;++i,j+=4)
        output[i]=((UI)input[j])|(((UI)input[j+1])<<8)|
        (((UI)input[j+2])<<16)|(((UI)input[j+3])<<24);
}

//四轮处理,每轮16次迭代,参数为:存放结果的寄存器和欲处理的512bit明文
void work(UI reg[4],UC buf[64])
{
    UI i,j,reg2[4],M[16];
    for(i=0;i<4;++i) reg2[i]=reg[i];
    CtoI(buf,M,64);
    for(i=0;i<4;++i)
        for(j=0;j<16;++j)
            FunctionG(reg2[ID[j%4][0]],reg2[ID[j%4][1]],reg2[ID[j%4][2]],reg2[ID[j%4][3]],M[P[i][j]],T[i][j],S[i][j%4],i);
    for(i=0;i<4;++i) reg[i]+=reg2[i];
    memset(M,0,sizeof(M));
}

//填充消息、添加明文长度
void add(MD5 &md5,UC *str,UI L)
{
    UI i,rmlen,pos=(UI)((md5.len[0]>>3)&0x3f);       //已有消息长度(字节)对64取模
    md5.len[0]+=(L<<3);                     //更新消息长度(bit)
    if(md5.len[0]<(L<<3))                   //发生了溢出,说明产生了进位
        ++md5.len[1];
    md5.len[1]+=(L>>29);                    //高位加上8*L>>32即L>>29
    rmlen=64-pos;                              //需要补充的字节数
    if(L>=rmlen)                               //消息长度大于需补充的字节数
    {
        memcpy((UC *)&md5.buf[pos],(UC *)str,rmlen);       //用当前消息补充rm个字节即可
        work(md5.reg,md5.buf);              //对填充好的消息进行处理,结果保存至reg中
        for(i=rmlen;i+63<L;i+=64)             //对剩下的消息,从第rm个字节开始,每次取64个字节填充处理之
            work(md5.reg,&str[i]);
        pos=0;
    }
    else                                    //消息长度不足以补充所缺字节数
        i=0;
    memcpy((UC *)&md5.buf[pos],(UC *)&str[i],L-i);      //填充剩下的字节(不足以达到512字节),等待最终处理
}

//最终处理,参数为:保存结果的16个寄存器(128bit),待处理消息
void solve(UC reg[16],MD5 &md5)
{
    UC length[8];
    UI pos=(UI)((md5.len[0]>>3)&0x3f),rmlen;
    //将要被转换的信息的长度拷贝到length中
    ItoC(md5.len,length,8);
    //需要填充的字节数(需要留有8个字节存放length)
    rmlen=(pos<56)?(56-pos):(120-pos);
    add(md5,PADDING,rmlen);         //添10000……
    add(md5,length,8);              //添上原始信息长度
    ItoC(md5.reg,reg,16);           //最终结果放到reg中
    memset(&md5,0,sizeof(md5));
}

UC plaintext[maxn],ciphertext[17];

int main(int argc,char* argv[])
{
    MD5 md5;
    scanf("%s",plaintext);
    add(md5,plaintext,strlen((char *)plaintext));         //填充消息、添加明文长度
    solve(ciphertext,md5);
    for(int i=0;i<16;++i) printf("%02x",ciphertext[i]);
    puts("");
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值