如何在python中实现ECDSA你知道吗


Posted in Python onNovember 23, 2021
import six
import timeit#查找任何特定代码执行的确切时间
from ecdsa.curves import curves
#定义do函数,计算时间
def do(setup_statements, statement):
    # extracted from timeit.py
    t = timeit.Timer(stmt=statement, setup="\n".join(setup_statements))
    # determine number so that 0.2 <= total time < 2.0
    for i in range(1, 10):
        number = 10 ** i #**为次方
        x = t.timeit(number)
        if x >= 0.2:
            break
    return x / number

NIST为数字测试套件关于NIST详解

GF§ (素数域)曲线,密钥长度为192、224、256、384和521bit

OpenSSL工具(openssl ecparam -list_curves)所知道的这些曲线的 "简称 "是:prime192v1secp224r1prime256v1secp384r1secp521r1。它包括比特币使用的256位曲线secp256k1。它还支持160到512位的Brainpool曲线的常规(非扭曲)变体。这些曲线的 "简称 "是:BrainpoolP160r1, brainpoolP192r1, brainpoolP224r1, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, brainpoolP512r1。少数来自SEC标准的小曲线也包括在内(主要是为了加快库的测试),它们是:secp112r1, secp112r2, secp128r1, 和secp160r1。没有包括其他的曲线,但要增加对更多素数域的曲线的支持并不难。

#不是很懂 sep=":",unit="s",form=".5f",form_inv=".2f",
prnt_form = (
    "{name:>16}{sep:1} {siglen:>6} {keygen:>9{form}}{unit:1} "
    "{keygen_inv:>9{form_inv}} {sign:>9{form}}{unit:1} "
    "{sign_inv:>9{form_inv}} {verify:>9{form}}{unit:1} "
    "{verify_inv:>9{form_inv}} {verify_single:>13{form}}{unit:1} "
    "{verify_single_inv:>14{form_inv}}"
)
print(
    prnt_form.format(
        siglen="siglen",
        keygen="keygen",
        keygen_inv="keygen/s",
        sign="sign",
        sign_inv="sign/s",
        verify="verify",
        verify_inv="verify/s",
        verify_single="no PC verify",
        verify_single_inv="no PC verify/s",
        name="",
        sep="",
        unit="",
        form="",
        form_inv="",
    )
)
for curve in [i.name for i in curves]:
    S1 = "import six; from ecdsa import SigningKey, %s" % curve
    S2 = "sk = SigningKey.generate(%s)" % curve #产生私钥
    S3 = "msg = six.b('msg')" #消息
    S4 = "sig = sk.sign(msg)" #签名
    S5 = "vk = sk.get_verifying_key()"#公钥由私钥得出  get_verifying_key()函数
    S6 = "vk.precompute()"#不懂
    S7 = "vk.verify(sig, msg)"#用公钥验证签名
    # 我们碰巧知道.generate()也在计算验证密钥,这是最耗时的部分。如果将代码改为懒惰地计算vk,我们就需要将这个基准改为在S5上循环,而不是在S2上。
    keygen = do([S1], S2)
    sign = do([S1, S2, S3], S4)
    verf = do([S1, S2, S3, S4, S5, S6], S7)
    verf_single = do([S1, S2, S3, S4, S5], S7)
    import ecdsa
    c = getattr(ecdsa, curve)#从名字上看获取属性值
    sig = ecdsa.SigningKey.generate(c).sign(six.b("msg"))
    #密钥对(keygen)、签署数据(sign)、验证这些签名(verify)、共享秘密(ecdh)以及在没有特定密钥预计算的情况下验证签名(no PC verify)、原始签名的大小(通常是签名可以被编码的最小方式)也在siglen栏中提供
    print(
        prnt_form.format(
            name=curve,#所有的曲线
            sep=":",
            siglen=len(sig),
            unit="s",
            keygen=keygen,
            keygen_inv=1.0 / keygen,
            sign=sign,
            sign_inv=1.0 / sign,
            verify=verf,
            verify_inv=1.0 / verf,
            verify_single=verf_single,
            verify_single_inv=1.0 / verf_single,
            form=".5f",#小数点后面为5位
            form_inv=".2f",#小数点后面为2位
        )
    )
print("")

ED25519和Cureve5519

ecdh_form = "{name:>16}{sep:1} {ecdh:>9{form}}{unit:1} {ecdh_inv:>9{form_inv}}"
print(
    ecdh_form.format(
        ecdh="ecdh",
        ecdh_inv="ecdh/s",
        name="",
        sep="",
        unit="",
        form="",
        form_inv="",
    )
)
for curve in [i.name for i in curves]:
    if curve == "Ed25519" or curve == "Ed448":
        continue
    S1 = "from ecdsa import SigningKey, ECDH, {0}".format(curve)
    S2 = "our = SigningKey.generate({0})".format(curve)#私钥
    S3 = "remote = SigningKey.generate({0}).verifying_key".format(curve)#公钥
    S4 = "ecdh = ECDH(private_key=our, public_key=remote)"
    S5 = "ecdh.generate_sharedsecret_bytes()"#产生共享密钥
    ecdh = do([S1, S2, S3, S4], S5)
    print(
        ecdh_form.format(
            name=curve,
            sep=":",
            unit="s",
            form=".5f",
            form_inv=".2f",
            ecdh=ecdh,
            ecdh_inv=1.0 / ecdh,
        )
    )

 

如何在python中实现ECDSA你知道吗

from ecdsa import SigningKey
sk = SigningKey.generate() # uses NIST192p生成私钥
vk = sk.verifying_key#在私钥的基础上生成公钥
signature = sk.sign(b"message")#用私钥对消息进行签名
assert vk.verify(signature, b"message")#用公钥去验证。assert为一断言函数:不满足条件直接触发异常忙不执行接下来的代码,括号中为condition
from ecdsa import SigningKey, NIST384p#384位NIST素域椭圆曲线,其中私钥/公钥都与特定的曲线相关联,更长的曲线更安全,但时间长,密钥和签名也长
sk = SigningKey.generate(curve=NIST384p)
vk = sk.verifying_key
signature = sk.sign(b"message")
assert vk.verify(signature, b"message")
#将签名密钥(私钥)序列化成不同的格式。
from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
sk_string = sk.to_string()#最短的调用,然后再重新创建私钥。to_string():将括号内的数字转化为字符串,实际返回的类型bytes
sk2 = SigningKey.from_string(sk_string, curve=NIST384p)#重新创建私钥,第一个参数是我们要处理的字符,如果点编码无效或不在指定曲线上,from_string()将引发MalformedPointError
print(sk_string.hex())
print(sk2.to_string().hex())
from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
sk_pem = sk.to_pem()#sk.to_pem()和sk.to_der()将把签名密钥序列化为OpenSSL使用的相同格式
sk2 = SigningKey.from_pem(sk_pem)#SigningKey.from_pem()/.from_der()将撤销这种序列化。这些格式包括了曲线名称,所以你不需要向反序列化器传递曲线标识符。如果文件是畸形的,from_der()和from_pem()将引发UnexpectedDER或MalformedPointError。
# sk and sk2 are the same key
from ecdsa import SigningKey, VerifyingKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
vk = sk.verifying_key
vk_string = vk.to_string()#公钥可以用同样的方式进行序列化
vk2 = VerifyingKey.from_string(vk_string, curve=NIST384p)
# vk and vk2 are the same key
from ecdsa import SigningKey, VerifyingKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
vk = sk.verifying_key
vk_pem = vk.to_pem()
vk2 = VerifyingKey.from_pem(vk_pem)
# vk and vk2 are the same key
import os
from ecdsa import NIST384p, SigningKey
from ecdsa.util import randrange_from_seed__trytryagain#产生随机数
def make_key(seed):
  secexp = randrange_from_seed__trytryagain(seed, NIST384p.order)
  return SigningKey.from_secret_exponent(secexp, curve=NIST384p)
seed = os.urandom(NIST384p.baselen) # or other starting point,返回一个适合加密的比特串
sk1a = make_key(seed)
sk1b = make_key(seed)
# note: sk1a and sk1b are the same key
assert sk1a.to_string() == sk1b.to_string()
sk2 = make_key(b"2-"+seed)  # different key  b为比特
assert sk1a.to_string() != sk2.to_string()
from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
vk = sk.verifying_key
vk.precompute()
signature = sk.sign(b"message")
assert vk.verify(signature, b"message")
# openssl ecparam -name prime256v1 -genkey -out sk.pem
# openssl ec -in sk.pem -pubout -out vk.pem
# echo "data for signing" > data
# openssl dgst -sha256 -sign sk.pem -out data.sig data
# openssl dgst -sha256 -verify vk.pem -signature data.sig data
# openssl dgst -sha256 -prverify sk.pem -signature data.sig data
#OpenSSL 使用 PEM 文件格式存储证书和密钥。PEM 实质上是 Base64 编码的二进制内容
import hashlib#
from ecdsa import SigningKey, VerifyingKey
from ecdsa.util import sigencode_der, sigdecode_der#从ecdsa.util写入和读取签名
with open("vk.pem") as f:#公钥文件
   vk = VerifyingKey.from_pem(f.read())
with open("data", "rb") as f:#open()为读取模式,with语句直接调用close方法,r为读模式,w/wb为写模式,rb模式打开二进制文件,消息data
   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)
 
# openssl dgst -sha256 -verify vk.pem -signature data.sig2 data
#如果需要与OpenSSL 1.0.0或更早的版本兼容,可以使用ecdsa.util中的sigencode_string和sigdecode_string来分别写入和读取签名。
from ecdsa import SigningKey, VerifyingKey
with open("sk.pem") as f:
    sk = SigningKey.from_pem(f.read())
with open("sk.pem", "wb") as f:
    f.write(sk.to_pem())
with open("vk.pem") as f:
    vk = VerifyingKey.from_pem(f.read())
with open("vk.pem", "wb") as f:
    f.write(vk.to_pem())
#ecdsa.util.PRNG 工具在这里很方便:它需要一个种子并从中产生一个强的伪随机流。
#os.urandom的函数作为entropy=参数来做不同的事情
#ECDSA的签名生成也需要一个随机数,而且每个签名都必须使用不同的随机数(两次使用相同的数字会立即暴露出私人签名密钥)。
# sk.sign()方法需要一个entropy=参数,其行为与SigningKey.generate(entropy=)相同。
from ecdsa.util import PRNG
from ecdsa import SigningKey
rng1 = PRNG(b"seed")
sk1 = SigningKey.generate(entropy=rng1)
rng2 = PRNG(b"seed")
sk2 = SigningKey.generate(entropy=rng2)
# sk1 and sk2 are the same key
#如果你调用SigningKey.sign_deterministic(data)而不是.sign(data),代码将生成一个确定性的签名,而不是随机的。
# 这使用RFC6979中的算法来安全地生成一个唯一的K值,该值来自于私钥和被签名的信息。每次你用相同的密钥签署相同的信息时,你将得到相同的签名(使用相同的k)。
#创建一个NIST521p密钥对
from ecdsa import SigningKey, NIST521p
sk = SigningKey.generate(curve=NIST521p)
vk = sk.verifying_key
#从一个主种子创建三个独立的签名密钥
from ecdsa import NIST192p, SigningKey
from ecdsa.util import randrange_from_seed__trytryagain
def make_key_from_seed(seed, curve=NIST192p):
    secexp = randrange_from_seed__trytryagain(seed, curve.order)
    return SigningKey.from_secret_exponent(secexp, curve)
sk1 = make_key_from_seed("1:%s" % seed)
sk2 = make_key_from_seed("2:%s" % seed)
sk3 = make_key_from_seed("3:%s" % seed)
#从磁盘上加载一个验证密钥,并使用十六进制编码以未压缩和压缩的格式打印出来(在X9.62和SEC1标准中定义)。
from ecdsa import VerifyingKey
with open("public.pem") as f:#加载验证密钥
    vk = VerifyingKey.from_pem(f.read())
print("uncompressed: {0}".format(vk.to_string("uncompressed").hex()))
print("compressed: {0}".format(vk.to_string("compressed").hex()))
#从压缩格式的十六进制字符串中加载验证密钥,以未压缩的格式输出。
from ecdsa import VerifyingKey, NIST256p
comp_str = '022799c0d0ee09772fdd337d4f28dc155581951d07082fb19a38aa396b67e77759'
vk = VerifyingKey.from_string(bytearray.fromhex(comp_str), curve=NIST256p)
print(vk.to_string("uncompressed").hex())
#与远程方进行ECDH密钥交换。
from ecdsa import ECDH, NIST256p
ecdh = ECDH(curve=NIST256p)
ecdh.generate_private_key()
local_public_key = ecdh.get_public_key()
#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)
secret = ecdh.generate_sharedsecret_bytes()

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!

Python 相关文章推荐
python 解析html之BeautifulSoup
Jul 07 Python
Python实现二分法算法实例
Feb 02 Python
python实现数组插入新元素的方法
May 22 Python
举例简单讲解Python中的数据存储模块shelve的用法
Mar 03 Python
Python引用模块和查找模块路径
Mar 17 Python
利用OpenCV和Python实现查找图片差异
Dec 19 Python
Python通过socketserver处理多个链接
Mar 18 Python
pytorch 中的重要模块化接口nn.Module的使用
Apr 02 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
Jul 31 Python
Python操作word文档插入图片和表格的实例演示
Oct 25 Python
Python各协议下socket黏包问题原理
Apr 12 Python
Python基本的内置数据类型及使用方法
Apr 13 Python
Python jiaba库的使用详解
Nov 23 #Python
python 中的jieba分词库
Nov 23 #Python
python周期任务调度工具Schedule使用详解
Nov 23 #Python
python百行代码实现汉服圈图片爬取
python可视化大屏库big_screen示例详解
python数据可视化JupyterLab实用扩展程序Mito
python入门学习关于for else的特殊特性讲解
Nov 20 #Python
You might like
用PHP编程开发“虚拟域名”系统
2006/10/09 PHP
php 生成饼图 三维饼图
2009/09/28 PHP
Apache服务器无法使用的解决方法
2013/05/08 PHP
php实现微信公众号企业转账功能
2018/10/01 PHP
PHP连接MySQL数据库的三种方式实例分析【mysql、mysqli、pdo】
2019/11/04 PHP
游戏人文件夹程序 ver 4.03
2006/07/14 Javascript
IE和firefox浏览器的event事件兼容性汇总
2009/12/06 Javascript
js 函数的副作用分析
2011/08/23 Javascript
基于jquery库的tab新形式使用
2012/11/16 Javascript
EditPlus注册码生成器(js代码实现)
2013/03/25 Javascript
使用简洁的jQuery方法实现隔行换色功能
2014/01/02 Javascript
一个简单的jQuery插件ajaxfileupload.js实现ajax上传文件例子
2014/06/26 Javascript
使用jQuery在对象中缓存选择器的简单方法
2015/06/30 Javascript
jquery实现倒计时效果
2015/12/14 Javascript
jQuery EasyUI之验证框validatebox实例详解
2017/04/10 jQuery
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
JavaScript标准对象_动力节点Java学院整理
2017/06/27 Javascript
Vue学习笔记进阶篇之vue-router安装及使用方法
2017/07/19 Javascript
利用纯js + transition动画实现移动端web轮播图详解
2017/09/10 Javascript
Three.js 再探 - 写一个微信跳一跳极简版游戏
2018/01/04 Javascript
Vue中使用的EventBus有生命周期
2018/07/12 Javascript
微信小程序利用swiper+css实现购物车商品删除功能
2019/03/06 Javascript
详解vue+axios给开发环境和生产环境配置不同的接口地址
2019/08/16 Javascript
浅谈vue中$bus的使用和涉及到的问题
2020/07/28 Javascript
vue等两个接口都返回结果再执行下一步的实例
2020/09/08 Javascript
[02:15]2014DOTA2国际邀请赛 赛后退役选手回顾
2014/08/01 DOTA
[56:13]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第一场 1月10日
2021/03/11 DOTA
Python基于Socket实现的简单聊天程序示例
2017/08/05 Python
python将一组数分成每3个一组的实例
2018/11/14 Python
Django缓存系统实现过程解析
2019/08/02 Python
Python 处理文件的几种方式
2019/08/23 Python
善意的谎言事例
2014/02/15 职场文书
党员干部观看《周恩来四个昼夜》思想汇报
2014/09/10 职场文书
行政申诉状范文
2015/05/20 职场文书
2016五一劳动节慰问信
2015/11/30 职场文书
golang中的并发和并行
2021/05/08 Golang