SwiftGUI_Encryption 0.0.2__tar.gz → 0.0.4__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.
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/PKG-INFO +1 -1
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/pyproject.toml +1 -1
- swiftgui_encryption-0.0.4/src/SwiftGUI_Encryption/__init__.py +14 -0
- swiftgui_encryption-0.0.4/src/SwiftGUI_Encryption/basics.py +85 -0
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/src/SwiftGUI_Encryption/key_files.py +1 -1
- swiftgui_encryption-0.0.4/src/SwiftGUI_Encryption/sg/__init__.py +5 -0
- swiftgui_encryption-0.0.4/src/SwiftGUI_Encryption/sg/dictFile.py +164 -0
- swiftgui_encryption-0.0.4/src/SwiftGUI_Encryption/sg/popup_create_password.py +168 -0
- swiftgui_encryption-0.0.2/src/SwiftGUI_Encryption/__init__.py +0 -5
- swiftgui_encryption-0.0.2/src/SwiftGUI_Encryption/basics.py +0 -35
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/LICENSE +0 -0
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/README.md +0 -0
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/src/SwiftGUI_Encryption/Advanced/__init__.py +0 -0
- {swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/src/SwiftGUI_Encryption/Advanced/low_level.py +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
from . import Advanced
|
|
3
|
+
random_key = Advanced.random_key
|
|
4
|
+
|
|
5
|
+
from .basics import decrypt_full, encrypt_full, encrypt_with_password, decrypt_with_password, password_to_key
|
|
6
|
+
from .key_files import KeyFile, KeyHandler, BaseKeyFile
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import SwiftGUI
|
|
10
|
+
except ImportError:
|
|
11
|
+
...
|
|
12
|
+
else:
|
|
13
|
+
from . import sg
|
|
14
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import argon2pure
|
|
2
|
+
from Crypto.Cipher import AES
|
|
3
|
+
import os
|
|
4
|
+
import hashlib
|
|
5
|
+
|
|
6
|
+
from SwiftGUI_Encryption import Advanced as adv
|
|
7
|
+
|
|
8
|
+
# This should not be chanced, it just doesn't feel right to add magic numbers...
|
|
9
|
+
NONCE_LEN = 32
|
|
10
|
+
SALT_LEN = 16
|
|
11
|
+
|
|
12
|
+
def encrypt_full(data: bytes, key: bytes) -> bytes:
|
|
13
|
+
"""
|
|
14
|
+
Encrypt some data
|
|
15
|
+
|
|
16
|
+
:param key:
|
|
17
|
+
:param data:
|
|
18
|
+
:return:
|
|
19
|
+
"""
|
|
20
|
+
nonce = adv.random_key(NONCE_LEN)
|
|
21
|
+
|
|
22
|
+
return nonce + adv.encrypt(data, key, nonce)
|
|
23
|
+
|
|
24
|
+
def decrypt_full(data: bytes, key: bytes) -> bytes:
|
|
25
|
+
"""
|
|
26
|
+
Decrypt some data with its key
|
|
27
|
+
|
|
28
|
+
:param data:
|
|
29
|
+
:param key:
|
|
30
|
+
:return:
|
|
31
|
+
"""
|
|
32
|
+
nonce = data[:NONCE_LEN]
|
|
33
|
+
data = data[NONCE_LEN:]
|
|
34
|
+
|
|
35
|
+
return adv.decrypt(data, key, nonce)
|
|
36
|
+
|
|
37
|
+
def encrypt_with_password(data: bytes, password: str, security_multiplier: int = 1) -> bytes:
|
|
38
|
+
"""
|
|
39
|
+
IMPORTANT:
|
|
40
|
+
This needs to be decrypted with decrypt_with_password.
|
|
41
|
+
It is not compatible with decrypt_full.
|
|
42
|
+
|
|
43
|
+
But this function is very secure, because each encryption generates its own key.
|
|
44
|
+
|
|
45
|
+
:param data: What to encrypt
|
|
46
|
+
:param password:
|
|
47
|
+
:param security_multiplier:
|
|
48
|
+
:return:
|
|
49
|
+
"""
|
|
50
|
+
salt = adv.random_key(SALT_LEN)
|
|
51
|
+
key = adv.argon2_key_derivation(password.encode(), salt, multiplier=security_multiplier)
|
|
52
|
+
|
|
53
|
+
return salt + encrypt_full(data, key)
|
|
54
|
+
|
|
55
|
+
def decrypt_with_password(data: bytes, password: str, security_multiplier: int = 1) -> bytes:
|
|
56
|
+
"""
|
|
57
|
+
IMPORTANT:
|
|
58
|
+
This needs data from encrypt_with_password.
|
|
59
|
+
encrypt_full doesn't work on this.
|
|
60
|
+
|
|
61
|
+
:param data: What to decrypt
|
|
62
|
+
:param password:
|
|
63
|
+
:param security_multiplier: Needs to be the same as with the encryption
|
|
64
|
+
:return:
|
|
65
|
+
"""
|
|
66
|
+
salt = data[:SALT_LEN]
|
|
67
|
+
key = adv.argon2_key_derivation(password.encode(), salt, multiplier=security_multiplier)
|
|
68
|
+
|
|
69
|
+
return decrypt_full(data[SALT_LEN:], key)
|
|
70
|
+
|
|
71
|
+
def password_to_key(password: str, security_multiplier: int = 1) -> bytes:
|
|
72
|
+
"""
|
|
73
|
+
WARNING!
|
|
74
|
+
If anyone finds out what this function returned (the key), he might be able to find your password.
|
|
75
|
+
It's still quite secure, but not against people with supercomputers.
|
|
76
|
+
The attack is called pre-calculation-attack, or rainbow-table-attack.
|
|
77
|
+
|
|
78
|
+
Increasing the security_multiplier helps, but not as much as it does normally.
|
|
79
|
+
|
|
80
|
+
:param password:
|
|
81
|
+
:param security_multiplier: Needs to be the same as with the encryption
|
|
82
|
+
:return:
|
|
83
|
+
"""
|
|
84
|
+
return adv.argon2_key_derivation(password.encode(), salt=b"", multiplier=security_multiplier)
|
|
85
|
+
|
{swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/src/SwiftGUI_Encryption/key_files.py
RENAMED
|
@@ -23,7 +23,7 @@ class BaseKeyFile:
|
|
|
23
23
|
:param saved_key: The key that is to be stored inside the file. Leave empty for random key
|
|
24
24
|
"""
|
|
25
25
|
# Create folders containing this file
|
|
26
|
-
assert file_key or file_password, "You need to specify either a file_password, or a file_key for
|
|
26
|
+
assert file_key or file_password, "You need to specify either a file_password, or a file_key for every KeyFile!"
|
|
27
27
|
|
|
28
28
|
self._salt: bytes = adv.random_key(SALT_LEN) # Placeholder if a key is used instead of a password
|
|
29
29
|
self._key: bytes | None = saved_key # Key stored in the file
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
import SwiftGUI.Files as files
|
|
5
|
+
from SwiftGUI_Encryption import encrypt_full, decrypt_full, random_key
|
|
6
|
+
from SwiftGUI_Encryption import Advanced as adv
|
|
7
|
+
|
|
8
|
+
NONCE_LEN = 32
|
|
9
|
+
SALT_LEN = 16
|
|
10
|
+
|
|
11
|
+
class EncryptedJSONDictFile(files.BaseDictFile):
|
|
12
|
+
"""
|
|
13
|
+
An encrypted json-dictfile
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
path: str | Path,
|
|
19
|
+
file_key: bytes,
|
|
20
|
+
*,
|
|
21
|
+
defaults: dict = None,
|
|
22
|
+
add_defaults_to_values: bool = None,
|
|
23
|
+
auto_save: bool = None,
|
|
24
|
+
**kwargs
|
|
25
|
+
):
|
|
26
|
+
assert not isinstance(file_key, str), "Keys are always in the byte-format.\nIf you tired to pass a password, use PasswordJSONDictFile instead."
|
|
27
|
+
|
|
28
|
+
self._filekey = file_key # Key to encrypt the file with
|
|
29
|
+
|
|
30
|
+
super().__init__(
|
|
31
|
+
path=path,
|
|
32
|
+
defaults=defaults,
|
|
33
|
+
add_defaults_to_values=add_defaults_to_values,
|
|
34
|
+
auto_save=auto_save,
|
|
35
|
+
**kwargs
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def change_key(self, new_key: bytes):
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
:param new_key:
|
|
42
|
+
:return:
|
|
43
|
+
"""
|
|
44
|
+
self._filekey = new_key
|
|
45
|
+
self._do_auto_save()
|
|
46
|
+
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def key(self) -> bytes:
|
|
51
|
+
return self._filekey
|
|
52
|
+
|
|
53
|
+
def _save_to_file(
|
|
54
|
+
self,
|
|
55
|
+
values: dict,
|
|
56
|
+
path: Path,
|
|
57
|
+
):
|
|
58
|
+
raw = json.dumps(values)
|
|
59
|
+
|
|
60
|
+
path.write_bytes(
|
|
61
|
+
encrypt_full(raw.encode(), self._filekey)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def _load_from_file(
|
|
65
|
+
self,
|
|
66
|
+
path: Path
|
|
67
|
+
) -> dict:
|
|
68
|
+
raw = path.read_bytes()
|
|
69
|
+
|
|
70
|
+
raw = decrypt_full(raw, self._filekey).decode()
|
|
71
|
+
return json.loads(raw)
|
|
72
|
+
|
|
73
|
+
class PasswordJSONDictFile(EncryptedJSONDictFile):
|
|
74
|
+
"""
|
|
75
|
+
An encrypted JSON-dictfile that requires a password instead of a key
|
|
76
|
+
"""
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
path: str | Path,
|
|
80
|
+
password: str,
|
|
81
|
+
*,
|
|
82
|
+
defaults: dict = None,
|
|
83
|
+
add_defaults_to_values: bool = None,
|
|
84
|
+
auto_save: bool = None,
|
|
85
|
+
**kwargs
|
|
86
|
+
):
|
|
87
|
+
path = Path(path)
|
|
88
|
+
|
|
89
|
+
exists = path.exists()
|
|
90
|
+
self._regenerated_key = not exists # Regenerate the key on next save, if it already exists
|
|
91
|
+
if exists:
|
|
92
|
+
salt = path.read_bytes()[:SALT_LEN]
|
|
93
|
+
else:
|
|
94
|
+
salt = random_key(SALT_LEN)
|
|
95
|
+
|
|
96
|
+
self._salt = salt
|
|
97
|
+
self._password = password
|
|
98
|
+
|
|
99
|
+
self._filekey = adv.argon2_key_derivation(password.encode(), salt) # Key to encrypt the file with
|
|
100
|
+
|
|
101
|
+
super(EncryptedJSONDictFile, self).__init__(
|
|
102
|
+
path=path,
|
|
103
|
+
#file_key=self._filekey,
|
|
104
|
+
defaults=defaults,
|
|
105
|
+
add_defaults_to_values=add_defaults_to_values,
|
|
106
|
+
auto_save=auto_save,
|
|
107
|
+
**kwargs
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def _regenerate_key(self, new_salt = True):
|
|
111
|
+
if new_salt:
|
|
112
|
+
self._salt = random_key(SALT_LEN)
|
|
113
|
+
|
|
114
|
+
self._filekey = adv.argon2_key_derivation(self._password.encode(), self._salt)
|
|
115
|
+
|
|
116
|
+
def change_key(self, new_key: bytes):
|
|
117
|
+
"""
|
|
118
|
+
NOT IMPLEMENTED!
|
|
119
|
+
|
|
120
|
+
:param new_key:
|
|
121
|
+
:return:
|
|
122
|
+
"""
|
|
123
|
+
raise NotImplementedError("Setting a key directly on a Password-file is not possible. Use .change_password instead!")
|
|
124
|
+
|
|
125
|
+
def change_password(self, new_password: str):
|
|
126
|
+
"""
|
|
127
|
+
Specify a new password for this file
|
|
128
|
+
|
|
129
|
+
:param new_password:
|
|
130
|
+
:return:
|
|
131
|
+
"""
|
|
132
|
+
self._password = new_password
|
|
133
|
+
self._regenerate_key()
|
|
134
|
+
|
|
135
|
+
def _save_to_file(
|
|
136
|
+
self,
|
|
137
|
+
values: dict,
|
|
138
|
+
path: Path,
|
|
139
|
+
):
|
|
140
|
+
raw = json.dumps(values)
|
|
141
|
+
|
|
142
|
+
if not self._regenerated_key:
|
|
143
|
+
self._regenerate_key()
|
|
144
|
+
self._regenerated_key = False
|
|
145
|
+
|
|
146
|
+
path.write_bytes(
|
|
147
|
+
self._salt + encrypt_full(raw.encode(), self._filekey)
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def _load_from_file(
|
|
151
|
+
self,
|
|
152
|
+
path: Path
|
|
153
|
+
) -> dict:
|
|
154
|
+
raw = path.read_bytes()
|
|
155
|
+
|
|
156
|
+
salt = raw[:SALT_LEN]
|
|
157
|
+
if salt != self._salt:
|
|
158
|
+
self._salt = salt
|
|
159
|
+
self._regenerate_key(new_salt=False)
|
|
160
|
+
|
|
161
|
+
raw = decrypt_full(raw[SALT_LEN:], self._filekey).decode()
|
|
162
|
+
return json.loads(raw)
|
|
163
|
+
|
|
164
|
+
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from typing import Hashable, Callable
|
|
2
|
+
from string import ascii_uppercase, ascii_lowercase, digits, ascii_letters, punctuation
|
|
3
|
+
|
|
4
|
+
ascii_letters: set = set(ascii_letters)
|
|
5
|
+
ascii_uppercase: set = set(ascii_uppercase)
|
|
6
|
+
ascii_lowercase: set = set(ascii_lowercase)
|
|
7
|
+
digits: set = set(digits)
|
|
8
|
+
punctuation: set = set(punctuation)
|
|
9
|
+
|
|
10
|
+
import SwiftGUI as sg
|
|
11
|
+
from SwiftGUI import ValueDict
|
|
12
|
+
|
|
13
|
+
# This class was originally created as an example for new SwiftGUI users.
|
|
14
|
+
# That's why it has so many comments.
|
|
15
|
+
class popup_create_password(sg.BasePopup, str):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
title: str = "Create your password",
|
|
19
|
+
min_length: int = None,
|
|
20
|
+
must_include_upper: bool = None,
|
|
21
|
+
must_include_lower: bool = None,
|
|
22
|
+
must_include_special: bool = None,
|
|
23
|
+
must_include_digits: bool = None,
|
|
24
|
+
additional_check_function: Callable = None,
|
|
25
|
+
additional_check_text: str = None,
|
|
26
|
+
wrong_password_color: str | sg.Color = "#A52A2A",
|
|
27
|
+
**kwargs
|
|
28
|
+
):
|
|
29
|
+
self.min_length = min_length
|
|
30
|
+
self.must_include_upper = must_include_upper
|
|
31
|
+
self.must_include_lower = must_include_lower
|
|
32
|
+
self.must_include_special = must_include_special
|
|
33
|
+
self.must_include_digits = must_include_digits
|
|
34
|
+
|
|
35
|
+
self.additional_check_function = additional_check_function
|
|
36
|
+
self.additional_check_text = additional_check_text
|
|
37
|
+
|
|
38
|
+
self.wrong_password_color = wrong_password_color
|
|
39
|
+
|
|
40
|
+
layout = [
|
|
41
|
+
[
|
|
42
|
+
sg.T("Password:", width= 10),
|
|
43
|
+
password := sg.In(
|
|
44
|
+
key= "PW",
|
|
45
|
+
default_event= True,
|
|
46
|
+
pass_char= "*", # Hidden characters
|
|
47
|
+
).bind_event(
|
|
48
|
+
sg.Event.KeyEnter,
|
|
49
|
+
key_function= lambda w:w["Confirm"].set_focus() # Jump to next input-element
|
|
50
|
+
),
|
|
51
|
+
sg.Spacer(width=5),
|
|
52
|
+
sg.Checkbox(
|
|
53
|
+
"Show password",
|
|
54
|
+
default_event= True,
|
|
55
|
+
key_function= lambda val: password.update(pass_char = "" if val else "*"), # If the box is checked, reveal characters. Else hide them
|
|
56
|
+
takefocus= False, # Pressing tab should ignore this element
|
|
57
|
+
)
|
|
58
|
+
],[
|
|
59
|
+
sg.T("Confirm:", width= 10),
|
|
60
|
+
confirm := sg.In(
|
|
61
|
+
key= "Confirm",
|
|
62
|
+
default_event= True,
|
|
63
|
+
pass_char= "*", # Also hidden characters
|
|
64
|
+
).bind_event(
|
|
65
|
+
sg.Event.KeyEnter, # Same as clicking "Confirm"
|
|
66
|
+
key= "Done",
|
|
67
|
+
),
|
|
68
|
+
sg.T(expand=True)
|
|
69
|
+
],[
|
|
70
|
+
sg.HSep(),
|
|
71
|
+
], [
|
|
72
|
+
sg.Button(
|
|
73
|
+
"Confirm",
|
|
74
|
+
key= "Done",
|
|
75
|
+
),
|
|
76
|
+
sg.Button(
|
|
77
|
+
"Cancel",
|
|
78
|
+
key_function= lambda :self.done() # Call self.done() so the popup "returns" None
|
|
79
|
+
)
|
|
80
|
+
]
|
|
81
|
+
] + self._additional_layout()
|
|
82
|
+
self.password = password # Save these two for later
|
|
83
|
+
self.confirm = confirm
|
|
84
|
+
|
|
85
|
+
super().__init__(layout, title=title, **kwargs)
|
|
86
|
+
password.set_focus() # Start with the focus on the password-input-field
|
|
87
|
+
|
|
88
|
+
def _additional_layout(self) -> list[list[sg.BaseElement]]:
|
|
89
|
+
new_texts = []
|
|
90
|
+
|
|
91
|
+
if self.additional_check_text:
|
|
92
|
+
new_texts.append(self.additional_check_text)
|
|
93
|
+
|
|
94
|
+
if self.min_length:
|
|
95
|
+
new_texts.append(f"Must be at least {self.min_length} characters long")
|
|
96
|
+
|
|
97
|
+
if self.must_include_upper:
|
|
98
|
+
new_texts.append(f"Must include uppercase letters")
|
|
99
|
+
|
|
100
|
+
if self.must_include_lower:
|
|
101
|
+
new_texts.append(f"Must include lowercase letters")
|
|
102
|
+
|
|
103
|
+
if self.must_include_special:
|
|
104
|
+
new_texts.append(f"Must include special characters")
|
|
105
|
+
|
|
106
|
+
if self.must_include_digits:
|
|
107
|
+
new_texts.append(f"Must include digits")
|
|
108
|
+
|
|
109
|
+
new_layout = []
|
|
110
|
+
if new_texts:
|
|
111
|
+
new_layout.append([sg.HSep()])
|
|
112
|
+
new_layout.append([sg.T("The password...", expand=True)])
|
|
113
|
+
|
|
114
|
+
new_layout += [
|
|
115
|
+
[sg.T(text)] for text in new_texts
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
return new_layout
|
|
119
|
+
|
|
120
|
+
def _is_valid_password(self) -> bool:
|
|
121
|
+
"""Check if the entered password follows the rules"""
|
|
122
|
+
|
|
123
|
+
current_pw = self.password.value
|
|
124
|
+
|
|
125
|
+
if self.additional_check_function and not self.additional_check_function(current_pw):
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
if self.min_length and len(current_pw) < self.min_length:
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
current_pw: set = set(current_pw)
|
|
132
|
+
|
|
133
|
+
if self.must_include_upper and not (current_pw & ascii_uppercase):
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
if self.must_include_lower and not (current_pw & ascii_lowercase):
|
|
137
|
+
return False
|
|
138
|
+
|
|
139
|
+
if self.must_include_special and not (current_pw & punctuation):
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
if self.must_include_digits and not (current_pw & digits):
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
return True
|
|
146
|
+
|
|
147
|
+
def _event_loop(self, e: Hashable, v: sg.ValueDict):
|
|
148
|
+
pw_match = self.password.value == self.confirm.value
|
|
149
|
+
|
|
150
|
+
if e == "Done" and pw_match and self._is_valid_password():
|
|
151
|
+
self.done(self.password.value) # "Return" the password
|
|
152
|
+
|
|
153
|
+
if self._is_valid_password():
|
|
154
|
+
self.password.update_to_default_value("background_color")
|
|
155
|
+
else:
|
|
156
|
+
self.password.update(background_color=self.wrong_password_color)
|
|
157
|
+
|
|
158
|
+
# If any other key happened, check if the two input-values match
|
|
159
|
+
if pw_match:
|
|
160
|
+
# If they do, use the default background-color for the confirm-field
|
|
161
|
+
self.confirm.update_to_default_value("background_color")
|
|
162
|
+
else:
|
|
163
|
+
# Else, set it to red
|
|
164
|
+
self.confirm.update(background_color=self.wrong_password_color)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import argon2pure
|
|
2
|
-
from Crypto.Cipher import AES
|
|
3
|
-
import os
|
|
4
|
-
import hashlib
|
|
5
|
-
|
|
6
|
-
from SwiftGUI_Encryption import Advanced as adv
|
|
7
|
-
|
|
8
|
-
NONCE_LEN = 32 # This should not be chanced, but who am I to judge
|
|
9
|
-
|
|
10
|
-
def encrypt_full(data: bytes, key: bytes) -> bytes:
|
|
11
|
-
"""
|
|
12
|
-
Encrypt some data
|
|
13
|
-
|
|
14
|
-
:param key:
|
|
15
|
-
:param data:
|
|
16
|
-
:return:
|
|
17
|
-
"""
|
|
18
|
-
nonce = adv.random_key(NONCE_LEN)
|
|
19
|
-
|
|
20
|
-
return nonce + adv.encrypt(data, key, nonce)
|
|
21
|
-
|
|
22
|
-
def decrypt_full(data: bytes, key: bytes) -> bytes:
|
|
23
|
-
"""
|
|
24
|
-
Decrypt some data with its key
|
|
25
|
-
|
|
26
|
-
:param data:
|
|
27
|
-
:param key:
|
|
28
|
-
:return:
|
|
29
|
-
"""
|
|
30
|
-
nonce = data[:NONCE_LEN]
|
|
31
|
-
data = data[NONCE_LEN:]
|
|
32
|
-
|
|
33
|
-
return adv.decrypt(data, key, nonce)
|
|
34
|
-
|
|
35
|
-
|
|
File without changes
|
|
File without changes
|
{swiftgui_encryption-0.0.2 → swiftgui_encryption-0.0.4}/src/SwiftGUI_Encryption/Advanced/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|