Phase 1 in progress
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import os
|
||||
import base64
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
# === Constants ===
|
||||
SALT_LENGTH = 16
|
||||
IV_LENGTH = 12
|
||||
PBKDF2_ITERATIONS = 200_000
|
||||
KEY_LENGTH = 32 # 256 bits
|
||||
|
||||
# === Base64 Helpers ===
|
||||
def b64encode(data: bytes) -> str:
|
||||
return base64.b64encode(data).decode('utf-8')
|
||||
|
||||
def b64decode(data: str) -> bytes:
|
||||
return base64.b64decode(data.encode('utf-8'))
|
||||
|
||||
# === Key Derivation ===
|
||||
def derive_key(password: str, salt: bytes) -> bytes:
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=KEY_LENGTH,
|
||||
salt=salt,
|
||||
iterations=PBKDF2_ITERATIONS,
|
||||
backend=default_backend()
|
||||
)
|
||||
return kdf.derive(password.encode('utf-8'))
|
||||
|
||||
# === Encrypt Text ===
|
||||
def encrypt_text(plaintext: str, password: str) -> str:
|
||||
salt = os.urandom(SALT_LENGTH)
|
||||
iv = os.urandom(IV_LENGTH)
|
||||
key = derive_key(password, salt)
|
||||
|
||||
aesgcm = AESGCM(key)
|
||||
ciphertext = aesgcm.encrypt(iv, plaintext.encode('utf-8'), None)
|
||||
|
||||
payload = salt + iv + ciphertext
|
||||
return b64encode(payload)
|
||||
|
||||
# === Decrypt Text ===
|
||||
def decrypt_text(encrypted_b64: str, password: str) -> str:
|
||||
raw = b64decode(encrypted_b64)
|
||||
salt = raw[:SALT_LENGTH]
|
||||
iv = raw[SALT_LENGTH:SALT_LENGTH + IV_LENGTH]
|
||||
ciphertext = raw[SALT_LENGTH + IV_LENGTH:]
|
||||
|
||||
key = derive_key(password, salt)
|
||||
aesgcm = AESGCM(key)
|
||||
plaintext = aesgcm.decrypt(iv, ciphertext, None)
|
||||
return plaintext.decode('utf-8')
|
||||
|
||||
# === Metadata-less file interface (optional placeholders) ===
|
||||
def encrypt_file(in_path, out_path, key, metadata: Optional[dict] = None):
|
||||
raise NotImplementedError("File encryption not implemented yet.")
|
||||
|
||||
def decrypt_file(in_path, out_path, key, metadata: Optional[dict] = None):
|
||||
raise NotImplementedError("File decryption not implemented yet.")
|
||||
|
||||
# === Engine Name ===
|
||||
def get_name():
|
||||
return "AES-GCM"
|
||||
Reference in New Issue
Block a user