Nodejs進階:使用DiffieHellman金鑰交換演算法

程式猿小卡_casper發表於2019-02-16

簡介

Diffie-Hellman(簡稱DH)是金鑰交換演算法之一,它的作用是保證通訊雙方在非安全的通道中安全地交換金鑰。目前DH最重要的應用場景之一,就是在HTTPS的握手階段,客戶端、服務端利用DH演算法交換對稱金鑰。

下面會先簡單介紹DH的數理基礎,然後舉例說明如何在nodejs中使用DH相關的API。

數論基礎

要理解DH演算法,需要掌握一定的數論基礎。感興趣的可以進一步研究推導過程,或者直接記住下面結論,然後進入下一節。

  1. 假設 Y = a^X mod p,已知X的情況下,很容易算出Y;已知道Y的情況下,很難算出X;

  2. (a^Xa mod p)^Xb mod p = a^(Xa * Xb) mod p

握手步驟說明

假設客戶端、服務端挑選兩個素數a、p(都公開),然後

  • 客戶端:選擇自然數Xa,Ya = a^Xa mod p,並將Ya傳送給服務端;

  • 服務端:選擇自然數Xb,Yb = a^Xb mod p,並將Yb傳送給客戶端;

  • 客戶端:計算 Ka = Yb^Xa mod p

  • 服務端:計算 Kb = Ya^Xb mod p

Ka = Yb^Xa mod p

= (a^Xb mod p)^Xa mod p 
= a^(Xb * Xa) mod p
= (a^Xa mod p)^Xb mod p
= Ya^Xb mod p
= Kb

可以看到,儘管客戶端、服務端彼此不知道對方的Xa、Xb,但算出了相等的secret。

Nodejs程式碼示例

結合前面小結的介紹來看下面程式碼,其中,要點之一就是client、server採用相同的素數a、p。

var crypto = require(`crypto`);

var primeLength = 1024;  // 素數p的長度
var generator = 5;  // 素數a

// 建立客戶端的DH例項
var client = crypto.createDiffieHellman(primeLength, generator);
// 產生公、私鑰對,Ya = a^Xa mod p
var clientKey = client.generateKeys();

// 建立服務端的DH例項,採用跟客戶端相同的素數a、p
var server = crypto.createDiffieHellman(client.getPrime(), client.getGenerator());
// 產生公、私鑰對,Yb = a^Xb mod p
var serverKey = server.generateKeys();

// 計算 Ka = Yb^Xa mod p
var clientSecret = client.computeSecret(server.getPublicKey());
// 計算 Kb = Ya^Xb mod p
var serverSecret = server.computeSecret(client.getPublicKey());

// 由於素數p是動態生成的,所以每次列印都不一樣
// 但是 clientSecret === serverSecret
console.log(clientSecret.toString(`hex`));
console.log(serverSecret.toString(`hex`));

相關連結

理解 Deffie-Hellman 金鑰交換演算法

迪菲-赫爾曼金鑰交換

Secure messages in NodeJSusing ECDH

Keyless SSL: The Nitty Gritty Technical Details

相關文章