docrypt 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docrypt-0.1.0/PKG-INFO +21 -0
- docrypt-0.1.0/docrypt/__init__.py +296 -0
- docrypt-0.1.0/docrypt/aes.py +82 -0
- docrypt-0.1.0/docrypt/crunch.py +50 -0
- docrypt-0.1.0/docrypt/decrypt.py +32 -0
- docrypt-0.1.0/docrypt/dopo.py +68 -0
- docrypt-0.1.0/docrypt/light.py +71 -0
- docrypt-0.1.0/docrypt/m.py +56 -0
- docrypt-0.1.0/docrypt/maincrypt.py +23 -0
- docrypt-0.1.0/docrypt/max.py +59 -0
- docrypt-0.1.0/docrypt/much.py +65 -0
- docrypt-0.1.0/docrypt/mych.py +58 -0
- docrypt-0.1.0/docrypt/p.py +141 -0
- docrypt-0.1.0/docrypt/plus.py +61 -0
- docrypt-0.1.0/docrypt/rych.py +67 -0
- docrypt-0.1.0/docrypt/sha256.py +64 -0
- docrypt-0.1.0/docrypt/sha512.py +64 -0
- docrypt-0.1.0/docrypt/xor.py +41 -0
- docrypt-0.1.0/docrypt/z.py +60 -0
- docrypt-0.1.0/docrypt.egg-info/PKG-INFO +21 -0
- docrypt-0.1.0/docrypt.egg-info/SOURCES.txt +23 -0
- docrypt-0.1.0/docrypt.egg-info/dependency_links.txt +1 -0
- docrypt-0.1.0/docrypt.egg-info/top_level.txt +1 -0
- docrypt-0.1.0/pyproject.toml +47 -0
- docrypt-0.1.0/setup.cfg +4 -0
docrypt-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docrypt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Universal library for document encryption and secure storage
|
|
5
|
+
Author-email: vexikoff <vexikoff@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: crypto,encryption,decrypt,security,docrypt,files
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Security :: Cryptography
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Requires-Python: >=3.8
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
from .aes import (
|
|
2
|
+
decrypt_aes,
|
|
3
|
+
decrypt_aes_base64,
|
|
4
|
+
decrypt_aes_hex,
|
|
5
|
+
decrypt_aes_with_aad,
|
|
6
|
+
encrypt_aes,
|
|
7
|
+
encrypt_aes_base64,
|
|
8
|
+
encrypt_aes_hex,
|
|
9
|
+
encrypt_aes_with_aad,
|
|
10
|
+
generate_aes_key,
|
|
11
|
+
)
|
|
12
|
+
from .crunch import crunch_decrypt, crunch_encrypt, crunch_hash
|
|
13
|
+
from .decrypt import decrypt, decrypt_base64, decrypt_hex
|
|
14
|
+
from .dopo import (
|
|
15
|
+
decode_token,
|
|
16
|
+
describe_token,
|
|
17
|
+
encode_token,
|
|
18
|
+
pack_token,
|
|
19
|
+
token_length,
|
|
20
|
+
unpack_token,
|
|
21
|
+
)
|
|
22
|
+
from .light import (
|
|
23
|
+
light_crypt,
|
|
24
|
+
light_crypt_base64,
|
|
25
|
+
light_crypt_hex,
|
|
26
|
+
light_decrypt,
|
|
27
|
+
light_decrypt_base64,
|
|
28
|
+
light_decrypt_hex,
|
|
29
|
+
light_derive_key,
|
|
30
|
+
light_hash,
|
|
31
|
+
)
|
|
32
|
+
from .m import (
|
|
33
|
+
derive_key,
|
|
34
|
+
derive_key_base64,
|
|
35
|
+
derive_key_hex,
|
|
36
|
+
derive_key_with_info,
|
|
37
|
+
derive_two_keys,
|
|
38
|
+
merge_keys,
|
|
39
|
+
stretch_key,
|
|
40
|
+
stretch_key_hex,
|
|
41
|
+
)
|
|
42
|
+
from .maincrypt import crypt, crypt_base64, crypt_hex
|
|
43
|
+
from .max import (
|
|
44
|
+
max_crypt,
|
|
45
|
+
max_crypt_base64,
|
|
46
|
+
max_crypt_hex,
|
|
47
|
+
max_decrypt,
|
|
48
|
+
max_decrypt_base64,
|
|
49
|
+
max_decrypt_hex,
|
|
50
|
+
)
|
|
51
|
+
from .much import (
|
|
52
|
+
crypt_dict,
|
|
53
|
+
crypt_file,
|
|
54
|
+
crypt_file_hex,
|
|
55
|
+
crypt_many,
|
|
56
|
+
decrypt_dict,
|
|
57
|
+
decrypt_file,
|
|
58
|
+
decrypt_file_hex,
|
|
59
|
+
decrypt_many,
|
|
60
|
+
decrypt_many_str,
|
|
61
|
+
)
|
|
62
|
+
from .mych import (
|
|
63
|
+
mix_bytes,
|
|
64
|
+
mix_hex,
|
|
65
|
+
mix_keys,
|
|
66
|
+
mix_rounds,
|
|
67
|
+
unmix_bytes,
|
|
68
|
+
unmix_hex,
|
|
69
|
+
unmix_rounds,
|
|
70
|
+
)
|
|
71
|
+
from .p import (
|
|
72
|
+
chunk_bytes,
|
|
73
|
+
from_base32,
|
|
74
|
+
from_base64,
|
|
75
|
+
from_base64_url,
|
|
76
|
+
from_base85,
|
|
77
|
+
from_hex,
|
|
78
|
+
from_int,
|
|
79
|
+
join_bytes,
|
|
80
|
+
length_bytes,
|
|
81
|
+
pad_pkcs7,
|
|
82
|
+
repeat_bytes,
|
|
83
|
+
reverse_bytes,
|
|
84
|
+
split_bytes,
|
|
85
|
+
to_base32,
|
|
86
|
+
to_base64,
|
|
87
|
+
to_base64_url,
|
|
88
|
+
to_base85,
|
|
89
|
+
to_bytes,
|
|
90
|
+
to_hex,
|
|
91
|
+
to_int,
|
|
92
|
+
to_str,
|
|
93
|
+
unpad_pkcs7,
|
|
94
|
+
)
|
|
95
|
+
from .plus import (
|
|
96
|
+
crypt_and_sign,
|
|
97
|
+
decrypt_and_verify,
|
|
98
|
+
envelope_open,
|
|
99
|
+
envelope_seal,
|
|
100
|
+
sign_data,
|
|
101
|
+
sign_data_hex,
|
|
102
|
+
verify_signature,
|
|
103
|
+
)
|
|
104
|
+
from .rych import (
|
|
105
|
+
rych_crypt,
|
|
106
|
+
rych_crypt_hex,
|
|
107
|
+
rych_decrypt,
|
|
108
|
+
rych_decrypt_hex,
|
|
109
|
+
rych_derive,
|
|
110
|
+
rych_hash,
|
|
111
|
+
rych_mac,
|
|
112
|
+
)
|
|
113
|
+
from .sha256 import (
|
|
114
|
+
double_sha256,
|
|
115
|
+
double_sha256_bytes,
|
|
116
|
+
hash_sha256,
|
|
117
|
+
hash_sha256_bytes,
|
|
118
|
+
hmac_sha256,
|
|
119
|
+
hmac_sha256_bytes,
|
|
120
|
+
sha256_file,
|
|
121
|
+
sha256_rounds,
|
|
122
|
+
sha256_rounds_bytes,
|
|
123
|
+
verify_sha256,
|
|
124
|
+
)
|
|
125
|
+
from .sha512 import (
|
|
126
|
+
double_sha512,
|
|
127
|
+
double_sha512_bytes,
|
|
128
|
+
hash_sha512,
|
|
129
|
+
hash_sha512_bytes,
|
|
130
|
+
hmac_sha512,
|
|
131
|
+
hmac_sha512_bytes,
|
|
132
|
+
sha512_file,
|
|
133
|
+
sha512_rounds,
|
|
134
|
+
sha512_rounds_bytes,
|
|
135
|
+
verify_sha512,
|
|
136
|
+
)
|
|
137
|
+
from .xor import (
|
|
138
|
+
make_keystream,
|
|
139
|
+
xor_bytes,
|
|
140
|
+
xor_decrypt,
|
|
141
|
+
xor_decrypt_hex,
|
|
142
|
+
xor_encrypt,
|
|
143
|
+
xor_encrypt_hex,
|
|
144
|
+
)
|
|
145
|
+
from .z import (
|
|
146
|
+
generate_key,
|
|
147
|
+
generate_nonce,
|
|
148
|
+
generate_salt,
|
|
149
|
+
is_valid_key_length,
|
|
150
|
+
key_bit_length,
|
|
151
|
+
random_bytes,
|
|
152
|
+
random_hex,
|
|
153
|
+
random_int,
|
|
154
|
+
random_token,
|
|
155
|
+
secure_compare,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
__version__ = "1.1.0"
|
|
159
|
+
|
|
160
|
+
__all__ = [
|
|
161
|
+
"crypt",
|
|
162
|
+
"crypt_hex",
|
|
163
|
+
"crypt_base64",
|
|
164
|
+
"decrypt",
|
|
165
|
+
"decrypt_hex",
|
|
166
|
+
"decrypt_base64",
|
|
167
|
+
"encrypt_aes",
|
|
168
|
+
"decrypt_aes",
|
|
169
|
+
"encrypt_aes_hex",
|
|
170
|
+
"decrypt_aes_hex",
|
|
171
|
+
"encrypt_aes_base64",
|
|
172
|
+
"decrypt_aes_base64",
|
|
173
|
+
"encrypt_aes_with_aad",
|
|
174
|
+
"decrypt_aes_with_aad",
|
|
175
|
+
"generate_aes_key",
|
|
176
|
+
"crunch_encrypt",
|
|
177
|
+
"crunch_decrypt",
|
|
178
|
+
"crunch_hash",
|
|
179
|
+
"max_crypt",
|
|
180
|
+
"max_crypt_hex",
|
|
181
|
+
"max_crypt_base64",
|
|
182
|
+
"max_decrypt",
|
|
183
|
+
"max_decrypt_hex",
|
|
184
|
+
"max_decrypt_base64",
|
|
185
|
+
"light_crypt",
|
|
186
|
+
"light_crypt_hex",
|
|
187
|
+
"light_crypt_base64",
|
|
188
|
+
"light_decrypt",
|
|
189
|
+
"light_decrypt_hex",
|
|
190
|
+
"light_decrypt_base64",
|
|
191
|
+
"light_derive_key",
|
|
192
|
+
"light_hash",
|
|
193
|
+
"rych_crypt",
|
|
194
|
+
"rych_crypt_hex",
|
|
195
|
+
"rych_decrypt",
|
|
196
|
+
"rych_decrypt_hex",
|
|
197
|
+
"rych_derive",
|
|
198
|
+
"rych_hash",
|
|
199
|
+
"rych_mac",
|
|
200
|
+
"xor_encrypt",
|
|
201
|
+
"xor_decrypt",
|
|
202
|
+
"xor_encrypt_hex",
|
|
203
|
+
"xor_decrypt_hex",
|
|
204
|
+
"xor_bytes",
|
|
205
|
+
"make_keystream",
|
|
206
|
+
"mix_bytes",
|
|
207
|
+
"unmix_bytes",
|
|
208
|
+
"mix_hex",
|
|
209
|
+
"unmix_hex",
|
|
210
|
+
"mix_rounds",
|
|
211
|
+
"unmix_rounds",
|
|
212
|
+
"mix_keys",
|
|
213
|
+
"sign_data",
|
|
214
|
+
"sign_data_hex",
|
|
215
|
+
"verify_signature",
|
|
216
|
+
"crypt_and_sign",
|
|
217
|
+
"decrypt_and_verify",
|
|
218
|
+
"envelope_seal",
|
|
219
|
+
"envelope_open",
|
|
220
|
+
"crypt_many",
|
|
221
|
+
"decrypt_many",
|
|
222
|
+
"decrypt_many_str",
|
|
223
|
+
"crypt_dict",
|
|
224
|
+
"decrypt_dict",
|
|
225
|
+
"crypt_file",
|
|
226
|
+
"decrypt_file",
|
|
227
|
+
"crypt_file_hex",
|
|
228
|
+
"decrypt_file_hex",
|
|
229
|
+
"pack_token",
|
|
230
|
+
"unpack_token",
|
|
231
|
+
"encode_token",
|
|
232
|
+
"decode_token",
|
|
233
|
+
"token_length",
|
|
234
|
+
"describe_token",
|
|
235
|
+
"merge_keys",
|
|
236
|
+
"derive_key",
|
|
237
|
+
"derive_key_hex",
|
|
238
|
+
"derive_key_base64",
|
|
239
|
+
"derive_key_with_info",
|
|
240
|
+
"derive_two_keys",
|
|
241
|
+
"stretch_key",
|
|
242
|
+
"stretch_key_hex",
|
|
243
|
+
"hash_sha256",
|
|
244
|
+
"hash_sha256_bytes",
|
|
245
|
+
"hmac_sha256",
|
|
246
|
+
"hmac_sha256_bytes",
|
|
247
|
+
"double_sha256",
|
|
248
|
+
"double_sha256_bytes",
|
|
249
|
+
"sha256_rounds",
|
|
250
|
+
"sha256_rounds_bytes",
|
|
251
|
+
"sha256_file",
|
|
252
|
+
"verify_sha256",
|
|
253
|
+
"hash_sha512",
|
|
254
|
+
"hash_sha512_bytes",
|
|
255
|
+
"hmac_sha512",
|
|
256
|
+
"hmac_sha512_bytes",
|
|
257
|
+
"double_sha512",
|
|
258
|
+
"double_sha512_bytes",
|
|
259
|
+
"sha512_rounds",
|
|
260
|
+
"sha512_rounds_bytes",
|
|
261
|
+
"sha512_file",
|
|
262
|
+
"verify_sha512",
|
|
263
|
+
"to_bytes",
|
|
264
|
+
"to_str",
|
|
265
|
+
"to_hex",
|
|
266
|
+
"from_hex",
|
|
267
|
+
"to_base64",
|
|
268
|
+
"from_base64",
|
|
269
|
+
"to_base64_url",
|
|
270
|
+
"from_base64_url",
|
|
271
|
+
"to_base32",
|
|
272
|
+
"from_base32",
|
|
273
|
+
"to_base85",
|
|
274
|
+
"from_base85",
|
|
275
|
+
"to_int",
|
|
276
|
+
"from_int",
|
|
277
|
+
"pad_pkcs7",
|
|
278
|
+
"unpad_pkcs7",
|
|
279
|
+
"chunk_bytes",
|
|
280
|
+
"join_bytes",
|
|
281
|
+
"split_bytes",
|
|
282
|
+
"reverse_bytes",
|
|
283
|
+
"repeat_bytes",
|
|
284
|
+
"length_bytes",
|
|
285
|
+
"random_bytes",
|
|
286
|
+
"random_hex",
|
|
287
|
+
"random_int",
|
|
288
|
+
"random_token",
|
|
289
|
+
"generate_key",
|
|
290
|
+
"generate_salt",
|
|
291
|
+
"generate_nonce",
|
|
292
|
+
"secure_compare",
|
|
293
|
+
"is_valid_key_length",
|
|
294
|
+
"key_bit_length",
|
|
295
|
+
"__version__",
|
|
296
|
+
]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from cryptography.exceptions import InvalidTag
|
|
2
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
3
|
+
|
|
4
|
+
from .p import from_base64, from_hex, to_base64, to_bytes, to_hex
|
|
5
|
+
from .z import random_bytes
|
|
6
|
+
|
|
7
|
+
NONCE_SIZE = 12
|
|
8
|
+
TAG_SIZE = 16
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def generate_aes_key(bits=256):
|
|
12
|
+
if bits not in (128, 192, 256):
|
|
13
|
+
raise ValueError("bits must be 128, 192 or 256")
|
|
14
|
+
return AESGCM.generate_key(bit_length=bits)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def encrypt_aes(data, key):
|
|
18
|
+
raw = to_bytes(data)
|
|
19
|
+
key = to_bytes(key)
|
|
20
|
+
if len(key) not in (16, 24, 32):
|
|
21
|
+
raise ValueError("aes key must be 16, 24 or 32 bytes")
|
|
22
|
+
nonce = random_bytes(NONCE_SIZE)
|
|
23
|
+
cipher = AESGCM(key)
|
|
24
|
+
return nonce + cipher.encrypt(nonce, raw, None)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def decrypt_aes(data, key):
|
|
28
|
+
token = to_bytes(data)
|
|
29
|
+
key = to_bytes(key)
|
|
30
|
+
if len(key) not in (16, 24, 32):
|
|
31
|
+
raise ValueError("aes key must be 16, 24 or 32 bytes")
|
|
32
|
+
if len(token) < NONCE_SIZE + TAG_SIZE:
|
|
33
|
+
raise ValueError("invalid token size")
|
|
34
|
+
nonce = token[:NONCE_SIZE]
|
|
35
|
+
ciphertext = token[NONCE_SIZE:]
|
|
36
|
+
cipher = AESGCM(key)
|
|
37
|
+
try:
|
|
38
|
+
return cipher.decrypt(nonce, ciphertext, None)
|
|
39
|
+
except InvalidTag:
|
|
40
|
+
raise ValueError("decryption failed, invalid key or corrupted data")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def encrypt_aes_hex(data, key):
|
|
44
|
+
return to_hex(encrypt_aes(data, key))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def decrypt_aes_hex(data, key):
|
|
48
|
+
return decrypt_aes(from_hex(data), key)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def encrypt_aes_base64(data, key):
|
|
52
|
+
return to_base64(encrypt_aes(data, key))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def decrypt_aes_base64(data, key):
|
|
56
|
+
return decrypt_aes(from_base64(data), key)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def encrypt_aes_with_aad(data, key, aad):
|
|
60
|
+
raw = to_bytes(data)
|
|
61
|
+
key = to_bytes(key)
|
|
62
|
+
if len(key) not in (16, 24, 32):
|
|
63
|
+
raise ValueError("aes key must be 16, 24 or 32 bytes")
|
|
64
|
+
nonce = random_bytes(NONCE_SIZE)
|
|
65
|
+
cipher = AESGCM(key)
|
|
66
|
+
return nonce + cipher.encrypt(nonce, raw, to_bytes(aad))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def decrypt_aes_with_aad(data, key, aad):
|
|
70
|
+
token = to_bytes(data)
|
|
71
|
+
key = to_bytes(key)
|
|
72
|
+
if len(key) not in (16, 24, 32):
|
|
73
|
+
raise ValueError("aes key must be 16, 24 or 32 bytes")
|
|
74
|
+
if len(token) < NONCE_SIZE + TAG_SIZE:
|
|
75
|
+
raise ValueError("invalid token size")
|
|
76
|
+
nonce = token[:NONCE_SIZE]
|
|
77
|
+
ciphertext = token[NONCE_SIZE:]
|
|
78
|
+
cipher = AESGCM(key)
|
|
79
|
+
try:
|
|
80
|
+
return cipher.decrypt(nonce, ciphertext, to_bytes(aad))
|
|
81
|
+
except InvalidTag:
|
|
82
|
+
raise ValueError("decryption failed, invalid key or corrupted data")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from .aes import decrypt_aes, encrypt_aes
|
|
2
|
+
from .m import derive_key
|
|
3
|
+
from .p import to_bytes
|
|
4
|
+
from .sha512 import hash_sha512_bytes
|
|
5
|
+
from .xor import xor_encrypt
|
|
6
|
+
from .z import secure_compare
|
|
7
|
+
|
|
8
|
+
DIGEST_SIZE = 64
|
|
9
|
+
DEFAULT_ROUNDS = 3
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def crunch_encrypt(main, *keys, rounds=DEFAULT_ROUNDS):
|
|
13
|
+
if not keys:
|
|
14
|
+
raise ValueError("at least one key is required")
|
|
15
|
+
if not isinstance(rounds, int) or rounds < 1 or rounds > 255:
|
|
16
|
+
raise ValueError("rounds must be between 1 and 255")
|
|
17
|
+
data = to_bytes(main)
|
|
18
|
+
for index in range(rounds):
|
|
19
|
+
xor_key = derive_key(*keys, info=b"docrypt-crunch-xor-" + bytes([index]))
|
|
20
|
+
enc_key = derive_key(*keys, info=b"docrypt-crunch-enc-" + bytes([index]))
|
|
21
|
+
data = encrypt_aes(xor_encrypt(data, xor_key), enc_key)
|
|
22
|
+
return bytes([rounds]) + data + hash_sha512_bytes(data)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def crunch_decrypt(main, *keys):
|
|
26
|
+
if not keys:
|
|
27
|
+
raise ValueError("at least one key is required")
|
|
28
|
+
token = to_bytes(main)
|
|
29
|
+
if len(token) < 1 + DIGEST_SIZE + 12 + 16:
|
|
30
|
+
raise ValueError("invalid token size")
|
|
31
|
+
rounds = token[0]
|
|
32
|
+
body = token[1:-DIGEST_SIZE]
|
|
33
|
+
digest = token[-DIGEST_SIZE:]
|
|
34
|
+
if not secure_compare(hash_sha512_bytes(body), digest):
|
|
35
|
+
raise ValueError("integrity check failed, data is corrupted")
|
|
36
|
+
data = body
|
|
37
|
+
for index in range(rounds - 1, -1, -1):
|
|
38
|
+
xor_key = derive_key(*keys, info=b"docrypt-crunch-xor-" + bytes([index]))
|
|
39
|
+
enc_key = derive_key(*keys, info=b"docrypt-crunch-enc-" + bytes([index]))
|
|
40
|
+
data = xor_encrypt(decrypt_aes(data, enc_key), xor_key)
|
|
41
|
+
return data
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def crunch_hash(data, rounds=1000):
|
|
45
|
+
if rounds < 1:
|
|
46
|
+
raise ValueError("rounds must be at least 1")
|
|
47
|
+
digest = hash_sha512_bytes(data)
|
|
48
|
+
for _ in range(rounds - 1):
|
|
49
|
+
digest = hash_sha512_bytes(digest)
|
|
50
|
+
return digest.hex()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from .aes import decrypt_aes
|
|
2
|
+
from .m import derive_key
|
|
3
|
+
from .p import from_base64, from_hex, to_bytes
|
|
4
|
+
from .sha512 import hash_sha512_bytes
|
|
5
|
+
from .z import secure_compare
|
|
6
|
+
|
|
7
|
+
DIGEST_SIZE = 64
|
|
8
|
+
NONCE_SIZE = 12
|
|
9
|
+
TAG_SIZE = 16
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def decrypt(main, *keys):
|
|
13
|
+
if not keys:
|
|
14
|
+
raise ValueError("at least one key is required")
|
|
15
|
+
token = to_bytes(main)
|
|
16
|
+
if len(token) < DIGEST_SIZE + NONCE_SIZE + TAG_SIZE:
|
|
17
|
+
raise ValueError("invalid token size")
|
|
18
|
+
payload = token[:-DIGEST_SIZE]
|
|
19
|
+
digest = token[-DIGEST_SIZE:]
|
|
20
|
+
expected = hash_sha512_bytes(payload)
|
|
21
|
+
if not secure_compare(expected, digest):
|
|
22
|
+
raise ValueError("integrity check failed, data is corrupted")
|
|
23
|
+
key = derive_key(*keys)
|
|
24
|
+
return decrypt_aes(payload, key)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def decrypt_hex(main, *keys):
|
|
28
|
+
return decrypt(from_hex(main), *keys)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def decrypt_base64(main, *keys):
|
|
32
|
+
return decrypt(from_base64(main), *keys)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from .p import (
|
|
2
|
+
from_base32,
|
|
3
|
+
from_base64,
|
|
4
|
+
from_base64_url,
|
|
5
|
+
from_base85,
|
|
6
|
+
from_hex,
|
|
7
|
+
to_base32,
|
|
8
|
+
to_base64,
|
|
9
|
+
to_base64_url,
|
|
10
|
+
to_base85,
|
|
11
|
+
to_bytes,
|
|
12
|
+
to_hex,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
TOKEN_PREFIX = b"DC1"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def pack_token(token):
|
|
19
|
+
return TOKEN_PREFIX + to_bytes(token)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def unpack_token(token):
|
|
23
|
+
raw = to_bytes(token)
|
|
24
|
+
if not raw.startswith(TOKEN_PREFIX):
|
|
25
|
+
raise ValueError("unknown token prefix")
|
|
26
|
+
return raw[len(TOKEN_PREFIX):]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def encode_token(token, encoding):
|
|
30
|
+
raw = to_bytes(token)
|
|
31
|
+
if encoding == "hex":
|
|
32
|
+
return to_hex(raw)
|
|
33
|
+
if encoding == "base64":
|
|
34
|
+
return to_base64(raw)
|
|
35
|
+
if encoding == "base64url":
|
|
36
|
+
return to_base64_url(raw)
|
|
37
|
+
if encoding == "base32":
|
|
38
|
+
return to_base32(raw)
|
|
39
|
+
if encoding == "base85":
|
|
40
|
+
return to_base85(raw)
|
|
41
|
+
raise ValueError("unsupported encoding")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def decode_token(token, encoding):
|
|
45
|
+
if encoding == "hex":
|
|
46
|
+
return from_hex(token)
|
|
47
|
+
if encoding == "base64":
|
|
48
|
+
return from_base64(token)
|
|
49
|
+
if encoding == "base64url":
|
|
50
|
+
return from_base64_url(token)
|
|
51
|
+
if encoding == "base32":
|
|
52
|
+
return from_base32(token)
|
|
53
|
+
if encoding == "base85":
|
|
54
|
+
return from_base85(token)
|
|
55
|
+
raise ValueError("unsupported encoding")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def token_length(token):
|
|
59
|
+
return len(to_bytes(token))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def describe_token(token):
|
|
63
|
+
raw = to_bytes(token)
|
|
64
|
+
return {
|
|
65
|
+
"length": len(raw),
|
|
66
|
+
"hex_head": raw[:16].hex(),
|
|
67
|
+
"has_prefix": raw.startswith(TOKEN_PREFIX),
|
|
68
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import hmac as hmac_module
|
|
3
|
+
import secrets
|
|
4
|
+
|
|
5
|
+
from .p import from_base64, from_hex, to_base64, to_bytes, to_hex
|
|
6
|
+
|
|
7
|
+
DIGEST_SIZE = 64
|
|
8
|
+
NONCE_SIZE = 12
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def light_derive_key(*keys):
|
|
12
|
+
if not keys:
|
|
13
|
+
raise ValueError("at least one key is required")
|
|
14
|
+
parts = [hashlib.sha512(to_bytes(item)).digest() for item in keys]
|
|
15
|
+
return hashlib.sha512(b"".join(parts)).digest()[:32]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def light_keystream(key, length):
|
|
19
|
+
if length <= 0:
|
|
20
|
+
raise ValueError("length must be positive")
|
|
21
|
+
stream = bytearray()
|
|
22
|
+
counter = 0
|
|
23
|
+
while len(stream) < length:
|
|
24
|
+
stream.extend(hmac_module.new(key, counter.to_bytes(8, "big"), hashlib.sha512).digest())
|
|
25
|
+
counter += 1
|
|
26
|
+
return bytes(stream[:length])
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def light_crypt(main, *keys):
|
|
30
|
+
key = light_derive_key(*keys)
|
|
31
|
+
raw = to_bytes(main)
|
|
32
|
+
nonce = secrets.token_bytes(NONCE_SIZE)
|
|
33
|
+
stream = light_keystream(key + nonce, len(raw))
|
|
34
|
+
ciphertext = bytes(a ^ b for a, b in zip(raw, stream))
|
|
35
|
+
body = nonce + ciphertext
|
|
36
|
+
return body + hmac_module.new(key, body, hashlib.sha512).digest()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def light_decrypt(main, *keys):
|
|
40
|
+
key = light_derive_key(*keys)
|
|
41
|
+
token = to_bytes(main)
|
|
42
|
+
if len(token) < NONCE_SIZE + DIGEST_SIZE:
|
|
43
|
+
raise ValueError("invalid token size")
|
|
44
|
+
body = token[:-DIGEST_SIZE]
|
|
45
|
+
digest = token[-DIGEST_SIZE:]
|
|
46
|
+
if not hmac_module.compare_digest(hmac_module.new(key, body, hashlib.sha512).digest(), digest):
|
|
47
|
+
raise ValueError("decryption failed, invalid key or corrupted data")
|
|
48
|
+
nonce = body[:NONCE_SIZE]
|
|
49
|
+
ciphertext = body[NONCE_SIZE:]
|
|
50
|
+
stream = light_keystream(key + nonce, len(ciphertext))
|
|
51
|
+
return bytes(a ^ b for a, b in zip(ciphertext, stream))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def light_crypt_hex(main, *keys):
|
|
55
|
+
return to_hex(light_crypt(main, *keys))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def light_decrypt_hex(main, *keys):
|
|
59
|
+
return light_decrypt(from_hex(main), *keys)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def light_crypt_base64(main, *keys):
|
|
63
|
+
return to_base64(light_crypt(main, *keys))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def light_decrypt_base64(main, *keys):
|
|
67
|
+
return light_decrypt(from_base64(main), *keys)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def light_hash(data):
|
|
71
|
+
return hashlib.sha512(to_bytes(data)).hexdigest()
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
|
|
3
|
+
from cryptography.hazmat.primitives import hashes
|
|
4
|
+
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|
5
|
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
6
|
+
|
|
7
|
+
from .p import to_base64, to_bytes, to_hex
|
|
8
|
+
|
|
9
|
+
DERIVE_INFO = b"docrypt-aes-256-key"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def merge_keys(*keys):
|
|
13
|
+
if not keys:
|
|
14
|
+
raise ValueError("at least one key is required")
|
|
15
|
+
parts = []
|
|
16
|
+
for item in keys:
|
|
17
|
+
parts.append(hashlib.sha512(to_bytes(item)).digest())
|
|
18
|
+
return hashlib.sha512(b"".join(parts)).digest()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def derive_key(*keys, length=32, info=DERIVE_INFO):
|
|
22
|
+
if length not in (16, 24, 32):
|
|
23
|
+
raise ValueError("key length must be 16, 24 or 32 bytes")
|
|
24
|
+
material = merge_keys(*keys)
|
|
25
|
+
hkdf = HKDF(algorithm=hashes.SHA512(), length=length, salt=None, info=to_bytes(info))
|
|
26
|
+
return hkdf.derive(material)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def derive_key_hex(*keys, length=32, info=DERIVE_INFO):
|
|
30
|
+
return to_hex(derive_key(*keys, length=length, info=info))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def derive_key_base64(*keys, length=32, info=DERIVE_INFO):
|
|
34
|
+
return to_base64(derive_key(*keys, length=length, info=info))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def derive_key_with_info(*keys, info, length=32):
|
|
38
|
+
return derive_key(*keys, length=length, info=info)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def derive_two_keys(*keys):
|
|
42
|
+
material = merge_keys(*keys)
|
|
43
|
+
hkdf = HKDF(algorithm=hashes.SHA512(), length=64, salt=None, info=DERIVE_INFO)
|
|
44
|
+
block = hkdf.derive(material)
|
|
45
|
+
return block[:32], block[32:]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def stretch_key(password, salt, iterations=100000, length=32):
|
|
49
|
+
if length not in (16, 24, 32):
|
|
50
|
+
raise ValueError("key length must be 16, 24 or 32 bytes")
|
|
51
|
+
kdf = PBKDF2HMAC(algorithm=hashes.SHA512(), length=length, salt=to_bytes(salt), iterations=iterations)
|
|
52
|
+
return kdf.derive(to_bytes(password))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def stretch_key_hex(password, salt, iterations=100000, length=32):
|
|
56
|
+
return to_hex(stretch_key(password, salt, iterations=iterations, length=length))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .aes import encrypt_aes
|
|
2
|
+
from .m import derive_key
|
|
3
|
+
from .p import to_base64, to_hex
|
|
4
|
+
from .sha512 import hash_sha512_bytes
|
|
5
|
+
|
|
6
|
+
DIGEST_SIZE = 64
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def crypt(main, *keys):
|
|
10
|
+
if not keys:
|
|
11
|
+
raise ValueError("at least one key is required")
|
|
12
|
+
key = derive_key(*keys)
|
|
13
|
+
payload = encrypt_aes(main, key)
|
|
14
|
+
digest = hash_sha512_bytes(payload)
|
|
15
|
+
return payload + digest
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def crypt_hex(main, *keys):
|
|
19
|
+
return to_hex(crypt(main, *keys))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def crypt_base64(main, *keys):
|
|
23
|
+
return to_base64(crypt(main, *keys))
|