hashes.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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 Backend, 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__(
  58. self,
  59. algorithm: HashAlgorithm,
  60. backend: typing.Optional[Backend] = None,
  61. ctx: typing.Optional["HashContext"] = None,
  62. ):
  63. backend = _get_backend(backend)
  64. if not isinstance(backend, HashBackend):
  65. raise UnsupportedAlgorithm(
  66. "Backend object does not implement HashBackend.",
  67. _Reasons.BACKEND_MISSING_INTERFACE,
  68. )
  69. if not isinstance(algorithm, HashAlgorithm):
  70. raise TypeError("Expected instance of hashes.HashAlgorithm.")
  71. self._algorithm = algorithm
  72. self._backend = backend
  73. if ctx is None:
  74. self._ctx = self._backend.create_hash_ctx(self.algorithm)
  75. else:
  76. self._ctx = ctx
  77. @property
  78. def algorithm(self) -> HashAlgorithm:
  79. return self._algorithm
  80. def update(self, data: bytes) -> None:
  81. if self._ctx is None:
  82. raise AlreadyFinalized("Context was already finalized.")
  83. utils._check_byteslike("data", data)
  84. self._ctx.update(data)
  85. def copy(self) -> "Hash":
  86. if self._ctx is None:
  87. raise AlreadyFinalized("Context was already finalized.")
  88. return Hash(
  89. self.algorithm, backend=self._backend, ctx=self._ctx.copy()
  90. )
  91. def finalize(self) -> bytes:
  92. if self._ctx is None:
  93. raise AlreadyFinalized("Context was already finalized.")
  94. digest = self._ctx.finalize()
  95. self._ctx = None
  96. return digest
  97. class SHA1(HashAlgorithm):
  98. name = "sha1"
  99. digest_size = 20
  100. block_size = 64
  101. class SHA512_224(HashAlgorithm): # noqa: N801
  102. name = "sha512-224"
  103. digest_size = 28
  104. block_size = 128
  105. class SHA512_256(HashAlgorithm): # noqa: N801
  106. name = "sha512-256"
  107. digest_size = 32
  108. block_size = 128
  109. class SHA224(HashAlgorithm):
  110. name = "sha224"
  111. digest_size = 28
  112. block_size = 64
  113. class SHA256(HashAlgorithm):
  114. name = "sha256"
  115. digest_size = 32
  116. block_size = 64
  117. class SHA384(HashAlgorithm):
  118. name = "sha384"
  119. digest_size = 48
  120. block_size = 128
  121. class SHA512(HashAlgorithm):
  122. name = "sha512"
  123. digest_size = 64
  124. block_size = 128
  125. class SHA3_224(HashAlgorithm): # noqa: N801
  126. name = "sha3-224"
  127. digest_size = 28
  128. block_size = None
  129. class SHA3_256(HashAlgorithm): # noqa: N801
  130. name = "sha3-256"
  131. digest_size = 32
  132. block_size = None
  133. class SHA3_384(HashAlgorithm): # noqa: N801
  134. name = "sha3-384"
  135. digest_size = 48
  136. block_size = None
  137. class SHA3_512(HashAlgorithm): # noqa: N801
  138. name = "sha3-512"
  139. digest_size = 64
  140. block_size = None
  141. class SHAKE128(HashAlgorithm, ExtendableOutputFunction):
  142. name = "shake128"
  143. block_size = None
  144. def __init__(self, digest_size: int):
  145. if not isinstance(digest_size, int):
  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. @property
  151. def digest_size(self) -> int:
  152. return self._digest_size
  153. class SHAKE256(HashAlgorithm, ExtendableOutputFunction):
  154. name = "shake256"
  155. block_size = None
  156. def __init__(self, digest_size: int):
  157. if not isinstance(digest_size, int):
  158. raise TypeError("digest_size must be an integer")
  159. if digest_size < 1:
  160. raise ValueError("digest_size must be a positive integer")
  161. self._digest_size = digest_size
  162. @property
  163. def digest_size(self) -> int:
  164. return self._digest_size
  165. class MD5(HashAlgorithm):
  166. name = "md5"
  167. digest_size = 16
  168. block_size = 64
  169. class BLAKE2b(HashAlgorithm):
  170. name = "blake2b"
  171. _max_digest_size = 64
  172. _min_digest_size = 1
  173. block_size = 128
  174. def __init__(self, digest_size: int):
  175. if digest_size != 64:
  176. raise ValueError("Digest size must be 64")
  177. self._digest_size = digest_size
  178. @property
  179. def digest_size(self) -> int:
  180. return self._digest_size
  181. class BLAKE2s(HashAlgorithm):
  182. name = "blake2s"
  183. block_size = 64
  184. _max_digest_size = 32
  185. _min_digest_size = 1
  186. def __init__(self, digest_size: int):
  187. if digest_size != 32:
  188. raise ValueError("Digest size must be 32")
  189. self._digest_size = digest_size
  190. @property
  191. def digest_size(self) -> int:
  192. return self._digest_size
  193. class SM3(HashAlgorithm):
  194. name = "sm3"
  195. digest_size = 32
  196. block_size = 64