LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

安全加解密引擎基础(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秘钥参数有如下:

CurvePossible 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的使用。

posted on 2022-04-15 00:12  ArnoldLu  阅读(3371)  评论(0编辑  收藏  举报

导航