hashes.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import absolute_import, division, print_function
  5. import abc
  6. import six
  7. from cryptography import utils
  8. from cryptography.exceptions import (
  9. AlreadyFinalized,
  10. UnsupportedAlgorithm,
  11. _Reasons,
  12. )
  13. from cryptography.hazmat.backends import _get_backend
  14. from cryptography.hazmat.backends.interfaces import HashBackend
  15. @six.add_metaclass(abc.ABCMeta)
  16. class HashAlgorithm(object):
  17. @abc.abstractproperty
  18. def name(self):
  19. """
  20. A string naming this algorithm (e.g. "sha256", "md5").
  21. """
  22. @abc.abstractproperty
  23. def digest_size(self):
  24. """
  25. The size of the resulting digest in bytes.
  26. """
  27. @six.add_metaclass(abc.ABCMeta)
  28. class HashContext(object):
  29. @abc.abstractproperty
  30. def algorithm(self):
  31. """
  32. A HashAlgorithm that will be used by this context.
  33. """
  34. @abc.abstractmethod
  35. def update(self, data):
  36. """
  37. Processes the provided bytes through the hash.
  38. """
  39. @abc.abstractmethod
  40. def finalize(self):
  41. """
  42. Finalizes the hash context and returns the hash digest as bytes.
  43. """
  44. @abc.abstractmethod
  45. def copy(self):
  46. """
  47. Return a HashContext that is a copy of the current context.
  48. """
  49. @six.add_metaclass(abc.ABCMeta)
  50. class ExtendableOutputFunction(object):
  51. """
  52. An interface for extendable output functions.
  53. """
  54. @utils.register_interface(HashContext)
  55. class Hash(object):
  56. def __init__(self, algorithm, backend=None, ctx=None):
  57. backend = _get_backend(backend)
  58. if not isinstance(backend, HashBackend):
  59. raise UnsupportedAlgorithm(
  60. "Backend object does not implement HashBackend.",
  61. _Reasons.BACKEND_MISSING_INTERFACE,
  62. )
  63. if not isinstance(algorithm, HashAlgorithm):
  64. raise TypeError("Expected instance of hashes.HashAlgorithm.")
  65. self._algorithm = algorithm
  66. self._backend = backend
  67. if ctx is None:
  68. self._ctx = self._backend.create_hash_ctx(self.algorithm)
  69. else:
  70. self._ctx = ctx
  71. algorithm = utils.read_only_property("_algorithm")
  72. def update(self, data):
  73. if self._ctx is None:
  74. raise AlreadyFinalized("Context was already finalized.")
  75. utils._check_byteslike("data", data)
  76. self._ctx.update(data)
  77. def copy(self):
  78. if self._ctx is None:
  79. raise AlreadyFinalized("Context was already finalized.")
  80. return Hash(
  81. self.algorithm, backend=self._backend, ctx=self._ctx.copy()
  82. )
  83. def finalize(self):
  84. if self._ctx is None:
  85. raise AlreadyFinalized("Context was already finalized.")
  86. digest = self._ctx.finalize()
  87. self._ctx = None
  88. return digest
  89. @utils.register_interface(HashAlgorithm)
  90. class SHA1(object):
  91. name = "sha1"
  92. digest_size = 20
  93. block_size = 64
  94. @utils.register_interface(HashAlgorithm)
  95. class SHA512_224(object): # noqa: N801
  96. name = "sha512-224"
  97. digest_size = 28
  98. block_size = 128
  99. @utils.register_interface(HashAlgorithm)
  100. class SHA512_256(object): # noqa: N801
  101. name = "sha512-256"
  102. digest_size = 32
  103. block_size = 128
  104. @utils.register_interface(HashAlgorithm)
  105. class SHA224(object):
  106. name = "sha224"
  107. digest_size = 28
  108. block_size = 64
  109. @utils.register_interface(HashAlgorithm)
  110. class SHA256(object):
  111. name = "sha256"
  112. digest_size = 32
  113. block_size = 64
  114. @utils.register_interface(HashAlgorithm)
  115. class SHA384(object):
  116. name = "sha384"
  117. digest_size = 48
  118. block_size = 128
  119. @utils.register_interface(HashAlgorithm)
  120. class SHA512(object):
  121. name = "sha512"
  122. digest_size = 64
  123. block_size = 128
  124. @utils.register_interface(HashAlgorithm)
  125. class SHA3_224(object): # noqa: N801
  126. name = "sha3-224"
  127. digest_size = 28
  128. @utils.register_interface(HashAlgorithm)
  129. class SHA3_256(object): # noqa: N801
  130. name = "sha3-256"
  131. digest_size = 32
  132. @utils.register_interface(HashAlgorithm)
  133. class SHA3_384(object): # noqa: N801
  134. name = "sha3-384"
  135. digest_size = 48
  136. @utils.register_interface(HashAlgorithm)
  137. class SHA3_512(object): # noqa: N801
  138. name = "sha3-512"
  139. digest_size = 64
  140. @utils.register_interface(HashAlgorithm)
  141. @utils.register_interface(ExtendableOutputFunction)
  142. class SHAKE128(object):
  143. name = "shake128"
  144. def __init__(self, digest_size):
  145. if not isinstance(digest_size, six.integer_types):
  146. raise TypeError("digest_size must be an integer")
  147. if digest_size < 1:
  148. raise ValueError("digest_size must be a positive integer")
  149. self._digest_size = digest_size
  150. digest_size = utils.read_only_property("_digest_size")
  151. @utils.register_interface(HashAlgorithm)
  152. @utils.register_interface(ExtendableOutputFunction)
  153. class SHAKE256(object):
  154. name = "shake256"
  155. def __init__(self, digest_size):
  156. if not isinstance(digest_size, six.integer_types):
  157. raise TypeError("digest_size must be an integer")
  158. if digest_size < 1:
  159. raise ValueError("digest_size must be a positive integer")
  160. self._digest_size = digest_size
  161. digest_size = utils.read_only_property("_digest_size")
  162. @utils.register_interface(HashAlgorithm)
  163. class MD5(object):
  164. name = "md5"
  165. digest_size = 16
  166. block_size = 64
  167. @utils.register_interface(HashAlgorithm)
  168. class BLAKE2b(object):
  169. name = "blake2b"
  170. _max_digest_size = 64
  171. _min_digest_size = 1
  172. block_size = 128
  173. def __init__(self, digest_size):
  174. if digest_size != 64:
  175. raise ValueError("Digest size must be 64")
  176. self._digest_size = digest_size
  177. digest_size = utils.read_only_property("_digest_size")
  178. @utils.register_interface(HashAlgorithm)
  179. class BLAKE2s(object):
  180. name = "blake2s"
  181. block_size = 64
  182. _max_digest_size = 32
  183. _min_digest_size = 1
  184. def __init__(self, digest_size):
  185. if digest_size != 32:
  186. raise ValueError("Digest size must be 32")
  187. self._digest_size = digest_size
  188. digest_size = utils.read_only_property("_digest_size")