取任意长度的消息,生成一个固定长度的散列值,或者叫做摘要。哈希函数的实现都是公开的,它广泛应用于文件完整性检测、数字签名中。登录密码也有用到哈希函数,一般网站在数据库中不是直接存储的用户密码,而是密码的哈希值,这样即使数据库暴露,攻击者仍然是不知道密码的明文的。

这要求Hash函数拥有以下特性:一是单向性,即不可逆性,我们无法从哈希值反过来得到原文。二是冲突碰撞抵御能力,即找到两个不同的消息原文,他们的哈希值相同,这在计算上不可行。

实际上,MD5已经不再安全。在2005年,我国山东大学王小云教授成功破解MD5算法,使得使用普通电脑在数小时内即可找到哈希碰撞,这在国际密码学领域引发地震。

虽然在高保密安全领域已经被其他算法替代,MD5在普通生活中仍然广泛使用。openssl中提供了MD5的实现,下面是一个示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
* md5.cc
* - Using md5 with openSSL. MD5 returns a 128-bit hash value from a string.
*/
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/md5.h>
 
int main(int argc, char** argv) {
    MD5_CTX hash_ctx;
    char input_string[128];
    unsigned char hash_ret[16];
    int i;
 
    // check usage
    if (argc != 2) {
        fprintf(stderr, "%s <input string>\n", argv[0]);
        exit(-1);
    }
 
    // set the input string
    snprintf(input_string, sizeof(input_string), "%s\n", argv[1]);
 
    // initialize a hash context 
    MD5_Init(&hash_ctx);
 
    // update the input string to the hash context (you can update
    // more string to the hash context)
    MD5_Update(&hash_ctx, input_string, strlen(input_string));
 
    // compute the hash result
    MD5_Final(hash_ret, &hash_ctx);
 
    // print
    printf("Input string: %s", input_string);
    printf("Output string: ");
    for (i=0; i<32; ++i) {
        if (i % 2 == 0) {
            printf("%x", (hash_ret[i/2] >> 4) & 0xf);
        } else {
            printf("%x", (hash_ret[i/2]) & 0xf);
        }
    }
    printf("\n");
 
    return 0;
}

编译Makefile:

CC=g++
CFLAGS=-Wall -g -O2
LIBS=-lcrypto
 
all: md5
 
md5: md5.cc
    $(CC) $(CFLAGS) md5.cc -o $@ $(LIBS)
 
clean:
    @rm -f md5