Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3a8bc4e

Browse files
authoredJul 9, 2022
Merge pull request #290 from tomato42/docs-updates
Docs updates
2 parents 29a3cd0 + 1943ef3 commit 3a8bc4e

File tree

11 files changed

+662
-97
lines changed

11 files changed

+662
-97
lines changed
 

‎docs/source/basics.rst

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
======================
2+
Basics of ECC handling
3+
======================
4+
5+
The :term:`ECC`, as any asymmetric cryptography system, deals with private
6+
keys and public keys. Private keys are generally used to create signatures,
7+
and are kept, as the name suggest, private. That's because possession of a
8+
private key allows creating a signature that can be verified with a public key.
9+
If the public key is associated with an identity (like a person or an
10+
institution), possession of the private key will allow to impersonate
11+
that identity.
12+
13+
The public keys on the other hand are widely distributed, and they don't
14+
have to be kept private. The primary purpose of them, is to allow
15+
checking if a given signature was made with the associated private key.
16+
17+
Number representations
18+
======================
19+
20+
On a more low level, the private key is a single number, usually the
21+
size of the curve size: a NIST P-256 private key will have a size of 256 bits,
22+
though as it needs to be selected randomly, it may be a slightly smaller
23+
number (255-bit, 248-bit, etc.).
24+
Public points are a pair of numbers. That pair specifies a point on an
25+
elliptic curve (a pair of integers that satisfy the curve equation).
26+
Those two numbers are similarly close in size to the curve size, so both the
27+
``x`` and ``y`` coordinate of a NIST P-256 curve will also be around 256 bit in
28+
size.
29+
30+
.. note::
31+
To be more precise, the size of the private key is related to the
32+
curve *order*, i.e. the number of points on a curve. The coordinates
33+
of the curve depend on the *field* of the curve, which usually means the
34+
size of the *prime* used for operations on points. While the *order* and
35+
the *prime* size are related and fairly close in size, it's possible
36+
to have a curve where either of them is larger by a bit (i.e.
37+
it's possible to have a curve that uses a 256 bit *prime* that has a 257 bit
38+
*order*).
39+
40+
Since normally computers work with much smaller numbers, like 32 bit or 64 bit,
41+
we need to use special approaches to represent numbers that are hundreds of
42+
bits large.
43+
44+
First is to decide if the numbers should be stored in a big
45+
endian format, or in little endian format. In big endian, the most
46+
significant bits are stored first, so a number like :math:`2^{16}` is saved
47+
as a three bytes: byte with value 1 and two bytes with value 0.
48+
In little endian format the least significant bits are stored first, so
49+
the number like :math:`2^{16}` would be stored as three bytes:
50+
first two bytes with value 0, than a byte with value 1.
51+
52+
For :term:`ECDSA` big endian encoding is usually used, for :term:`EdDSA`
53+
little endian encoding is usually used.
54+
55+
Secondly, we need to decide if the numbers need to be stored as fixed length
56+
strings (zero padded if necessary), or if they should be stored with
57+
minimal number of bytes necessary.
58+
That depends on the format and place it's used, some require strict
59+
sizes (so even if the number encoded is 1, but the curve used is 128 bit large,
60+
that number 1 still needs to be encoded with 16 bytes, with fifteen most
61+
significant bytes equal zero).
62+
63+
Public key encoding
64+
===================
65+
66+
Generally, public keys (i.e. points) are expressed as fixed size byte strings.
67+
68+
While public keys can be saved as two integers, one to represent the
69+
``x`` coordinate and one to represent ``y`` coordinate, that actually
70+
provides a lot of redundancy. Because of the specifics of elliptic curves,
71+
for every valid ``x`` value there are only two valid ``y`` values.
72+
Moreover, if you have an ``x`` value, you can compute those two possible
73+
``y`` values (if they exist).
74+
As such, it's possible to save just the ``x`` coordinate and the sign
75+
of the ``y`` coordinate (as the two possible values are negatives of
76+
each-other: :math:`y_1 == -y_2`).
77+
78+
That gives us few options to represent the public point, the most common are:
79+
80+
1. As a concatenation of two fixed-length big-endian integers, so called
81+
:term:`raw encoding`.
82+
2. As a concatenation of two fixed-length big-endian integers prefixed with
83+
the type of the encoding, so called :term:`uncompressed` point
84+
representation (the type is represented by a 0x04 byte).
85+
3. As a fixed-length big-endian integer representing the ``x`` coordinate
86+
prefixed with the byte representing the combined type of the encoding
87+
and the sign of the ``y`` coordinate, so called :term:`compressed`
88+
point representation (the type is then represented by a 0x02 or a 0x03
89+
byte).
90+
91+
Interoperable file formats
92+
==========================
93+
94+
Now, while we can save the byte strings as-is and "remember" which curve
95+
was used to generate those private and public keys, interoperability usually
96+
requires to also save information about the curve together with the
97+
corresponding key. Here too there are many ways to do it:
98+
save the parameters of the used curve explicitly, use the name of the
99+
well-known curve as a string, use a numerical identifier of the well-known
100+
curve, etc.
101+
102+
For public keys the most interoperable format is the one described
103+
in RFC5912 (look for SubjectPublicKeyInfo structure).
104+
For private keys, the RFC5915 format (also known as the ssleay format)
105+
and the PKCS#8 format (described in RFC5958) are the most popular.
106+
107+
All three formats effectively support two ways of providing the information
108+
about the curve used: by specifying the curve parameters explicitly or
109+
by specifying the curve using ASN.1 OBJECT IDENTIFIER (OID), which is
110+
called ``named_curve``. ASN.1 OIDs are a hierarchical system of representing
111+
types of objects, for example, NIST P-256 curve is identified by the
112+
1.2.840.10045.3.1.7 OID (in dotted-decimal formatting of the OID, also
113+
known by the ``prime256v1`` OID node name or short name). Those OIDs
114+
uniquely, identify a particular curve, but the receiver needs to know
115+
which numerical OID maps to which curve parameters. Thus the prospect of
116+
using the explicit encoding, where all the needed parameters are provided
117+
is tempting, the downside is that curve parameters may specify a *weak*
118+
curve, which is easy to attack and break (that is to deduce the private key
119+
from the public key). To verify curve parameters is complex and computationally
120+
expensive, thus generally protocols use few specific curves and require
121+
all implementations to carry the parameters of them. As such, use of
122+
``named_curve`` parameters is generally recommended.
123+
124+
All of the mentioned formats specify a binary encoding, called DER. That
125+
encoding uses bytes with all possible numerical values, which means it's not
126+
possible to embed it directly in text files. For uses where it's useful to
127+
limit bytes to printable characters, so that the keys can be embedded in text
128+
files or text-only protocols (like email), the PEM formatting of the
129+
DER-encoded data can be used. The PEM formatting is just a base64 encoding
130+
with appropriate header and footer.
131+
132+
Signature formats
133+
=================
134+
135+
Finally, ECDSA signatures at the lowest level are a pair of numbers, usually
136+
called ``r`` and ``s``. While they are the ``x`` coordinates of special
137+
points on the curve, they are saved modulo *order* of the curve, not
138+
modulo *prime* of the curve (as a coordinate needs to be).
139+
140+
That again means we have multiple ways of encoding those two numbers.
141+
The two most popular formats are to save them as a concatenation of big-endian
142+
integers of fixed size (determined by the curve *order*) or as a DER
143+
structure with two INTEGERS.
144+
The first of those is called the :term:``raw encoding`` inside the Python
145+
ecdsa library.
146+
147+
As ASN.1 signature format requires the encoding of INTEGERS, and DER INTEGERs
148+
must use the fewest possible number of bytes, a numerically small value of
149+
``r`` or ``s`` will require fewer
150+
bytes to represent in the DER structure. Thus, DER encoding isn't fixed
151+
size for a given curve, but has a maximum possible size.
152+
153+
.. note::
154+
155+
As DER INTEGER uses so-called two's complement representation of
156+
numbers, the most significant bit of the most significant byte
157+
represents the *sign* of the number. If that bit is set, then the
158+
number is considered to be negative. Thus, to represent a number like
159+
255, which in binary representation is 0b11111111 (i.e. a byte with all
160+
bits set high), the DER encoding of it will require two bytes, one
161+
zero byte to make sure the sign bit is 0, and a byte with value 255 to
162+
encode the numerical value of the integer.

‎docs/source/conf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@
6161
# so a file named "default.css" will overwrite the builtin "default.css".
6262
html_static_path = ["_static"]
6363

64+
# Example configuration for intersphinx: refer to the Python standard library.
65+
intersphinx_mapping = {"https://docs.python.org/": None}
66+
6467
autodoc_default_options = {
6568
"undoc-members": True,
6669
"inherited-members": True,

‎docs/source/ec_arithmetic.rst

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
=========================
2+
Elliptic Curve arithmetic
3+
=========================
4+
5+
The python-ecdsa also provides generic API for performing operations on
6+
elliptic curve points.
7+
8+
.. warning::
9+
10+
This is documentation of a very low-level API, if you want to
11+
handle keys or signatures you should look at documentation of
12+
the :py:mod:`~ecdsa.keys` module.
13+
14+
Short Weierstrass curves
15+
========================
16+
17+
There are two low-level implementations for
18+
:term:`short Weierstrass curves <short Weierstrass curve>`:
19+
:py:class:`~ecdsa.ellipticcurve.Point` and
20+
:py:class:`~ecdsa.ellipticcurve.PointJacobi`.
21+
22+
Both of them use the curves specified using the
23+
:py:class:`~ecdsa.ellipticcurve.CurveFp` object.
24+
25+
You can either provide your own curve parameters or use one of the predefined
26+
curves.
27+
For example, to define a curve :math:`x^2 = x^3 + x + 4 \text{ mod } 5` use
28+
code like this:
29+
30+
.. code:: python
31+
32+
from ecdsa.ellipticcurve import CurveFp
33+
custom_curve = CurveFp(5, 1, 4)
34+
35+
The predefined curves are specified in the :py:mod:`~ecdsa.ecdsa` module,
36+
but it's much easier to use the helper functions (and proper names)
37+
from the :py:mod:`~ecdsa.curves` module.
38+
39+
For example, to get the curve parameters for the NIST P-256 curve use this
40+
code:
41+
42+
.. code:: python
43+
44+
from ecdsa.curves import NIST256p
45+
curve = NIST256p.curve
46+
47+
.. tip::
48+
49+
You can also use :py:class:`~ecdsa.curves.Curve` to get the curve
50+
parameters from a PEM or DER file. You can also use
51+
:py:func:`~ecdsa.curves.curve_by_name` to get a curve by specifying its
52+
name.
53+
Or use the
54+
:py:func:`~ecdsa.curves.find_curve` to get a curve by specifying its
55+
ASN.1 object identifier (OID).
56+
57+
Affine coordinates
58+
------------------
59+
60+
After taking hold of curve parameters you can create a point on the
61+
curve. The :py:class:`~ecdsa.ellipticcurve.Point` uses affine coordinates,
62+
i.e. the :math:`x` and :math:`y` from the curve equation directly.
63+
64+
To specify a point (1, 1) on the ``custom_curve`` you can use this code:
65+
66+
.. code:: python
67+
68+
from ecdsa.ellipticcurve import Point
69+
point_a = Point(custom_curve, 1, 1)
70+
71+
Then it's possible to either perform scalar multiplication:
72+
73+
.. code:: python
74+
75+
point_b = point_a * 3
76+
77+
Or specify other points and perform addition:
78+
79+
.. code:: python
80+
81+
point_b = Point(custom_curve, 3, 2)
82+
point_c = point_a + point_b
83+
84+
To get the affine coordinates of the point, call the ``x()`` and ``y()``
85+
methods of the object:
86+
87+
.. code:: python
88+
89+
print("x: {0}, y: {1}".format(point_c.x(), point_c.y()))
90+
91+
Projective coordinates
92+
----------------------
93+
94+
When using the Jacobi coordinates, the point is defined by 3 integers,
95+
which are related to the :math:`x` and :math:`y` in the following way:
96+
97+
.. math::
98+
99+
x = X/Z^2 \\
100+
y = Y/Z^3
101+
102+
That means that if you have point in affine coordinates, it's possible
103+
to convert them to Jacobi by simply assuming :math:`Z = 1`.
104+
105+
So the same points can be specified as so:
106+
107+
.. code:: python
108+
109+
from ecdsa.ellipticcurve import PointJacobi
110+
point_a = PointJacobi(custom_curve, 1, 1, 1)
111+
point_b = PointJacobi(custom_curve, 3, 2, 1)
112+
113+
114+
.. note::
115+
116+
Unlike the :py:class:`~ecdsa.ellipticcurve.Point`, the
117+
:py:class:`~ecdsa.ellipticcurve.PointJacobi` does **not** check if the
118+
coordinates specify a valid point on the curve as that operation is
119+
computationally expensive for Jacobi coordinates.
120+
If you want to verify if they specify a valid
121+
point, you need to convert the point to affine coordinates and use the
122+
:py:meth:`~ecdsa.ellipticcurve.CurveFp.contains_point` method.
123+
124+
Then all the operations work exactly the same as with regular
125+
:py:class:`~ecdsa.ellipticcurve.Point` implementation.
126+
While it's not possible to get the internal :math:`X`, :math:`Y`, and :math:`Z`
127+
coordinates, it's possible to get the affine projection just like with
128+
the regular implementation:
129+
130+
.. code:: python
131+
132+
point_c = point_a + point_b
133+
print("x: {0}, y: {1}".format(point_c.x(), point_c.y()))
134+
135+
All the other operations, like scalar multiplication or point addition work
136+
on projective points the same as with affine representation, but they
137+
are much more effective computationally.

‎docs/source/ecdsa.eddsa.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ecdsa.eddsa module
2+
==================
3+
4+
.. automodule:: ecdsa.eddsa
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

‎docs/source/ecdsa.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Submodules
1616
ecdsa.der
1717
ecdsa.ecdh
1818
ecdsa.ecdsa
19+
ecdsa.eddsa
1920
ecdsa.ellipticcurve
2021
ecdsa.errors
2122
ecdsa.keys

‎docs/source/glossary.rst

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
.. _glossary:
2+
3+
Glossary
4+
========
5+
6+
.. glossary::
7+
:sorted:
8+
9+
ECC
10+
Elliptic Curve Cryptography, a term for all the different ways of using
11+
elliptic curves in cryptography. Also combined term for :term:`ECDSA`,
12+
:term:`EdDSA`, :term:`ECDH`.
13+
14+
ECDSA
15+
Elliptic Curve Digital Signature Algorithm
16+
17+
EdDSA
18+
Edwards curve based Digital Signature Algorithm, the alternative
19+
digital signature algorithm that's used for Curve25519 or Curve448
20+
21+
ECDH
22+
Elliptic Curve Diffie-Hellman
23+
24+
raw encoding
25+
Conversion of public, private keys and signatures (which in
26+
mathematical sense are integers or pairs of integers) to strings of
27+
bytes that does not use any special tags or encoding rules.
28+
For any given curve, all keys of the same type or signatures will be
29+
encoded to byte strings of the same length. In more formal sense,
30+
the integers are encoded as big-endian, constant length byte strings,
31+
where the string length is determined by the curve order (e.g.
32+
for NIST256p the order is 256 bits long, so the private key will be 32
33+
bytes long while public key will be 64 bytes long). The encoding of a
34+
single integer is zero-padded on the left if the numerical value is
35+
low. In case of public keys and signatures, which are comprised of two
36+
integers, the integers are simply concatenated.
37+
38+
uncompressed
39+
The most common formatting specified in PKIX standards. Specified in
40+
X9.62 and SEC1 standards. The only difference between it and
41+
:term:`raw encoding` is the prepending of a 0x04 byte. Thus an
42+
uncompressed NIST256p public key encoding will be 65 bytes long.
43+
44+
compressed
45+
The public point representation that uses half of bytes of the
46+
:term:`uncompressed` encoding (rounded up). It uses the first byte of
47+
the encoding to specify the sign of the y coordinate and encodes the
48+
x coordinate as-is. The first byte of the encoding is equal to
49+
0x02 or 0x03. Compressed encoding of NIST256p public key will be 33
50+
bytes long.
51+
52+
hybrid
53+
A combination of :term:`uncompressed` and :term:`compressed` encodings.
54+
Both x and y coordinates are stored just as in :term:`compressed`
55+
encoding, but the first byte reflects the sign of the y coordinate. The
56+
first byte of the encoding will be equal to 0x06 or 0x7. Hybrid
57+
encoding of NIST256p public key will be 65 bytes long.
58+
59+
PEM
60+
The acronym stands for Privacy Enhanced Mail, but currently it is used
61+
primarily as the way to encode :term:`DER` objects into text that can
62+
be either easily copy-pasted or transferred over email.
63+
It uses headers like ``-----BEGIN <type of contents>-----`` and footers
64+
like ``-----END <type of contents>-----`` to separate multiple
65+
types of objects in the same file or the object from the surrounding
66+
comments. The actual object stored is base64 encoded.
67+
68+
DER
69+
Distinguished Encoding Rules, the way to encode :term:`ASN.1` objects
70+
deterministically and uniquely into byte strings.
71+
72+
ASN.1
73+
Abstract Syntax Notation 1 is a standard description language for
74+
specifying serialisation and deserialisation of data structures in a
75+
portable and cross-platform way.
76+
77+
bytes-like object
78+
All the types that implement the buffer protocol. That includes
79+
``str`` (only on python2), ``bytes``, ``bytearray``, ``array.array``
80+
and ``memoryview`` of those objects.
81+
Please note that ``array.array`` serialisation (converting it to byte
82+
string) is endianess dependant! Signature computed over ``array.array``
83+
of integers on a big-endian system will not be verified on a
84+
little-endian system and vice-versa.
85+
86+
set-like object
87+
All the types that support the ``in`` operator, like ``list``,
88+
``tuple``, ``set``, ``frozenset``, etc.
89+
90+
short Weierstrass curve
91+
A curve with the curve equation: :math:`x^2=y^3+ax+b`. Most popular
92+
curves use equation of this format (e.g. NIST256p).

‎docs/source/index.rst

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,56 @@
66
Welcome to python-ecdsa's documentation!
77
========================================
88

9+
``ecdsa`` implements
10+
`elliptic-curve cryptography (ECC) <https://en.wikipedia.org/wiki/Elliptic-curve_cryptography>`_,
11+
more specifically the
12+
`Elliptic Curve Digital Signature Algorithm (ECDSA) <https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm>`_,
13+
`Edwards-curve Digital Signature Algorithm (EdDSA) <https://en.wikipedia.org/wiki/EdDSA>`_
14+
and the
15+
`Elliptic Curve Diffie-Hellman (ECDH) <https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman>`_
16+
algorithms.
17+
All of those algorithms are used in many protocols in practice, like
18+
in
19+
`TLS <https://en.wikipedia.org/wiki/Transport_Layer_Security>`_
20+
or
21+
`SSH <https://en.wikipedia.org/wiki/Secure_Shell_Protocol>`_.
22+
23+
This library provides key generation, signing, verifying, and shared secret
24+
derivation for five
25+
popular NIST "Suite B" GF(p) (*prime field*) curves, with key lengths of 192,
26+
224, 256, 384, and 521 bits. The "short names" for these curves, as known by
27+
the OpenSSL tool (``openssl ecparam -list_curves``), are: ``prime192v1``,
28+
``secp224r1``, ``prime256v1``, ``secp384r1``, and ``secp521r1``. It includes
29+
the
30+
256-bit curve ``secp256k1`` used by Bitcoin. There is also support for the
31+
regular (non-twisted) variants of Brainpool curves from 160 to 512 bits. The
32+
"short names" of those curves are: ``brainpoolP160r1``, ``brainpoolP192r1``,
33+
``brainpoolP224r1``, ``brainpoolP256r1``, ``brainpoolP320r1``,
34+
``brainpoolP384r1``,
35+
``brainpoolP512r1``. Few of the small curves from SEC standard are also
36+
included (mainly to speed-up testing of the library), those are:
37+
``secp112r1``, ``secp112r2``, ``secp128r1``, and ``secp160r1``.
38+
Key generation, siging and verifying is also supported for Ed25519 and Ed448
39+
curves.
40+
No other curves are included, but it is not too hard to add support for more
41+
curves over prime fields.
42+
943
.. toctree::
1044
:maxdepth: 2
1145
:caption: Contents:
46+
:hidden:
1247

48+
quickstart
49+
basics
50+
ec_arithmetic
51+
glossary
52+
modules
1353

1454

1555
Indices and tables
1656
==================
1757

1858
* :ref:`genindex`
1959
* :ref:`modindex`
60+
* :ref:`glossary`
2061
* :ref:`search`

‎docs/source/modules.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
src
2-
===
1+
python-ecdsa API
2+
================
33

44
.. toctree::
55
:maxdepth: 4

‎docs/source/quickstart.rst

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
===============
2+
Getting started
3+
===============
4+
5+
The library has just one mandatory dependency: ``six``.
6+
If you install ``python-ecdsa`` through pip, it should automatically
7+
install ``six`` too.
8+
9+
To install it you can run the following command:
10+
11+
.. code:: bash
12+
13+
pip install ecdsa
14+
15+
The high level API provided by the library is primarily in the
16+
:py:class:`~ecdsa.keys` module.
17+
There you will find the :py:class:`~ecdsa.keys.SigningKey` (the class
18+
that enables handling of the private keys) and the
19+
:py:class:`~ecdsa.keys.VerifyingKey` (the class that enables handling of
20+
the public keys).
21+
22+
To handle shared key derivation, the :py:class:`~ecdsa.ecdh.ECDH` class
23+
is used.
24+
25+
Finally, in case use of custom elliptic curves is necessary, the
26+
:py:class:`~ecdsa.curves.Curve` class may be needed.
27+
28+
Key generation
29+
==============
30+
31+
To generate a key, import the :py:class:`~ecdsa.keys.SigningKey` and
32+
call the :py:func:`~ecdsa.keys.SigningKey.generate` function in it:
33+
34+
.. code:: python
35+
36+
from ecdsa.keys import SigningKey
37+
38+
key = SigningKey.generate()
39+
40+
By default, that will create a key that uses the NIST P-192 curve. To
41+
select a more secure curve, like NIST P-256, import it from the
42+
:py:mod:`ecdsa.curves` or from the :py:mod:`ecdsa` module:
43+
44+
.. code:: python
45+
46+
from ecdsa import SigningKey, NIST256p
47+
48+
key = SigningKey.generate(curve=NIST256p)
49+
50+
Private key storage and retrieval
51+
=================================
52+
53+
To store a key as string or file, you can serialise it using many formats,
54+
in general we recommend the PKCS#8 PEM encoding.
55+
56+
If you have a :py:class:`~ecdsa.keys.SigningKey` object in ``key`` and
57+
want to save it to a file like ``priv_key.pem`` you can run the following
58+
code:
59+
60+
.. code:: python
61+
62+
with open("priv_key.pem", "wb") as f:
63+
f.write(key.to_pem(format="pkcs8"))
64+
65+
.. warning::
66+
67+
Not specifying the ``format=pkcs8`` will create a file that uses the legacy
68+
``ssleay`` file format which is most commonly used by applications
69+
that use OpenSSL, as that was originally the only format supported by it.
70+
For a long time though OpenSSL supports the PKCS# 8 format too.
71+
72+
To read that file back, you can run code like this:
73+
74+
.. code:: python
75+
76+
from ecdsa import SigningKey
77+
78+
with open("priv_key.pem") as f:
79+
key = SigningKey.from_pem(f.read())
80+
81+
.. tip::
82+
83+
As the format is self-describing, the parser will automatically detect
84+
if the provided file is in the ``ssleay`` or the ``pkcs8`` format
85+
and process it accordingly.
86+
87+
Public key derivation
88+
=====================
89+
90+
To get the public key associated with the given private key, either
91+
call the :py:func:`~ecdsa.keys.SigningKey.get_verifying_key` method or
92+
access the ``verifying_key`` attribute in
93+
:py:class:`~ecdsa.keys.SigningKey` directly:
94+
95+
.. code:: python
96+
97+
from ecdsa import SigningKey, NIST256p
98+
99+
private_key = SigningKey.generate(curve=NIST256p)
100+
101+
public_key = private_key.verifying_key
102+
103+
Public key storage and retrieval
104+
================================
105+
106+
Similarly to private keys, public keys can be stored in files:
107+
108+
.. code:: python
109+
110+
from ecdsa import SigningKey
111+
112+
private_key = SigningKey.generate()
113+
114+
public_key = private_key.verifying_key
115+
116+
with open("pub_key.pem", "wb") as f:
117+
f.write(public_key.to_pem())
118+
119+
And read from files:
120+
121+
.. code:: python
122+
123+
from ecdsa import VerifyingKey
124+
125+
with open("pub_key.pem") as f:
126+
public_key = VerifyingKey.from_pem(f.read())
127+
128+
Signing
129+
=======
130+
131+
To sign a byte string stored in variable ``message`` using SigningKey in
132+
``private_key``, SHA-256, get a signature in the DER format and save it to a
133+
file, you can use the following code:
134+
135+
.. code:: python
136+
137+
from hashlib import sha256
138+
from ecdsa.util import sigencode_der
139+
140+
sig = private_key.sign_deterministic(
141+
message,
142+
hashfunc=sha256,
143+
sigencode=sigencode_der
144+
)
145+
146+
with open("message.sig", "wb") as f:
147+
f.write(sig)
148+
149+
.. note::
150+
151+
As cryptographic hashes (SHA-256, SHA3-256, etc.) operate on *bytes* not
152+
text strings, any text needs to be serialised into *bytes* before it can
153+
be signed. This is because encoding of string "text" results in very
154+
different bytes when it's encoded using UTF-8 and when it's encoded using
155+
UCS-2.
156+
157+
Verifying
158+
=========
159+
160+
To verify a signature of a byte string in ``message`` using a VerifyingKey
161+
in ``public_key``, SHA-256 and a DER signature in a ``message.sig`` file,
162+
you can use the following code:
163+
164+
.. code:: python
165+
166+
from hashlib import sha256
167+
from ecdsa import BadSignatureError
168+
from ecdsa.util import sigdecode_der
169+
170+
with open("message.sig", "rb") as f:
171+
sig = f.read()
172+
173+
try:
174+
ret = public_key.verify(sig, message, sha256, sigdecode=sigdecode_der)
175+
assert ret
176+
print("Valid signature")
177+
except BadSignatureError:
178+
print("Incorrect signature")

‎src/ecdsa/ellipticcurve.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@
5656

5757
@python_2_unicode_compatible
5858
class CurveFp(object):
59-
"""Short Weierstrass Elliptic Curve over a prime field."""
59+
"""
60+
:term:`Short Weierstrass Elliptic Curve <short Weierstrass curve>` over a
61+
prime field.
62+
"""
6063

6164
if GMPY: # pragma: no branch
6265

‎src/ecdsa/keys.py

Lines changed: 35 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,5 @@
11
"""
22
Primary classes for performing signing and verification operations.
3-
4-
.. glossary::
5-
6-
raw encoding
7-
Conversion of public, private keys and signatures (which in
8-
mathematical sense are integers or pairs of integers) to strings of
9-
bytes that does not use any special tags or encoding rules.
10-
For any given curve, all keys of the same type or signatures will be
11-
encoded to byte strings of the same length. In more formal sense,
12-
the integers are encoded as big-endian, constant length byte strings,
13-
where the string length is determined by the curve order (e.g.
14-
for NIST256p the order is 256 bits long, so the private key will be 32
15-
bytes long while public key will be 64 bytes long). The encoding of a
16-
single integer is zero-padded on the left if the numerical value is
17-
low. In case of public keys and signatures, which are comprised of two
18-
integers, the integers are simply concatenated.
19-
20-
uncompressed
21-
The most common formatting specified in PKIX standards. Specified in
22-
X9.62 and SEC1 standards. The only difference between it and
23-
:term:`raw encoding` is the prepending of a 0x04 byte. Thus an
24-
uncompressed NIST256p public key encoding will be 65 bytes long.
25-
26-
compressed
27-
The public point representation that uses half of bytes of the
28-
:term:`uncompressed` encoding (rounded up). It uses the first byte of
29-
the encoding to specify the sign of the y coordinate and encodes the
30-
x coordinate as-is. The first byte of the encoding is equal to
31-
0x02 or 0x03. Compressed encoding of NIST256p public key will be 33
32-
bytes long.
33-
34-
hybrid
35-
A combination of :term:`uncompressed` and :term:`compressed` encodings.
36-
Both x and y coordinates are stored just as in :term:`compressed`
37-
encoding, but the first byte reflects the sign of the y coordinate. The
38-
first byte of the encoding will be equal to 0x06 or 0x7. Hybrid
39-
encoding of NIST256p public key will be 65 bytes long.
40-
41-
PEM
42-
The acronym stands for Privacy Enhanced Email, but currently it is used
43-
primarily as the way to encode :term:`DER` objects into text that can
44-
be either easily copy-pasted or transferred over email.
45-
It uses headers like ``-----BEGIN <type of contents>-----`` and footers
46-
like ``-----END <type of contents>-----`` to separate multiple
47-
types of objects in the same file or the object from the surrounding
48-
comments. The actual object stored is base64 encoded.
49-
50-
DER
51-
Distinguished Encoding Rules, the way to encode :term:`ASN.1` objects
52-
deterministically and uniquely into byte strings.
53-
54-
ASN.1
55-
Abstract Syntax Notation 1 is a standard description language for
56-
specifying serialisation and deserialisation of data structures in a
57-
portable and cross-platform way.
58-
59-
bytes-like object
60-
All the types that implement the buffer protocol. That includes
61-
``str`` (only on python2), ``bytes``, ``bytesarray``, ``array.array``
62-
and ``memoryview`` of those objects.
63-
Please note that ``array.array`` serialisation (converting it to byte
64-
string) is endianess dependant! Signature computed over ``array.array``
65-
of integers on a big-endian system will not be verified on a
66-
little-endian system and vice-versa.
67-
68-
set-like object
69-
All the types that support the ``in`` operator, like ``list``,
70-
``tuple``, ``set``, ``frozenset``, etc.
713
"""
724

735
import binascii
@@ -704,7 +636,7 @@ def verify(
704636
:type signature: sigdecode method dependent
705637
:param data: data signed by the `signature`, will be hashed using
706638
`hashfunc`, if specified, or default hash function
707-
:type data: bytes like object
639+
:type data: :term:`bytes-like object`
708640
:param hashfunc: The default hash function that will be used for
709641
verification, needs to implement the same interface as hashlib.sha1
710642
:type hashfunc: callable
@@ -758,7 +690,7 @@ def verify_digest(
758690
:param signature: encoding of the signature
759691
:type signature: sigdecode method dependent
760692
:param digest: raw hash value that the signature authenticates.
761-
:type digest: bytes like object
693+
:type digest: :term:`bytes-like object`
762694
:param sigdecode: Callable to define the way the signature needs to
763695
be decoded to an object, needs to handle `signature` as the
764696
first parameter, the curve order (an int) as the second and return
@@ -801,7 +733,7 @@ class SigningKey(object):
801733
"""
802734
Class for handling keys that can create signatures (private keys).
803735
804-
:ivar `~ecdsa.curves.Curve` ~.curve: The Curve over which all the
736+
:ivar `~ecdsa.curves.Curve` curve: The Curve over which all the
805737
cryptographic operations will take place
806738
:ivar default_hashfunc: the function that will be used for hashing the
807739
data. Should implement the same API as :py:class:`hashlib.sha1`
@@ -947,7 +879,7 @@ def from_string(cls, string, curve=NIST192p, hashfunc=sha1):
947879
In Python 3, the expected type is `bytes`.
948880
949881
:param string: the raw encoding of the private key
950-
:type string: bytes like object
882+
:type string: :term:`bytes-like object`
951883
:param curve: The curve on which the point needs to reside
952884
:type curve: ~ecdsa.curves.Curve
953885
:param hashfunc: The default hash function that will be used for
@@ -1080,7 +1012,7 @@ def from_der(cls, string, hashfunc=sha1, valid_curve_encodings=None):
10801012
in them will not be detected.
10811013
10821014
:param string: binary string with DER-encoded private ECDSA key
1083-
:type string: bytes like object
1015+
:type string: :term:`bytes-like object`
10841016
:param valid_curve_encodings: list of allowed encoding formats
10851017
for curve parameters. By default (``None``) all are supported:
10861018
``named_curve`` and ``explicit``.
@@ -1383,7 +1315,7 @@ def sign_deterministic(
13831315
of data is necessary.
13841316
13851317
:param data: data to be hashed and computed signature over
1386-
:type data: bytes like object
1318+
:type data: :term:`bytes-like object`
13871319
:param hashfunc: hash function to use for computing the signature,
13881320
if unspecified, the default hash function selected during
13891321
object initialisation will be used (see
@@ -1402,7 +1334,7 @@ def sign_deterministic(
14021334
:param extra_entropy: additional data that will be fed into the random
14031335
number generator used in the RFC6979 process. Entirely optional.
14041336
Ignored with EdDSA.
1405-
:type extra_entropy: bytes like object
1337+
:type extra_entropy: :term:`bytes-like object`
14061338
14071339
:return: encoded signature over `data`
14081340
:rtype: bytes or sigencode function dependent type
@@ -1442,24 +1374,26 @@ def sign_digest_deterministic(
14421374
hashing of data is necessary.
14431375
14441376
:param digest: hash of data that will be signed
1445-
:type digest: bytes like object
1377+
:type digest: :term:`bytes-like object`
14461378
:param hashfunc: hash function to use for computing the random "k"
14471379
value from RFC6979 process,
14481380
if unspecified, the default hash function selected during
14491381
object initialisation will be used (see
1450-
`VerifyingKey.default_hashfunc`). The object needs to implement
1451-
the same interface as hashlib.sha1.
1382+
:attr:`.VerifyingKey.default_hashfunc`). The object needs to
1383+
implement
1384+
the same interface as :func:`~hashlib.sha1` from :py:mod:`hashlib`.
14521385
:type hashfunc: callable
14531386
:param sigencode: function used to encode the signature.
14541387
The function needs to accept three parameters: the two integers
14551388
that are the signature and the order of the curve over which the
14561389
signature was computed. It needs to return an encoded signature.
1457-
See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der`
1390+
See :func:`~ecdsa.util.sigencode_string` and
1391+
:func:`~ecdsa.util.sigencode_der`
14581392
as examples of such functions.
14591393
:type sigencode: callable
14601394
:param extra_entropy: additional data that will be fed into the random
14611395
number generator used in the RFC6979 process. Entirely optional.
1462-
:type extra_entropy: bytes like object
1396+
:type extra_entropy: :term:`bytes-like object`
14631397
:param bool allow_truncate: if True, the provided digest can have
14641398
bigger bit-size than the order of the curve, the extra bits (at
14651399
the end of the digest) will be truncated. Use it when signing
@@ -1524,46 +1458,53 @@ def sign(
15241458
method instead of this one.
15251459
15261460
:param data: data that will be hashed for signing
1527-
:type data: bytes like object
1528-
:param callable entropy: randomness source, os.urandom by default.
1529-
Ignored with EdDSA.
1530-
:param hashfunc: hash function to use for hashing the provided `data`.
1461+
:type data: :term:`bytes-like object`
1462+
:param callable entropy: randomness source, :func:`os.urandom` by
1463+
default. Ignored with EdDSA.
1464+
:param hashfunc: hash function to use for hashing the provided
1465+
``data``.
15311466
If unspecified the default hash function selected during
15321467
object initialisation will be used (see
1533-
`VerifyingKey.default_hashfunc`).
1534-
Should behave like hashlib.sha1. The output length of the
1468+
:attr:`.VerifyingKey.default_hashfunc`).
1469+
Should behave like :func:`~hashlib.sha1` from :py:mod:`hashlib`.
1470+
The output length of the
15351471
hash (in bytes) must not be longer than the length of the curve
15361472
order (rounded up to the nearest byte), so using SHA256 with
15371473
NIST256p is ok, but SHA256 with NIST192p is not. (In the 2**-96ish
15381474
unlikely event of a hash output larger than the curve order, the
15391475
hash will effectively be wrapped mod n).
1540-
Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode,
1541-
or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256.
1476+
If you want to explicitly allow use of large hashes with small
1477+
curves set the ``allow_truncate`` to ``True``.
1478+
Use ``hashfunc=hashlib.sha1`` to match openssl's
1479+
``-ecdsa-with-SHA1`` mode,
1480+
or ``hashfunc=hashlib.sha256`` for openssl-1.0.0's
1481+
``-ecdsa-with-SHA256``.
15421482
Ignored for EdDSA
15431483
:type hashfunc: callable
15441484
:param sigencode: function used to encode the signature.
15451485
The function needs to accept three parameters: the two integers
15461486
that are the signature and the order of the curve over which the
15471487
signature was computed. It needs to return an encoded signature.
1548-
See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der`
1488+
See :func:`~ecdsa.util.sigencode_string` and
1489+
:func:`~ecdsa.util.sigencode_der`
15491490
as examples of such functions.
15501491
Ignored for EdDSA
15511492
:type sigencode: callable
15521493
:param int k: a pre-selected nonce for calculating the signature.
15531494
In typical use cases, it should be set to None (the default) to
15541495
allow its generation from an entropy source.
15551496
Ignored for EdDSA.
1556-
:param bool allow_truncate: if True, the provided digest can have
1497+
:param bool allow_truncate: if ``True``, the provided digest can have
15571498
bigger bit-size than the order of the curve, the extra bits (at
15581499
the end of the digest) will be truncated. Use it when signing
15591500
SHA-384 output using NIST256p or in similar situations. True by
15601501
default.
15611502
Ignored for EdDSA.
15621503
1563-
:raises RSZeroError: in the unlikely event when "r" parameter or
1564-
"s" parameter of the created signature is equal 0, as that would
1504+
:raises RSZeroError: in the unlikely event when *r* parameter or
1505+
*s* parameter of the created signature is equal 0, as that would
15651506
leak the key. Caller should try a better entropy source, retry with
1566-
different 'k', or use the
1507+
different ``k``, or use the
15671508
:func:`~SigningKey.sign_deterministic` in such case.
15681509
15691510
:return: encoded signature of the hash of `data`
@@ -1597,7 +1538,7 @@ def sign_digest(
15971538
instead of this one.
15981539
15991540
:param digest: hash value that will be signed
1600-
:type digest: bytes like object
1541+
:type digest: :term:`bytes-like object`
16011542
:param callable entropy: randomness source, os.urandom by default
16021543
:param sigencode: function used to encode the signature.
16031544
The function needs to accept three parameters: the two integers

0 commit comments

Comments
 (0)
Please sign in to comment.