Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
python-ecdsa — подпись/проверка ECDSA и согласование ключей ECDH на чистом Python | Kitploit
Инструменты/GitHubGitHub/tlsfuzzer/python-ecdsa
Инструменты шифрования/дешифрованияКриптографияУтилиты и фреймворкиАутентификацияОбучение и Образование
GitHubtlsfuzzer/python-ecdsa

python-ecdsa

подпись/проверка ECDSA и согласование ключей ECDH на чистом Python

Репозиторий
9753422 месяцев назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

ECDSA и ECDH на чистом Python

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

Это простая в использовании реализация ECC (эллиптической криптографии) с поддержкой ECDSA (алгоритма цифровой подписи на эллиптических кривых), EdDSA (алгоритма цифровой подписи на кривых Эдвардса) и ECDH (протокола Диффи—Хеллмана на эллиптических кривых), реализованная чисто на Python и распространяемая под лицензией MIT. С помощью этой библиотеки вы можете быстро создавать пары ключей (подписывающий ключ и проверяющий ключ), подписывать сообщения и проверять подписи. Вы также можете согласовать общий секретный ключ на основе обменянных открытых ключей. Ключи и подписи очень короткие, что упрощает их обработку и включение в другие протоколы.

ПРИМЕЧАНИЕ. Эту библиотеку не следует использовать в производственных средах; подробнее см. Security.

Возможности

Эта библиотека обеспечивает генерацию ключей, подписание, проверку и вывод общего секретного ключа для пяти популярных кривых NIST «Suite B» GF(p) (простого поля) с длиной ключа 192, 224, 256, 384 и 521 бит. «Короткие имена» этих кривых, известные инструменту OpenSSL (openssl ecparam -list_curves): prime192v1, secp224r1, prime256v1, secp384r1 и secp521r1. Также включена 256-битная кривая secp256k1, используемая в Bitcoin. Кроме того, поддерживаются обычные (не скрученные) варианты кривых Brainpool от 160 до 512 бит. «Короткие имена» этих кривых: brainpoolP160r1, brainpoolP192r1, brainpoolP224r1, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, . Также включены некоторые небольшие кривые из стандарта 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:~
## Speed

В следующей таблице показано, сколько времени занимает эта библиотека для генерации пар ключей
(`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 (см. Использование ниже).
Для ключа NIST192p три основные представления требуют строк следующих длин (в байтах):

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 году Питер Пирсон объявил о своей реализации ECDSA на чистом Python в сообщении в sci.crypt, доступной с его сайта для загрузки. В 2010 году Брайан Уорнер написал обёртку вокруг этого кода, чтобы сделать его немного проще и безопаснее в использовании. В 2020 году Хуберт Карио включил реализацию криптографии на эллиптических кривых, которая внутренне использует координаты Якоби, что повысило производительность примерно в 20 раз. Вы видите README этой обёртки.

Тестирование

Чтобы запустить полный набор тестов, сделайте следующее:

root@kitploit:~
tox -e coverage

На Intel Core i7 4790K @ 4.0GHz выполнение тестов занимает около 18 секунд. Тестовый набор использует hypothesis, поэтому время выполнения набора тестов имеет некоторую присущую изменчивость.

Одна часть test_pyecdsa.py и test_ecdh.py проверяет совместимость с 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-armored
`"-----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(). Тот же аргумент curve= требуется для VerifyingKey.from_string().```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 принимает число, представляющее подписываемые данные, и возвращает
пару чисел, представляющих подпись. Аргумент `hashfunc=` для
`sk.sign()` и `vk.verify()` используется для преобразования произвольной строки в
дайджест фиксированной длины, который затем превращается в число, которое ECDSA может подписать,
и подпись, и проверка должны использовать один и тот же подход. Значение по умолчанию —
`hashlib.sha1`, но если вы используете NIST256p или более длинную кривую, можно использовать
`hashlib.sha256`.

Также существует несколько способов представления подписи. Методы по умолчанию
`sk.sign()` и `vk.verify()` представляют её как короткую строку, для
простоты и минимальных накладных расходов. Чтобы использовать другую схему, используйте
аргументы `sk.sign(sigencode=)` и `vk.verify(sigdecode=)`. В модуле
`ecdsa.util` есть вспомогательные функции, которые могут быть полезны здесь.

Также можно создать `SigningKey` из «seed» (зерна), что является
детерминированным. Это можно использовать в протоколах, где требуется получать
согласованные ключи подписи из какого-то другого секрета, например, когда нужно
три отдельных ключа, а хранить хочется только один главный секрет. Следует
начинать с равномерно распределённого неугадываемого зерна с примерно `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 подписей.

Для выполнения предварительных вычислений можно вызвать метод precompute() на экземпляре VerifyingKey:```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 или более ранними версиями, sigencode_string и sigdecode_string из ecdsa.util можно использовать для записи и чтения сигнатур соответственно.

Ключи также могут быть записаны в формате, который может обрабатывать 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` здесь удобна: она принимает seed и создаёт из него
сильный псевдослучайный поток:```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=).

Детерминированные подписи

Если вместо .sign(data) вызвать SigningKey.sign_deterministic(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()))

Загрузите проверочный ключ из 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()
Скачать инструмент
brainpoolP512r1
secp112r1
secp112r2
secp128r1
secp160r1