hashes.py 5.9 KB

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