淺談md5加密 以及C++實現

只爭朝夕^ω^)↗發表於2018-08-28

md5加密是我們生活中十分常見的加密演算法。

起因:我是最近在寫一個H5 的專案時接觸到的這個演算法,這個演算法極大的引起了我的好奇心,是登陸介面,要求是將使用者輸入的密碼使用md5加密之後,再傳回伺服器,當時我十分不理解原因是什麼.

廢話少說
原因
1、密碼在前端進行加密,然後伺服器使用摘要進行比對,這樣在整個密碼的校驗過程中是在伺服器端不知道明碼的情況下進行的,極大的保證了密碼的安全,試想一下,一個銀行管理員,如果他可以通過伺服器獲取到明文密碼,那麼他一旦變心了,咋辦,那豈不是太危險,所以通過md5加密便很好地解決了這個問題
2、在避免檔案內容被篡改方面有重大作用,md5可以對字串進行不可逆的加密,這使得可以生成一個128bit的大數,由於md5演算法的原因,他與原始檔相對應,即使在檔案中做了很小的修改,那麼生成的字串也是差別巨大
3、在破解md5方面,最常用的方法是“跑字典”,有兩種方法得到字典,一種是日常蒐集的用做密碼的字串表,另一種是用排列組合方法生成的,先用MD5程式計算出這些字典項的MD5值,然後再用目標的MD5值在這個字典中檢索。我們假設密碼的最大長度為8位位元組(8 Bytes),同時密碼只能是字母和數字,共26+26+10=62個位元組,排列組合出的字典的項數則是P(62,1)+P(62,2)….+P(62,8),那也已經是一個很天文的數字了,儲存這個字典就需要TB級的磁碟陣列,而且這種方法還有一個前提,就是能獲得目標賬戶的密碼MD5值的情況下才可以。

所以總體而言,md5加密是十分安全的,即使有一些瑕疵,但並不影響具體的使用,外加md5是免費的,所以它的應用還是十分廣泛的

附加一份C++的md5加密演算法原始碼

#include<iostream>
#include<string>
using namespace std;
#define shift(x, n) (((x) << (n)) | ((x) >> (32-(n))))//右移的時候,高位一定要補零,而不是補充符號位
#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 A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
//strBaye的長度
unsigned int strlength;
//A,B,C,D的臨時變數
unsigned int atemp;
unsigned int btemp;
unsigned int ctemp;
unsigned int dtemp;
//常量ti unsigned int(abs(sin(i+1))*(2pow32))
const unsigned int k[]={
        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};
//向左位移數
const unsigned int s[]={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};
const char str16[]="0123456789abcdef";
void mainLoop(unsigned int M[])
{
    unsigned int f,g;
    unsigned int a=atemp;
    unsigned int b=btemp;
    unsigned int c=ctemp;
    unsigned int d=dtemp;
    for (unsigned int i = 0; i < 64; i++)
    {
        if(i<16){
            f=F(b,c,d);
            g=i;
        }else if (i<32)
        {
            f=G(b,c,d);
            g=(5*i+1)%16;
        }else if(i<48){
            f=H(b,c,d);
            g=(3*i+5)%16;
        }else{
            f=I(b,c,d);
            g=(7*i)%16;
        }
        unsigned int tmp=d;
        d=c;
        c=b;
        b=b+shift((a+f+k[i]+M[g]),s[i]);
        a=tmp;
    }
    atemp=a+atemp;
    btemp=b+btemp;
    ctemp=c+ctemp;
    dtemp=d+dtemp;
}
/*
*填充函式
*處理後應滿足bits≡448(mod512),位元組就是bytes≡56(mode64)
*填充方式為先加一個1,其它位補零
*最後加上64位的原來長度
*/
unsigned int* add(string str)
{
    unsigned int num=((str.length()+8)/64)+1;//以512位,64個位元組為一組
    unsigned int *strByte=new unsigned int[num*16];    //64/4=16,所以有16個整數
    strlength=num*16;
    for (unsigned int i = 0; i < num*16; i++)
        strByte[i]=0;
    for (unsigned int i=0; i <str.length(); i++)
    {
        strByte[i>>2]|=(str[i])<<((i%4)*8);//一個整數儲存四個位元組,i>>2表示i/4 一個unsigned int對應4個位元組,儲存4個字元資訊
    }
    strByte[str.length()>>2]|=0x80<<(((str.length()%4))*8);//尾部新增1 一個unsigned int儲存4個字元資訊,所以用128左移
    /*
    *新增原長度,長度指位的長度,所以要乘8,然後是小端序,所以放在倒數第二個,這裡長度只用了32位
    */
    strByte[num*16-2]=str.length()*8;
    return strByte;
}
string changeHex(int a)
{
    int b;
    string str1;
    string str="";
    for(int i=0;i<4;i++)
    {
        str1="";
        b=((a>>i*8)%(1<<8))&0xff;   //逆序處理每個位元組
        for (int j = 0; j < 2; j++)
        {
            str1.insert(0,1,str16[b%16]);
            b=b/16;
        }
        str+=str1;
    }
    return str;
}
string getMD5(string source)
{
    atemp=A;    //初始化
    btemp=B;
    ctemp=C;
    dtemp=D;
    unsigned int *strByte=add(source);
    for(unsigned int i=0;i<strlength/16;i++)
    {
        unsigned int num[16];
        for(unsigned int j=0;j<16;j++)
            num[j]=strByte[i*16+j];
        mainLoop(num);
    }
    return changeHex(atemp).append(changeHex(btemp)).append(changeHex(ctemp)).append(changeHex(dtemp));
}
  int main()
{
    string ss;
//    cin>>ss;
    string s=getMD5("456");
    cout<<s;
    return 0;
}

引自:https://blog.csdn.net/qq_32635069/article/details/72860033

相關文章