Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/PyNaCl-1.6.0.dev1-py3.8-linux-x86_64.egg/nacl/signing.py: 65%
86 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-06 06:06 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-06 06:06 +0000
1# Copyright 2013 Donald Stufft and individual contributors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14from typing import Optional
16import nacl.bindings
17from nacl import encoding
18from nacl import exceptions as exc
19from nacl.public import (
20 PrivateKey as _Curve25519_PrivateKey,
21 PublicKey as _Curve25519_PublicKey,
22)
23from nacl.utils import StringFixer, random
26class SignedMessage(bytes):
27 """
28 A bytes subclass that holds a messaged that has been signed by a
29 :class:`SigningKey`.
30 """
32 _signature: bytes
33 _message: bytes
35 @classmethod
36 def _from_parts(
37 cls, signature: bytes, message: bytes, combined: bytes
38 ) -> "SignedMessage":
39 obj = cls(combined)
40 obj._signature = signature
41 obj._message = message
42 return obj
44 @property
45 def signature(self) -> bytes:
46 """
47 The signature contained within the :class:`SignedMessage`.
48 """
49 return self._signature
51 @property
52 def message(self) -> bytes:
53 """
54 The message contained within the :class:`SignedMessage`.
55 """
56 return self._message
59class VerifyKey(encoding.Encodable, StringFixer):
60 """
61 The public key counterpart to an Ed25519 SigningKey for producing digital
62 signatures.
64 :param key: [:class:`bytes`] Serialized Ed25519 public key
65 :param encoder: A class that is able to decode the `key`
66 """
68 def __init__(
69 self, key: bytes, encoder: encoding.Encoder = encoding.RawEncoder
70 ):
71 # Decode the key
72 key = encoder.decode(key)
73 if not isinstance(key, bytes):
74 raise exc.TypeError("VerifyKey must be created from 32 bytes")
76 if len(key) != nacl.bindings.crypto_sign_PUBLICKEYBYTES:
77 raise exc.ValueError(
78 "The key must be exactly %s bytes long"
79 % nacl.bindings.crypto_sign_PUBLICKEYBYTES,
80 )
82 self._key = key
84 def __bytes__(self) -> bytes:
85 return self._key
87 def __hash__(self) -> int:
88 return hash(bytes(self))
90 def __eq__(self, other: object) -> bool:
91 if not isinstance(other, self.__class__):
92 return False
93 return nacl.bindings.sodium_memcmp(bytes(self), bytes(other))
95 def __ne__(self, other: object) -> bool:
96 return not (self == other)
98 def verify(
99 self,
100 smessage: bytes,
101 signature: Optional[bytes] = None,
102 encoder: encoding.Encoder = encoding.RawEncoder,
103 ) -> bytes:
104 """
105 Verifies the signature of a signed message, returning the message
106 if it has not been tampered with else raising
107 :class:`~nacl.signing.BadSignatureError`.
109 :param smessage: [:class:`bytes`] Either the original messaged or a
110 signature and message concated together.
111 :param signature: [:class:`bytes`] If an unsigned message is given for
112 smessage then the detached signature must be provided.
113 :param encoder: A class that is able to decode the secret message and
114 signature.
115 :rtype: :class:`bytes`
116 """
117 if signature is not None:
118 # If we were given the message and signature separately, validate
119 # signature size and combine them.
120 if not isinstance(signature, bytes):
121 raise exc.TypeError(
122 "Verification signature must be created from %d bytes"
123 % nacl.bindings.crypto_sign_BYTES,
124 )
126 if len(signature) != nacl.bindings.crypto_sign_BYTES:
127 raise exc.ValueError(
128 "The signature must be exactly %d bytes long"
129 % nacl.bindings.crypto_sign_BYTES,
130 )
132 smessage = signature + encoder.decode(smessage)
133 else:
134 # Decode the signed message
135 smessage = encoder.decode(smessage)
137 return nacl.bindings.crypto_sign_open(smessage, self._key)
139 def to_curve25519_public_key(self) -> _Curve25519_PublicKey:
140 """
141 Converts a :class:`~nacl.signing.VerifyKey` to a
142 :class:`~nacl.public.PublicKey`
144 :rtype: :class:`~nacl.public.PublicKey`
145 """
146 raw_pk = nacl.bindings.crypto_sign_ed25519_pk_to_curve25519(self._key)
147 return _Curve25519_PublicKey(raw_pk)
150class SigningKey(encoding.Encodable, StringFixer):
151 """
152 Private key for producing digital signatures using the Ed25519 algorithm.
154 Signing keys are produced from a 32-byte (256-bit) random seed value. This
155 value can be passed into the :class:`~nacl.signing.SigningKey` as a
156 :func:`bytes` whose length is 32.
158 .. warning:: This **must** be protected and remain secret. Anyone who knows
159 the value of your :class:`~nacl.signing.SigningKey` or it's seed can
160 masquerade as you.
162 :param seed: [:class:`bytes`] Random 32-byte value (i.e. private key)
163 :param encoder: A class that is able to decode the seed
165 :ivar: verify_key: [:class:`~nacl.signing.VerifyKey`] The verify
166 (i.e. public) key that corresponds with this signing key.
167 """
169 def __init__(
170 self,
171 seed: bytes,
172 encoder: encoding.Encoder = encoding.RawEncoder,
173 ):
174 # Decode the seed
175 seed = encoder.decode(seed)
176 if not isinstance(seed, bytes):
177 raise exc.TypeError(
178 "SigningKey must be created from a 32 byte seed"
179 )
181 # Verify that our seed is the proper size
182 if len(seed) != nacl.bindings.crypto_sign_SEEDBYTES:
183 raise exc.ValueError(
184 "The seed must be exactly %d bytes long"
185 % nacl.bindings.crypto_sign_SEEDBYTES
186 )
188 public_key, secret_key = nacl.bindings.crypto_sign_seed_keypair(seed)
190 self._seed = seed
191 self._signing_key = secret_key
192 self.verify_key = VerifyKey(public_key)
194 def __bytes__(self) -> bytes:
195 return self._seed
197 def __hash__(self) -> int:
198 return hash(bytes(self))
200 def __eq__(self, other: object) -> bool:
201 if not isinstance(other, self.__class__):
202 return False
203 return nacl.bindings.sodium_memcmp(bytes(self), bytes(other))
205 def __ne__(self, other: object) -> bool:
206 return not (self == other)
208 @classmethod
209 def generate(cls) -> "SigningKey":
210 """
211 Generates a random :class:`~nacl.signing.SigningKey` object.
213 :rtype: :class:`~nacl.signing.SigningKey`
214 """
215 return cls(
216 random(nacl.bindings.crypto_sign_SEEDBYTES),
217 encoder=encoding.RawEncoder,
218 )
220 def sign(
221 self,
222 message: bytes,
223 encoder: encoding.Encoder = encoding.RawEncoder,
224 ) -> SignedMessage:
225 """
226 Sign a message using this key.
228 :param message: [:class:`bytes`] The data to be signed.
229 :param encoder: A class that is used to encode the signed message.
230 :rtype: :class:`~nacl.signing.SignedMessage`
231 """
232 raw_signed = nacl.bindings.crypto_sign(message, self._signing_key)
234 crypto_sign_BYTES = nacl.bindings.crypto_sign_BYTES
235 signature = encoder.encode(raw_signed[:crypto_sign_BYTES])
236 message = encoder.encode(raw_signed[crypto_sign_BYTES:])
237 signed = encoder.encode(raw_signed)
239 return SignedMessage._from_parts(signature, message, signed)
241 def to_curve25519_private_key(self) -> _Curve25519_PrivateKey:
242 """
243 Converts a :class:`~nacl.signing.SigningKey` to a
244 :class:`~nacl.public.PrivateKey`
246 :rtype: :class:`~nacl.public.PrivateKey`
247 """
248 sk = self._signing_key
249 raw_private = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(sk)
250 return _Curve25519_PrivateKey(raw_private)