-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathencryption.py
More file actions
166 lines (143 loc) · 6.45 KB
/
Copy pathencryption.py
File metadata and controls
166 lines (143 loc) · 6.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import json
import os
import random
import string
import secrets
from config import SecurityConfig
# Constants
KDF_ITERATIONS = 480000
VAULT_KDF_ITERATIONS = 100000
MIN_FAKE_PASSWORDS = 5
MAX_FAKE_PASSWORDS = 15
MIN_PASSWORD_LENGTH = 8
MAX_PASSWORD_LENGTH = 16
PEPPER = b'S3cur3P3pp3r2024'
STORAGE_KEY = b'Tr1v1alK3y2024'
def simple_encrypt(data: bytes, key: bytes) -> bytes:
"""Simple XOR encryption for .enc file obfuscation."""
return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
def simple_decrypt(data: bytes, key: bytes) -> bytes:
"""Simple XOR decryption for .enc file obfuscation."""
return simple_encrypt(data, key) # XOR is its own inverse
class EncryptionManager:
def __init__(self):
self.fernet = None
self.vault_id = None
self.vault_id_hash = None
self.encryption_salt = None
self.vault_salt = None
def setup_encryption(self, master_password: str) -> None:
"""Set up encryption with the master password."""
if not master_password:
raise ValueError("Master password cannot be empty")
# Generate vault ID using only pepper for consistency
vault_kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=16,
salt=PEPPER,
iterations=VAULT_KDF_ITERATIONS,
)
self.vault_id = base64.urlsafe_b64encode(
vault_kdf.derive(master_password.encode())
).decode('utf-8')
digest = hashes.Hash(hashes.SHA256())
digest.update(self.vault_id.encode())
self.vault_id_hash = digest.finalize().hex()
# Try to load existing vault to get its salts
if os.path.exists('passwords.enc'):
with open('passwords.enc', 'rb') as f:
encrypted_data = f.read()
decrypted_data = simple_decrypt(encrypted_data, STORAGE_KEY)
vaults = json.loads(decrypted_data)
# Look for existing vault
for vault in vaults:
if vault.get('id_hash') == self.vault_id_hash:
self.encryption_salt = base64.b64decode(vault['encryption_salt'])
self.vault_salt = base64.b64decode(vault['vault_salt'])
break
else:
# No existing vault found, generate new salts
self.encryption_salt = secrets.token_bytes(16)
self.vault_salt = secrets.token_bytes(16)
else:
# No vaults file exists, generate new salts
self.encryption_salt = secrets.token_bytes(16)
self.vault_salt = secrets.token_bytes(16)
# Derive encryption key with salt and pepper for real passwords
params = SecurityConfig.get_key_derivation_params()
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=self.encryption_salt + PEPPER,
iterations=KDF_ITERATIONS,
)
key = base64.urlsafe_b64encode(kdf.derive(master_password.encode()))
self.fernet = Fernet(key)
def generate_fake_passwords(self):
h = hmac.HMAC(self.vault_id.encode(), hashes.SHA256())
h.update(b'fake_password_seed')
seed = int.from_bytes(h.finalize(), 'big')
random.seed(seed)
num_passwords = random.randint(MIN_FAKE_PASSWORDS, MAX_FAKE_PASSWORDS)
fake_passwords = []
for _ in range(num_passwords):
length = random.randint(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH)
chars = string.ascii_letters + string.digits + string.punctuation
password = ''.join(random.choice(chars) for _ in range(length))
fake_passwords.append(password)
return fake_passwords
def load_passwords(self):
try:
if os.path.exists('passwords.enc'):
with open('passwords.enc', 'rb') as f:
encrypted_data = f.read()
decrypted_data = simple_decrypt(encrypted_data, STORAGE_KEY)
vaults = json.loads(decrypted_data)
else:
return self.generate_fake_passwords()
for vault in vaults:
if vault.get('id_hash') == self.vault_id_hash:
try:
self.encryption_salt = base64.b64decode(vault['encryption_salt'])
self.vault_salt = base64.b64decode(vault['vault_salt'])
decrypted_data = self.fernet.decrypt(vault['data'].encode())
return json.loads(decrypted_data)
except InvalidToken:
return self.generate_fake_passwords()
return self.generate_fake_passwords()
except Exception as e:
print(f"Error loading passwords: {e}")
return []
def save_passwords(self, passwords):
try:
if os.path.exists('passwords.enc'):
with open('passwords.enc', 'rb') as f:
encrypted_data = f.read()
decrypted_data = simple_decrypt(encrypted_data, STORAGE_KEY)
vaults = json.loads(decrypted_data)
else:
vaults = []
encrypted_data = self.fernet.encrypt(json.dumps(passwords).encode()).decode('utf-8')
new_vault = {
'id_hash': self.vault_id_hash,
'encryption_salt': base64.b64encode(self.encryption_salt).decode('utf-8'),
'vault_salt': base64.b64encode(self.vault_salt).decode('utf-8'),
'data': encrypted_data
}
# Update or add vault
for i, vault in enumerate(vaults):
if vault.get('id_hash') == self.vault_id_hash:
vaults[i] = new_vault
break
else:
vaults.append(new_vault)
final_data = json.dumps(vaults).encode()
encrypted_storage = simple_encrypt(final_data, STORAGE_KEY)
with open('passwords.enc', 'wb') as f:
f.write(encrypted_storage)
except Exception as e:
print(f"Error saving passwords: {e}")