• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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