- ecdsa · PyPI
- GitHub – tlsfuzzer/python-ecdsa: pure-python ECDSA signature/verification and ECDH key agreement
- Command Line Elliptic Curve Operations – OpenSSLWiki
- openssl command
The Elliptic Curve Diffie Hellman (ECDH) for key agreement and Elliptic Curve Digital Signature Algorithm (ECDSA) for signing/verifying.
This is an easy-to-use implementation of ECC (Elliptic Curve Cryptography) with support for ECDSA (Elliptic Curve Digital Signature Algorithm), EdDSA (Edwards-curve Digital Signature Algorithm) and ECDH (Elliptic Curve Diffie-Hellman), implemented purely in Python, released under the MIT license. With this library, you can quickly create key pairs (signing key and verifying key), sign messages, and verify the signatures. You can also agree on a shared secret key based on exchanged public keys. The keys and signatures are very short, making them easy to handle and incorporate into other protocols.
NOTE: This library should not be used in production settings, see Security for more details.
pip install ecdsa
You start by creating a
SigningKey. You can use this to sign data, by passing in data as a byte string and getting back the signature (also a byte string). You can also ask a
SigningKey to give you the corresponding
VerifyingKey can be used to verify a signature, by passing it both the data string and the signature byte string: it either returns True or raises
from ecdsa import SigningKey sk = SigningKey.generate() # uses NIST192p vk = sk.verifying_key signature = sk.sign(b"message") assert vk.verify(signature, b"message")
from ecdsa import SigningKey sk = SigningKey.generate() # uses NIST192p vk = sk.verifying_key bytes_text = bytes("The first sample string|The second sample string", 'utf-8') signature = sk.sign(bytes_text) assert vk.verify(signature, bytes_text)
VerifyingKey is associated with a specific curve, like NIST192p (the default one). Longer curves are more secure, but take longer to use, and result in longer keys and signatures.
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 can be serialized into several different formats: the shortest is to call
s=sk.to_string(), and then re-create it with
SigningKey.from_string(s, curve) . This short form does not record the curve, so you must be sure to pass to
from_string() the same curve you used for the original key. The short form of a NIST192p-based signing key is just 24 bytes long. If a point encoding is invalid or it does not lie on the specified curve,
from_string() will raise
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())
from ecdsa import SigningKey, NIST256p sk = SigningKey.generate(curve=NIST256p) vk = sk.verifying_key signature = sk.sign(b"message") assert vk.verify(signature, b"message") print("OK") sk_string = sk.to_string() sk_hex = sk_string.hex() print(sk_hex) sig_hex = signature.hex() print(sig_hex)
Note: while the methods are called
to_string() the type they return is actually
bytes, the “string” part is leftover from Python 2.
sk.to_der() will serialize the signing key into the same formats that OpenSSL uses. The PEM file looks like the familiar ASCII-armored
"-----BEGIN EC PRIVATE KEY-----" base64-encoded format, and the DER format is a shorter binary form of the same data.
SigningKey.from_pem()/.from_der() will undo this serialization. These formats include the curve name, so you do not need to pass in a curve identifier to the deserializer. In case the file is malformed
from_pem() will raise
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 can be serialized in the same way:
to_der()/from_der(). The same
curve= argument is needed for
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
There are a couple of different ways to compute a signature. Fundamentally, ECDSA takes a number that represents the data being signed, and returns a pair of numbers that represent the signature. The
hashfunc= argument to
vk.verify() is used to turn an arbitrary string into a fixed-length digest, which is then turned into a number that ECDSA can sign, and both sign and verify must use the same approach. The default value is
hashlib.sha1, but if you use NIST256p or a longer curve, you can use