安全加解密引擎基礎(PKE ECC/ECDH/ECDSA)


關鍵詞:ECC、ECDH、ECDSA、PyCryptodome、ecdsa、OpenSSL等。

1 基本概念

1.1 ECC

Elliptic Curves Cryptography,橢圓曲線密碼學(英語:Elliptic curve cryptography,縮寫為ECC),一種建立公開密鑰加密算法,基於橢圓曲線數學。橢圓曲線在密碼學中的使用是在1985年由Neal Koblitz和Victor Miller分別獨立提出的。

ECC的主要優勢是在某些情況下它比其他的方法使用更小的 密鑰(比如 RSA加密算法)提供相當的或更高等級的安全。ECC的另一個優勢是可以定義群之間的 雙線性映射,基於Weil對或是Tate對;雙線性映射已經在密碼學中發現了大量的應用,例如基於身份的加密。
其缺點是同長度密鑰下加密和解密操作的實現比其他機制花費的時間長 ,但由於可以使用更短的密鑰達到同級的安全程度,所以同級安全程度下速度相對更快。一般認為160比特的橢圓曲線密鑰提供的安全強度與1024比特RSA密鑰相當。

1.1.1 ECC參數

ECC的參數可以有很多,通過openssl ecparam -list_curves查看:

...
  secp160r1 : SECG curve over a 160 bit prime field
  secp224r1 : NIST/SECG curve over a 224 bit prime field
  secp384r1 : NIST/SECG curve over a 384 bit prime field
  secp521r1 : NIST/SECG curve over a 521 bit prime field
  brainpoolP160r1: RFC 5639 curve over a 160 bit prime field
  brainpoolP192r1: RFC 5639 curve over a 192 bit prime field
  brainpoolP224r1: RFC 5639 curve over a 224 bit prime field
  brainpoolP256r1: RFC 5639 curve over a 256 bit prime field
  brainpoolP384r1: RFC 5639 curve over a 384 bit prime field
  brainpoolP512r1: RFC 5639 curve over a 512 bit prime field
  SM2       : SM2 curve over a 256 bit prime field

更多參考:

SECG | Standard curve database (neuromancer.sk)》-SEC 2: Recommended Elliptic Curve Domain Parameters version 2.0 January 27, 2010

SEC 2, ver. 2.0 (secg.org)》-SEC 2: Recommended Elliptic Curve Domain Parameters

1.2 ECDH

橢圓曲線迪菲-赫爾曼金鑰交換(英語:Elliptic Curve Diffie–Hellman key Exchange,縮寫為ECDH),一種匿名的密鑰合意協議(Key-agreement protocol)。

在這個協定下,雙方通過迪菲-赫爾曼密鑰交換算法,利用由橢圓曲線加密建立的公鑰與私鑰對,在一個不安全的通道中,建立起安全的共有加密資料。這是迪菲-赫爾曼密鑰交換的變種,采用橢圓曲線加密來加強安全性。

ECDH全稱是橢圓曲線迪菲-赫爾曼秘鑰交換(Elliptic Curve Diffie–Hellman key Exchange),主要是用來在一個不安全的通道中建立起安全的共有加密資料,一般來說交換的都是私鑰,這個密鑰一般作為“對稱加密”的密鑰而被雙方在后續數據傳輸中使用。ECDH是ECC算法和DH結合使用,用於密鑰磋商,這個密鑰交換算法稱為ECDH。交換雙方可以在不共享任何秘密的情況下協商出一個密鑰。ECC是建立在基於橢圓曲線的離散對數問題上的密碼體制。

1.2.1 ECDH流程

1.3 ECDSA

ECDSA(橢圓曲線數字簽名算法)是DSA(數字簽名算法)的橢圓曲線實現。橢圓曲線密碼術能夠以較小的密鑰提供與RSA相對相同的安全級別。它還具有DSA對不良RNG敏感的缺點。

ECDSA是數字簽名算法,是DSA的變體。在數字簽名算法中,消息發送方對消息進行簽名,消息接收方對消息驗簽,這樣能夠保證數據的完整性(保證消息內容未被第三方篡改)、消息源鑒別(確定消息是由本人發出,而不是他人偽造)和不可否認性(消息發送方無法否認自己發出過這則消息)。

1.3.1 ECDSA流程

更多參考:

淺談ECC&ECDH&ECDSA》-介紹了ECC、ECDH、ECDSA基本概念和基本原理。

2 openssl關於ECC/DECDH/ECDSA的使用

生成ECC私鑰和公鑰:

openssl ecparam -name prime256v1 -genkey -out sk.pem
openssl ec -in sk.pem -pubout -out vk.pem

生成ECC簽名:

openssl dgst -sha256 -sign sk.pem -out data.sig data

ECC驗簽:

openssl dgst -sha256 -verify vk.pem -signature data.sig data

將Python ecdsa和OpenSSL對比測試如下:

import hashlib
from ecdsa import SigningKey, VerifyingKey
from ecdsa.util import sigencode_der, sigdecode_der
import os

if __name__ == '__main__':
    os.system("openssl ecparam -name prime256v1 -genkey -out sk.pem")
    os.system("openssl ec -in sk.pem -pubout -out vk.pem")
    os.system("echo \"data for signing\" > data")
    os.system("openssl dgst -sha256 -sign sk.pem -out data.sig data")
    os.system("openssl dgst -sha256 -verify vk.pem -signature data.sig data")
    os.system("openssl dgst -sha256 -prverify sk.pem -signature data.sig data")
    with open("vk.pem") as f:
        vk = VerifyingKey.from_pem(f.read())

    with open("data", "rb") as f:
        data = f.read()

    with open("data.sig", "rb") as f:
        signature = f.read()

    assert vk.verify(signature, data, hashlib.sha256, sigdecode=sigdecode_der)

    with open("sk.pem") as f:
        sk = SigningKey.from_pem(f.read(), hashlib.sha256)

    new_signature = sk.sign_deterministic(data, sigencode=sigencode_der)

    with open("data.sig2", "wb") as f:
        f.write(new_signature)

    os.system("openssl dgst -sha256 -verify vk.pem -signature data.sig2 data")

3 Python中PyCryptodome關於ECC、ECDSA和ecdsa關於ECDH的使用

3.1 PyCryptodome關於ECC和ECDSA使用

首先使用PyCryptodome生成ECC私鑰和公鑰,然后使用DSA進行簽名和驗簽:

from Crypto.Hash import SHA256
from Crypto.PublicKey import ECC
from Crypto.Signature import DSS

if __name__ == '__main__':
    key = ECC.generate(curve='secp256r1')

    with open('myprikey.pem', 'wt') as f:
        f.write(key.export_key(format='PEM'))
    f.close()

    with open('mypubkey.pem', 'wt') as f:
        f.write(key.public_key().export_key(format='PEM'))
    f.close()

    message = b'This is a sample.'
    key = ECC.import_key(open('myprikey.pem').read())
    h = SHA256.new(message)
    signer = DSS.new(key, 'fips-186-3')
    signature = signer.sign(h)

    key = ECC.import_key(open('mypubkey.pem').read())
    verifier = DSS.new(key, 'fips-186-3')
    try:
        verifier.verify(h, signature)
        print("The message is authentic.")
    except ValueError:
        print("The message is not authentic.")

關於ECC秘鑰參數有如下:

Curve Possible identifiers
NIST P-192 'NIST P-192''p192''P-192''prime192v1''secp192r1'
NIST P-224 'NIST P-224''p224''P-224''prime224v1''secp224r1'
NIST P-256 'NIST P-256''p256''P-256''prime256v1''secp256r1'
NIST P-384 'NIST P-384''p384''P-384''prime384v1''secp384r1'
NIST P-521 'NIST P-521''p521''P-521''prime521v1''secp521r1'

更多參考:

ECC — PyCryptodome 3.14.1 documentation》-關於ECC秘鑰生成。

Digital Signature Algorithm (DSA and ECDSA) — PyCryptodome 3.14.1 documentation》-關於ECDSA的使用方法。

3.2 ecdsa關於ECDSA和ECDH的使用

使用ecdsa進行簽名驗簽:

from ecdsa import SigningKey, NIST384p

if __name__ == '__main__':
    sk = SigningKey.generate(curve=NIST384p)
    vk = sk.verifying_key
    signature = sk.sign(b"This is a sample")
    assert vk.verify(signature, b"This is a sample")

使用ecdsa進行ECDH密鑰磋商:

from ecdsa import ECDH, NIST256p

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    ecdh = ECDH(curve=NIST256p)
    ecdh.generate_private_key()
    local_public_key = ecdh.get_public_key()
    with open('remote_public_key.pem', 'wb') as f:
        f.write(local_public_key.to_pem())
    f.close()
    # send `local_public_key` to remote party and receive `remote_public_key` from remote party
    with open("remote_public_key.pem") as e:
        remote_public_key = e.read()
    ecdh.load_received_public_key_pem(remote_public_key)

    try:
        secret = ecdh.generate_sharedsecret_bytes()
        print("Generate shared secret from local private key and remote public key.")
    except:
        print("public_key curve not the same as self.curve or public_key or private_key is not set")

更多參考:

ecdsa · PyPI》-介紹了ECDH和ECDSA的使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM