ecdsa加密签名库(纯python)
ecdsa的Python项目详细描述
纯python ecdsa
这是ecdsa密码(椭圆曲线)的一个易于使用的实现 数字签名算法),纯用python实现,发布于 麻省理工学院的执照。使用此库,您可以快速创建密钥对(签名 密钥和验证密钥)、签名消息和验证签名。钥匙 签名很短,便于处理和合并 其他协议。
功能
这个库为5个
流行的NIST"套件B"GF(P)曲线,关键长度为192、224、256、384,
521位。这些曲线的"短名称",如openssl所知
工具(openssl ecparam--list_curves
)是:prime192v1,secp224r1,
prime256v1、secp384r1和secp521r1。它还包括使用的256位曲线
比特币,简称secp256k1。不包括其他曲线,但
再加一点也不难。
依赖关系
这个库只使用python。它需要python2.6或更高版本的 python2.x系列。它还与python3.2和3.3兼容。
要运行OpenSSL兼容性测试,必须在 $路径。这个版本已经在openssl 0.9.8o上测试成功 和1.0.0A。
速度
下表显示了此库生成密钥对所需的时间 (keygen=),对数据签名(sign=),并验证这些签名(verify=),打开 我的2008 Mac笔记本电脑。所有时间都以秒为单位。它还显示了 签名(字节):验证("public")密钥通常相同 长度作为签名,签名("私有")密钥是该长度的一半。使用"python setup.py speed"在您自己的计算机上生成此表。
- NIST192P:siglen=48,keygen=0.160s,sign=0.058s,verify=0.116s
- NIST224P:siglen=56,keygen=0.230s,sign=0.086s,verify=0.165s
- nist256p:siglen=64,keygen=0.305s,sign=0.112s,verify=0.220s
- NIST384P:siglen=96,keygen=0.801s,sign=0.289s,verify=0.558s
- NIST521P:siglen=132,keygen=1.582s,sign=0.584s,verify=1.152s
比较,典型的ECDSA(Cuffto++)的质量C++实现 在2.88ms内计算NIST256P签名,在8.53ms内计算验证,关于 快30-40倍。
密钥和签名可以以不同的方式序列化(参见下面的用法)。 对于NIST192P密钥,三个基本表示需要 以下长度(字节):
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
历史记录
2006年,peter pearson在 发送给sci.crypt的消息,可从他的下载站点获得。2010, Brian Warner为这段代码编写了一个包装器,使它更容易 使用更安全。您正在查看此包装的自述文件。
测试
有四个测试套件,三个用于原始皮尔逊模块,还有一个 更多关于wrapp的信息呃.要运行它们,请执行以下操作:
python setup.py test
在我的2014款Mac Mini上,综合测试大约需要20秒才能运行。在一 2.4GHz P4 Linux盒,需要81秒。
py的一个组件通过 运行"openssl"cli工具。如果这个工具不在你的$路径上,你可以 想注释这个测试(最简单的方法是添加一行 "del openssl"到test_pyecdsa.py的末尾。
安全性
此库无法防止定时攻击。不允许攻击者 测量生成密钥对或签名消息所需的时间。 这个库依赖于一个强大的随机数源。不要用它 一个os.urandom()很弱的系统。
用法
首先创建一个signingkey。通过传递 在数据字符串中并获取签名(也是字符串)。你也可以 请一个签名密钥给你相应的验证密钥。验证密钥 可用于验证签名,方法是将数据字符串和 签名字符串:返回true或引发BadSignatureRor。
from ecdsa import SigningKey
sk = SigningKey.generate() # uses NIST192p
vk = sk.get_verifying_key()
signature = sk.sign("message")
assert vk.verify(signature, "message")
每个signingkey/verifyingkey都与一个特定的曲线相关联,比如 NIST192P(默认)。较长的曲线更安全,但是 使用并生成更长的密钥和签名。
from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
vk = sk.get_verifying_key()
signature = sk.sign("message")
assert vk.verify(signature, "message")
signingkey可以序列化为几种不同的格式:最短的
是调用s=sk.to_string()
,然后用
signingkey.from_string(s,curve)
。这个简短的表格没有记录
曲线,因此必须确保从字符串()中分辨出用于
原来的钥匙。基于NIST192P的签名密钥的缩写形式只有24
字节长。
from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
sk_string = sk.to_string()
sk2 = SigningKey.from_string(sk_string, curve=NIST384p)
# sk and sk2 are the same key
sk.to_pem()
和sk.to_der()
将签名密钥序列化为
OpenSSL使用的格式。pem文件看起来像熟悉的ascii装甲
"———开始EC私钥——"
base64编码格式,以及DER格式
是相同数据的较短二进制形式。
signingkey.from_pem()/.from_der()
将撤消此序列化。这些
格式包括曲线名称,因此不需要传入曲线
反序列化程序的标识符。
from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
sk_pem = sk.to_pem()
sk2 = SigningKey.from_pem(sk_pem)
# sk and sk2 are the same key
同样,verifyingkey也可以以同样的方式序列化:
vk.to_string()/verifyingkey.from_string()
,to_pem()/from_pem()
,以及
到'u der()/从'u der()
。需要相同的curve=参数
verifyingkey.from_string()
from ecdsa import SigningKey, VerifyingKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
vk = sk.get_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.get_verifying_key()
vk_pem = vk.to_pem()
vk2 = VerifyingKey.from_pem(vk_pem)
# vk and vk2 are the same key
有两种不同的方法来计算签名。从根本上说,
ecdsa接受一个表示要签名的数据的数字,并返回一个
代表签名的一对数字。hashfunc=参数
sk.sign()
和vk.verify()
用于将任意字符串转换为
固定长度摘要,然后将其转换为ecdsa可以签名的数字,
签名和验证必须使用相同的方法。默认值为
hashlib.sha1,但是如果使用nist256p或更长的曲线,则可以使用
取而代之的是hashlib.sha256。
还有多种方式来表示签名。默认值
sk.sign()
和vk.verify()
方法将其表示为一个短字符串,用于
简单和最少的开销。若要使用其他方案,请使用
sk.sign(signode=)
和vk.verify(sigdode=)
参数。有帮手
"ecdsa.util"模块中可在此处使用的功能。
也可以从"seed"创建一个signingkey,它是
确定性。这可以用于要派生的协议中
来自其他机密的一致签名密钥,例如
三个独立的密钥,只想存储一个主密钥。你应该
从一个均匀分布的不可求种子开始,使用about curve.baselen
字节的熵,然后使用ecdsa.util中的一个helper函数
将其转换为in在正确的范围内,然后最后通过
进入signingkey.from_secret_exponent()
,如下所示:
from pyecdsa import NIST384p, SigningKey
from pyecdsa.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
sk2 = make_key("2-"+seed) # different key
OpenSSL兼容性
生成可由openssl工具验证的签名,或验证 由这些工具生成的签名,请使用:
# openssl ecparam -name secp224r1 -genkey -out sk.pem
# openssl ec -in sk.pem -pubout -out vk.pem
# openssl dgst -ecdsa-with-SHA1 -sign sk.pem -out data.sig data
# openssl dgst -ecdsa-with-SHA1 -verify vk.pem -signature data.sig data
# openssl dgst -ecdsa-with-SHA1 -prverify sk.pem -signature data.sig data
sk.sign(msg, hashfunc=hashlib.sha1, sigencode=ecdsa.util.sigencode_der)
vk.verify(sig, msg, hashfunc=hashlib.sha1, sigdecode=ecdsa.util.sigdecode_der)
openssl处理的密钥可以如下读写:
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
0
熵
使用signing key.generate()
创建签名密钥需要某种形式的
熵(与from_secret_exponent/from_string/from_der/from_pem相反,
它们是确定性的,不需要熵源)。默认值
源代码是
os.urandom()
,但您可以传递任何其他行为
就像os.urandom的熵=做一些不同的事情。这可能
在想要获得可重复结果的单元测试中非常有用。这个
ecdsa.util.prng实用程序在这里很方便:它接受一个种子并生成一个强
来自它的伪随机流:
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
1
同样,ecdsa签名生成需要一个随机数,并且每个
签名必须使用不同的数字(使用相同的数字两次将
立即显示私有签名密钥)。sk.sign()
方法接受
熵=参数,其行为与signingkey.generate(熵=)
相同
确定性特征
如果您调用signingkey.sign_deterministic(data)
而不是。sign(data)
,
代码将生成一个确定性签名,而不是随机签名。
这使用rfc6979中的算法来安全地生成一个唯一的k
值,
从私钥和正在签名的消息派生。每次你签字
同一个消息具有相同的密钥,您将获得相同的签名(使用
相同的k
)。
在将来的版本中,这可能成为默认值,因为它不易受到 熵源失效。
示例
创建NIST192P密钥对并立即将它们保存到磁盘:
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
2
从磁盘加载签名密钥,使用它对消息进行签名,然后写入 签名到磁盘:
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
3
从磁盘加载验证密钥、消息和签名,并验证 签名:
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
4
创建NIST521P密钥对
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
5
从主种子创建三个独立的签名密钥:
to_string: signkey= 24, verifykey= 48, signature=48
DER: signkey=106, verifykey= 80, signature=55
PEM: signkey=278, verifykey=162, (no support for PEM signatures)
6