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