DH密钥交换算法,是第一个提出的公开密钥算法,它比RSA还要早提出。它使得在公开的不可信信道安全地交换密钥成为可能。但DH算法无法抵御中间人攻击,必须借用数字签名才足够安全。

下面是使用openssl进行DH密钥交换的示例程序:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
* dh.cc
* - Show the usage of Diffie-Hellman. (in key management)
* - Read Diffie-Hellman parameters from a file* - Example:
*   ./dh dh1024.pem
*/
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/pem.h>
 
int main(int argc, char** argv) {
    FILE* fp;
    DH* dh1;
    DH* dh2;
    int i;
 
    // check usage
    if (argc != 2) {
        fprintf(stderr, "%s <DH param file>\n", argv[0]);
        exit(-1);
    }
 
    // open the PEM file and generate the DH keys
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "Unable to open %s for DH params\n", argv[1]);
        return NULL;
    }
    if ((dh1 = PEM_read_DHparams(fp, NULL, NULL, NULL)) == NULL) {
        fprintf(stderr, "Unable to read parameters\n");
        return NULL;
    }                                                         
    fclose(fp);
 
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "Unable to open %s for DH params\n", argv[1]);
        return NULL;
    }
    if ((dh2 = PEM_read_DHparams(fp, NULL, NULL, NULL)) == NULL) {
        fprintf(stderr, "Unable to read parameters\n");
        return NULL;
    }                                                         
    fclose(fp);
 
    if (!DH_generate_key(dh1)) {
        fprintf(stderr, "Unable to generate public/private keys\n");
        return NULL;
    }
    if (!DH_generate_key(dh2)) {
        fprintf(stderr, "Unable to generate public/private keys\n");
        return NULL;
    }
 
    // key exchange
    unsigned char* key1 = (unsigned char*)calloc(DH_size(dh1),
            sizeof(unsigned char));
    unsigned char* key2 = (unsigned char*)calloc(DH_size(dh2),
            sizeof(unsigned char));
    DH_compute_key(key1, dh2->pub_key, dh1);
    DH_compute_key(key2, dh1->pub_key, dh2);
 
    // print
    printf("DH's p = %s\n", BN_bn2hex(dh1->p));
    printf("DH's g = %s\n", BN_bn2hex(dh1->g));
    printf("key1 = ");
    for (i=0; i<DH_size(dh1); ++i) {
        printf("%x%x", (key1[i] >> 4) & 0xf, key1[i] & 0xf);
    }
    printf("\n");
    printf("key2 = ");
    for (i=0; i<DH_size(dh2); ++i) {
        printf("%x%x", (key2[i] >> 4) & 0xf, key2[i] & 0xf);
    }
    printf("\n");
 
    return 0;
}

编译Makefile:

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