md5 Length Extension Attack

来源:互联网 发布:电视盒子软件2017 编辑:程序博客网 时间:2024/05/17 09:38

描述

设msg为原始消息(对于攻击者来说是未知的),padding为msg的补齐部分,append为附加的数据。
根据msg的长度可以推算出padding(如果长度未知则可以从1开始暴力枚举),根据md5(msg)可以计算出md5(msg + padding + append)。

原理分析

md5算法对消息进行分组,每组64个字节,不足64个字节的部分用padding补齐。padding补齐的规则是,在最末一个字节之后补充0x80,其余部分填充为0x00,padding最后的8个字节用来表示需要哈希的消息的位长度。补齐总是进行的,即如果消息的长度刚好是64个字节的整数倍,则也需要补齐64个字节。
在对消息进行分组以及padding后,md5算法依次对魅族消息进行压缩,经过64轮数学变换。在这个过程中,一开始会有定义好的初始化向量,为4个中间值,初始化向量是标准里定义的,为
vi[0] = 0x67452301
vi[1] = 0xEFCDAB89
vi[2] = 0x98BADCFE
vi[3] = 0x10325476
md5 length extension attack的理论基础,就是将已知的压缩后的结果,直接拿过来作为新的压缩输入。在这个过程中,只需要上一次压缩后的结果,而不需要知道原来的消息内容
所以把md5(msg)还原为4个变量替换掉vi中的4个变量即可计算出md5(msg + padding + append)的值

参考

  • [rfc1321](https://www.ietf.org/rfc/rfc1321.txt

应对方法

计算md5时,加密前的字符串的最后一位用双方约定的secret_key即可。

代码

#include <stdio.h>#include <string.h>#include <iostream>#include <string>#include <vector>using namespace std;typedef unsigned char uint_8;typedef unsigned short uint_16;typedef unsigned int uint_32;typedef unsigned long long uint_64;#define ustring basic_string<unsigned char>//十进制转16进制string int2hex(uint_32 a){    string hexStr = "";    if(a == 0){        hexStr += "0";    }else{        uint_32 i;        char str[2] = "0";        while(a > 0){            i = a % 16;            a >>= 4;            if(i <= 9){                hexStr = to_string((long long unsigned int)i) + hexStr;            }else{                str[0] = (char)(i - 10 + (int)'a');                hexStr = string(str) + hexStr;            }        }    }    return hexStr;}uint_32 hex2int(string s){    if(s == "0"){        return 0;    }    uint_32 a = 0, b;    for(int i = 0; i < s.length(); i++){        a <<= 4;        if(s[i] >= '0' && s[i] <= '9'){            b = (int) (s[i] - '0');        }else if(s[i] >= 'a' && s[i] <= 'z'){            b = (int) (s[i] - 'a') + 10;        }else if(s[i] >= 'A' && s[i] <= 'Z'){            b = (int) (s[i] - 'A') + 10;        }else{            b = 0;        }        a += b;    }    return a;}void str2ascii(const unsigned char *str, int length){    for(int i = 0; i < length; i++){        if(i > 0) printf(" ");        cout << int2hex((int)str[i]);    }}uint_32 rotate_left(uint_32 x, uint_32 n){    return (x << n) | (x >> (32-n));}uint_32 F(uint_32 X, uint_32 Y, uint_32 Z){    return (X&Y)|((~X)&Z);}uint_32 G(uint_32 X, uint_32 Y, uint_32 Z){    return (X&Z)|(Y&(~Z));}uint_32 H(uint_32 X, uint_32 Y, uint_32 Z){    return X^Y^Z;}uint_32 I(uint_32 X, uint_32 Y, uint_32 Z){    return Y^(X|(~Z));}void FF(uint_32 &a, uint_32 b, uint_32 c, uint_32 d, uint_32 m, uint_32 s, uint_32 t){    a=b+rotate_left((a+F(b,c,d)+m+t), s);}void GG(uint_32 &a, uint_32 b, uint_32 c, uint_32 d, uint_32 m, uint_32 s, uint_32 t){    a=b+rotate_left((a+G(b,c,d)+m+t), s);}void HH(uint_32 &a, uint_32 b, uint_32 c, uint_32 d, uint_32 m, uint_32 s, uint_32 t){    a=b+rotate_left((a+H(b,c,d)+m+t), s);}void II(uint_32 &a, uint_32 b, uint_32 c, uint_32 d, uint_32 m, uint_32 s, uint_32 t){    a=b+rotate_left((a+I(b,c,d)+m+t), s);}class Md5{public:    static string encrypt(ustring input);    static void length_extension_attack(ustring md5Str, ustring appendStr);    static ustring md5_padding(ustring input);    static ustring md5_padding_with_length(ustring input, uint_64 bitLen = 0, uint_64 writeBitLen = 0);    static ustring to_ustring(string input);    static string to_string(ustring input);protected:    static string encrypt_with_vec(ustring paddingStr, vector<uint_32> vi);};string Md5::encrypt(ustring input){    /*{{{*/    vector<uint_32> vi(4);    vi[0] = 0x67452301;    vi[1] = 0xEFCDAB89;    vi[2] = 0x98BADCFE;    vi[3] = 0x10325476;    ustring paddingStr = md5_padding(input);    return encrypt_with_vec(paddingStr, vi);    /*}}}*/}string Md5::encrypt_with_vec(ustring paddingStr, vector<uint_32> vi){    /*{{{*/    if(vi.size() < 4){        printf("vi至少要有4各元素");        return "";    }    uint_32 a=vi[0], b=vi[1], c=vi[2], d=vi[3];    uint_32 aa, bb, cc, dd;    uint_32 m[16];    uint_64 length = paddingStr.length();    int i, j;    for(i = 0; i < length / 64; i++){        for(j = 0; j < 64; j += 4){            m[j / 4] = (uint_32)paddingStr[i * 64 + j] + ((uint_32)paddingStr[i * 64 + j + 1] << 8)                   + ((uint_32)paddingStr[i * 64 + j + 2] << 16) + ((uint_32)paddingStr[i * 64 + j + 3] << 24);        }        aa = a;        bb = b;        cc = c;        dd = d;        /*{{{第一轮*/        FF(a,b,c,d,m[0],7,0xd76aa478);        FF(d,a,b,c,m[1],12,0xe8c7b756);        FF(c,d,a,b,m[2],17,0x242070db);        FF(b,c,d,a,m[3],22,0xc1bdceee);        FF(a,b,c,d,m[4],7,0xf57c0faf);        FF(d,a,b,c,m[5],12,0x4787c62a);        FF(c,d,a,b,m[6],17,0xa8304613);        FF(b,c,d,a,m[7],22,0xfd469501);        FF(a,b,c,d,m[8],7,0x698098d8);        FF(d,a,b,c,m[9],12,0x8b44f7af);        FF(c,d,a,b,m[10],17,0xffff5bb1);        FF(b,c,d,a,m[11],22,0x895cd7be);        FF(a,b,c,d,m[12],7,0x6b901122);        FF(d,a,b,c,m[13],12,0xfd987193);        FF(c,d,a,b,m[14],17,0xa679438e);        FF(b,c,d,a,m[15],22,0x49b40821);        /*}}}*/        /*{{{第二轮*/        GG(a,b,c,d,m[1],5,0xf61e2562);        GG(d,a,b,c,m[6],9,0xc040b340);        GG(c,d,a,b,m[11],14,0x265e5a51);        GG(b,c,d,a,m[0],20,0xe9b6c7aa);        GG(a,b,c,d,m[5],5,0xd62f105d);        GG(d,a,b,c,m[10],9,0x02441453);        GG(c,d,a,b,m[15],14,0xd8a1e681);        GG(b,c,d,a,m[4],20,0xe7d3fbc8);        GG(a,b,c,d,m[9],5,0x21e1cde6);        GG(d,a,b,c,m[14],9,0xc33707d6);        GG(c,d,a,b,m[3],14,0xf4d50d87);        GG(b,c,d,a,m[8],20,0x455a14ed);        GG(a,b,c,d,m[13],5,0xa9e3e905);        GG(d,a,b,c,m[2],9,0xfcefa3f8);        GG(c,d,a,b,m[7],14,0x676f02d9);        GG(b,c,d,a,m[12],20,0x8d2a4c8a);        /*}}}*/        /*{{{第三轮*/        HH(a,b,c,d,m[5],4,0xfffa3942);        HH(d,a,b,c,m[8],11,0x8771f681);        HH(c,d,a,b,m[11],16,0x6d9d6122);        HH(b,c,d,a,m[14],23,0xfde5380c);        HH(a,b,c,d,m[1],4,0xa4beea44);        HH(d,a,b,c,m[4],11,0x4bdecfa9);        HH(c,d,a,b,m[7],16,0xf6bb4b60);        HH(b,c,d,a,m[10],23,0xbebfbc70);        HH(a,b,c,d,m[13],4,0x289b7ec6);        HH(d,a,b,c,m[0],11,0xeaa127fa);        HH(c,d,a,b,m[3],16,0xd4ef3085);        HH(b,c,d,a,m[6],23,0x04881d05);        HH(a,b,c,d,m[9],4,0xd9d4d039);        HH(d,a,b,c,m[12],11,0xe6db99e5);        HH(c,d,a,b,m[15],16,0x1fa27cf8);        HH(b,c,d,a,m[2],23,0xc4ac5665);        /*}}}*/        /*{{{第四轮*/        II(a,b,c,d,m[0],6,0xf4292244);        II(d,a,b,c,m[7],10,0x432aff97);        II(c,d,a,b,m[14],15,0xab9423a7);        II(b,c,d,a,m[5],21,0xfc93a039);        II(a,b,c,d,m[12],6,0x655b59c3);        II(d,a,b,c,m[3],10,0x8f0ccc92);        II(c,d,a,b,m[10],15,0xffeff47d);        II(b,c,d,a,m[1],21,0x85845dd1);        II(a,b,c,d,m[8],6,0x6fa87e4f);        II(d,a,b,c,m[15],10,0xfe2ce6e0);        II(c,d,a,b,m[6],15,0xa3014314);        II(b,c,d,a,m[13],21,0x4e0811a1);        II(a,b,c,d,m[4],6,0xf7537e82);        II(d,a,b,c,m[11],10,0xbd3af235);        II(c,d,a,b,m[2],15,0x2ad7d2bb);        II(b,c,d,a,m[9],21,0xeb86d391);        /*}}}*/        a += aa;        b += bb;        c += cc;        d += dd;    }    uint_32 i4[4] = {a, b, c, d};    string md5Str = "", tmpStr;    for(i = 0; i < 4; i++){        tmpStr = "";        for(j = 0; j < 4; j++){            tmpStr += int2hex((i4[i] >> 4) & 0XF) + int2hex(i4[i] & 0XF);            i4[i] >>= 8;        }        md5Str += tmpStr;    }    return md5Str;    /*}}}*/}ustring Md5::md5_padding(ustring input){    // 填充长度    return md5_padding_with_length(input);}/* * @param bitLen : 填充后的字符串的位长度,不包括最后64位用于存储原始字符串长度的位数 */ustring Md5::md5_padding_with_length(ustring input, uint_64 bitLen, uint_64 writeBitLen){    /*{{{填充长度*/    int bitLenMod;    uint_32 strLen;    uint_64 inputBitLen;    inputBitLen = (uint_64)input.length() * 8;    bitLenMod = inputBitLen % 512;    if(bitLen == 0){        if(bitLenMod < 448){            bitLen = inputBitLen + 448 - bitLenMod;        }else{            bitLen = inputBitLen + 512 - (bitLenMod - 448);        }    }    strLen = (bitLen / 8) + 8;    ustring str;    str.resize(strLen, '\0');    int i, j;    for(i = 0; i < input.length(); i++){        str[i] = input[i];    }    str[i++] = 0X80;    for(; i < strLen - 8; i++){        str[i++] = 0;    }    //最后8个字符为填充前的长度    if(writeBitLen == 0){        writeBitLen = inputBitLen;    }    for(i = strLen - 8; i < strLen; i++, writeBitLen >>= 8){        str[i] = 0XFF & writeBitLen;    }    return str;    /*}}}*/}ustring Md5::to_ustring(string input){    ustring str;    str.resize(input.size());    for(int i = 0; i < input.size(); i++){        str[i] = (uint_8) input[i];    }    return str;}string Md5::to_string(ustring input){    string str;    str.resize(input.size());    for(int i = 0; i < input.size(); i++){        str[i] = (char) input[i];    }    return str;}void Md5::length_extension_attack(ustring input, ustring appendStr){    /*{{{*/    string md5Str =  Md5::encrypt(input);    vector<uint_32> m(4);    int i, j;    for(i = 0; i < 32; i += 8){        m[i >> 3] = 0;        for(j = 6; j >= 0; j -= 2){            m[i >> 3] <<= 8;            m[i >> 3] |= hex2int(md5Str.substr(i + j, 2));        }    }    ustring newStr, paddingStr;    string guessedMd5, realMd5;     newStr = md5_padding(input) + appendStr;    realMd5 = encrypt(newStr);    cout << "md5_padding(newStr): " << endl;    cout << "realMd5 : " << realMd5 << endl;    paddingStr = md5_padding_with_length(appendStr, 448, newStr.length() * 8);    guessedMd5 = encrypt_with_vec(paddingStr,  m);    cout << "guessedMd5 : " << guessedMd5 << endl;    /*}}}*/}int main (int argc,char *argv[]){    string md5Str;    ustring input;    input = Md5::to_ustring("0.12204316770657897");    ustring appendStr = Md5::to_ustring("axis is smart!");    md5Str =  Md5::encrypt(input);    cout << "md5(" << Md5::to_string(input) << ") = " << md5Str << endl;    Md5::length_extension_attack(input, appendStr);    return 0;   }
原创粉丝点击