
pure-python firma/verificación ECDSA y acuerdo de claves ECDH
Esta es una implementación fácil de usar de ECC (Criptografía de Curva Elíptica) con soporte para ECDSA (Algoritmo de Firma Digital de Curva Elíptica), EdDSA (Algoritmo de Firma Digital de Curva Edwards) y ECDH (Diffie-Hellman de Curva Elíptica), implementada puramente en Python, publicada bajo la licencia MIT. Con esta biblioteca, puede crear rápidamente pares de claves (clave de firma y clave de verificación), firmar mensajes y verificar las firmas. También puede acordar una clave secreta compartida basada en claves públicas intercambiadas. Las claves y las firmas son muy cortas, lo que facilita su manejo e incorporación en otros protocolos.
NOTA: Esta biblioteca no debería utilizarse en entornos de producción; consulte Seguridad para más detalles.
Esta biblioteca proporciona generación de claves, firma, verificación y derivación
de secreto compartido para cinco
curvas NIST "Suite B" GF(p) (campo primo) populares, con longitudes de clave de 192,
224, 256, 384 y 521 bits. Los "nombres cortos" de estas curvas, conocidos por
la herramienta OpenSSL (openssl ecparam -list_curves), son: prime192v1,
secp224r1, prime256v1, secp384r1 y secp521r1. Incluye la
curva de 256 bits secp256k1 utilizada por Bitcoin. También hay soporte para las
variantes normales (no retorcidas) de las curvas Brainpool de 160 a 512 bits. Los
"nombres cortos" de estas curvas son: brainpoolP160r1, brainpoolP192r1,
brainpoolP224r1, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1,
. También se incluyen algunas de las curvas pequeñas del estándar SEC
(principalmente para acelerar las pruebas de la biblioteca), que son:
, , y .
La generación de claves, la firma y la verificación también son compatibles con las curvas Ed25519 y
Ed448.
No se incluyen otras curvas, pero no es demasiado difícil añadir soporte para más
curvas sobre campos primos.
Esta biblioteca utiliza solo Python y el paquete 'six'. Es compatible con Python 2.6, 2.7 y 3.6+. También admite la ejecución en implementaciones alternativas como pypy y pypy3.
Si gmpy2 o gmpy están instalados, se utilizarán para una aritmética más rápida.
Cualquiera de ellos puede instalarse después de que esta biblioteca esté instalada;
python-ecdsa detectará su presencia al inicio y los utilizará
automáticamente.
Debería preferir gmpy2 en Python3 para un rendimiento óptimo.
Para ejecutar las pruebas de compatibilidad con OpenSSL, la herramienta 'openssl' debe estar en su
PATH. Esta versión se ha probado con éxito contra OpenSSL 0.9.8o,
1.0.0a, 1.0.2f, 1.1.1d y 3.0.1 (entre otros).
Esta biblioteca está disponible en PyPI; se recomienda instalarla con pip:```
pip install ecdsa
En caso de que se quiera un mayor rendimiento y el uso de código nativo no sea un problema, es posible especificar la instalación junto con `gmpy2`:```
pip install ecdsa[gmpy2]
o (opción más lenta, heredada):``` pip install ecdsa[gmpy]
## Velocidad
La siguiente tabla muestra cuánto tarda esta librería en generar pares de claves (`keygen`), en firmar datos (`sign`), en verificar esas firmas (`verify`), en derivar un secreto compartido (`ecdh`) y en verificar las firmas sin precomputación específica de clave (`no PC verify`). Todos esos valores están en segundos. Por conveniencia, también se proporcionan los inversos de esos valores: cuántas claves por segundo se pueden generar (`keygen/s`), cuántas firmas se pueden realizar por segundo (`sign/s`), cuántas firmas se pueden verificar por segundo (`verify/s`), cuántos secretos compartidos se pueden derivar por segundo (`ecdh/s`) y cuántas firmas sin precomputación específica de clave se pueden verificar por segundo (`no PC verify/s`). El tamaño de la firma bruta (generalmente la forma más pequeña en que se puede codificar una firma) también se proporciona en la columna `siglen`. Usa `tox -e speed` para generar esta tabla en tu propio equipo. En un Intel Core i7 4790K @ 4.0GHz obtengo el siguiente rendimiento:```
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
Para probar el rendimiento con gmpy2 cargado, usa tox -e speedgmpy2.
En la misma máquina obtengo el siguiente rendimiento con 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
(también hay una versión `gmpy`, ejecútala usando `tox -e speedgmpy`)
Para comparar, una implementación altamente optimizada (incluido ensamblador específico para algunas curvas), como la de OpenSSL 1.1.1d, proporciona los siguientes números de rendimiento en la misma máquina.
Ejecuta `openssl speed ecdsa` y `openssl speed ecdh` para reproducirlo:```
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
Las claves y las firmas se pueden serializar de diferentes maneras (consulte Uso, más abajo). Para una clave NIST192p, las tres representaciones básicas requieren cadenas de las siguientes longitudes (en bytes):
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)
En 2006, Peter Pearson anunció su implementación de ECDSA en Python puro en un mensaje para sci.crypt, disponible desde su sitio de descarga. En 2010, Brian Warner escribió un envoltorio alrededor de este código, para hacerlo un poco más fácil y seguro de usar. En 2020, Hubert Kario incluyó una implementación de criptografía de curva elíptica que utiliza coordenadas jacobianas internamente, mejorando el rendimiento unas 20 veces. Está viendo el README de este envoltorio.
Para ejecutar la suite de pruebas completa, haga esto:
tox -e coverage
En un Intel Core i7 4790K @ 4.0GHz, las pruebas tardan unos 18 segundos en ejecutarse.
La suite de pruebas utiliza
hypothesis, por lo que hay cierta
variabilidad inherente en el tiempo de ejecución de la suite de pruebas.
Una parte de test_pyecdsa.py y test_ecdh.py comprueba la compatibilidad con
OpenSSL, ejecutando la herramienta CLI "openssl"; asegúrese de que esté en su PATH si
desea probar la compatibilidad con ella (si OpenSSL falta, es demasiado antiguo o
no admite todas las curvas soportadas en las versiones upstream, verá
pruebas omitidas en la ejecución de coverage anterior).
Esta biblioteca no fue diseñada teniendo en cuenta la seguridad. Si está procesando datos que necesitan protección, le sugerimos que utilice un envoltorio de calidad alrededor de OpenSSL. pyca/cryptography es un ejemplo de dicho envoltorio. El caso de uso principal de esta biblioteca es como biblioteca portátil para pruebas de interoperabilidad y como herramienta educativa.
Esta biblioteca no protege contra ataques de canal lateral.
No permita que los atacantes midan cuánto tiempo le lleva generar un par de claves o firmar un mensaje. No permita que los atacantes ejecuten código en la misma máquina física mientras se lleva a cabo la generación del par de claves o la firma (esto incluye máquinas virtuales). No permita que los atacantes midan cuánta energía consume su computadora mientras genera el par de claves o firma un mensaje. No permita que los atacantes midan la interferencia de radiofrecuencia proveniente de su computadora mientras genera un par de claves o firma un mensaje. Nota: simplemente cargar la clave privada provocará la generación del par de claves. Otras operaciones o vectores de ataque también pueden ser vulnerables a ataques. Para un atacante sofisticado, observar una sola operación con una clave privada será suficiente para reconstruir completamente la clave privada.
Tenga en cuenta también que cualquier biblioteca criptográfica en Python puro será vulnerable
a los mismos ataques de canal lateral. Esto se debe a que Python no proporciona
primitivas seguras contra canales laterales (con la excepción de
hmac.compare_digest()), lo que hace la programación segura contra canales laterales
imposible.
Esta biblioteca depende de una fuente sólida de números aleatorios. No la utilice en
un sistema donde os.urandom() no proporcione números aleatorios
criptográficamente seguros.
Comience creando una SigningKey. Puede usarla para firmar datos, pasando
los datos como una cadena de bytes y obteniendo la firma (también una cadena de bytes).
También puede pedirle a una SigningKey que le proporcione la VerifyingKey correspondiente.
La VerifyingKey se puede usar para verificar una firma, pasándole tanto la
cadena de datos como la cadena de bytes de la firma: devuelve True o lanza
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")
Cada `SigningKey`/`VerifyingKey` está asociada con una curva específica, como
NIST192p (la predeterminada). Las curvas más largas son más seguras, pero
tardan más en usarse y generan claves y firmas más largas.```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")
La SigningKey se puede serializar en varios formatos diferentes: el más corto es llamar a s=sk.to_string(), y luego recrearla con SigningKey.from_string(s, curve) . Esta forma corta no registra la curva, por lo que debe asegurarse de pasar a from_string() la misma curva que usó para la clave original. La forma corta de una clave de firma basada en NIST192p tiene solo 24 bytes de longitud. Si una codificación de punto es inválida o no se encuentra en la curva especificada, from_string() lanzará 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())
Nota: aunque los métodos se llaman `to_string()`, el tipo que devuelven es
en realidad `bytes`, la parte de "string" es un remanente de Python 2.
`sk.to_pem()` y `sk.to_der()` serializarán la clave de firma en los mismos
formatos que usa OpenSSL. El archivo PEM tiene el conocido formato
ASCII-armored `"-----BEGIN EC PRIVATE KEY-----"` codificado en base64, y el
formato DER es una forma binaria más corta de los mismos datos.
`SigningKey.from_pem()/.from_der()` desharán esta serialización. Estos
formatos incluyen el nombre de la curva, por lo que no es necesario pasar un
identificador de curva al deserializador. En caso de que el archivo esté
malformado, `from_der()` y `from_pem()` lanzarán `UnexpectedDER` o` 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
Del mismo modo, VerifyingKey se puede serializar de la misma manera:
vk.to_string()/VerifyingKey.from_string(), to_pem()/from_pem(), y
to_der()/from_der(). El mismo argumento curve= se necesita para
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)
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)
Hay un par de formas diferentes de calcular una firma. Fundamentalmente,
ECDSA toma un número que representa los datos que se están firmando y devuelve un
par de números que representan la firma. El argumento `hashfunc=` de
`sk.sign()` y `vk.verify()` se utiliza para convertir una cadena arbitraria en un
resumen de longitud fija, que luego se convierte en un número que ECDSA puede firmar,
y tanto la firma como la verificación deben usar el mismo enfoque. El valor predeterminado es
`hashlib.sha1`, pero si usas NIST256p o una curva más larga, puedes usar
`hashlib.sha256` en su lugar.
También hay múltiples formas de representar una firma. Los métodos
`sk.sign()` y `vk.verify()` predeterminados la presentan como una cadena corta, por
simplicidad y mínima sobrecarga. Para usar un esquema diferente, utiliza los
argumentos `sk.sign(sigencode=)` y `vk.verify(sigdecode=)`. Hay funciones
auxiliares en el módulo `ecdsa.util` que pueden ser útiles aquí.
También es posible crear un `SigningKey` a partir de una "semilla", que es
determinista. Esto se puede usar en protocolos donde quieras derivar
claves de firma consistentes de algún otro secreto, por ejemplo cuando quieras
tres claves separadas y solo quieras almacenar un único secreto maestro. Debes
comenzar con una semilla uniformemente distribuida e imposible de adivinar con aproximadamente `curve.baselen`
bytes de entropía, y luego usar una de las funciones auxiliares en `ecdsa.util` para
convertirla en un entero en el rango correcto, y finalmente pasarla
a `SigningKey.from_secret_exponent()`, de esta manera:```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()
En caso de que la aplicación verifique muchas firmas realizadas con una sola clave, es posible precalcular algunos de los valores internos para que la verificación de firmas sea significativamente más rápida. El punto de equilibrio se produce alrededor de 100 firmas verificadas.
Para realizar el precálculo, puede llamar al método precompute() en una
instancia de 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")
Una vez que se llamó a `precompute()`, todas las verificaciones de firma con esta clave serán
más rápidas de ejecutar.
## Compatibilidad con OpenSSL
Para producir firmas que puedan ser verificadas por herramientas OpenSSL, o para verificar
firmas producidas por esas herramientas, use:```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
Nota: si es necesaria la compatibilidad con OpenSSL 1.0.0 o anterior, se pueden usar sigencode_string y sigdecode_string de ecdsa.util para escribir y leer las firmas, respectivamente.
Las claves también se pueden escribir en un formato que openssl pueda manejar:```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())
## Entropía
Crear una clave de firma con `SigningKey.generate()` requiere alguna forma de
entropía (a diferencia de
`from_secret_exponent`/`from_string`/`from_der`/`from_pem`,
que son deterministas y no requieren una fuente de entropía). La fuente
predeterminada es `os.urandom()`, pero puedes pasar cualquier otra función que se
comporte como `os.urandom` como el argumento `entropy=` para hacer algo diferente. Esto
puede ser útil en pruebas unitarias, donde quieras lograr resultados repetibles. La
utilidad `ecdsa.util.PRNG` es práctica aquí: toma una semilla y produce un flujo
pseudoaleatorio fuerte a partir de ella:```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
Del mismo modo, la generación de firmas ECDSA requiere un número aleatorio, y cada
firma debe usar uno diferente (usar el mismo número dos veces
revelará inmediatamente la clave de firma privada). El método sk.sign() toma un
argumento entropy= que se comporta igual que SigningKey.generate(entropy=).
Si llamas a SigningKey.sign_deterministic(data) en lugar de .sign(data),
el código generará una firma determinista en lugar de una aleatoria.
Esto utiliza el algoritmo de RFC6979 para generar de forma segura un valor k único,
derivado de la clave privada y del mensaje que se está firmando. Cada vez que firmes
el mismo mensaje con la misma clave, obtendrás la misma firma (usando
el mismo k).
Esto podría convertirse en el comportamiento predeterminado en una versión futura, ya que no es vulnerable a fallos de la fuente de entropía.
Crea un par de claves NIST192p y guarda ambas inmediatamente en disco:```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())
Carga una clave de firma desde el disco, úsala para firmar un mensaje (usando SHA-1) y escribe
la firma en el disco:```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)
Cargue la clave de verificación, el mensaje y la firma desde el disco, y verifique la firma (suponga hash 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"
Crea un par de claves NIST521p:```python
from ecdsa import SigningKey, NIST521p
sk = SigningKey.generate(curve=NIST521p)
vk = sk.verifying_key
Crear tres claves de firma independientes a partir de una semilla maestra:```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)
Cargue una clave de verificación desde el disco e imprímala usando codificación hexadecimal en
formato sin comprimir y comprimido (definido en los estándares X9.62 y 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()))
Cargar una clave de verificación desde una cadena hexadecimal en formato comprimido, salida sin comprimir:```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())
Intercambio de claves ECDH con la parte remota:```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()
brainpoolP512r1secp112r1secp112r2secp128r1secp160r1