signing.py 7.2 KB

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