欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MD5(MD5 消息摘要算法)

程序员文章站 2024-03-19 13:18:34
...

MD5(MD5 消息摘要算法)

MD5 简介

MD5 消息摘要算法(MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个 128 位(16 字节)的散列值(hash value),用于确保信息传输完整一致。MD5 由美国密码学家罗纳德 · 李维斯特(Ronald Linn Rivest)设计,于 1992 年公开,用以取代 MD4 算法。这套算法的程序在 RFC 1321 中被加以规范。

散列算法基础原理:将数据(如一段文字)运算变为另一固定长度值。

1996 年后被证实存在弱点,可以被加以**,对于需要高度安全性的数据,专家一般建议改用其他算法,如 SHA-2。2004 年,证实 MD5 算法无法防止碰撞(collision),因此不适用于安全性认证,如 SSL 公开**认证或是数字签名等用途。

由于 MD5 算法普遍、稳定、快速的特点。仍广泛应用于普通数据的错误检查领域。(如软件将通过计算 MD5 检验下载到的文件片段的完整性)

MD5 算法

MD5 算法对输入数据的长度没有限制,允许输入任意长度的数据。输出固定长度 128-bits (16 Byte)。

MD5 算法经由程序流程,生成 4 组 32 bits (4 Byte)数据,最后联合起来成为一个 128-bits 的散列。

基本方式为:求余、取余、调整长度、与链接变量进行循环运算。

C++ 版本代码如下:


#include<iostream>
#include<string>

#define LEFT_ROTATE_SHIFT(x, n)     (((x) << (n)) | ((x) >> (32-(n))))  
#define F(x, y, z)                  (((x) & (y)) | (~(x) & (z)))        // (X AND Y) OR ((NOT X) AND Z)
#define G(x, y, z)                  (((x) & (z)) | ((y) & ~(z)))        // (X AND 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
#define HEX_NUM_CHAR_MAX            16
#define HEX_NUM_UPPER_CHAR_SET      "0123456789ABCDEF"
#define HEX_NUM_LOWER_CHAR_SET      "0123456789abcdef"
#define HEX_NUM_CHAR_SET            HEX_NUM_LOWER_CHAR_SET

const static char msc_hexChars[] = HEX_NUM_CHAR_SET;

// 常量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,
    };

void mainLoop(unsigned int M[], unsigned int temp[]) {
    unsigned int f, g, tmp;
    unsigned int a = temp[0];
    unsigned int b = temp[1];
    unsigned int c = temp[2];
    unsigned int d = temp[3];
    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;
        }
        tmp = d;
        d = c;
        c = b;
        b = b + LEFT_ROTATE_SHIFT((a + f + k[i] + M[g]), s[i]);
        a = tmp;
    }
    temp[0] += a;
    temp[1] += b;
    temp[2] += c;
    temp[3] += d;
}

/*
 * 填充函数
 * 处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64)
 * 填充方式为先加一个1,其它位补零
 * 最后加上64位的原来长度
 */
unsigned int* add(std::string& str, unsigned int * out_len) {
    unsigned int len = str.length();
    unsigned int num = ((len + 8) / 64) + 1;
    const int strlength = num * 16;
    unsigned int *strByte = new unsigned int[strlength];
    for (unsigned int i = 0; i < strlength; ++i) {
        strByte[i] = 0;
    }
    for (unsigned int i = 0; i < len; ++i) {
        strByte[i >> 2] |= (str[i]) << ((i & 0x03) << 3);
    }
    strByte[len >> 2] |= 0x80 << ((len & 0x03) << 3);
    strByte[strlength - 2]=len * 8;
    *out_len = strlength;
    return strByte;
}

void DecToHex(unsigned int num, char * out) {
    out[8] = 0;
    for(int i = 0; i < 4; ++i) {
        unsigned int byte_val = (num >> (i << 3)) & 0xff;
        for (int j = 0; j < 2; ++j) {
            out[i << 1 | (1 - j)] = msc_hexChars[byte_val & 0x0f];
            byte_val >>= 4;
        }
    }
}

std::string getMD5(std::string& source) {
    unsigned int temp[] = { A, B, C, D };
    unsigned int strlength = 0;
    unsigned int *strByte = add(source, &strlength);
    for (unsigned int i = 0, len = strlength / 16; i < len; ++i){
        unsigned int num[16];
        for (unsigned int j = 0; j < 16; ++j){
            num[j] = strByte[(i << 4) + j];
        }
        mainLoop(num, temp);
    }
    delete[] strByte;

    char hex[32 + 1] = { 0 };
    for (int i = 0; i < 4; ++ i) {
        DecToHex(temp[i], hex + (i << 3));
    }
    return std::string(hex);
}

测试代码:
(需要与 Linux 的 md5sum 命令对比结果,由于用到的 echo 命令自带换行,所以测试代码加了个换行)


// 测试代码
int main(int argc, char *argv[]) {
    if (argc == 1) {
        return -1;
    }
    std::string val = argv[1];
    val += "\n";

    std::string md5 = getMD5(val);
    std::cout << md5 << " : " << val << std::endl;
    return 0;
}

测试结果如下:


[email protected]:/data/code# g++ md5.cpp && ./a.out zone && echo zone > a.txt && md5sum a.txt
8ac8489932db6327334c9b6d58544cfe : zone

8ac8489932db6327334c9b6d58544cfe  a.txt
[email protected]:/data/code# g++ md5.cpp && ./a.out zone_test000 && echo zone_test000 > a.txt && md5sum a.txt
8a2f1e93bdccbc0e4168973a2cd8b9f5 : zone_test000

8a2f1e93bdccbc0e4168973a2cd8b9f5  a.txt

转载于:https://www.jianshu.com/p/6a7e9f329c3a