跳转到主要内容

ECDSA加密签名库(纯Python实现)

项目描述

纯Python实现的ECDSA和ECDH

Build Status Documentation Status Coverage Status condition coverage mutation score CodeQL Latest Version Code style: black

这是一个易于使用的ECC(椭圆曲线密码学)实现,支持ECDSA(椭圆曲线数字签名算法)、EdDSA(Edwards曲线数字签名算法)和ECDH(椭圆曲线Diffie-Hellman),完全使用Python编写,并在MIT许可证下发布。使用这个库,您可以快速创建密钥对(签名密钥和验证密钥)、签名消息和验证签名。您还可以基于交换的公钥同意一个共享的密钥。密钥和签名非常短,易于处理和集成到其他协议中。

注意:此库不应在生产环境中使用,有关更多信息,请参阅安全

功能

本库为五种流行的NIST "Suite B" GF(p)(素域)曲线提供密钥生成、签名、验证和共享密钥派生功能,密钥长度分别为192、224、256、384和521位。这些曲线的“短名称”是OpenSSL工具(openssl ecparam -list_curves)所知的,分别为:prime192v1secp224r1prime256v1secp384r1secp521r1。它还包括比特币使用的256位曲线secp256k1。还支持从160到512位的Brainpool曲线的常规(非扭曲)变体。这些曲线的“短名称”为:brainpoolP160r1brainpoolP192r1brainpoolP224r1brainpoolP256r1brainpoolP320r1brainpoolP384r1brainpoolP512r1。还包括SEC标准中的一些小曲线(主要为了加快库的测试),这些曲线是:secp112r1secp112r2secp128r1secp160r1。还支持Ed25519和Ed448曲线的密钥生成、签名和验证。不包括其他曲线,但添加对更多素域曲线的支持并不太难。

依赖项

本库仅使用Python和'six'包。它与Python 2.6、2.7和3.5+兼容。它还支持在pypy和pypy3等替代实现上执行。

如果已安装gmpy2gmpy,它们将被用于更快的算术。可以在安装此库之后安装其中任何一个,python-ecdsa将在启动时检测它们的存在并自动使用它们。在Python 3上应优先使用gmpy2以获得最佳性能。

要运行OpenSSL兼容性测试,'openssl'工具必须在您的PATH中。本版本已成功测试与OpenSSL 0.9.8o、1.0.0a、1.0.2f、1.1.1d和3.0.1(以及其他版本)的兼容性。

安装

本库可在PyPI上找到,建议使用pip安装。

pip install ecdsa

如果需要更高的性能并且使用原生代码没有问题,可以在安装时指定与gmpy2一起安装。

pip install ecdsa[gmpy2]

或(较慢的旧选项)

pip install ecdsa[gmpy]

速度

下表显示了本库生成密钥对(keygen)、签名数据(sign)、验证这些签名(verify)、派生共享密钥(ecdh)以及验证不带密钥特定预计算的签名(no PC verify)所需的时间。所有这些值都以秒为单位。为了方便,还提供了这些值的倒数:每秒可以生成多少密钥(keygen/s)、每秒可以制作多少签名(sign/s)、每秒可以验证多少签名(verify/s)、每秒可以派生多少共享密钥(ecdh/s)以及每秒可以验证多少不带密钥特定预计算的签名(no PC verify/s)。原始签名的大小(通常是最小的编码方式)也在siglen列中提供。使用tox -e speed在您的计算机上生成此表。在我的Intel Core i7 4790K @ 4.0GHz上,我得到了以下性能

                  siglen    keygen   keygen/s      sign     sign/s    verify   verify/s  no PC verify  no PC verify/s
        NIST192p:     48   0.00032s   3134.06   0.00033s   2985.53   0.00063s   1598.36       0.00129s         774.43
        NIST224p:     56   0.00040s   2469.24   0.00042s   2367.88   0.00081s   1233.41       0.00170s         586.66
        NIST256p:     64   0.00051s   1952.73   0.00054s   1867.80   0.00098s   1021.86       0.00212s         471.27
        NIST384p:     96   0.00107s    935.92   0.00111s    904.23   0.00203s    491.77       0.00446s         224.00
        NIST521p:    132   0.00210s    475.52   0.00215s    464.16   0.00398s    251.28       0.00874s         114.39
       SECP256k1:     64   0.00052s   1921.54   0.00054s   1847.49   0.00105s    948.68       0.00210s         477.01
 BRAINPOOLP160r1:     40   0.00025s   4003.88   0.00026s   3845.12   0.00053s   1893.93       0.00105s         949.92
 BRAINPOOLP192r1:     48   0.00033s   3043.97   0.00034s   2975.98   0.00063s   1581.50       0.00135s         742.29
 BRAINPOOLP224r1:     56   0.00041s   2436.44   0.00043s   2315.51   0.00078s   1278.49       0.00180s         556.16
 BRAINPOOLP256r1:     64   0.00053s   1892.49   0.00054s   1846.24   0.00114s    875.64       0.00229s         437.25
 BRAINPOOLP320r1:     80   0.00073s   1361.26   0.00076s   1309.25   0.00143s    699.29       0.00322s         310.49
 BRAINPOOLP384r1:     96   0.00107s    931.29   0.00111s    901.80   0.00230s    434.19       0.00476s         210.20
 BRAINPOOLP512r1:    128   0.00207s    483.41   0.00212s    471.42   0.00425s    235.43       0.00912s         109.61
       SECP112r1:     28   0.00015s   6672.53   0.00016s   6440.34   0.00031s   3265.41       0.00056s        1774.20
       SECP112r2:     28   0.00015s   6697.11   0.00015s   6479.98   0.00028s   3524.72       0.00058s        1716.16
       SECP128r1:     32   0.00018s   5497.65   0.00019s   5272.89   0.00036s   2747.39       0.00072s        1396.16
       SECP160r1:     42   0.00025s   3949.32   0.00026s   3894.45   0.00046s   2153.85       0.00102s         985.07
         Ed25519:     64   0.00076s   1324.48   0.00042s   2405.01   0.00109s    918.05       0.00344s         290.50
           Ed448:    114   0.00176s    569.53   0.00115s    870.94   0.00282s    355.04       0.01024s          97.69

                       ecdh     ecdh/s
        NIST192p:   0.00104s    964.89
        NIST224p:   0.00134s    748.63
        NIST256p:   0.00170s    587.08
        NIST384p:   0.00352s    283.90
        NIST521p:   0.00717s    139.51
       SECP256k1:   0.00154s    648.40
 BRAINPOOLP160r1:   0.00082s   1220.70
 BRAINPOOLP192r1:   0.00105s    956.75
 BRAINPOOLP224r1:   0.00136s    734.52
 BRAINPOOLP256r1:   0.00178s    563.32
 BRAINPOOLP320r1:   0.00252s    397.23
 BRAINPOOLP384r1:   0.00376s    266.27
 BRAINPOOLP512r1:   0.00733s    136.35
       SECP112r1:   0.00046s   2180.40
       SECP112r2:   0.00045s   2229.14
       SECP128r1:   0.00054s   1868.15
       SECP160r1:   0.00080s   1243.98

要测试加载gmpy2时的性能,请使用tox -e speedgmpy2。在同一台机器上,我得到了以下使用gmpy2的性能

                  siglen    keygen   keygen/s      sign     sign/s    verify   verify/s  no PC verify  no PC verify/s
        NIST192p:     48   0.00017s   5933.40   0.00017s   5751.70   0.00032s   3125.28       0.00067s        1502.41
        NIST224p:     56   0.00021s   4782.87   0.00022s   4610.05   0.00040s   2487.04       0.00089s        1126.90
        NIST256p:     64   0.00023s   4263.98   0.00024s   4125.16   0.00045s   2200.88       0.00098s        1016.82
        NIST384p:     96   0.00041s   2449.54   0.00042s   2399.96   0.00083s   1210.57       0.00172s         581.43
        NIST521p:    132   0.00071s   1416.07   0.00072s   1389.81   0.00144s    692.93       0.00312s         320.40
       SECP256k1:     64   0.00024s   4245.05   0.00024s   4122.09   0.00045s   2206.40       0.00094s        1068.32
 BRAINPOOLP160r1:     40   0.00014s   6939.17   0.00015s   6681.55   0.00029s   3452.43       0.00057s        1769.81
 BRAINPOOLP192r1:     48   0.00017s   5920.05   0.00017s   5774.36   0.00034s   2979.00       0.00069s        1453.19
 BRAINPOOLP224r1:     56   0.00021s   4732.12   0.00022s   4622.65   0.00041s   2422.47       0.00087s        1149.87
 BRAINPOOLP256r1:     64   0.00024s   4233.02   0.00024s   4115.20   0.00047s   2143.27       0.00098s        1015.60
 BRAINPOOLP320r1:     80   0.00032s   3162.38   0.00032s   3077.62   0.00063s   1598.83       0.00136s         737.34
 BRAINPOOLP384r1:     96   0.00041s   2436.88   0.00042s   2395.62   0.00083s   1202.68       0.00178s         562.85
 BRAINPOOLP512r1:    128   0.00063s   1587.60   0.00064s   1558.83   0.00125s    799.96       0.00281s         355.83
       SECP112r1:     28   0.00009s  11118.66   0.00009s  10775.48   0.00018s   5456.00       0.00033s        3020.83
       SECP112r2:     28   0.00009s  11322.97   0.00009s  10857.71   0.00017s   5748.77       0.00032s        3094.28
       SECP128r1:     32   0.00010s  10078.39   0.00010s   9665.27   0.00019s   5200.58       0.00036s        2760.88
       SECP160r1:     42   0.00015s   6875.51   0.00015s   6647.35   0.00029s   3422.41       0.00057s        1768.35
         Ed25519:     64   0.00030s   3322.56   0.00018s   5568.63   0.00046s   2165.35       0.00153s         654.02
           Ed448:    114   0.00060s   1680.53   0.00039s   2567.40   0.00096s   1036.67       0.00350s         285.62

                       ecdh     ecdh/s
        NIST192p:   0.00050s   1985.70
        NIST224p:   0.00066s   1524.16
        NIST256p:   0.00071s   1413.07
        NIST384p:   0.00127s    788.89
        NIST521p:   0.00230s    434.85
       SECP256k1:   0.00071s   1409.95
 BRAINPOOLP160r1:   0.00042s   2374.65
 BRAINPOOLP192r1:   0.00051s   1960.01
 BRAINPOOLP224r1:   0.00066s   1518.37
 BRAINPOOLP256r1:   0.00071s   1399.90
 BRAINPOOLP320r1:   0.00100s    997.21
 BRAINPOOLP384r1:   0.00129s    777.51
 BRAINPOOLP512r1:   0.00210s    475.99
       SECP112r1:   0.00022s   4457.70
       SECP112r2:   0.00024s   4252.33
       SECP128r1:   0.00028s   3589.31
       SECP160r1:   0.00043s   2305.02

(还有gmpy版本,使用tox -e speedgmpy执行)

为了比较,像OpenSSL 1.1.1d中那样高度优化的实现(包括某些曲线的曲线特定汇编),在同一台机器上提供了以下性能数据。运行openssl speed ecdsaopenssl speed ecdh以重现它

                              sign    verify    sign/s verify/s
 192 bits ecdsa (nistp192)   0.0002s   0.0002s   4785.6   5380.7
 224 bits ecdsa (nistp224)   0.0000s   0.0001s  22475.6   9822.0
 256 bits ecdsa (nistp256)   0.0000s   0.0001s  45069.6  14166.6
 384 bits ecdsa (nistp384)   0.0008s   0.0006s   1265.6   1648.1
 521 bits ecdsa (nistp521)   0.0003s   0.0005s   3753.1   1819.5
 256 bits ecdsa (brainpoolP256r1)   0.0003s   0.0003s   2983.5   3333.2
 384 bits ecdsa (brainpoolP384r1)   0.0008s   0.0007s   1258.8   1528.1
 512 bits ecdsa (brainpoolP512r1)   0.0015s   0.0012s    675.1    860.1

                              sign    verify    sign/s verify/s
 253 bits EdDSA (Ed25519)   0.0000s   0.0001s  28217.9  10897.7
 456 bits EdDSA (Ed448)     0.0003s   0.0005s   3926.5   2147.7

                               op      op/s
 192 bits ecdh (nistp192)   0.0002s   4853.4
 224 bits ecdh (nistp224)   0.0001s  15252.1
 256 bits ecdh (nistp256)   0.0001s  18436.3
 384 bits ecdh (nistp384)   0.0008s   1292.7
 521 bits ecdh (nistp521)   0.0003s   2884.7
 256 bits ecdh (brainpoolP256r1)   0.0003s   3066.5
 384 bits ecdh (brainpoolP384r1)   0.0008s   1298.0
 512 bits ecdh (brainpoolP512r1)   0.0014s    694.8

密钥和签名可以用不同的方式序列化(见下文使用说明)。对于NIST192p密钥,三种基本表示法需要的字符串长度(以字节为单位)如下

to_string:  signkey= 24, verifykey= 48, signature=48
compressed: signkey=n/a, verifykey= 25, signature=n/a
DER:        signkey=106, verifykey= 80, signature=55
PEM:        signkey=278, verifykey=162, (no support for PEM signatures)

历史

2006年,彼得·皮尔森在sci.crypt论坛上发布了他纯Python实现的ECDSA,可在他的下载站点找到。2010年,布莱恩·沃纳编写了一个代码包装器,使其使用起来更加简单和安全。2020年,休伯特·卡里奥在其内部使用了雅可比坐标的椭圆曲线密码学实现,将性能提高了约20倍。你现在看到的是这个包装器的README。

测试

要运行完整的测试套件,请执行以下操作

tox -e coverage

在Intel Core i7 4790K @ 4.0GHz的机器上,测试执行大约需要18秒。测试套件使用hypothesis,因此测试套件执行时间存在一些固有的可变性。

test_pyecdsa.pytest_ecdh.py的一部分检查与OpenSSL的兼容性,通过运行"openssl" CLI工具,如果你想要测试与其的兼容性,请确保它在你的PATH中(如果OpenSSL不存在、版本太旧或不支持上游版本中支持的所有曲线,你将在上述coverage运行中看到跳过的测试)。

安全性

这个库不是以安全为导向设计的。如果你正在处理需要保护的数据,我们建议你使用OpenSSL的优质包装器。pyca/cryptography是此类包装器的一个例子。这个库的主要用途是作为互操作性测试的可移植库和教学工具。

这个库不能保护免受旁路攻击。

不要让攻击者测量你生成密钥对或签名消息所需的时间。不要允许攻击者在密钥对生成或签名过程中在同一台物理机器上运行代码(这包括虚拟机)。不要允许攻击者测量你在生成密钥对或签名消息时电脑的功耗。不要允许攻击者测量在生成密钥对或签名消息时从电脑发出的射频干扰。注意:仅加载私钥就会导致生成密钥对。其他操作或攻击向量也可能容易受到攻击。对于经验丰富的攻击者来说,仅观察一次使用私钥的操作就足以完全重建私钥

请注意,任何纯Python加密库都会受到相同的旁路攻击的威胁。这是因为Python不提供旁路安全原语(除了hmac.compare_digest()之外),使得旁路安全编程变得不可能。

这个库依赖于一个强大的随机数源。不要在os.urandom()不提供密码学安全随机数的系统上使用它。

用法

你首先创建一个SigningKey。你可以使用它来签名数据,通过传递一个字节字符串作为数据,并返回签名(也是一个字节字符串)。你也可以让一个SigningKey给你相应的VerifyingKeyVerifyingKey可以用来验证签名,通过传递数据字符串和签名字节字符串:它要么返回True,要么抛出BadSignatureError

from ecdsa import SigningKey
sk = SigningKey.generate() # uses NIST192p
vk = sk.verifying_key
signature = sk.sign(b"message")
assert vk.verify(signature, b"message")

每个SigningKey/VerifyingKey都与一个特定的曲线相关联,如NIST192p(默认值)。更长的曲线更安全,但使用时间更长,导致密钥和签名更长。

from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
vk = sk.verifying_key
signature = sk.sign(b"message")
assert vk.verify(signature, b"message")

SigningKey 可以序列化为几种不同的格式:最短的方式是调用 s=sk.to_string(),然后用 SigningKey.from_string(s, curve) 重新创建。这种简短形式不记录曲线,因此你必须确保将相同的曲线传递给 from_string(),以便与原始密钥相同。基于 NIST192p 的签名密钥的简短形式只有 24 个字节长。如果点编码无效或它不在指定的曲线上,from_string() 将引发 MalformedPointError

from ecdsa import SigningKey, NIST384p
sk = SigningKey.generate(curve=NIST384p)
sk_string = sk.to_string()
sk2 = SigningKey.from_string(sk_string, curve=NIST384p)
print(sk_string.hex())
print(sk2.to_string().hex())

注意:虽然方法被命名为 to_string(),但它们返回的类型实际上是 bytes,"string" 这一部分是 Python 2 时代留下的。

sk.to_pem()sk.to_der() 将签名密钥序列化为 OpenSSL 使用的相同格式。PEM 文件看起来像熟悉的 ASCII-武装的 "-----BEGIN EC PRIVATE KEY-----" 基于Base64的格式,DER 格式是相同数据的更短的二进制形式。SigningKey.from_pem()/.from_der() 将撤销这种序列化。这些格式包括曲线名称,因此不需要传递曲线标识符给反序列化器。如果文件格式不正确,from_der()from_pem() 将引发 UnexpectedDERMalformedPointError

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(),以及 to_der()/from_der()。对于 VerifyingKey.from_string() 需要相同的 curve= 参数。

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

计算签名有几种不同的方式。本质上,ECDSA 取一个表示待签名数据的数字,并返回一个表示签名的数字对。在 sk.sign()vk.verify() 中,hashfunc= 参数用于将任意字符串转换为固定长度的摘要,然后将其转换为 ECDSA 可以签名的数字,签名和验证都必须使用相同的方法。默认值是 hashlib.sha1,但如果使用 NIST256p 或更长的曲线,则可以使用 hashlib.sha256

还有多种方式可以表示签名。默认的 sk.sign()vk.verify() 方法将其表示为简短字符串,以简化并最小化开销。要使用不同的方案,请使用 sk.sign(sigencode=)vk.verify(sigdecode=) 参数。在 ecdsa.util 模块中有一些辅助函数可能在这里很有用。

还可以从“种子”创建 SigningKey,这是一个确定性的种子。这可以在需要从其他秘密派生一致的签名密钥的协议中使用,例如,当您想要三个单独的密钥但只想存储单个主密钥时。您应该从一个具有大约 curve.baselen 字节熵的均匀分布且难以猜测的种子开始,然后使用 ecdsa.util 中的辅助函数将其转换为正确的范围内的整数,最后将其传递给 SigningKey.from_secret_exponent(),如下所示

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
assert sk1a.to_string() != sk2.to_string()

如果应用程序将验证大量使用单个密钥制作的签名,则可以预先计算一些内部值以使签名验证大大加快。盈亏平衡点发生在大约 100 个验证签名。

要执行预计算,可以调用 VerifyingKey 实例上的 precompute() 方法

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")

一旦调用了 precompute(),所有使用此密钥进行的签名验证都将更快地执行。

OpenSSL 兼容性

要生成可以由 OpenSSL 工具验证的签名,或者验证由这些工具生成的签名,请使用

# 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

import hashlib
from ecdsa import SigningKey, VerifyingKey
from ecdsa.util import sigencode_der, sigdecode_der

with open("vk.pem") as f:
   vk = VerifyingKey.from_pem(f.read())

with open("data", "rb") as f:
   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_stringsigdecode_string 分别写入和读取签名。

密钥还可以以 OpenSSL 可以处理的形式写入

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())

使用 SigningKey.generate() 创建签名密钥需要某种形式的熵(与 from_secret_exponent/from_string/from_der/from_pem 相反,后者是确定性的,不需要熵源)。默认源是 os.urandom(),但您可以将任何其他类似 os.urandom 的函数作为 entropy= 参数传递以执行不同的操作。这在单元测试中可能很有用,因为在单元测试中,您希望得到可重复的结果。在此处,ecdsa.util.PRNG 工具很方便:它接受一个种子并从中生成一个强伪随机流。

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

同样,ECDSA 签名生成需要一个随机数,并且每个签名必须使用不同的随机数(使用相同的数字两次将立即泄露私钥签名密钥)。sk.sign() 方法接受一个 entropy= 参数,其行为与 SigningKey.generate(entropy=) 相同。

确定性签名

如果您调用 SigningKey.sign_deterministic(data) 而不是 .sign(data),则代码将生成一个确定性签名而不是随机签名。这使用 RFC6979 算法安全地生成一个独特的 k 值,该值由私钥和要签名的消息推导而来。每次您使用相同的密钥签同样的消息时,您都会得到相同的签名(使用相同的 k)。

这可能在未来的版本中成为默认设置,因为它不受熵源失败的影响。

示例

创建一个 NIST192p 密钥对并将其立即保存到磁盘上

from ecdsa import SigningKey
sk = SigningKey.generate()
vk = sk.verifying_key
with open("private.pem", "wb") as f:
    f.write(sk.to_pem())
with open("public.pem", "wb") as f:
    f.write(vk.to_pem())

从磁盘加载签名密钥,使用它来签名一条消息(使用 SHA-1),并将签名写入磁盘

from ecdsa import SigningKey
with open("private.pem") as f:
    sk = SigningKey.from_pem(f.read())
with open("message", "rb") as f:
    message = f.read()
sig = sk.sign(message)
with open("signature", "wb") as f:
    f.write(sig)

从磁盘加载验证密钥、消息和签名,并验证签名(假设 SHA-1 哈希)

from ecdsa import VerifyingKey, BadSignatureError
vk = VerifyingKey.from_pem(open("public.pem").read())
with open("message", "rb") as f:
    message = f.read()
with open("signature", "rb") as f:
    sig = f.read()
try:
    vk.verify(sig, message)
    print "good signature"
except BadSignatureError:
    print "BAD SIGNATURE"

创建一个 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()

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪一个,请了解更多关于 安装软件包 的信息。

源分布

ecdsa-0.19.0.tar.gz (197.8 kB 查看哈希值)

上传时间

构建分布

ecdsa-0.19.0-py2.py3-none-any.whl (149.3 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下支持