• 跳至主要導覽
  • 跳至主要內容
  • 跳至主要資訊欄
Office 指南

Office 指南

辦公室工作實用教學

  • Excel
  • Word
  • PowerPoint
  • Windows
  • PowerShell
  • R

C 語言使用 OpenSSL 實作橢圓曲線 ECDH 金鑰交換教學與範例

介紹如何在 C 語言中使用 OpenSSL 實作橢圓曲線 ECDH 金鑰交換。

產生橢圓曲線金鑰對

在實作橢圓曲線 ECDH 金鑰交換之前,要先產生兩對橢圓曲線的金鑰對,以下是以 C 語言程式的方式來產生金鑰的範例:

#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>

// 產生並儲存橢圓曲線金鑰
void generateECKey(const char *privKeyFile, const char *pubKeyFile) {
	// 產生 secp256k1 金鑰對
	EVP_PKEY *ecKey = EVP_EC_gen("secp256k1");

	// 輸出公鑰與私鑰資訊
	//EVP_PKEY_print_public_fp(stdout, ecKey, 0, NULL);
	EVP_PKEY_print_private_fp(stdout, ecKey, 0, NULL);

	// 將私鑰寫入 privKeyFile 中
	BIO *bioPrivKey = BIO_new_file(privKeyFile, "w");
	PEM_write_bio_PrivateKey(bioPrivKey, ecKey, NULL, NULL, 0, NULL, NULL);
	BIO_free(bioPrivKey);

	// 將公鑰寫入 pubKeyFile 中
	BIO *bioPubKey = BIO_new_file(pubKeyFile, "w");
	PEM_write_bio_PUBKEY(bioPubKey, ecKey);
	BIO_free(bioPubKey);

	// 釋放橢圓曲線金鑰空間
	EVP_PKEY_free(ecKey);
}

int main() {
	// 產生兩組橢圓曲線金鑰對
	generateECKey("ec_private_key1.pem", "ec_public_key1.pem");
	generateECKey("ec_private_key2.pem", "ec_public_key2.pem");

	return EXIT_SUCCESS;
}

這裡為了方便初學者閱讀,所以實作上省略了所有的錯誤檢查,實務上每一條函數呼叫都要檢查傳回值是否正確。

將這段程式碼儲存至 gen_ec_keys.c,並用以下指令進行編譯:

# 編譯金鑰產生程式
gcc -o gen_ec_keys gen_ec_keys.c -lcrypto

編譯之後,會產生 gen_ec_keys 這個執行檔,執行後即可產生兩組橢圓曲線的金鑰對:

# 執行金鑰產生程式
./gen_ec_keys
Private-Key: (256 bit)
priv:
    71:0a:27:9e:11:58:cd:51:e6:7a:83:1b:18:0f:d2:
    cc:03:29:7b:80:61:43:23:6f:20:ea:b7:17:44:75:
    26:f5
pub:
    04:d1:7f:73:c6:31:14:bf:5e:01:52:14:15:5f:7e:
    bc:12:49:cf:ce:7c:e3:b0:57:31:43:25:15:27:6a:
    f7:9d:96:9e:06:67:be:78:dd:6e:c3:58:05:73:ba:
    92:c8:14:09:b5:82:7c:08:5c:91:ee:82:10:bd:b0:
    23:2c:59:c9:64
ASN1 OID: secp256k1
Private-Key: (256 bit)
priv:
    f3:d9:9f:d0:b7:c5:df:24:0d:cb:30:c9:b7:b6:7c:
    c9:08:ee:4d:71:eb:d4:65:bc:93:a8:08:c7:04:e2:
    68:f6
pub:
    04:b8:b2:71:6f:58:48:2a:97:61:04:86:8b:2d:98:
    ca:b8:ee:af:eb:65:90:ac:3a:39:69:4d:69:89:f1:
    92:e3:2e:2a:64:5e:9a:99:71:bc:46:50:fd:bc:de:
    c9:29:31:b7:d8:30:a6:bc:37:e9:50:87:a0:4c:fd:
    9a:7e:3d:99:22
ASN1 OID: secp256k1

除了使用 C 語言之外,我們也可以參考 OpenSSL 指令實作橢圓曲線 ECDH 金鑰交換與 AES 加密教學與範例,以 OpenSSL 指令來產生橢圓曲線金鑰對。

橢圓曲線 ECDH 金鑰交換

當雙方都準備好自己的橢圓曲線金鑰對,並將公鑰交給對方之後,就可以透過 ECDH 金鑰交換的方式,計算出共享密鑰,以下是 C 語言實作的範例:

#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>

// 橢圓曲線 ECDH 金鑰交換
void ecdh(const char *privKeyFile, const char *peerPubKeyFile, const char *secretFile) {
	// 讀取己方私鑰
	EVP_PKEY *privKey;
	BIO *bioPrivKey = BIO_new_file(privKeyFile, "r");
	PEM_read_bio_PrivateKey(bioPrivKey, &privKey, NULL, NULL);
	BIO_free(bioPrivKey);

	// 讀取對方公鑰
	EVP_PKEY *peerPubKey;
	BIO *bioPubKey = BIO_new_file(peerPubKeyFile, "r");
	PEM_read_bio_PUBKEY(bioPubKey, &peerPubKey, NULL, NULL);
	BIO_free(bioPrivKey);

	// 建立 context
	EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(NULL, privKey, NULL);
	EVP_PKEY_derive_init(ctx);
	EVP_PKEY_derive_set_peer(ctx, peerPubKey);

	// 取得共享密鑰長度
	size_t secretLen;
	EVP_PKEY_derive(ctx, NULL, &secretLen);

	// 計算共享密鑰
	unsigned char secret[secretLen];
	EVP_PKEY_derive(ctx, secret, &secretLen);

	// 將共享密鑰儲存至檔案
	BIO *bioSecret = BIO_new_file(secretFile, "wb");
	BIO_write(bioSecret, secret, secretLen);
	BIO_free(bioSecret);

	// 釋放 context 空間
	EVP_PKEY_CTX_free(ctx);
}

int main() {
	// 橢圓曲線 ECDH 金鑰交換
	ecdh("ec_private_key1.pem", "ec_public_key2.pem", "ec_shared_secret1.bin");
	ecdh("ec_private_key2.pem", "ec_public_key1.pem", "ec_shared_secret2.bin");

	return EXIT_SUCCESS;
}

將這段程式碼儲存至 ecdh.c,並用以下指令進行編譯:

# 編譯金鑰產生程式
gcc -o ecdh ecdh.c -lcrypto

編譯之後,會產生 ecdh 這個執行檔,執行後就會模擬雙方各拿自己的私鑰加上對方的公鑰,計算共享密鑰:

# 執行金鑰產生程式
./ecdh

產生的密鑰會存放於 ec_shared_secret1.bin 與 ec_shared_secret2.bin,理論上這兩組密鑰會是一模一樣的。

我們同時可以使用 OpenSSL 指令以同樣的方式計算共享密鑰:

# 產生共享密鑰
openssl pkeyutl -derive -inkey ec_private_key1.pem \
    -peerkey ec_public_key2.pem -out ec_shared_secret1_cmd.bin
openssl pkeyutl -derive -inkey ec_private_key2.pem \
    -peerkey ec_public_key1.pem -out ec_shared_secret2_cmd.bin

最後驗證所有的共享密鑰是否相同:

# 驗證共享密鑰一致性
sha1sum ec_shared_secret*.bin
a62d3612640007905ac21e827631a6bce9ab6bcd  ec_shared_secret1.bin
a62d3612640007905ac21e827631a6bce9ab6bcd  ec_shared_secret1_cmd.bin
a62d3612640007905ac21e827631a6bce9ab6bcd  ec_shared_secret2.bin
a62d3612640007905ac21e827631a6bce9ab6bcd  ec_shared_secret2_cmd.bin

參考資料

  • OpenSSL Wiki:Elliptic Curve Diffie Hellman
  • OpenSSL:EVP_KEYEXCH-ECDH
  • OpenSSL:EVP_PKEY-EC
  • OpenSSL:EVP_PKEY_derive

分類:C/C++ 標籤:OpenSSL, 資訊安全

主要資訊欄

搜尋

近期文章

  • Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤
  • Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例
  • Linux 網路設定 ip 指令用法教學與範例
  • Windows 使用 TPM 虛擬智慧卡保護 SSH 金鑰教學與範例
  • Linux 以 Shamir’s Secret Sharing 分割保存金鑰教學與範例
  • Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例
  • Linux 以 Cryptsetup 與 LUKS 加密磁碟教學與範例
  • Linux 使用 age 簡潔的加密、解密工具使用教學與範例

推薦網站

  • Udemy 線上教學課程
  • Coursera 線上教學課程

關注本站

  • 電子郵件
  • Facebook

公益

  • 家扶基金會
  • 台灣世界展望會
  • Yahoo 奇摩公益
  • igiving 公益網
  • 兒福聯盟

Copyright © 2021 · Office Guide