| =============== |
| Getting started |
| =============== |
| |
| The library has just one mandatory dependency: ``six``. |
| If you install ``python-ecdsa`` through pip, it should automatically |
| install ``six`` too. |
| |
| To install it you can run the following command: |
| |
| .. code:: bash |
| |
| pip install ecdsa |
| |
| The high level API provided by the library is primarily in the |
| :py:class:`~ecdsa.keys` module. |
| There you will find the :py:class:`~ecdsa.keys.SigningKey` (the class |
| that enables handling of the private keys) and the |
| :py:class:`~ecdsa.keys.VerifyingKey` (the class that enables handling of |
| the public keys). |
| |
| To handle shared key derivation, the :py:class:`~ecdsa.ecdh.ECDH` class |
| is used. |
| |
| Finally, in case use of custom elliptic curves is necessary, the |
| :py:class:`~ecdsa.curves.Curve` class may be needed. |
| |
| Key generation |
| ============== |
| |
| To generate a key, import the :py:class:`~ecdsa.keys.SigningKey` and |
| call the :py:func:`~ecdsa.keys.SigningKey.generate` function in it: |
| |
| .. code:: python |
| |
| from ecdsa.keys import SigningKey |
| |
| key = SigningKey.generate() |
| |
| By default, that will create a key that uses the NIST P-192 curve. To |
| select a more secure curve, like NIST P-256, import it from the |
| :py:mod:`ecdsa.curves` or from the :py:mod:`ecdsa` module: |
| |
| .. code:: python |
| |
| from ecdsa import SigningKey, NIST256p |
| |
| key = SigningKey.generate(curve=NIST256p) |
| |
| Private key storage and retrieval |
| ================================= |
| |
| To store a key as string or file, you can serialise it using many formats, |
| in general we recommend the PKCS#8 PEM encoding. |
| |
| If you have a :py:class:`~ecdsa.keys.SigningKey` object in ``key`` and |
| want to save it to a file like ``priv_key.pem`` you can run the following |
| code: |
| |
| .. code:: python |
| |
| with open("priv_key.pem", "wb") as f: |
| f.write(key.to_pem(format="pkcs8")) |
| |
| .. warning:: |
| |
| Not specifying the ``format=pkcs8`` will create a file that uses the legacy |
| ``ssleay`` file format which is most commonly used by applications |
| that use OpenSSL, as that was originally the only format supported by it. |
| For a long time though OpenSSL supports the PKCS# 8 format too. |
| |
| To read that file back, you can run code like this: |
| |
| .. code:: python |
| |
| from ecdsa import SigningKey |
| |
| with open("priv_key.pem") as f: |
| key = SigningKey.from_pem(f.read()) |
| |
| .. tip:: |
| |
| As the format is self-describing, the parser will automatically detect |
| if the provided file is in the ``ssleay`` or the ``pkcs8`` format |
| and process it accordingly. |
| |
| Public key derivation |
| ===================== |
| |
| To get the public key associated with the given private key, either |
| call the :py:func:`~ecdsa.keys.SigningKey.get_verifying_key` method or |
| access the ``verifying_key`` attribute in |
| :py:class:`~ecdsa.keys.SigningKey` directly: |
| |
| .. code:: python |
| |
| from ecdsa import SigningKey, NIST256p |
| |
| private_key = SigningKey.generate(curve=NIST256p) |
| |
| public_key = private_key.verifying_key |
| |
| Public key storage and retrieval |
| ================================ |
| |
| Similarly to private keys, public keys can be stored in files: |
| |
| .. code:: python |
| |
| from ecdsa import SigningKey |
| |
| private_key = SigningKey.generate() |
| |
| public_key = private_key.verifying_key |
| |
| with open("pub_key.pem", "wb") as f: |
| f.write(public_key.to_pem()) |
| |
| And read from files: |
| |
| .. code:: python |
| |
| from ecdsa import VerifyingKey |
| |
| with open("pub_key.pem") as f: |
| public_key = VerifyingKey.from_pem(f.read()) |
| |
| Signing |
| ======= |
| |
| To sign a byte string stored in variable ``message`` using SigningKey in |
| ``private_key``, SHA-256, get a signature in the DER format and save it to a |
| file, you can use the following code: |
| |
| .. code:: python |
| |
| from hashlib import sha256 |
| from ecdsa.util import sigencode_der |
| |
| sig = private_key.sign_deterministic( |
| message, |
| hashfunc=sha256, |
| sigencode=sigencode_der |
| ) |
| |
| with open("message.sig", "wb") as f: |
| f.write(sig) |
| |
| .. note:: |
| |
| As cryptographic hashes (SHA-256, SHA3-256, etc.) operate on *bytes* not |
| text strings, any text needs to be serialised into *bytes* before it can |
| be signed. This is because encoding of string "text" results in very |
| different bytes when it's encoded using UTF-8 and when it's encoded using |
| UCS-2. |
| |
| Verifying |
| ========= |
| |
| To verify a signature of a byte string in ``message`` using a VerifyingKey |
| in ``public_key``, SHA-256 and a DER signature in a ``message.sig`` file, |
| you can use the following code: |
| |
| .. code:: python |
| |
| from hashlib import sha256 |
| from ecdsa import BadSignatureError |
| from ecdsa.util import sigdecode_der |
| |
| with open("message.sig", "rb") as f: |
| sig = f.read() |
| |
| try: |
| ret = public_key.verify(sig, message, sha256, sigdecode=sigdecode_der) |
| assert ret |
| print("Valid signature") |
| except BadSignatureError: |
| print("Incorrect signature") |