1# Copyright 2017 Donald Stufft and individual contributors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14from __future__ import annotations
15
16from nacl import exceptions as exc
17from nacl._sodium import ffi, lib
18from nacl.exceptions import ensure
19
20"""
21Implementations of authenticated encription with associated data (*AEAD*)
22constructions building on the chacha20 stream cipher and the poly1305
23authenticator
24"""
25
26crypto_aead_chacha20poly1305_ietf_KEYBYTES: int = (
27 lib.crypto_aead_chacha20poly1305_ietf_keybytes()
28)
29crypto_aead_chacha20poly1305_ietf_NSECBYTES: int = (
30 lib.crypto_aead_chacha20poly1305_ietf_nsecbytes()
31)
32crypto_aead_chacha20poly1305_ietf_NPUBBYTES: int = (
33 lib.crypto_aead_chacha20poly1305_ietf_npubbytes()
34)
35crypto_aead_chacha20poly1305_ietf_ABYTES: int = (
36 lib.crypto_aead_chacha20poly1305_ietf_abytes()
37)
38crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX: int = (
39 lib.crypto_aead_chacha20poly1305_ietf_messagebytes_max()
40)
41_aead_chacha20poly1305_ietf_CRYPTBYTES_MAX = (
42 crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX
43 + crypto_aead_chacha20poly1305_ietf_ABYTES
44)
45
46crypto_aead_chacha20poly1305_KEYBYTES: int = (
47 lib.crypto_aead_chacha20poly1305_keybytes()
48)
49crypto_aead_chacha20poly1305_NSECBYTES: int = (
50 lib.crypto_aead_chacha20poly1305_nsecbytes()
51)
52crypto_aead_chacha20poly1305_NPUBBYTES: int = (
53 lib.crypto_aead_chacha20poly1305_npubbytes()
54)
55crypto_aead_chacha20poly1305_ABYTES: int = (
56 lib.crypto_aead_chacha20poly1305_abytes()
57)
58crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX: int = (
59 lib.crypto_aead_chacha20poly1305_messagebytes_max()
60)
61_aead_chacha20poly1305_CRYPTBYTES_MAX = (
62 crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX
63 + crypto_aead_chacha20poly1305_ABYTES
64)
65
66crypto_aead_xchacha20poly1305_ietf_KEYBYTES: int = (
67 lib.crypto_aead_xchacha20poly1305_ietf_keybytes()
68)
69crypto_aead_xchacha20poly1305_ietf_NSECBYTES: int = (
70 lib.crypto_aead_xchacha20poly1305_ietf_nsecbytes()
71)
72crypto_aead_xchacha20poly1305_ietf_NPUBBYTES: int = (
73 lib.crypto_aead_xchacha20poly1305_ietf_npubbytes()
74)
75crypto_aead_xchacha20poly1305_ietf_ABYTES: int = (
76 lib.crypto_aead_xchacha20poly1305_ietf_abytes()
77)
78crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX: int = (
79 lib.crypto_aead_xchacha20poly1305_ietf_messagebytes_max()
80)
81_aead_xchacha20poly1305_ietf_CRYPTBYTES_MAX = (
82 crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX
83 + crypto_aead_xchacha20poly1305_ietf_ABYTES
84)
85
86crypto_aead_aegis256_KEYBYTES: int = lib.crypto_aead_aegis256_keybytes()
87crypto_aead_aegis256_NSECBYTES: int = lib.crypto_aead_aegis256_nsecbytes()
88crypto_aead_aegis256_NPUBBYTES: int = lib.crypto_aead_aegis256_npubbytes()
89crypto_aead_aegis256_ABYTES: int = lib.crypto_aead_aegis256_abytes()
90crypto_aead_aegis256_MESSAGEBYTES_MAX: int = (
91 lib.crypto_aead_aegis256_messagebytes_max()
92)
93_aead_aegis256_CRYPTBYTES_MAX = (
94 crypto_aead_aegis256_MESSAGEBYTES_MAX + crypto_aead_aegis256_ABYTES
95)
96
97crypto_aead_aegis128l_KEYBYTES: int = lib.crypto_aead_aegis128l_keybytes()
98crypto_aead_aegis128l_NSECBYTES: int = lib.crypto_aead_aegis128l_nsecbytes()
99crypto_aead_aegis128l_NPUBBYTES: int = lib.crypto_aead_aegis128l_npubbytes()
100crypto_aead_aegis128l_ABYTES: int = lib.crypto_aead_aegis128l_abytes()
101crypto_aead_aegis128l_MESSAGEBYTES_MAX: int = (
102 lib.crypto_aead_aegis128l_messagebytes_max()
103)
104_aead_aegis256_CRYPTBYTES_MAX = (
105 crypto_aead_aegis128l_MESSAGEBYTES_MAX + crypto_aead_aegis128l_ABYTES
106)
107
108crypto_aead_aes256gcm_KEYBYTES: int = lib.crypto_aead_aes256gcm_keybytes()
109crypto_aead_aes256gcm_NSECBYTES: int = lib.crypto_aead_aes256gcm_nsecbytes()
110crypto_aead_aes256gcm_NPUBBYTES: int = lib.crypto_aead_aes256gcm_npubbytes()
111crypto_aead_aes256gcm_ABYTES: int = lib.crypto_aead_aes256gcm_abytes()
112crypto_aead_aes256gcm_MESSAGEBYTES_MAX: int = (
113 lib.crypto_aead_aes256gcm_messagebytes_max()
114)
115_aead_aegis256_CRYPTBYTES_MAX = (
116 crypto_aead_aes256gcm_MESSAGEBYTES_MAX + crypto_aead_aes256gcm_ABYTES
117)
118
119
120def crypto_aead_chacha20poly1305_ietf_encrypt(
121 message: bytes, aad: bytes | None, nonce: bytes, key: bytes
122) -> bytes:
123 """
124 Encrypt the given ``message`` using the IETF ratified chacha20poly1305
125 construction described in RFC7539.
126
127 :param message:
128 :type message: bytes
129 :param aad:
130 :type aad: Optional[bytes]
131 :param nonce:
132 :type nonce: bytes
133 :param key:
134 :type key: bytes
135 :return: authenticated ciphertext
136 :rtype: bytes
137 """
138 ensure(
139 isinstance(message, bytes),
140 "Input message type must be bytes",
141 raising=exc.TypeError,
142 )
143
144 mlen = len(message)
145
146 ensure(
147 mlen <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX,
148 f"Message must be at most {crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX} bytes long",
149 raising=exc.ValueError,
150 )
151
152 ensure(
153 isinstance(aad, bytes) or (aad is None),
154 "Additional data must be bytes or None",
155 raising=exc.TypeError,
156 )
157
158 ensure(
159 isinstance(nonce, bytes)
160 and len(nonce) == crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
161 f"Nonce must be a {crypto_aead_chacha20poly1305_ietf_NPUBBYTES} bytes long bytes sequence",
162 raising=exc.TypeError,
163 )
164
165 ensure(
166 isinstance(key, bytes)
167 and len(key) == crypto_aead_chacha20poly1305_ietf_KEYBYTES,
168 f"Key must be a {crypto_aead_chacha20poly1305_ietf_KEYBYTES} bytes long bytes sequence",
169 raising=exc.TypeError,
170 )
171
172 if aad:
173 _aad = aad
174 aalen = len(aad)
175 else:
176 _aad = ffi.NULL
177 aalen = 0
178
179 mxout = mlen + crypto_aead_chacha20poly1305_ietf_ABYTES
180
181 clen = ffi.new("unsigned long long *")
182
183 ciphertext = ffi.new("unsigned char[]", mxout)
184
185 res = lib.crypto_aead_chacha20poly1305_ietf_encrypt(
186 ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key
187 )
188
189 ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
190 return ffi.buffer(ciphertext, clen[0])[:]
191
192
193def crypto_aead_chacha20poly1305_ietf_decrypt(
194 ciphertext: bytes, aad: bytes | None, nonce: bytes, key: bytes
195) -> bytes:
196 """
197 Decrypt the given ``ciphertext`` using the IETF ratified chacha20poly1305
198 construction described in RFC7539.
199
200 :param ciphertext:
201 :type ciphertext: bytes
202 :param aad:
203 :type aad: Optional[bytes]
204 :param nonce:
205 :type nonce: bytes
206 :param key:
207 :type key: bytes
208 :return: message
209 :rtype: bytes
210 """
211 ensure(
212 isinstance(ciphertext, bytes),
213 "Input ciphertext type must be bytes",
214 raising=exc.TypeError,
215 )
216
217 clen = len(ciphertext)
218
219 ensure(
220 clen <= _aead_chacha20poly1305_ietf_CRYPTBYTES_MAX,
221 f"Ciphertext must be at most {_aead_chacha20poly1305_ietf_CRYPTBYTES_MAX} bytes long",
222 raising=exc.ValueError,
223 )
224
225 ensure(
226 isinstance(aad, bytes) or (aad is None),
227 "Additional data must be bytes or None",
228 raising=exc.TypeError,
229 )
230
231 ensure(
232 isinstance(nonce, bytes)
233 and len(nonce) == crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
234 f"Nonce must be a {crypto_aead_chacha20poly1305_ietf_NPUBBYTES} bytes long bytes sequence",
235 raising=exc.TypeError,
236 )
237
238 ensure(
239 isinstance(key, bytes)
240 and len(key) == crypto_aead_chacha20poly1305_ietf_KEYBYTES,
241 f"Key must be a {crypto_aead_chacha20poly1305_ietf_KEYBYTES} bytes long bytes sequence",
242 raising=exc.TypeError,
243 )
244
245 mxout = clen - crypto_aead_chacha20poly1305_ietf_ABYTES
246
247 mlen = ffi.new("unsigned long long *")
248 message = ffi.new("unsigned char[]", mxout)
249
250 if aad:
251 _aad = aad
252 aalen = len(aad)
253 else:
254 _aad = ffi.NULL
255 aalen = 0
256
257 res = lib.crypto_aead_chacha20poly1305_ietf_decrypt(
258 message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key
259 )
260
261 ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)
262
263 return ffi.buffer(message, mlen[0])[:]
264
265
266def crypto_aead_chacha20poly1305_encrypt(
267 message: bytes, aad: bytes | None, nonce: bytes, key: bytes
268) -> bytes:
269 """
270 Encrypt the given ``message`` using the "legacy" construction
271 described in draft-agl-tls-chacha20poly1305.
272
273 :param message:
274 :type message: bytes
275 :param aad:
276 :type aad: Optional[bytes]
277 :param nonce:
278 :type nonce: bytes
279 :param key:
280 :type key: bytes
281 :return: authenticated ciphertext
282 :rtype: bytes
283 """
284 ensure(
285 isinstance(message, bytes),
286 "Input message type must be bytes",
287 raising=exc.TypeError,
288 )
289
290 mlen = len(message)
291
292 ensure(
293 mlen <= crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX,
294 f"Message must be at most {crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX} bytes long",
295 raising=exc.ValueError,
296 )
297
298 ensure(
299 isinstance(aad, bytes) or (aad is None),
300 "Additional data must be bytes or None",
301 raising=exc.TypeError,
302 )
303
304 ensure(
305 isinstance(nonce, bytes)
306 and len(nonce) == crypto_aead_chacha20poly1305_NPUBBYTES,
307 f"Nonce must be a {crypto_aead_chacha20poly1305_NPUBBYTES} bytes long bytes sequence",
308 raising=exc.TypeError,
309 )
310
311 ensure(
312 isinstance(key, bytes)
313 and len(key) == crypto_aead_chacha20poly1305_KEYBYTES,
314 f"Key must be a {crypto_aead_chacha20poly1305_KEYBYTES} bytes long bytes sequence",
315 raising=exc.TypeError,
316 )
317
318 if aad:
319 _aad = aad
320 aalen = len(aad)
321 else:
322 _aad = ffi.NULL
323 aalen = 0
324
325 mxout = mlen + crypto_aead_chacha20poly1305_ietf_ABYTES
326
327 clen = ffi.new("unsigned long long *")
328
329 ciphertext = ffi.new("unsigned char[]", mxout)
330
331 res = lib.crypto_aead_chacha20poly1305_encrypt(
332 ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key
333 )
334
335 ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
336 return ffi.buffer(ciphertext, clen[0])[:]
337
338
339def crypto_aead_chacha20poly1305_decrypt(
340 ciphertext: bytes, aad: bytes | None, nonce: bytes, key: bytes
341) -> bytes:
342 """
343 Decrypt the given ``ciphertext`` using the "legacy" construction
344 described in draft-agl-tls-chacha20poly1305.
345
346 :param ciphertext: authenticated ciphertext
347 :type ciphertext: bytes
348 :param aad:
349 :type aad: Optional[bytes]
350 :param nonce:
351 :type nonce: bytes
352 :param key:
353 :type key: bytes
354 :return: message
355 :rtype: bytes
356 """
357 ensure(
358 isinstance(ciphertext, bytes),
359 "Input ciphertext type must be bytes",
360 raising=exc.TypeError,
361 )
362
363 clen = len(ciphertext)
364
365 ensure(
366 clen <= _aead_chacha20poly1305_CRYPTBYTES_MAX,
367 f"Ciphertext must be at most {_aead_chacha20poly1305_CRYPTBYTES_MAX} bytes long",
368 raising=exc.ValueError,
369 )
370
371 ensure(
372 isinstance(aad, bytes) or (aad is None),
373 "Additional data must be bytes or None",
374 raising=exc.TypeError,
375 )
376
377 ensure(
378 isinstance(nonce, bytes)
379 and len(nonce) == crypto_aead_chacha20poly1305_NPUBBYTES,
380 f"Nonce must be a {crypto_aead_chacha20poly1305_NPUBBYTES} bytes long bytes sequence",
381 raising=exc.TypeError,
382 )
383
384 ensure(
385 isinstance(key, bytes)
386 and len(key) == crypto_aead_chacha20poly1305_KEYBYTES,
387 f"Key must be a {crypto_aead_chacha20poly1305_KEYBYTES} bytes long bytes sequence",
388 raising=exc.TypeError,
389 )
390
391 mxout = clen - crypto_aead_chacha20poly1305_ABYTES
392
393 mlen = ffi.new("unsigned long long *")
394 message = ffi.new("unsigned char[]", mxout)
395
396 if aad:
397 _aad = aad
398 aalen = len(aad)
399 else:
400 _aad = ffi.NULL
401 aalen = 0
402
403 res = lib.crypto_aead_chacha20poly1305_decrypt(
404 message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key
405 )
406
407 ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)
408
409 return ffi.buffer(message, mlen[0])[:]
410
411
412def crypto_aead_xchacha20poly1305_ietf_encrypt(
413 message: bytes, aad: bytes | None, nonce: bytes, key: bytes
414) -> bytes:
415 """
416 Encrypt the given ``message`` using the long-nonces xchacha20poly1305
417 construction.
418
419 :param message:
420 :type message: bytes
421 :param aad:
422 :type aad: Optional[bytes]
423 :param nonce:
424 :type nonce: bytes
425 :param key:
426 :type key: bytes
427 :return: authenticated ciphertext
428 :rtype: bytes
429 """
430 ensure(
431 isinstance(message, bytes),
432 "Input message type must be bytes",
433 raising=exc.TypeError,
434 )
435
436 mlen = len(message)
437
438 ensure(
439 mlen <= crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX,
440 f"Message must be at most {crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX} bytes long",
441 raising=exc.ValueError,
442 )
443
444 ensure(
445 isinstance(aad, bytes) or (aad is None),
446 "Additional data must be bytes or None",
447 raising=exc.TypeError,
448 )
449
450 ensure(
451 isinstance(nonce, bytes)
452 and len(nonce) == crypto_aead_xchacha20poly1305_ietf_NPUBBYTES,
453 f"Nonce must be a {crypto_aead_xchacha20poly1305_ietf_NPUBBYTES} bytes long bytes sequence",
454 raising=exc.TypeError,
455 )
456
457 ensure(
458 isinstance(key, bytes)
459 and len(key) == crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
460 f"Key must be a {crypto_aead_xchacha20poly1305_ietf_KEYBYTES} bytes long bytes sequence",
461 raising=exc.TypeError,
462 )
463
464 if aad:
465 _aad = aad
466 aalen = len(aad)
467 else:
468 _aad = ffi.NULL
469 aalen = 0
470
471 mxout = mlen + crypto_aead_xchacha20poly1305_ietf_ABYTES
472
473 clen = ffi.new("unsigned long long *")
474
475 ciphertext = ffi.new("unsigned char[]", mxout)
476
477 res = lib.crypto_aead_xchacha20poly1305_ietf_encrypt(
478 ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key
479 )
480
481 ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
482 return ffi.buffer(ciphertext, clen[0])[:]
483
484
485def crypto_aead_xchacha20poly1305_ietf_decrypt(
486 ciphertext: bytes, aad: bytes | None, nonce: bytes, key: bytes
487) -> bytes:
488 """
489 Decrypt the given ``ciphertext`` using the long-nonces xchacha20poly1305
490 construction.
491
492 :param ciphertext: authenticated ciphertext
493 :type ciphertext: bytes
494 :param aad:
495 :type aad: Optional[bytes]
496 :param nonce:
497 :type nonce: bytes
498 :param key:
499 :type key: bytes
500 :return: message
501 :rtype: bytes
502 """
503 ensure(
504 isinstance(ciphertext, bytes),
505 "Input ciphertext type must be bytes",
506 raising=exc.TypeError,
507 )
508
509 clen = len(ciphertext)
510
511 ensure(
512 clen <= _aead_xchacha20poly1305_ietf_CRYPTBYTES_MAX,
513 f"Ciphertext must be at most {_aead_xchacha20poly1305_ietf_CRYPTBYTES_MAX} bytes long",
514 raising=exc.ValueError,
515 )
516
517 ensure(
518 isinstance(aad, bytes) or (aad is None),
519 "Additional data must be bytes or None",
520 raising=exc.TypeError,
521 )
522
523 ensure(
524 isinstance(nonce, bytes)
525 and len(nonce) == crypto_aead_xchacha20poly1305_ietf_NPUBBYTES,
526 f"Nonce must be a {crypto_aead_xchacha20poly1305_ietf_NPUBBYTES} bytes long bytes sequence",
527 raising=exc.TypeError,
528 )
529
530 ensure(
531 isinstance(key, bytes)
532 and len(key) == crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
533 f"Key must be a {crypto_aead_xchacha20poly1305_ietf_KEYBYTES} bytes long bytes sequence",
534 raising=exc.TypeError,
535 )
536
537 mxout = clen - crypto_aead_xchacha20poly1305_ietf_ABYTES
538 mlen = ffi.new("unsigned long long *")
539 message = ffi.new("unsigned char[]", mxout)
540
541 if aad:
542 _aad = aad
543 aalen = len(aad)
544 else:
545 _aad = ffi.NULL
546 aalen = 0
547
548 res = lib.crypto_aead_xchacha20poly1305_ietf_decrypt(
549 message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key
550 )
551
552 ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)
553
554 return ffi.buffer(message, mlen[0])[:]
555
556
557def crypto_aead_aegis256_encrypt(
558 message: bytes, aad: bytes | None, nonce: bytes, key: bytes
559) -> bytes:
560 """
561 Encrypt the given ``message`` using the AEGIS-256
562 construction.
563
564 :param message:
565 :type message: bytes
566 :param aad:
567 :type aad: Optional[bytes]
568 :param nonce:
569 :type nonce: bytes
570 :param key:
571 :type key: bytes
572 :return: authenticated ciphertext
573 :rtype: bytes
574 """
575 ensure(
576 isinstance(message, bytes),
577 "Input message type must be bytes",
578 raising=exc.TypeError,
579 )
580
581 mlen = len(message)
582
583 ensure(
584 mlen <= crypto_aead_aegis256_MESSAGEBYTES_MAX,
585 f"Message must be at most {crypto_aead_aegis256_MESSAGEBYTES_MAX} bytes long",
586 raising=exc.ValueError,
587 )
588
589 ensure(
590 isinstance(aad, bytes) or (aad is None),
591 "Additional data must be bytes or None",
592 raising=exc.TypeError,
593 )
594
595 ensure(
596 isinstance(nonce, bytes)
597 and len(nonce) == crypto_aead_aegis256_NPUBBYTES,
598 f"Nonce must be a {crypto_aead_aegis256_NPUBBYTES} bytes long bytes sequence",
599 raising=exc.TypeError,
600 )
601
602 ensure(
603 isinstance(key, bytes) and len(key) == crypto_aead_aegis256_KEYBYTES,
604 f"Key must be a {crypto_aead_aegis256_KEYBYTES} bytes long bytes sequence",
605 raising=exc.TypeError,
606 )
607
608 if aad:
609 _aad = aad
610 aalen = len(aad)
611 else:
612 _aad = ffi.NULL
613 aalen = 0
614
615 mxout = mlen + crypto_aead_aegis256_ABYTES
616
617 clen = ffi.new("unsigned long long *")
618
619 ciphertext = ffi.new("unsigned char[]", mxout)
620
621 res = lib.crypto_aead_aegis256_encrypt(
622 ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key
623 )
624
625 ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
626 return ffi.buffer(ciphertext, clen[0])[:]
627
628
629def crypto_aead_aegis256_decrypt(
630 ciphertext: bytes, aad: bytes | None, nonce: bytes, key: bytes
631) -> bytes:
632 """
633 Decrypt the given ``ciphertext`` using the AEGIS-256
634 construction.
635
636 :param ciphertext: authenticated ciphertext
637 :type ciphertext: bytes
638 :param aad:
639 :type aad: Optional[bytes]
640 :param nonce:
641 :type nonce: bytes
642 :param key:
643 :type key: bytes
644 :return: message
645 :rtype: bytes
646 """
647 ensure(
648 isinstance(ciphertext, bytes),
649 "Input ciphertext type must be bytes",
650 raising=exc.TypeError,
651 )
652
653 clen = len(ciphertext)
654
655 ensure(
656 clen <= _aead_aegis256_CRYPTBYTES_MAX,
657 f"Ciphertext must be at most {_aead_aegis256_CRYPTBYTES_MAX} bytes long",
658 raising=exc.ValueError,
659 )
660
661 ensure(
662 isinstance(aad, bytes) or (aad is None),
663 "Additional data must be bytes or None",
664 raising=exc.TypeError,
665 )
666
667 ensure(
668 isinstance(nonce, bytes)
669 and len(nonce) == crypto_aead_aegis256_NPUBBYTES,
670 f"Nonce must be a {crypto_aead_aegis256_NPUBBYTES} bytes long bytes sequence",
671 raising=exc.TypeError,
672 )
673
674 ensure(
675 isinstance(key, bytes) and len(key) == crypto_aead_aegis256_KEYBYTES,
676 f"Key must be a {crypto_aead_aegis256_KEYBYTES} bytes long bytes sequence",
677 raising=exc.TypeError,
678 )
679
680 mxout = clen - crypto_aead_aegis256_ABYTES
681 mlen = ffi.new("unsigned long long *")
682 message = ffi.new("unsigned char[]", mxout)
683
684 if aad:
685 _aad = aad
686 aalen = len(aad)
687 else:
688 _aad = ffi.NULL
689 aalen = 0
690
691 res = lib.crypto_aead_aegis256_decrypt(
692 message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key
693 )
694
695 ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)
696
697 return ffi.buffer(message, mlen[0])[:]
698
699
700def crypto_aead_aegis128l_encrypt(
701 message: bytes, aad: bytes | None, nonce: bytes, key: bytes
702) -> bytes:
703 """
704 Encrypt the given ``message`` using the AEGIS-128L
705 construction.
706
707 :param message:
708 :type message: bytes
709 :param aad:
710 :type aad: Optional[bytes]
711 :param nonce:
712 :type nonce: bytes
713 :param key:
714 :type key: bytes
715 :return: authenticated ciphertext
716 :rtype: bytes
717 """
718 ensure(
719 isinstance(message, bytes),
720 "Input message type must be bytes",
721 raising=exc.TypeError,
722 )
723
724 mlen = len(message)
725
726 ensure(
727 mlen <= crypto_aead_aegis128l_MESSAGEBYTES_MAX,
728 f"Message must be at most {crypto_aead_aegis128l_MESSAGEBYTES_MAX} bytes long",
729 raising=exc.ValueError,
730 )
731
732 ensure(
733 isinstance(aad, bytes) or (aad is None),
734 "Additional data must be bytes or None",
735 raising=exc.TypeError,
736 )
737
738 ensure(
739 isinstance(nonce, bytes)
740 and len(nonce) == crypto_aead_aegis128l_NPUBBYTES,
741 f"Nonce must be a {crypto_aead_aegis128l_NPUBBYTES} bytes long bytes sequence",
742 raising=exc.TypeError,
743 )
744
745 ensure(
746 isinstance(key, bytes) and len(key) == crypto_aead_aegis128l_KEYBYTES,
747 f"Key must be a {crypto_aead_aegis128l_KEYBYTES} bytes long bytes sequence",
748 raising=exc.TypeError,
749 )
750
751 if aad:
752 _aad = aad
753 aalen = len(aad)
754 else:
755 _aad = ffi.NULL
756 aalen = 0
757
758 mxout = mlen + crypto_aead_aegis128l_ABYTES
759
760 clen = ffi.new("unsigned long long *")
761
762 ciphertext = ffi.new("unsigned char[]", mxout)
763
764 res = lib.crypto_aead_aegis128l_encrypt(
765 ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key
766 )
767
768 ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
769 return ffi.buffer(ciphertext, clen[0])[:]
770
771
772def crypto_aead_aegis128l_decrypt(
773 ciphertext: bytes, aad: bytes | None, nonce: bytes, key: bytes
774) -> bytes:
775 """
776 Decrypt the given ``ciphertext`` using the AEGIS-128L
777 construction.
778
779 :param ciphertext: authenticated ciphertext
780 :type ciphertext: bytes
781 :param aad:
782 :type aad: Optional[bytes]
783 :param nonce:
784 :type nonce: bytes
785 :param key:
786 :type key: bytes
787 :return: message
788 :rtype: bytes
789 """
790 ensure(
791 isinstance(ciphertext, bytes),
792 "Input ciphertext type must be bytes",
793 raising=exc.TypeError,
794 )
795
796 clen = len(ciphertext)
797
798 ensure(
799 clen <= _aead_aegis256_CRYPTBYTES_MAX,
800 f"Ciphertext must be at most {_aead_aegis256_CRYPTBYTES_MAX} bytes long",
801 raising=exc.ValueError,
802 )
803
804 ensure(
805 isinstance(aad, bytes) or (aad is None),
806 "Additional data must be bytes or None",
807 raising=exc.TypeError,
808 )
809
810 ensure(
811 isinstance(nonce, bytes)
812 and len(nonce) == crypto_aead_aegis128l_NPUBBYTES,
813 f"Nonce must be a {crypto_aead_aegis128l_NPUBBYTES} bytes long bytes sequence",
814 raising=exc.TypeError,
815 )
816
817 ensure(
818 isinstance(key, bytes) and len(key) == crypto_aead_aegis128l_KEYBYTES,
819 f"Key must be a {crypto_aead_aegis128l_KEYBYTES} bytes long bytes sequence",
820 raising=exc.TypeError,
821 )
822
823 mxout = clen - crypto_aead_aegis128l_ABYTES
824 mlen = ffi.new("unsigned long long *")
825 message = ffi.new("unsigned char[]", mxout)
826
827 if aad:
828 _aad = aad
829 aalen = len(aad)
830 else:
831 _aad = ffi.NULL
832 aalen = 0
833
834 res = lib.crypto_aead_aegis128l_decrypt(
835 message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key
836 )
837
838 ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)
839
840 return ffi.buffer(message, mlen[0])[:]
841
842
843def crypto_aead_aes256gcm_encrypt(
844 message: bytes, aad: bytes | None, nonce: bytes, key: bytes
845) -> bytes:
846 """
847 Encrypt the given ``message`` using the AES-256-GCM
848 construction. Requires the Intel AES-NI extensions,
849 or the ARM Crypto extensions.
850
851 :param message:
852 :type message: bytes
853 :param aad:
854 :type aad: Optional[bytes]
855 :param nonce:
856 :type nonce: bytes
857 :param key:
858 :type key: bytes
859 :return: authenticated ciphertext
860 :rtype: bytes
861 """
862 ensure(
863 lib.crypto_aead_aes256gcm_is_available() == 1,
864 "Construction requires hardware acceleration",
865 raising=exc.UnavailableError,
866 )
867
868 ensure(
869 isinstance(message, bytes),
870 "Input message type must be bytes",
871 raising=exc.TypeError,
872 )
873
874 mlen = len(message)
875
876 ensure(
877 mlen <= crypto_aead_aes256gcm_MESSAGEBYTES_MAX,
878 f"Message must be at most {crypto_aead_aes256gcm_MESSAGEBYTES_MAX} bytes long",
879 raising=exc.ValueError,
880 )
881
882 ensure(
883 isinstance(aad, bytes) or (aad is None),
884 "Additional data must be bytes or None",
885 raising=exc.TypeError,
886 )
887
888 ensure(
889 isinstance(nonce, bytes)
890 and len(nonce) == crypto_aead_aes256gcm_NPUBBYTES,
891 f"Nonce must be a {crypto_aead_aes256gcm_NPUBBYTES} bytes long bytes sequence",
892 raising=exc.TypeError,
893 )
894
895 ensure(
896 isinstance(key, bytes) and len(key) == crypto_aead_aes256gcm_KEYBYTES,
897 f"Key must be a {crypto_aead_aes256gcm_KEYBYTES} bytes long bytes sequence",
898 raising=exc.TypeError,
899 )
900
901 if aad:
902 _aad = aad
903 aalen = len(aad)
904 else:
905 _aad = ffi.NULL
906 aalen = 0
907
908 mxout = mlen + crypto_aead_aes256gcm_ABYTES
909
910 clen = ffi.new("unsigned long long *")
911
912 ciphertext = ffi.new("unsigned char[]", mxout)
913
914 res = lib.crypto_aead_aes256gcm_encrypt(
915 ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key
916 )
917
918 ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
919 return ffi.buffer(ciphertext, clen[0])[:]
920
921
922def crypto_aead_aes256gcm_decrypt(
923 ciphertext: bytes, aad: bytes | None, nonce: bytes, key: bytes
924) -> bytes:
925 """
926 Decrypt the given ``ciphertext`` using the AES-256-GCM
927 construction. Requires the Intel AES-NI extensions,
928 or the ARM Crypto extensions.
929
930 :param ciphertext: authenticated ciphertext
931 :type ciphertext: bytes
932 :param aad:
933 :type aad: Optional[bytes]
934 :param nonce:
935 :type nonce: bytes
936 :param key:
937 :type key: bytes
938 :return: message
939 :rtype: bytes
940 """
941 ensure(
942 lib.crypto_aead_aes256gcm_is_available() == 1,
943 "Construction requires hardware acceleration",
944 raising=exc.UnavailableError,
945 )
946
947 ensure(
948 isinstance(ciphertext, bytes),
949 "Input ciphertext type must be bytes",
950 raising=exc.TypeError,
951 )
952
953 clen = len(ciphertext)
954
955 ensure(
956 clen <= _aead_aegis256_CRYPTBYTES_MAX,
957 f"Ciphertext must be at most {_aead_aegis256_CRYPTBYTES_MAX} bytes long",
958 raising=exc.ValueError,
959 )
960
961 ensure(
962 isinstance(aad, bytes) or (aad is None),
963 "Additional data must be bytes or None",
964 raising=exc.TypeError,
965 )
966
967 ensure(
968 isinstance(nonce, bytes)
969 and len(nonce) == crypto_aead_aes256gcm_NPUBBYTES,
970 f"Nonce must be a {crypto_aead_aes256gcm_NPUBBYTES} bytes long bytes sequence",
971 raising=exc.TypeError,
972 )
973
974 ensure(
975 isinstance(key, bytes) and len(key) == crypto_aead_aes256gcm_KEYBYTES,
976 f"Key must be a {crypto_aead_aes256gcm_KEYBYTES} bytes long bytes sequence",
977 raising=exc.TypeError,
978 )
979
980 mxout = clen - crypto_aead_aes256gcm_ABYTES
981 mlen = ffi.new("unsigned long long *")
982 message = ffi.new("unsigned char[]", mxout)
983
984 if aad:
985 _aad = aad
986 aalen = len(aad)
987 else:
988 _aad = ffi.NULL
989 aalen = 0
990
991 res = lib.crypto_aead_aes256gcm_decrypt(
992 message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key
993 )
994
995 ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)
996
997 return ffi.buffer(message, mlen[0])[:]