• 安全加解密引擎基础(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的使用。

  • 相关阅读:
    woocommerce调用产品相册gallery图片如何操作?wordpress技巧
    phpcms切换到php7.2后无法修改文章提示Uncaught Error: [] operator not supported for strings
    yandexbot ip列表整理做俄罗斯市场的站长可以关注一下
    phpcms网站迁移无法更新内容提示Table 'led_com.lz_' doesn't exist的解决方法
    phpcms邮箱smtp配置163企业邮测试可用
    phpcms添加https后台分页错误的解决方法
    linux防止恶意采集攻防战
    ThinkPHP获取当前页URL添加canonical
    如何让ThinkPHP支持模糊搜索
    火车头内容发布规则为保存本地文件时的注意事项
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/16145623.html
Copyright © 2020-2023  润新知