Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/aead.py: 68%
187 statements
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-14 06:36 +0000
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-14 06:36 +0000
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.
6import os
7import typing
9from cryptography import exceptions, utils
10from cryptography.hazmat.backends.openssl import aead
11from cryptography.hazmat.backends.openssl.backend import backend
12from cryptography.hazmat.bindings._rust import FixedPool
15class ChaCha20Poly1305:
16 _MAX_SIZE = 2**31 - 1
18 def __init__(self, key: bytes):
19 if not backend.aead_cipher_supported(self):
20 raise exceptions.UnsupportedAlgorithm(
21 "ChaCha20Poly1305 is not supported by this version of OpenSSL",
22 exceptions._Reasons.UNSUPPORTED_CIPHER,
23 )
24 utils._check_byteslike("key", key)
26 if len(key) != 32:
27 raise ValueError("ChaCha20Poly1305 key must be 32 bytes.")
29 self._key = key
30 self._pool = FixedPool(self._create_fn)
32 @classmethod
33 def generate_key(cls) -> bytes:
34 return os.urandom(32)
36 def _create_fn(self):
37 return aead._aead_create_ctx(backend, self, self._key)
39 def encrypt(
40 self,
41 nonce: bytes,
42 data: bytes,
43 associated_data: typing.Optional[bytes],
44 ) -> bytes:
45 if associated_data is None:
46 associated_data = b""
48 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
49 # This is OverflowError to match what cffi would raise
50 raise OverflowError(
51 "Data or associated data too long. Max 2**31 - 1 bytes"
52 )
54 self._check_params(nonce, data, associated_data)
55 with self._pool.acquire() as ctx:
56 return aead._encrypt(
57 backend, self, nonce, data, [associated_data], 16, ctx
58 )
60 def decrypt(
61 self,
62 nonce: bytes,
63 data: bytes,
64 associated_data: typing.Optional[bytes],
65 ) -> bytes:
66 if associated_data is None:
67 associated_data = b""
69 self._check_params(nonce, data, associated_data)
70 with self._pool.acquire() as ctx:
71 return aead._decrypt(
72 backend, self, nonce, data, [associated_data], 16, ctx
73 )
75 def _check_params(
76 self,
77 nonce: bytes,
78 data: bytes,
79 associated_data: bytes,
80 ) -> None:
81 utils._check_byteslike("nonce", nonce)
82 utils._check_byteslike("data", data)
83 utils._check_byteslike("associated_data", associated_data)
84 if len(nonce) != 12:
85 raise ValueError("Nonce must be 12 bytes")
88class AESCCM:
89 _MAX_SIZE = 2**31 - 1
91 def __init__(self, key: bytes, tag_length: int = 16):
92 utils._check_byteslike("key", key)
93 if len(key) not in (16, 24, 32):
94 raise ValueError("AESCCM key must be 128, 192, or 256 bits.")
96 self._key = key
97 if not isinstance(tag_length, int):
98 raise TypeError("tag_length must be an integer")
100 if tag_length not in (4, 6, 8, 10, 12, 14, 16):
101 raise ValueError("Invalid tag_length")
103 self._tag_length = tag_length
105 if not backend.aead_cipher_supported(self):
106 raise exceptions.UnsupportedAlgorithm(
107 "AESCCM is not supported by this version of OpenSSL",
108 exceptions._Reasons.UNSUPPORTED_CIPHER,
109 )
111 @classmethod
112 def generate_key(cls, bit_length: int) -> bytes:
113 if not isinstance(bit_length, int):
114 raise TypeError("bit_length must be an integer")
116 if bit_length not in (128, 192, 256):
117 raise ValueError("bit_length must be 128, 192, or 256")
119 return os.urandom(bit_length // 8)
121 def encrypt(
122 self,
123 nonce: bytes,
124 data: bytes,
125 associated_data: typing.Optional[bytes],
126 ) -> bytes:
127 if associated_data is None:
128 associated_data = b""
130 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
131 # This is OverflowError to match what cffi would raise
132 raise OverflowError(
133 "Data or associated data too long. Max 2**31 - 1 bytes"
134 )
136 self._check_params(nonce, data, associated_data)
137 self._validate_lengths(nonce, len(data))
138 return aead._encrypt(
139 backend, self, nonce, data, [associated_data], self._tag_length
140 )
142 def decrypt(
143 self,
144 nonce: bytes,
145 data: bytes,
146 associated_data: typing.Optional[bytes],
147 ) -> bytes:
148 if associated_data is None:
149 associated_data = b""
151 self._check_params(nonce, data, associated_data)
152 return aead._decrypt(
153 backend, self, nonce, data, [associated_data], self._tag_length
154 )
156 def _validate_lengths(self, nonce: bytes, data_len: int) -> None:
157 # For information about computing this, see
158 # https://tools.ietf.org/html/rfc3610#section-2.1
159 l_val = 15 - len(nonce)
160 if 2 ** (8 * l_val) < data_len:
161 raise ValueError("Data too long for nonce")
163 def _check_params(
164 self, nonce: bytes, data: bytes, associated_data: bytes
165 ) -> None:
166 utils._check_byteslike("nonce", nonce)
167 utils._check_byteslike("data", data)
168 utils._check_byteslike("associated_data", associated_data)
169 if not 7 <= len(nonce) <= 13:
170 raise ValueError("Nonce must be between 7 and 13 bytes")
173class AESGCM:
174 _MAX_SIZE = 2**31 - 1
176 def __init__(self, key: bytes):
177 utils._check_byteslike("key", key)
178 if len(key) not in (16, 24, 32):
179 raise ValueError("AESGCM key must be 128, 192, or 256 bits.")
181 self._key = key
183 @classmethod
184 def generate_key(cls, bit_length: int) -> bytes:
185 if not isinstance(bit_length, int):
186 raise TypeError("bit_length must be an integer")
188 if bit_length not in (128, 192, 256):
189 raise ValueError("bit_length must be 128, 192, or 256")
191 return os.urandom(bit_length // 8)
193 def encrypt(
194 self,
195 nonce: bytes,
196 data: bytes,
197 associated_data: typing.Optional[bytes],
198 ) -> bytes:
199 if associated_data is None:
200 associated_data = b""
202 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
203 # This is OverflowError to match what cffi would raise
204 raise OverflowError(
205 "Data or associated data too long. Max 2**31 - 1 bytes"
206 )
208 self._check_params(nonce, data, associated_data)
209 return aead._encrypt(backend, self, nonce, data, [associated_data], 16)
211 def decrypt(
212 self,
213 nonce: bytes,
214 data: bytes,
215 associated_data: typing.Optional[bytes],
216 ) -> bytes:
217 if associated_data is None:
218 associated_data = b""
220 self._check_params(nonce, data, associated_data)
221 return aead._decrypt(backend, self, nonce, data, [associated_data], 16)
223 def _check_params(
224 self,
225 nonce: bytes,
226 data: bytes,
227 associated_data: bytes,
228 ) -> None:
229 utils._check_byteslike("nonce", nonce)
230 utils._check_byteslike("data", data)
231 utils._check_byteslike("associated_data", associated_data)
232 if len(nonce) < 8 or len(nonce) > 128:
233 raise ValueError("Nonce must be between 8 and 128 bytes")
236class AESOCB3:
237 _MAX_SIZE = 2**31 - 1
239 def __init__(self, key: bytes):
240 utils._check_byteslike("key", key)
241 if len(key) not in (16, 24, 32):
242 raise ValueError("AESOCB3 key must be 128, 192, or 256 bits.")
244 self._key = key
246 if not backend.aead_cipher_supported(self):
247 raise exceptions.UnsupportedAlgorithm(
248 "OCB3 is not supported by this version of OpenSSL",
249 exceptions._Reasons.UNSUPPORTED_CIPHER,
250 )
252 @classmethod
253 def generate_key(cls, bit_length: int) -> bytes:
254 if not isinstance(bit_length, int):
255 raise TypeError("bit_length must be an integer")
257 if bit_length not in (128, 192, 256):
258 raise ValueError("bit_length must be 128, 192, or 256")
260 return os.urandom(bit_length // 8)
262 def encrypt(
263 self,
264 nonce: bytes,
265 data: bytes,
266 associated_data: typing.Optional[bytes],
267 ) -> bytes:
268 if associated_data is None:
269 associated_data = b""
271 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
272 # This is OverflowError to match what cffi would raise
273 raise OverflowError(
274 "Data or associated data too long. Max 2**31 - 1 bytes"
275 )
277 self._check_params(nonce, data, associated_data)
278 return aead._encrypt(backend, self, nonce, data, [associated_data], 16)
280 def decrypt(
281 self,
282 nonce: bytes,
283 data: bytes,
284 associated_data: typing.Optional[bytes],
285 ) -> bytes:
286 if associated_data is None:
287 associated_data = b""
289 self._check_params(nonce, data, associated_data)
290 return aead._decrypt(backend, self, nonce, data, [associated_data], 16)
292 def _check_params(
293 self,
294 nonce: bytes,
295 data: bytes,
296 associated_data: bytes,
297 ) -> None:
298 utils._check_byteslike("nonce", nonce)
299 utils._check_byteslike("data", data)
300 utils._check_byteslike("associated_data", associated_data)
301 if len(nonce) < 12 or len(nonce) > 15:
302 raise ValueError("Nonce must be between 12 and 15 bytes")
305class AESSIV:
306 _MAX_SIZE = 2**31 - 1
308 def __init__(self, key: bytes):
309 utils._check_byteslike("key", key)
310 if len(key) not in (32, 48, 64):
311 raise ValueError("AESSIV key must be 256, 384, or 512 bits.")
313 self._key = key
315 if not backend.aead_cipher_supported(self):
316 raise exceptions.UnsupportedAlgorithm(
317 "AES-SIV is not supported by this version of OpenSSL",
318 exceptions._Reasons.UNSUPPORTED_CIPHER,
319 )
321 @classmethod
322 def generate_key(cls, bit_length: int) -> bytes:
323 if not isinstance(bit_length, int):
324 raise TypeError("bit_length must be an integer")
326 if bit_length not in (256, 384, 512):
327 raise ValueError("bit_length must be 256, 384, or 512")
329 return os.urandom(bit_length // 8)
331 def encrypt(
332 self,
333 data: bytes,
334 associated_data: typing.Optional[typing.List[bytes]],
335 ) -> bytes:
336 if associated_data is None:
337 associated_data = []
339 self._check_params(data, associated_data)
341 if len(data) > self._MAX_SIZE or any(
342 len(ad) > self._MAX_SIZE for ad in associated_data
343 ):
344 # This is OverflowError to match what cffi would raise
345 raise OverflowError(
346 "Data or associated data too long. Max 2**31 - 1 bytes"
347 )
349 return aead._encrypt(backend, self, b"", data, associated_data, 16)
351 def decrypt(
352 self,
353 data: bytes,
354 associated_data: typing.Optional[typing.List[bytes]],
355 ) -> bytes:
356 if associated_data is None:
357 associated_data = []
359 self._check_params(data, associated_data)
361 return aead._decrypt(backend, self, b"", data, associated_data, 16)
363 def _check_params(
364 self,
365 data: bytes,
366 associated_data: typing.List[bytes],
367 ) -> None:
368 utils._check_byteslike("data", data)
369 if len(data) == 0:
370 raise ValueError("data must not be zero length")
372 if not isinstance(associated_data, list):
373 raise TypeError(
374 "associated_data must be a list of bytes-like objects or None"
375 )
376 for x in associated_data:
377 utils._check_byteslike("associated_data elements", x)