signing.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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.
  14. from typing import Optional
  15. import nacl.bindings
  16. from nacl import encoding
  17. from nacl import exceptions as exc
  18. from nacl.public import (
  19. PrivateKey as _Curve25519_PrivateKey,
  20. PublicKey as _Curve25519_PublicKey,
  21. )
  22. from nacl.utils import StringFixer, random
  23. class SignedMessage(bytes):
  24. """
  25. A bytes subclass that holds a messaged that has been signed by a
  26. :class:`SigningKey`.
  27. """
  28. _signature: bytes
  29. _message: bytes
  30. @classmethod
  31. def _from_parts(
  32. cls, signature: bytes, message: bytes, combined: bytes
  33. ) -> "SignedMessage":
  34. obj = cls(combined)
  35. obj._signature = signature
  36. obj._message = message
  37. return obj
  38. @property
  39. def signature(self) -> bytes:
  40. """
  41. The signature contained within the :class:`SignedMessage`.
  42. """
  43. return self._signature
  44. @property
  45. def message(self) -> bytes:
  46. """
  47. The message contained within the :class:`SignedMessage`.
  48. """
  49. return self._message
  50. class VerifyKey(encoding.Encodable, StringFixer):
  51. """
  52. The public key counterpart to an Ed25519 SigningKey for producing digital
  53. signatures.
  54. :param key: [:class:`bytes`] Serialized Ed25519 public key
  55. :param encoder: A class that is able to decode the `key`
  56. """
  57. def __init__(
  58. self, key: bytes, encoder: encoding.Encoder = encoding.RawEncoder
  59. ):
  60. # Decode the key
  61. key = encoder.decode(key)
  62. if not isinstance(key, bytes):
  63. raise exc.TypeError("VerifyKey must be created from 32 bytes")
  64. if len(key) != nacl.bindings.crypto_sign_PUBLICKEYBYTES:
  65. raise exc.ValueError(
  66. "The key must be exactly %s bytes long"
  67. % nacl.bindings.crypto_sign_PUBLICKEYBYTES,
  68. )
  69. self._key = key
  70. def __bytes__(self) -> bytes:
  71. return self._key
  72. def __hash__(self) -> int:
  73. return hash(bytes(self))
  74. def __eq__(self, other: object) -> bool:
  75. if not isinstance(other, self.__class__):
  76. return False
  77. return nacl.bindings.sodium_memcmp(bytes(self), bytes(other))
  78. def __ne__(self, other: object) -> bool:
  79. return not (self == other)
  80. def verify(
  81. self,
  82. smessage: bytes,
  83. signature: Optional[bytes] = None,
  84. encoder: encoding.Encoder = encoding.RawEncoder,
  85. ) -> bytes:
  86. """
  87. Verifies the signature of a signed message, returning the message
  88. if it has not been tampered with else raising
  89. :class:`~nacl.signing.BadSignatureError`.
  90. :param smessage: [:class:`bytes`] Either the original messaged or a
  91. signature and message concated together.
  92. :param signature: [:class:`bytes`] If an unsigned message is given for
  93. smessage then the detached signature must be provided.
  94. :param encoder: A class that is able to decode the secret message and
  95. signature.
  96. :rtype: :class:`bytes`
  97. """
  98. if signature is not None:
  99. # If we were given the message and signature separately, validate
  100. # signature size and combine them.
  101. if not isinstance(signature, bytes):
  102. raise exc.TypeError(
  103. "Verification signature must be created from %d bytes"
  104. % nacl.bindings.crypto_sign_BYTES,
  105. )
  106. if len(signature) != nacl.bindings.crypto_sign_BYTES:
  107. raise exc.ValueError(
  108. "The signature must be exactly %d bytes long"
  109. % nacl.bindings.crypto_sign_BYTES,
  110. )
  111. smessage = signature + encoder.decode(smessage)
  112. else:
  113. # Decode the signed message
  114. smessage = encoder.decode(smessage)
  115. return nacl.bindings.crypto_sign_open(smessage, self._key)
  116. def to_curve25519_public_key(self) -> _Curve25519_PublicKey:
  117. """
  118. Converts a :class:`~nacl.signing.VerifyKey` to a
  119. :class:`~nacl.public.PublicKey`
  120. :rtype: :class:`~nacl.public.PublicKey`
  121. """
  122. raw_pk = nacl.bindings.crypto_sign_ed25519_pk_to_curve25519(self._key)
  123. return _Curve25519_PublicKey(raw_pk)
  124. class SigningKey(encoding.Encodable, StringFixer):
  125. """
  126. Private key for producing digital signatures using the Ed25519 algorithm.
  127. Signing keys are produced from a 32-byte (256-bit) random seed value. This
  128. value can be passed into the :class:`~nacl.signing.SigningKey` as a
  129. :func:`bytes` whose length is 32.
  130. .. warning:: This **must** be protected and remain secret. Anyone who knows
  131. the value of your :class:`~nacl.signing.SigningKey` or it's seed can
  132. masquerade as you.
  133. :param seed: [:class:`bytes`] Random 32-byte value (i.e. private key)
  134. :param encoder: A class that is able to decode the seed
  135. :ivar: verify_key: [:class:`~nacl.signing.VerifyKey`] The verify
  136. (i.e. public) key that corresponds with this signing key.
  137. """
  138. def __init__(
  139. self,
  140. seed: bytes,
  141. encoder: encoding.Encoder = encoding.RawEncoder,
  142. ):
  143. # Decode the seed
  144. seed = encoder.decode(seed)
  145. if not isinstance(seed, bytes):
  146. raise exc.TypeError(
  147. "SigningKey must be created from a 32 byte seed"
  148. )
  149. # Verify that our seed is the proper size
  150. if len(seed) != nacl.bindings.crypto_sign_SEEDBYTES:
  151. raise exc.ValueError(
  152. "The seed must be exactly %d bytes long"
  153. % nacl.bindings.crypto_sign_SEEDBYTES
  154. )
  155. public_key, secret_key = nacl.bindings.crypto_sign_seed_keypair(seed)
  156. self._seed = seed
  157. self._signing_key = secret_key
  158. self.verify_key = VerifyKey(public_key)
  159. def __bytes__(self) -> bytes:
  160. return self._seed
  161. def __hash__(self) -> int:
  162. return hash(bytes(self))
  163. def __eq__(self, other: object) -> bool:
  164. if not isinstance(other, self.__class__):
  165. return False
  166. return nacl.bindings.sodium_memcmp(bytes(self), bytes(other))
  167. def __ne__(self, other: object) -> bool:
  168. return not (self == other)
  169. @classmethod
  170. def generate(cls) -> "SigningKey":
  171. """
  172. Generates a random :class:`~nacl.signing.SigningKey` object.
  173. :rtype: :class:`~nacl.signing.SigningKey`
  174. """
  175. return cls(
  176. random(nacl.bindings.crypto_sign_SEEDBYTES),
  177. encoder=encoding.RawEncoder,
  178. )
  179. def sign(
  180. self,
  181. message: bytes,
  182. encoder: encoding.Encoder = encoding.RawEncoder,
  183. ) -> SignedMessage:
  184. """
  185. Sign a message using this key.
  186. :param message: [:class:`bytes`] The data to be signed.
  187. :param encoder: A class that is used to encode the signed message.
  188. :rtype: :class:`~nacl.signing.SignedMessage`
  189. """
  190. raw_signed = nacl.bindings.crypto_sign(message, self._signing_key)
  191. crypto_sign_BYTES = nacl.bindings.crypto_sign_BYTES
  192. signature = encoder.encode(raw_signed[:crypto_sign_BYTES])
  193. message = encoder.encode(raw_signed[crypto_sign_BYTES:])
  194. signed = encoder.encode(raw_signed)
  195. return SignedMessage._from_parts(signature, message, signed)
  196. def to_curve25519_private_key(self) -> _Curve25519_PrivateKey:
  197. """
  198. Converts a :class:`~nacl.signing.SigningKey` to a
  199. :class:`~nacl.public.PrivateKey`
  200. :rtype: :class:`~nacl.public.PrivateKey`
  201. """
  202. sk = self._signing_key
  203. raw_private = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(sk)
  204. return _Curve25519_PrivateKey(raw_private)