使用 openssl 实现 DH 算法

本文最后更新于:2022年5月1日 晚上

〇、前言

DH(Diffie–Hellman)算法简介

一、生成 DH 密钥对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//! \param prime. DH 的 prime.
//! \param gen. DH 的 gen.
//! \param dh. 返回数据.
//! \return. 成功与否.
int generate_dh_key(const char *prime, const char *gen, DH *dh)
{
BIGNUM *p = BN_new();
BIGNUM *g = BN_new();

BN_hex2bn(&p, prime);
BN_hex2bn(&g, gen);
DH_set0_pqg(dh, p, NULL, g);

/* generate key */
if (1 != DH_generate_key(dh)) {
perror("DH_generate_key failed!");
return -1;
}

return 0;
}

二、生成 DH 共享密钥

此处有坑:openssl DH_compute_key() 函数计算 DH 密钥长度不对的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//! \param dh. DH,其中有本端的公钥和私钥.
//! \param peer_pub_key. 对端 DH 公钥.
//! \param peer_pub_key_len. 对端 DH 公钥长度.
//! \param shared_key. 输出 DH 共享密钥.
//! \return. DH 共享密钥长度.
int gene_shared_key(DH *dh, uint8_t *peer_pub_key,
uint16_t peer_pub_key_len, unsigned char *shared_key) {
BIGNUM *p_pub_key = BN_bin2bn(peer_pub_key, peer_pub_key_len, NULL);

/* computer shared_dh_secret */
int shared_key_len = DH_compute_key_padded(shared_key, p_pub_key, dh);
if(-1 == shared_key_len) {
perror("DH_compute_key_padded failed!");
return -1;
}

return shared_key_len;
}

三、中间人攻击

  • 截获双方发送的 DH 公共值
  • 修改为自己的公共值发送给双方
  • 使用两端的公共值同自身的 DH 分别生成中间人到客户端以及中间人到服务器的共享密钥
  • 实现中间人