如何在python中实现ECDSA你知道吗
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)所知道的这些曲线的 "简称 "是:prime192v1、secp224r1、prime256v1、secp384r1和secp521r1。它包括⽐特币使⽤的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 = ate(%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 = ate(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 = ate({0})".format(curve)#私钥
S3 = "remote = ate({0}).verifying_key".format(curve)#公钥
S4 = "ecdh = ECDH(private_key=our, public_key=remote)"
S5 = "ate_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,
)
)
from ecdsa import SigningKey
sk = ate() # 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 = ate(curve=NIST384p)
vk = sk.verifying_key
signature = sk.sign(b"message")
assert vk.verify(signature, b"message")
#将签名密钥(私钥)序列化成不同的格式。
from ecdsa import SigningKey, NIST384p
sk = ate(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())
_string().hex())
from ecdsa import SigningKey, NIST384p
sk = ate(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 = ate(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 = ate(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, der)
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
_string() == _string()
sk2 = make_key(b"2-"+seed)  # different key  b为⽐特
_string() != _string()
from ecdsa import SigningKey, NIST384p
sk = ate(curve=NIST384p)
vk = sk.verifying_key
vk.precompute()
printform
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_ad())
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_ad(), 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_ad())
with open("sk.pem", "wb") as f:
f._pem())
with open("vk.pem") as f:
vk = VerifyingKey.from_ad())
with open("vk.pem", "wb") as f:
f._pem())
#ecdsa.util.PRNG ⼯具在这⾥很⽅便:它需要⼀个种⼦并从中产⽣⼀个强的伪随机流。
#os.urandom的函数作为entropy=参数来做不同的事情
#ECDSA的签名⽣成也需要⼀个随机数,⽽且每个签名都必须使⽤不同的随机数(两次使⽤相同的数字会⽴即暴露出私⼈签名密钥)。
# sk.sign()⽅法需要⼀个entropy=参数,其⾏为与ate(entropy=)相同。
from ecdsa.util import PRNG
from ecdsa import SigningKey
rng1 = PRNG(b"seed")
sk1 = ate(entropy=rng1)
rng2 = PRNG(b"seed")
sk2 = ate(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 = ate(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, der)
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_ad())
print("uncompressed: {0}"._string("uncompressed").hex()))
print("compressed: {0}"._string("compressed").hex()))
#从压缩格式的⼗六进制字符串中加载验证密钥,以未压缩的格式输出。
from ecdsa import VerifyingKey, NIST256p
comp_str = '022799c0d0ee09772fdd337d4f28dc155581951d07082fb19a38aa396b67e77759'
vk = VerifyingKey.from_string(bytearray.fromhex(comp_str), curve=NIST256p)
_string("uncompressed").hex())
#与远程⽅进⾏ECDH密钥交换。
from ecdsa import ECDH, NIST256p
ecdh = ECDH(curve=NIST256p)
local_public_key = _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 = ate_sharedsecret_bytes()
总结
本篇⽂章就到这⾥了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。