如何在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中SocketServer 实现客户端与服务器间非阻塞通信
Dec 15 Python
Mac中升级Python2.7到Python3.5步骤详解
Apr 27 Python
python 移除字符串尾部的数字方法
Jul 17 Python
Python使用matplotlib绘制随机漫步图
Aug 27 Python
Python面向对象之类的定义与继承用法示例
Jan 14 Python
对Python Class之间函数的调用关系详解
Jan 23 Python
Python操作rabbitMQ的示例代码
Mar 19 Python
python 读取更新中的log 或其它文本方式
Dec 24 Python
深入了解python列表(LIST)
Jun 08 Python
python3.6中anaconda安装sklearn踩坑实录
Jul 28 Python
python中四舍五入的正确打开方式
Jan 18 Python
python pandas 解析(读取、写入)CSV 文件的操作方法
Dec 24 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 Memcached应用实现代码
2010/02/08 PHP
PHP 5.3 下载时 VC9、VC6、Thread Safe、Non Thread Safe的区别分析
2011/03/28 PHP
php while循环得到循环次数
2013/10/26 PHP
PHP QRCODE生成彩色二维码的方法
2016/05/19 PHP
JQuery 自定义CircleAnimation,Animate方法学习笔记
2011/07/10 Javascript
jquery刷新页面的实现代码(局部及全页面刷新)
2011/07/11 Javascript
ScrollDown的基本操作示例
2013/06/09 Javascript
cookie.js 加载顺序问题怎么才有效
2013/07/31 Javascript
js 文本滚动效果的实例代码
2013/08/17 Javascript
js截取字符串的两种方法及区别详解
2013/11/05 Javascript
javascript打印html内容功能的方法示例
2013/11/28 Javascript
jQuery知识点整理
2015/01/30 Javascript
图解js图片轮播效果
2015/12/20 Javascript
全屏js头像上传插件源码高清版
2016/03/29 Javascript
JavaScript必看小技巧(必看)
2016/06/07 Javascript
微信小程序 教程之WXML
2016/10/18 Javascript
angular ng-repeat数组中的数组实例
2017/02/18 Javascript
jQuery:unbind方法的使用详解
2017/08/14 jQuery
vue2.0模拟锚点的实例
2018/03/14 Javascript
vue forEach循环数组拿到自己想要的数据方法
2018/09/21 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
2019/06/10 Javascript
深入了解Vue.js 混入(mixins)
2020/07/23 Javascript
vue 重塑数组之修改数组指定index的值操作
2020/08/09 Javascript
javascript实现电商放大镜效果
2020/11/23 Javascript
为什么JavaScript中0.1 + 0.2 != 0.3
2020/12/03 Javascript
python-django中的APPEND_SLASH实现方法
2019/06/21 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
2020/03/10 Python
大学新生欢迎词
2014/01/10 职场文书
一般党员对照检查材料
2014/09/24 职场文书
村党支部书记四风问题个人对照检查材料思想汇报
2014/10/06 职场文书
2014财务年度工作总结
2014/11/11 职场文书
中学综治宣传月活动总结
2015/05/07 职场文书
四群教育工作总结
2015/08/10 职场文书
JavaScript 对象创建的3种方法
2021/11/17 Javascript
利用uni-app生成微信小程序的踩坑记录
2022/04/05 Javascript
Java死锁的排查
2022/05/11 Java/Android