File: signing.rst

package info (click to toggle)
python-nacl 1.5.0-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,772 kB
  • sloc: ansic: 45,889; python: 7,249; sh: 6,752; asm: 2,974; makefile: 1,010; cs: 35; xml: 30; pascal: 11
file content (336 lines) | stat: -rw-r--r-- 12,513 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
Digital Signatures
==================

.. currentmodule:: nacl.signing

You can use a digital signature for many of the same reasons that you might
sign a paper document. A valid digital signature gives a recipient reason to
believe that the message was created by a known sender such that they cannot
deny sending it (authentication and non-repudiation) and that the message was
not altered in transit (integrity).

Digital signatures allow you to publish a public key, and then you can use your
private signing key to sign messages. Others who have your public key can then
use it to validate that your messages are actually authentic.


Example
-------

Signing and verifying a message without encoding the key or message

Signer's perspective (:class:`~nacl.signing.SigningKey`)

.. testcode::

    from nacl.signing import SigningKey

    # Generate a new random signing key
    signing_key = SigningKey.generate()

    # Sign a message with the signing key
    signed = signing_key.sign(b"Attack at Dawn")

    # Obtain the verify key for a given signing key
    verify_key = signing_key.verify_key

    # Serialize the verify key to send it to a third party
    verify_key_bytes = verify_key.encode()

Verifier's perspective (:class:`~nacl.signing.VerifyKey`)

.. testcode::

    from nacl.signing import VerifyKey

    # Create a VerifyKey object from a hex serialized public key
    verify_key = VerifyKey(verify_key_bytes)

    # Check the validity of a message's signature
    # The message and the signature can either be passed together, or
    # separately if the signature is decoded to raw bytes.
    # These are equivalent:
    verify_key.verify(signed)
    verify_key.verify(signed.message, signed.signature)

    # Alter the signed message text
    forged = signed[:-1] + bytes([int(signed[-1]) ^ 1])
    # Will raise nacl.exceptions.BadSignatureError, since the signature check
    # is failing
    verify_key.verify(forged)

.. testoutput::

    Traceback (most recent call last):
     ...
    nacl.exceptions.BadSignatureError: Signature was forged or corrupt


Example
-------

Signing and verifying a message encoded with HexEncoder

Signer's perspective (:class:`~nacl.signing.SigningKey`)

.. testcode::

    from nacl.encoding import HexEncoder
    from nacl.signing import SigningKey

    # Generate a new random signing key
    signing_key = SigningKey.generate()

    # Sign a message with the signing key
    signed_hex = signing_key.sign(b"Attack at Dawn", encoder=HexEncoder)

    # Obtain the verify key for a given signing key
    verify_key = signing_key.verify_key

    # Serialize the verify key to send it to a third party
    verify_key_hex = verify_key.encode(encoder=HexEncoder)

Verifier's perspective (:class:`~nacl.signing.VerifyKey`)

.. testcode::

    from nacl.encoding import HexEncoder
    from nacl.signing import VerifyKey

    # Create a VerifyKey object from a hex serialized public key
    verify_key = VerifyKey(verify_key_hex, encoder=HexEncoder)

    # Check the validity of a message's signature
    # The message and the signature can either be passed together, or
    # separately if the signature is decoded to raw bytes.
    # These are equivalent:
    verify_key.verify(signed_hex, encoder=HexEncoder)
    signature_bytes = HexEncoder.decode(signed_hex.signature)
    verify_key.verify(signed_hex.message, signature_bytes,
                      encoder=HexEncoder)

    # Alter the signed message text
    forged = signed_hex[:-1] + bytes([int(signed_hex[-1]) ^ 1])
    # Will raise nacl.exceptions.BadSignatureError, since the signature check
    # is failing
    verify_key.verify(forged)

.. testoutput::

    Traceback (most recent call last):
     ...
    nacl.exceptions.BadSignatureError: Signature was forged or corrupt


Example
-------

Signing and verifying a message encoded with Base64Encoder

Signer's perspective (:class:`~nacl.signing.SigningKey`)

.. testcode::

    from nacl.encoding import Base64Encoder
    from nacl.signing import SigningKey

    # Generate a new random signing key
    signing_key = SigningKey.generate()

    # Sign a message with the signing key
    signed_b64 = signing_key.sign(b"Attack at Dawn", encoder=Base64Encoder)

    # Obtain the verify key for a given signing key
    verify_key = signing_key.verify_key

    # Serialize the verify key to send it to a third party
    verify_key_b64 = verify_key.encode(encoder=Base64Encoder)

Verifier's perspective (:class:`~nacl.signing.VerifyKey`)

.. testcode::

    from nacl.encoding import Base64Encoder
    from nacl.signing import VerifyKey

    # Create a VerifyKey object from a base64 serialized public key
    verify_key = VerifyKey(verify_key_b64, encoder=Base64Encoder)

    # Check the validity of a message's signature
    # The message and the signature can either be passed together, or
    # separately if the signature is decoded to raw bytes.
    # These are equivalent:
    verify_key.verify(signed_b64, encoder=Base64Encoder)
    signature_bytes = Base64Encoder.decode(signed_b64.signature)
    verify_key.verify(signed_b64.message, signature_bytes,
                      encoder=Base64Encoder)

    # Alter the signed message text
    forged = signed_b64[:-1] + bytes([int(signed_b64[-1]) ^ 1])
    # Will raise nacl.exceptions.BadSignatureError, since the signature check
    # is failing
    verify_key.verify(forged)

.. testoutput::

    Traceback (most recent call last):
     ...
    nacl.exceptions.BadSignatureError: Signature was forged or corrupt


Reference
---------

.. class:: SigningKey(seed, encoder)

    Private key for producing digital signatures using the Ed25519 algorithm.

    Signing keys are produced from a 32-byte (256-bit) random seed value. This
    value can be passed into the :class:`~nacl.signing.SigningKey` as a
    :func:`bytes` whose length is 32.

    .. warning:: This **must** be protected and remain secret. Anyone who knows
        the value of your :class:`~nacl.signing.SigningKey` or its seed can
        masquerade as you.

    :param bytes seed: Random 32-byte value (i.e. private key).
    :param encoder: A class that is able to decode the ``seed``.

    .. attribute:: verify_key

        An instance of :class:`~.nacl.signing.VerifyKey` (i.e. public key)
        that corresponds with the signing key.

    .. classmethod:: generate()

        Generates a random :class:`~nacl.signing.SigningKey` object

        :return: An instance of :class:`~nacl.signing.SigningKey`.

    .. method:: sign(message, encoder)

        Sign a message using this key.

        :param bytes message: The data to be signed.
        :param encoder: A class that is able to decode the signed message.

        :return: An instance of :class:`~nacl.signing.SignedMessage`.

.. class:: VerifyKey(key, encoder)

    The public key counterpart to an Ed25519 :class:`~nacl.signing.SigningKey`
    for producing digital signatures.

    :param bytes key: A serialized Ed25519 public key.
    :param encoder: A class that is able to decode the ``key``.

    .. method:: verify(smessage, signature, encoder)

        Verifies the signature of a signed message.

        :param bytes smessage: The signed message to verify. This is either
            the original message or the concatenated signature and message.
        :param bytes signature: The signature of the message to verify against.
            If the value of ``smessage`` is the concatenated signature and message,
            this parameter can be ``None``.
        :param encoder: A class that is able to decode the secret message and
            signature.

        :return bytes: The message if successfully verified.

        :raises nacl.exceptions.BadSignatureError: This is raised if the
            signature is invalid.

.. class:: SignedMessage()

    A bytes subclass that holds a messaged that has been signed by a
    :class:`SigningKey`.

    .. attribute:: signature

        The signature contained within the
        :class:`~nacl.signing.SignedMessage`.

    .. attribute:: message

        The message contained within the :class:`~nacl.signing.SignedMessage`.

Ed25519
-------

Ed25519 is a public-key signature system with several attractive features:

* **Fast single-signature verification:** Ed25519 takes only 273364 cycles
  to verify a signature on Intel's widely deployed Nehalem/Westmere lines of
  CPUs. (This performance measurement is for short messages; for very long
  messages, verification time is dominated by hashing time.) Nehalem and
  Westmere include all Core i7, i5, and i3 CPUs released between 2008 and
  2010, and most Xeon CPUs released in the same period.
* **Even faster batch verification:** Ed25519 performs a batch of 64
  separate signature verifications (verifying 64 signatures of 64 messages
  under 64 public keys) in only 8.55 million cycles, i.e., under 134000
  cycles per signature. Ed25519 fits easily into L1 cache, so contention
  between cores is negligible: a quad-core 2.4GHz Westmere verifies 71000
  signatures per second, while keeping the maximum verification latency
  below 4 milliseconds.
* **Very fast signing:** Ed25519 takes only 87548 cycles to sign a
  message. A quad-core 2.4GHz Westmere signs 109000 messages per second.
* **Fast key generation:** Key generation is almost as fast as signing. There
  is a slight penalty for key generation to obtain a secure random number
  from the operating system; /dev/urandom under Linux costs about 6000
  cycles.
* **High security level:** This system has a 2^128 security target; breaking it
  has similar difficulty to breaking NIST P-256, RSA with ~3000-bit keys,
  strong 128-bit block ciphers, etc. The best attacks known actually cost
  more than 2^140 bit operations on average, and degrade quadratically in
  success probability as the number of bit operations drops.
* **Collision resilience:** Hash-function collisions do not break this system.
  This adds a layer of defense against the possibility of weakness in the
  selected hash function.
* **No secret array indices:** Ed25519 never reads or writes data from secret
  addresses in RAM; the pattern of addresses is completely predictable.
  Ed25519 is therefore immune to cache-timing attacks, hyperthreading
  attacks, and other side-channel attacks that rely on leakage of addresses
  through the CPU cache.
* **No secret branch conditions:** Ed25519 never performs conditional branches
  based on secret data; the pattern of jumps is completely predictable.
  Ed25519 is therefore immune to side-channel attacks that rely on leakage of
  information through the branch-prediction unit.
* **Small signatures:** Ed25519 signatures are only 512-bits (64 bytes), one
  of the smallest signature sizes available.
* **Small keys:** Ed25519 keys are only 256-bits (32 bytes), making them small
  enough to easily copy and paste. Ed25519 also allows the public key to be
  derived from the private key, meaning that it doesn't need to be included
  in a serialized private key in cases you want both.
* **Deterministic:** Unlike (EC)DSA, Ed25519 does not rely on an entropy
  source when signing messages (which has lead to `catastrophic private key <https://arstechnica.com/gaming/2010/12/ps3-hacked-through-poor-implementation-of-cryptography/>`_
  compromises), but instead computes signature nonces from a combination of
  a hash of the signing key's "seed" and the message to be signed. This
  avoids using an entropy source for nonces, which can be a potential attack
  vector if the entropy source is not generating good random numbers. Even a
  single reused nonce can lead to a complete disclosure of the private key in
  these schemes, which Ed25519 avoids entirely by being deterministic instead
  of tied to an entropy source.

The numbers 87548 and 273364 shown above are official
`eBATS <https://bench.cr.yp.to/>`_ reports for a Westmere CPU (Intel Xeon E5620,
hydra2).

Ed25519 signatures are elliptic-curve signatures, carefully engineered at
several levels of design and implementation to achieve very high speeds without
compromising security.


Algorithm
~~~~~~~~~

* **Signatures:** `Ed25519 digital signature system <https://ed25519.cr.yp.to/>`_

.. image:: _static/ed25519.png

:k: Ed25519 private key (passed into :class:`~nacl.signing.SigningKey`)
:A: Ed25519 public key derived from k
:M: message to be signed
:R: a deterministic nonce value calculated from a combination of private key
    data RH and the message M
:S: Ed25519 signature