|
20 | 20 |
|
21 | 21 | """Chacha20-Poly1305 symmetric encryption handler""" |
22 | 22 |
|
23 | | -from ctypes import c_ulonglong, create_string_buffer |
24 | 23 | from typing import Optional, Tuple |
25 | 24 |
|
26 | 25 | from cryptography.exceptions import InvalidSignature |
|
32 | 31 | from .cipher import register_cipher |
33 | 32 |
|
34 | 33 |
|
35 | | -if backend.poly1305_supported(): |
36 | | - _CTR_0 = (0).to_bytes(8, 'little') |
37 | | - _CTR_1 = (1).to_bytes(8, 'little') |
| 34 | +chacha_available = backend.poly1305_supported() |
38 | 35 |
|
39 | | - _POLY1305_KEYBYTES = 32 |
40 | 36 |
|
41 | | - def chacha20(key: bytes, data: bytes, nonce: bytes, ctr: int) -> bytes: |
42 | | - """Encrypt/decrypt a block of data with the ChaCha20 cipher""" |
| 37 | +_CTR_0 = (0).to_bytes(8, 'little') |
| 38 | +_CTR_1 = (1).to_bytes(8, 'little') |
43 | 39 |
|
44 | | - return Cipher(ChaCha20(key, (_CTR_1 if ctr else _CTR_0) + nonce), |
45 | | - mode=None).encryptor().update(data) |
| 40 | +_POLY1305_KEYBYTES = 32 |
46 | 41 |
|
47 | | - def poly1305_key(key: bytes, nonce: bytes) -> bytes: |
48 | | - """Derive a Poly1305 key""" |
| 42 | +def chacha20(key: bytes, data: bytes, nonce: bytes, ctr: int) -> bytes: |
| 43 | + """Encrypt/decrypt a block of data with the ChaCha20 cipher""" |
49 | 44 |
|
50 | | - return chacha20(key, _POLY1305_KEYBYTES * b'\0', nonce, 0) |
| 45 | + return Cipher(ChaCha20(key, (_CTR_1 if ctr else _CTR_0) + nonce), |
| 46 | + mode=None).encryptor().update(data) |
51 | 47 |
|
52 | | - def poly1305(key: bytes, data: bytes, nonce: bytes) -> bytes: |
53 | | - """Compute a Poly1305 tag for a block of data""" |
| 48 | +def poly1305_key(key: bytes, nonce: bytes) -> bytes: |
| 49 | + """Derive a Poly1305 key""" |
54 | 50 |
|
55 | | - return Poly1305.generate_tag(poly1305_key(key, nonce), data) |
| 51 | + return chacha20(key, _POLY1305_KEYBYTES * b'\0', nonce, 0) |
56 | 52 |
|
57 | | - def poly1305_verify(key: bytes, data: bytes, |
58 | | - nonce: bytes, tag: bytes) -> bool: |
59 | | - """Verify a Poly1305 tag for a block of data""" |
| 53 | +def poly1305(key: bytes, data: bytes, nonce: bytes) -> bytes: |
| 54 | + """Compute a Poly1305 tag for a block of data""" |
60 | 55 |
|
61 | | - try: |
62 | | - Poly1305.verify_tag(poly1305_key(key, nonce), data, tag) |
63 | | - return True |
64 | | - except InvalidSignature: |
65 | | - return False |
| 56 | + return Poly1305.generate_tag(poly1305_key(key, nonce), data) |
66 | 57 |
|
67 | | - chacha_available = True |
68 | | -else: # pragma: no cover |
69 | | - try: |
70 | | - from libnacl import nacl |
71 | | - |
72 | | - _chacha20 = nacl.crypto_stream_chacha20 |
73 | | - _chacha20_xor_ic = nacl.crypto_stream_chacha20_xor_ic |
74 | | - |
75 | | - _POLY1305_BYTES = nacl.crypto_onetimeauth_poly1305_bytes() |
76 | | - _POLY1305_KEYBYTES = nacl.crypto_onetimeauth_poly1305_keybytes() |
77 | | - |
78 | | - _poly1305 = nacl.crypto_onetimeauth_poly1305 |
79 | | - _poly1305_verify = nacl.crypto_onetimeauth_poly1305_verify |
80 | | - |
81 | | - def chacha20(key: bytes, data: bytes, nonce: bytes, ctr: int) -> bytes: |
82 | | - """Encrypt/decrypt a block of data with the ChaCha20 cipher""" |
83 | | - |
84 | | - datalen = len(data) |
85 | | - result = create_string_buffer(datalen) |
86 | | - ull_datalen = c_ulonglong(datalen) |
87 | | - ull_ctr = c_ulonglong(ctr) |
88 | | - |
89 | | - _chacha20_xor_ic(result, data, ull_datalen, nonce, ull_ctr, key) |
90 | | - |
91 | | - return result.raw |
92 | | - |
93 | | - def poly1305_key(key: bytes, nonce: bytes) -> bytes: |
94 | | - """Derive a Poly1305 key""" |
95 | | - |
96 | | - polykey = create_string_buffer(_POLY1305_KEYBYTES) |
97 | | - ull_polykeylen = c_ulonglong(_POLY1305_KEYBYTES) |
| 58 | +def poly1305_verify(key: bytes, data: bytes, |
| 59 | + nonce: bytes, tag: bytes) -> bool: |
| 60 | + """Verify a Poly1305 tag for a block of data""" |
98 | 61 |
|
99 | | - _chacha20(polykey, ull_polykeylen, nonce, key) |
100 | | - |
101 | | - return polykey.raw |
102 | | - |
103 | | - def poly1305(key: bytes, data: bytes, nonce: bytes) -> bytes: |
104 | | - """Compute a Poly1305 tag for a block of data""" |
105 | | - |
106 | | - tag = create_string_buffer(_POLY1305_BYTES) |
107 | | - ull_datalen = c_ulonglong(len(data)) |
108 | | - polykey = poly1305_key(key, nonce) |
109 | | - |
110 | | - _poly1305(tag, data, ull_datalen, polykey) |
111 | | - |
112 | | - return tag.raw |
113 | | - |
114 | | - def poly1305_verify(key: bytes, data: bytes, |
115 | | - nonce: bytes, tag: bytes) -> bool: |
116 | | - """Verify a Poly1305 tag for a block of data""" |
117 | | - |
118 | | - ull_datalen = c_ulonglong(len(data)) |
119 | | - polykey = poly1305_key(key, nonce) |
120 | | - |
121 | | - return _poly1305_verify(tag, data, ull_datalen, polykey) == 0 |
122 | | - |
123 | | - chacha_available = True |
124 | | - except (ImportError, OSError, AttributeError): |
125 | | - chacha_available = False |
| 62 | + try: |
| 63 | + Poly1305.verify_tag(poly1305_key(key, nonce), data, tag) |
| 64 | + return True |
| 65 | + except InvalidSignature: |
| 66 | + return False |
126 | 67 |
|
127 | 68 |
|
128 | 69 | class ChachaCipher: |
|
0 commit comments