2019/01/19
			
						
			7,979
			
		
		在我之前的博客中聊到了 DH 密钥交换的原理 . 这里来讨论如何使用 OPENSSL 进行 DH 密钥交换。
一 原理验证
OPENSSL 提供了一系列API, 可以在方便地进行大数计算。在这里我们先对 DH 密钥交换的原理 中讲到的原理进行代码级别的验证。对原理不感兴趣的可以跳过这一小节。
由于在 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 | class DHBase { public:     DHBase() : m_pri_key(NULL) {}     virtual ~DHBase() {         if (m_pri_key)             BN_free(m_pri_key);     };     const BIGNUM *GetSharedNum() {         if (!m_pri_key)             GenRandomData();         BN_CTX *ctx = BN_CTX_new();         const BIGNUM *g = DH_get0_g(m_dh);         const BIGNUM *p = DH_get0_p(m_dh);         BIGNUM *r = BN_new();         // r = g ^ m_pri_key % p         int rst = BN_mod_exp(r, g, m_pri_key, p, ctx);         assert(rst == 1);         BN_CTX_free(ctx);         return r;     }     BIGNUM *GenKey(const BIGNUM *shared_num) {         if (!m_pri_key)             GenRandomData();         BIGNUM *key = BN_new();         BN_CTX *ctx = BN_CTX_new();         // key = shared_num ^ m_pri_key % p         int rst = BN_mod_exp(key, shared_num, m_pri_key, DH_get0_p(m_dh), ctx);         assert(rst == 1);         BN_CTX_free(ctx);         std::cout << m_name << ": received shared num: " << GetNumString(shared_num) << std::endl;         std::cout << m_name << ": generated KEY: " << GetNumString(key) << std::endl;         return key;     }     std::string GetName() {         return m_name;     }     static std::string GetNumString(const BIGNUM *num) {         return BN_bn2hex(num);     } private:     void GenRandomData() {         assert(m_dh);         m_pri_key = BN_new();         int rst = BN_rand_range(m_pri_key, DH_get0_p(m_dh));         assert(rst == 1);         while (BN_is_zero(m_pri_key)) {             BN_rand_range(m_pri_key, DH_get0_p(m_dh));         }         std::cout << m_name << ": generated the private num" << std::endl;     } protected:     DH *m_dh;     std::string m_name; private:     BIGNUM *m_pri_key; }; | 
- m_pri_key是双方生成的私密随机数。
- GetSharedNum()返回双方交换的中间变量- G^A mod P
- GenKey()即完成了密钥交换,返回交换成功后的密钥。