Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
python-ecdsa — 纯Python ECDSA 签名/验证和 ECDH 密钥协商 | Kitploit
工具/GitHubGitHub/tlsfuzzer/python-ecdsa
加密/解密工具密码学实用工具与框架身份验证学习与教育
GitHubtlsfuzzer/python-ecdsa

python-ecdsa

纯Python ECDSA 签名/验证和 ECDH 密钥协商

查看仓库
9753422个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Pure-Python ECDSA and ECDH

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

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

注意:此库不应在生产环境中使用,详情请参阅 Security。

特性

此库为五种流行的 NIST“Suite B”GF(p)(素数域)曲线提供密钥生成、签名、验证和共享密钥派生功能,密钥长度分别为 192、224、256、384 和 521 位。这些曲线在 OpenSSL 工具(openssl ecparam -list_curves)中的“短名称”为:prime192v1、secp224r1、prime256v1、secp384r1 和 secp521r1。它还包含 Bitcoin 所使用的 256 位曲线 secp256k1。此外还支持 Brainpool 曲线从 160 到 512 位的常规(非扭曲)变体。这些曲线的“短名称”为:brainpoolP160r1、brainpoolP192r1、brainpoolP224r1、brainpoolP256r1、brainpoolP320r1、brainpoolP384r1、brainpoolP512r1。SEC 标准中的少量小曲线也被包含在内(主要用于加速库的测试),它们是:、、 和 。同时支持 Ed25519 和 Ed448 曲线的密钥生成、签名和验证。库中未包含其他曲线,但要添加对更多素数域曲线的支持并不困难。

依赖

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

如果安装了 gmpy2 或 gmpy,它们将被用于加速算术运算。它们中的任何一个都可以在本库安装后安装,python-ecdsa 会在启动时检测到它们的存在并自动使用。在 Python3 上,为了获得最佳性能,您应该优先选择 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

root@kitploit:~
如果需要更高的性能,并且使用原生代码没有问题,可以指定与 `gmpy2` 一起安装:```
pip install ecdsa[gmpy2]

或(较慢的旧版选项):``` pip install ecdsa[gmpy]

root@kitploit:~
## 速度

下表展示了此库生成密钥对(`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

root@kitploit:~
                   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

root@kitploit:~
(还有 `gmpy` 版本,使用 `tox -e speedgmpy` 运行它)

作为对比,一个高度优化的实现(包括针对某些曲线的特定汇编优化),例如 OpenSSL 1.1.1d 中的实现,在同一台机器上可以提供以下性能数据。
运行 `openssl speed ecdsa` 和 `openssl 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

Keys and signature can be serialized in different ways (see Usage, below). For a NIST192p key, the three basic representations require strings of the following lengths (in bytes):

root@kitploit:~
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 年,Peter Pearson 在致 sci.crypt 的消息中宣布了他的纯 Python ECDSA 实现,该实现可从他的下载站点获取。2010 年,Brian Warner 围绕该代码编写了一个封装,使其使用起来更简单、更安全。2020 年,Hubert Kario 加入了一个在内部使用雅可比坐标的椭圆曲线密码学实现,将性能提高了约 20 倍。您现在看到的正是这个封装的 README。

测试

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

root@kitploit:~
tox -e coverage

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

test_pyecdsa.py 和 test_ecdh.py 的部分内容通过运行 "openssl" 命令行工具来检查与 OpenSSL 的兼容性。如果您想测试与 OpenSSL 的兼容性,请确保它位于您的 PATH 中(如果 OpenSSL 缺失、版本过旧或不支持上游版本支持的所有曲线,您会在上述 coverage 运行中看到被跳过的测试)。

安全性

该库在设计之初并未考虑安全性。如果您正在处理需要保护的数据,我们建议您使用 OpenSSL 的优质封装。pyca/cryptography 就是此类封装的一个例子。该库的主要用途是作为互操作性测试的可移植库和教学工具。

该库不防范侧信道攻击。

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

另请注意,任何纯 Python 加密库都会受到相同的侧信道攻击的影响。这是因为 Python 不提供侧信道安全的原语(hmac.compare_digest() 除外),因此进行侧信道安全编程是不可能的。

该库依赖于强随机数来源。请勿在 os.urandom() 无法提供加密安全随机数的系统上使用它。

用法

首先创建一个 SigningKey。您可以使用它对数据进行签名,方法是将数据作为字节字符串传入,然后取回签名(同样是一个字节字符串)。您还可以让 SigningKey 为您提供对应的 VerifyingKey。VerifyingKey 可用于验证签名,即将数据字符串和签名字节字符串都传给它:它会返回 True 或抛出 BadSignatureError。```python from ecdsa import SigningKey sk = SigningKey.generate() # uses NIST192p vk = sk.verifying_key signature = sk.sign(b"message") assert vk.verify(signature, b"message")

root@kitploit:~
每个 `SigningKey`/`VerifyingKey` 都与一个特定曲线关联,例如
NIST192p(默认曲线)。较长的曲线更安全,但使用时间更长,并产生更
长的密钥和签名。```python
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。```python 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())

root@kitploit:~
注意:虽然这些方法名为 `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()` 将抛出 `UnexpectedDER` 或` MalformedPointError`。```python
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= 参数。```python 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

root@kitploit:~
计算签名有多种不同的方式。从根本上说,
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()`,如下所示:```python
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() 方法:```python 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")

root@kitploit:~
一旦调用了 `precompute()`,使用此密钥进行的所有签名验证都将
执行得更快。

## OpenSSL 兼容性

要生成可由 OpenSSL 工具验证的签名,或验证由这些工具生成的签名,请使用:```python
# 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_string 和 sigdecode_string 来写入和读取签名。

密钥也可以写成 openssl 可以处理的格式:```python 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())

root@kitploit:~
## 熵

使用 `SigningKey.generate()` 创建签名密钥需要某种形式的
熵(与
`from_secret_exponent`/`from_string`/`from_der`/`from_pem` 不同,
这些方法是确定性的,不需要熵源)。默认
熵源是 `os.urandom()`,但你也可以传入任何行为
类似 `os.urandom` 的函数作为 `entropy=` 参数,以实现不同的行为。这
在单元测试中可能很有用,因为你可能希望获得可重复的结果。
`ecdsa.util.PRNG` 工具在这里很方便:它接受一个种子,并从中产生一个强
伪随机流:```python
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 密钥对,并立即将两者保存到磁盘:```python 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())

root@kitploit:~
从磁盘加载签名密钥,使用它签署消息(使用SHA-1),并将签名写入磁盘:```python
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 哈希):```python 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"

root@kitploit:~
创建 NIST521p 密钥对:```python
from ecdsa import SigningKey, NIST521p
sk = SigningKey.generate(curve=NIST521p)
vk = sk.verifying_key

从主种子创建三个独立的签名密钥:```python 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)

root@kitploit:~
从磁盘加载验证密钥,并使用十六进制编码以
未压缩和压缩格式(定义于 X9.62 和 SEC1 标准)打印它:```python
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()))

从压缩格式的十六进制字符串加载验证密钥,输出非压缩格式:```python from ecdsa import VerifyingKey, NIST256p

comp_str = '022799c0d0ee09772fdd337d4f28dc155581951d07082fb19a38aa396b67e77759' vk = VerifyingKey.from_string(bytearray.fromhex(comp_str), curve=NIST256p) print(vk.to_string("uncompressed").hex())

root@kitploit:~
与远程方进行 ECDH 密钥交换:```python
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()
下载工具
secp112r1
secp112r2
secp128r1
secp160r1