如何在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 相关文章推荐
下载给定网页上图片的方法
Feb 18 Python
Python实现获取网站PR及百度权重
Jan 21 Python
Python的Flask框架中使用Flask-SQLAlchemy管理数据库的教程
Jun 14 Python
Python3 适合初学者学习的银行账户登录系统实例
Aug 08 Python
一些Centos Python 生产环境的部署命令(推荐)
May 07 Python
Python实现的拟合二元一次函数功能示例【基于scipy模块】
May 15 Python
详解python读取image
Apr 03 Python
解决pycharm每次打开项目都需要配置解释器和安装库问题
Feb 26 Python
jupyternotebook 撤销删除的操作方式
Apr 17 Python
如何设置PyCharm中的Python代码模版(推荐)
Nov 20 Python
mac系统下安装pycharm、永久激活、中文汉化详细教程
Nov 24 Python
Python装饰器的练习题
Nov 23 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 身份验证方面的函数
2009/10/11 PHP
php代码书写习惯优化小结
2013/06/20 PHP
php json与xml序列化/反序列化
2013/10/28 PHP
django中的ajax组件教程详解
2018/10/18 PHP
php web环境和命令行环境下查找php.ini的位置
2019/07/17 PHP
走出JavaScript初学困境—js初学
2008/12/29 Javascript
JS 实现导航栏悬停效果
2013/09/23 Javascript
JS中typeof与instanceof之间的区别总结
2013/11/14 Javascript
javascript刷新父页面的各种方法汇总
2014/09/03 Javascript
详解Backbone.js框架中的模型Model与其集合collection
2016/05/05 Javascript
bootstrap table 表格中增加下拉菜单末行出现滚动条的快速解决方法
2017/01/05 Javascript
微信小程序 摇一摇抽奖简单实例实现代码
2017/01/09 Javascript
js实现百度搜索提示框
2017/02/05 Javascript
javascript数据结构中栈的应用之符号平衡问题
2017/04/11 Javascript
javaScript动态添加Li元素的实例
2018/02/24 Javascript
Vue项目报错:Uncaught SyntaxError: Unexpected token
2018/11/10 Javascript
基于JS实现简单滑块拼图游戏
2019/10/12 Javascript
JS实现前端路由功能示例【原生路由】
2020/05/29 Javascript
vue实现图片裁剪后上传
2020/12/16 Vue.js
利用Python绘制MySQL数据图实现数据可视化
2015/03/30 Python
老生常谈Python之装饰器、迭代器和生成器
2017/07/26 Python
Tensorflow的可视化工具Tensorboard的初步使用详解
2018/02/11 Python
Python 抓取数据存储到Redis中的操作
2020/07/16 Python
python利用递归方法实现求集合的幂集
2020/09/07 Python
Python的信号库Blinker用法详解
2020/12/31 Python
使用postMessage让 iframe自适应高度的方法示例
2019/10/08 HTML / CSS
来自南加州灵感的工作和娱乐服装:TravisMathew
2019/05/01 全球购物
实习教师自我鉴定
2013/12/09 职场文书
班会关于环保演讲稿
2013/12/29 职场文书
简短证婚人证婚词
2014/01/09 职场文书
家长会主持词
2014/03/26 职场文书
运动会横幅标语
2014/06/17 职场文书
党员学习党的群众路线思想汇报(5篇)
2014/09/10 职场文书
2014年教研组工作总结
2014/11/26 职场文书
用python画城市轮播地图
2021/05/28 Python
Python使用Opencv打开笔记本电脑摄像头报错解问题及解决
2022/06/21 Python