import os from Cryptodome.Cipher import AES from Cryptodome.Protocol.KDF import PBKDF2 from Cryptodome.Random import get_random_bytes # Use a new secret for the new encryption scheme SECRET = "KTVM-NEW-ENCRYPTION-SECRET" SALT_SIZE = 16 KEY_SIZE = 32 ITERATIONS = 100000 AUTH_TAG_LENGTH = 16 def encrypt_password(clear_string): """Encrypts a string using AES-GCM with a derived key.""" salt = get_random_bytes(SALT_SIZE) # Derive a key from the master secret and a random salt key = PBKDF2(SECRET, salt, dkLen=KEY_SIZE, count=ITERATIONS) cipher = AES.new(key, AES.MODE_GCM) # Encrypt the data ciphertext, tag = cipher.encrypt_and_digest(clear_string.encode('utf-8')) # Return a single hex-encoded string containing all parts return (salt + cipher.nonce + tag + ciphertext).hex() def decrypt_password(encrypted_string): """Decrypts a string encrypted with the above function.""" data = bytes.fromhex(encrypted_string) # Extract the components from the encrypted string salt = data[:SALT_SIZE] nonce = data[SALT_SIZE:SALT_SIZE + 16] tag = data[SALT_SIZE + 16:SALT_SIZE + 16 + AUTH_TAG_LENGTH] ciphertext = data[SALT_SIZE + 16 + AUTH_TAG_LENGTH:] # Re-derive the same key using the stored salt key = PBKDF2(SECRET, salt, dkLen=KEY_SIZE, count=ITERATIONS) cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) # Decrypt and verify the data try: decrypted_bytes = cipher.decrypt_and_verify(ciphertext, tag) return decrypted_bytes.decode('utf-8') except ValueError: # This will be raised if the MAC check fails (tampered data or wrong key) raise ValueError("Decryption failed: MAC check failed. The data may be corrupt or the key is incorrect.")