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 5from __future__ import absolute_import, division, print_function 6 7import abc 8 9import six 10 11from cryptography import utils 12from cryptography.exceptions import ( 13 AlreadyFinalized, UnsupportedAlgorithm, _Reasons 14) 15from cryptography.hazmat.backends.interfaces import HashBackend 16 17 18@six.add_metaclass(abc.ABCMeta) 19class HashAlgorithm(object): 20 @abc.abstractproperty 21 def name(self): 22 """ 23 A string naming this algorithm (e.g. "sha256", "md5"). 24 """ 25 26 @abc.abstractproperty 27 def digest_size(self): 28 """ 29 The size of the resulting digest in bytes. 30 """ 31 32 33@six.add_metaclass(abc.ABCMeta) 34class HashContext(object): 35 @abc.abstractproperty 36 def algorithm(self): 37 """ 38 A HashAlgorithm that will be used by this context. 39 """ 40 41 @abc.abstractmethod 42 def update(self, data): 43 """ 44 Processes the provided bytes through the hash. 45 """ 46 47 @abc.abstractmethod 48 def finalize(self): 49 """ 50 Finalizes the hash context and returns the hash digest as bytes. 51 """ 52 53 @abc.abstractmethod 54 def copy(self): 55 """ 56 Return a HashContext that is a copy of the current context. 57 """ 58 59 60@six.add_metaclass(abc.ABCMeta) 61class ExtendableOutputFunction(object): 62 """ 63 An interface for extendable output functions. 64 """ 65 66 67@utils.register_interface(HashContext) 68class Hash(object): 69 def __init__(self, algorithm, backend, ctx=None): 70 if not isinstance(backend, HashBackend): 71 raise UnsupportedAlgorithm( 72 "Backend object does not implement HashBackend.", 73 _Reasons.BACKEND_MISSING_INTERFACE 74 ) 75 76 if not isinstance(algorithm, HashAlgorithm): 77 raise TypeError("Expected instance of hashes.HashAlgorithm.") 78 self._algorithm = algorithm 79 80 self._backend = backend 81 82 if ctx is None: 83 self._ctx = self._backend.create_hash_ctx(self.algorithm) 84 else: 85 self._ctx = ctx 86 87 algorithm = utils.read_only_property("_algorithm") 88 89 def update(self, data): 90 if self._ctx is None: 91 raise AlreadyFinalized("Context was already finalized.") 92 utils._check_byteslike("data", data) 93 self._ctx.update(data) 94 95 def copy(self): 96 if self._ctx is None: 97 raise AlreadyFinalized("Context was already finalized.") 98 return Hash( 99 self.algorithm, backend=self._backend, ctx=self._ctx.copy() 100 ) 101 102 def finalize(self): 103 if self._ctx is None: 104 raise AlreadyFinalized("Context was already finalized.") 105 digest = self._ctx.finalize() 106 self._ctx = None 107 return digest 108 109 110@utils.register_interface(HashAlgorithm) 111class SHA1(object): 112 name = "sha1" 113 digest_size = 20 114 block_size = 64 115 116 117@utils.register_interface(HashAlgorithm) 118class SHA512_224(object): # noqa: N801 119 name = "sha512-224" 120 digest_size = 28 121 block_size = 128 122 123 124@utils.register_interface(HashAlgorithm) 125class SHA512_256(object): # noqa: N801 126 name = "sha512-256" 127 digest_size = 32 128 block_size = 128 129 130 131@utils.register_interface(HashAlgorithm) 132class SHA224(object): 133 name = "sha224" 134 digest_size = 28 135 block_size = 64 136 137 138@utils.register_interface(HashAlgorithm) 139class SHA256(object): 140 name = "sha256" 141 digest_size = 32 142 block_size = 64 143 144 145@utils.register_interface(HashAlgorithm) 146class SHA384(object): 147 name = "sha384" 148 digest_size = 48 149 block_size = 128 150 151 152@utils.register_interface(HashAlgorithm) 153class SHA512(object): 154 name = "sha512" 155 digest_size = 64 156 block_size = 128 157 158 159@utils.register_interface(HashAlgorithm) 160class SHA3_224(object): # noqa: N801 161 name = "sha3-224" 162 digest_size = 28 163 164 165@utils.register_interface(HashAlgorithm) 166class SHA3_256(object): # noqa: N801 167 name = "sha3-256" 168 digest_size = 32 169 170 171@utils.register_interface(HashAlgorithm) 172class SHA3_384(object): # noqa: N801 173 name = "sha3-384" 174 digest_size = 48 175 176 177@utils.register_interface(HashAlgorithm) 178class SHA3_512(object): # noqa: N801 179 name = "sha3-512" 180 digest_size = 64 181 182 183@utils.register_interface(HashAlgorithm) 184@utils.register_interface(ExtendableOutputFunction) 185class SHAKE128(object): 186 name = "shake128" 187 188 def __init__(self, digest_size): 189 if not isinstance(digest_size, six.integer_types): 190 raise TypeError("digest_size must be an integer") 191 192 if digest_size < 1: 193 raise ValueError("digest_size must be a positive integer") 194 195 self._digest_size = digest_size 196 197 digest_size = utils.read_only_property("_digest_size") 198 199 200@utils.register_interface(HashAlgorithm) 201@utils.register_interface(ExtendableOutputFunction) 202class SHAKE256(object): 203 name = "shake256" 204 205 def __init__(self, digest_size): 206 if not isinstance(digest_size, six.integer_types): 207 raise TypeError("digest_size must be an integer") 208 209 if digest_size < 1: 210 raise ValueError("digest_size must be a positive integer") 211 212 self._digest_size = digest_size 213 214 digest_size = utils.read_only_property("_digest_size") 215 216 217@utils.register_interface(HashAlgorithm) 218class MD5(object): 219 name = "md5" 220 digest_size = 16 221 block_size = 64 222 223 224@utils.register_interface(HashAlgorithm) 225class BLAKE2b(object): 226 name = "blake2b" 227 _max_digest_size = 64 228 _min_digest_size = 1 229 block_size = 128 230 231 def __init__(self, digest_size): 232 233 if digest_size != 64: 234 raise ValueError("Digest size must be 64") 235 236 self._digest_size = digest_size 237 238 digest_size = utils.read_only_property("_digest_size") 239 240 241@utils.register_interface(HashAlgorithm) 242class BLAKE2s(object): 243 name = "blake2s" 244 block_size = 64 245 _max_digest_size = 32 246 _min_digest_size = 1 247 248 def __init__(self, digest_size): 249 250 if digest_size != 32: 251 raise ValueError("Digest size must be 32") 252 253 self._digest_size = digest_size 254 255 digest_size = utils.read_only_property("_digest_size") 256