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

Office 指南

辦公室工作實用教學

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

OpenSSL 指令實作橢圓曲線 ECDH 金鑰交換與 AES 加密教學與範例

介紹如何以 OpenSSL 的指令實作橢圓曲線 ECDH 金鑰交換,並參考 ECIES 加密架構,搭配 AES 演算法加密資料。

本篇文章屬於個人學習記錄,內容可能有誤,僅供參考,請勿用於正式環境。

OpenSSL 指令實作 ECDH 金鑰交換

橢圓曲線迪菲-赫爾曼(Elliptic Curve Diffie–Hellman,簡稱 ECDH)金鑰交換方法是雙方利用由橢圓曲線密碼學建立的公鑰與私鑰對,在一個不安全的通道中,建立一組雙方共享的密鑰。

OpenSSL 支援的橢圓曲線很多,我們可以使用以下指令查詢:

# 查詢 OpenSSL 支援的橢圓曲線
openssl ecparam -list_curves
  secp112r1 : SECG/WTLS curve over a 112 bit prime field
  secp112r2 : SECG curve over a 112 bit prime field
  secp128r1 : SECG curve over a 128 bit prime field
  secp128r2 : SECG curve over a 128 bit prime field
  secp160k1 : SECG curve over a 160 bit prime field
  secp160r1 : SECG curve over a 160 bit prime field
  secp160r2 : SECG/WTLS curve over a 160 bit prime field
  secp192k1 : SECG curve over a 192 bit prime field
  secp224k1 : SECG curve over a 224 bit prime field
  secp224r1 : NIST/SECG curve over a 224 bit prime field
  secp256k1 : SECG curve over a 256 bit prime field
  secp384r1 : NIST/SECG curve over a 384 bit prime field
  secp521r1 : NIST/SECG curve over a 521 bit prime field
  prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field
  prime192v2: X9.62 curve over a 192 bit prime field
  prime192v3: X9.62 curve over a 192 bit prime field
  prime239v1: X9.62 curve over a 239 bit prime field
  prime239v2: X9.62 curve over a 239 bit prime field
  prime239v3: X9.62 curve over a 239 bit prime field
  prime256v1: X9.62/SECG curve over a 256 bit prime field
  sect113r1 : SECG curve over a 113 bit binary field
  sect113r2 : SECG curve over a 113 bit binary field
  sect131r1 : SECG/WTLS curve over a 131 bit binary field
  sect131r2 : SECG curve over a 131 bit binary field
  sect163k1 : NIST/SECG/WTLS curve over a 163 bit binary field
  sect163r1 : SECG curve over a 163 bit binary field
  sect163r2 : NIST/SECG curve over a 163 bit binary field
  sect193r1 : SECG curve over a 193 bit binary field
  sect193r2 : SECG curve over a 193 bit binary field
  sect233k1 : NIST/SECG/WTLS curve over a 233 bit binary field
  sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field
  sect239k1 : SECG curve over a 239 bit binary field
  sect283k1 : NIST/SECG curve over a 283 bit binary field
  sect283r1 : NIST/SECG curve over a 283 bit binary field
  sect409k1 : NIST/SECG curve over a 409 bit binary field
  sect409r1 : NIST/SECG curve over a 409 bit binary field
  sect571k1 : NIST/SECG curve over a 571 bit binary field
  sect571r1 : NIST/SECG curve over a 571 bit binary field
  c2pnb163v1: X9.62 curve over a 163 bit binary field
  c2pnb163v2: X9.62 curve over a 163 bit binary field
  c2pnb163v3: X9.62 curve over a 163 bit binary field
  c2pnb176v1: X9.62 curve over a 176 bit binary field
  c2tnb191v1: X9.62 curve over a 191 bit binary field
  c2tnb191v2: X9.62 curve over a 191 bit binary field
  c2tnb191v3: X9.62 curve over a 191 bit binary field
  c2pnb208w1: X9.62 curve over a 208 bit binary field
  c2tnb239v1: X9.62 curve over a 239 bit binary field
  c2tnb239v2: X9.62 curve over a 239 bit binary field
  c2tnb239v3: X9.62 curve over a 239 bit binary field
  c2pnb272w1: X9.62 curve over a 272 bit binary field
  c2pnb304w1: X9.62 curve over a 304 bit binary field
  c2tnb359v1: X9.62 curve over a 359 bit binary field
  c2pnb368w1: X9.62 curve over a 368 bit binary field
  c2tnb431r1: X9.62 curve over a 431 bit binary field
  wap-wsg-idm-ecid-wtls1: WTLS curve over a 113 bit binary field
  wap-wsg-idm-ecid-wtls3: NIST/SECG/WTLS curve over a 163 bit binary field
  wap-wsg-idm-ecid-wtls4: SECG curve over a 113 bit binary field
  wap-wsg-idm-ecid-wtls5: X9.62 curve over a 163 bit binary field
  wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field
  wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field
  wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field
  wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field
  wap-wsg-idm-ecid-wtls10: NIST/SECG/WTLS curve over a 233 bit binary field
  wap-wsg-idm-ecid-wtls11: NIST/SECG/WTLS curve over a 233 bit binary field
  wap-wsg-idm-ecid-wtls12: WTLS curve over a 224 bit prime field
  Oakley-EC2N-3:
        IPSec/IKE/Oakley curve #3 over a 155 bit binary field.
        Not suitable for ECDSA.
        Questionable extension field!
  Oakley-EC2N-4:
        IPSec/IKE/Oakley curve #4 over a 185 bit binary field.
        Not suitable for ECDSA.
        Questionable extension field!
  brainpoolP160r1: RFC 5639 curve over a 160 bit prime field
  brainpoolP160t1: RFC 5639 curve over a 160 bit prime field
  brainpoolP192r1: RFC 5639 curve over a 192 bit prime field
  brainpoolP192t1: RFC 5639 curve over a 192 bit prime field
  brainpoolP224r1: RFC 5639 curve over a 224 bit prime field
  brainpoolP224t1: RFC 5639 curve over a 224 bit prime field
  brainpoolP256r1: RFC 5639 curve over a 256 bit prime field
  brainpoolP256t1: RFC 5639 curve over a 256 bit prime field
  brainpoolP320r1: RFC 5639 curve over a 320 bit prime field
  brainpoolP320t1: RFC 5639 curve over a 320 bit prime field
  brainpoolP384r1: RFC 5639 curve over a 384 bit prime field
  brainpoolP384t1: RFC 5639 curve over a 384 bit prime field
  brainpoolP512r1: RFC 5639 curve over a 512 bit prime field
  brainpoolP512t1: RFC 5639 curve over a 512 bit prime field
  SM2       : SM2 curve over a 256 bit prime field

我們可以使用以下指令查看特定橢圓曲線的實際參數:

# 顯示 secp256k1 橢圓曲線參數
openssl ecparam -name secp256k1 -param_enc explicit -text -noout
EC-Parameters: (256 bit)
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
    ff:fc:2f
A:    0
B:    7 (0x7)
Generator (uncompressed):
    04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
    0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
    f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
    0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
    8f:fb:10:d4:b8
Order:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
    36:41:41
Cofactor:  1 (0x1)

確認要採用的橢圓曲線之後,即可產生私鑰,由於我們要模擬兩方透過不安全的通道建立共享密鑰,所以這裡的操作會區分為甲方與乙方,事實上雙方的指令都是相同的。

# 產生 secp256k1 橢圓曲線私鑰(甲方)
openssl ecparam -name secp256k1 -genkey -noout -out secp256k1_priv_key_1.pem

執行之後,產生的私鑰會儲存於 secp256k1_priv_key_1.pem 這個檔案中,我們可以查看私鑰的內容:

# 查看私鑰內容(甲方)
cat secp256k1_priv_key_1.pem
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIJDuX0R1BbAx2PDe67bnUHMz4PCnNpMg6f41NOaoY0BpoAcGBSuBBAAK
oUQDQgAEtzO2oa+wc884MGzZBn2tXciAW5AGlCLor00S6FnFFUPZHo9HEn4wAGTR
hTmFn/KRvRdm8Lk3EEQ5rY+KJYRZ/g==
-----END EC PRIVATE KEY-----

接著再從這把私鑰產生對應的公鑰:

# 從私鑰產生對應的公鑰(甲方)
openssl ec -in secp256k1_priv_key_1.pem -pubout -out secp256k1_pub_key_1.pem
read EC key
writing EC key

查看公鑰內容:

# 查看公鑰內容(甲方)
cat secp256k1_pub_key_1.pem
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtzO2oa+wc884MGzZBn2tXciAW5AGlCLo
r00S6FnFFUPZHo9HEn4wAGTRhTmFn/KRvRdm8Lk3EEQ5rY+KJYRZ/g==
-----END PUBLIC KEY-----

乙方也按照同樣的方式,產生另外一對私鑰與公鑰:

# 產生 secp256k1 橢圓曲線私鑰(乙方)
openssl ecparam -name secp256k1 -genkey -noout -out secp256k1_priv_key_2.pem

# 從私鑰產生對應的公鑰(乙方)
openssl ec -in secp256k1_priv_key_2.pem -pubout -out secp256k1_pub_key_2.pem

當雙方都以相同的橢圓曲線建立私鑰與公鑰之後,即可將各自的公鑰傳輸給對方,接著各自以對方的公鑰加上自己的私鑰產生共享密鑰:

# 產生共享密鑰(甲方)
openssl pkeyutl -derive -inkey secp256k1_priv_key_1.pem \
    -peerkey secp256k1_pub_key_2.pem -out secret_key_1.bin

# 產生共享密鑰(乙方)
openssl pkeyutl -derive -inkey secp256k1_priv_key_2.pem \
    -peerkey secp256k1_pub_key_1.pem -out secret_key_2.bin

這樣甲方所產生的密鑰 secret_key_1.bin 與乙方所產生的密鑰 secret_key_2.bin 就會是相同的,我們可以查看其內容:

# 查看密鑰內容(甲方)
od -x secret_key_1.bin
0000000 9f5a 1f06 4f5e f0bf cf1e ba0e 1730 cbb0
0000020 4cfc fa58 484b 3699 d13f 6f77 a291 bec7
0000040
# 查看密鑰內容(乙方)
od -x secret_key_2.bin
0000000 9f5a 1f06 4f5e f0bf cf1e ba0e 1730 cbb0
0000020 4cfc fa58 484b 3699 d13f 6f77 a291 bec7
0000040

當雙方產生了相同的共享密鑰 secret_key_1.bin 與 secret_key_2.bin 之後,即可使用 AES 這類的對稱式加密方式來加密所有的訊息:

# 產生原始訊息檔案(甲方)
echo 'top secret!!!' > message.txt

# 使用密鑰檔案以 AES-256 加密(甲方)
openssl enc -aes256 -pbkdf2 -pass file:./secret_key_1.bin \
    -in message.txt -out message.txt.enc

# 使用密鑰檔案以 AES-256 解密(乙方)
openssl enc -aes256 -d -pbkdf2 -pass file:./secret_key_2.bin \
    -in message.txt.enc -out message.txt.output

這裡使用 -pass 讀取密碼檔時,根據手冊說明,只會讀取密碼檔案中的第一行,所以可能對於二進位檔案會有讀取不完全的問題。

依據 ECIES 的架構,經過 ECDH 產生的密鑰要先經過 KDF 處理之後,才會作為 AES 加密的金鑰,跟這裡 OpenSSL 指令的實作方式有些差異,對於正式的環境,建議採用其他的標準的實作方式。

OpenSSL 指令實作 X25519

X25519 是將 Curve25519 作為 DH 函數並實作 ECDH 金鑰交換的方法,然而 X25519 並不屬於標準的橢圓曲線,所以在 OpenSSL 中的指令與標準的橢圓曲線不同,不能以 ecparams 或 ec 指令來進行 X25519 的操作,必須改用 genpkey,以下是使用 OpenSSL 指令實作 X25519 的流程。

以下同樣將指令分為甲、乙兩方,首先產生 X25519 的私鑰與公鑰:

# 產生 X25519 的私鑰(甲方)
openssl genpkey -algorithm X25519 -out x25519_priv_key_1.pem

# 從私鑰產生對應的公鑰(甲方)
openssl pkey -pubout -in x25519_priv_key_1.pem -out x25519_pub_key_1.pem

# 產生 X25519 的私鑰(乙方)
openssl genpkey -algorithm X25519 -out x25519_priv_key_2.pem

# 從私鑰產生對應的公鑰(乙方)
openssl pkey -pubout -in x25519_priv_key_2.pem -out x25519_pub_key_2.pem

雙方交換公鑰之後,即可用自己的私鑰加上對方的公鑰產生共享密鑰:

# 產生共享密鑰(甲方)
openssl pkeyutl -derive -inkey x25519_priv_key_1.pem \
    -peerkey x25519_pub_key_2.pem -out secret_key_1.bin

# 產生共享密鑰(乙方)
openssl pkeyutl -derive -inkey x25519_priv_key_2.pem \
    -peerkey x25519_pub_key_1.pem -out secret_key_2.bin

產生共享密鑰之後,後續就可以按照一般的方式採用 AES-256 進行資料的加密了。

參考資料

  • Practical Cryptography for Developers:ECDH Key Exchange
  • OpenSSL Wiki:Command Line Elliptic Curve Operations

分類:Linux 標籤: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