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