Files
dotfiles/ClipCascade/utils/cipher_manager.py
T
2026-07-23 16:48:58 +02:00

110 lines
3.6 KiB
Python
Executable File

import base64
import json
import hashlib
from Crypto.Cipher import AES
from core.constants import *
from core.config import Config
class CipherManager:
def __init__(self, config: Config):
self.config = config
# hash
self.hash_name = "sha256"
self.dklen = 32 # 256 bits for AES-256
# encryption
self.mode = AES.MODE_GCM
def hash_password(self, password: str) -> bytes:
return hashlib.pbkdf2_hmac(
hash_name=self.hash_name,
password=password.encode(),
salt=(
self.config.data["username"] + password + self.config.data["salt"]
).encode("utf-8"),
iterations=self.config.data["hash_rounds"],
dklen=self.dklen,
)
def encrypt(self, plaintext: str) -> dict:
key = self.config.data["hashed_password"]
plaintext_bytes = plaintext.encode("utf-8")
cipher = AES.new(key, self.mode)
ciphertext, tag = cipher.encrypt_and_digest(plaintext_bytes)
return {"nonce": cipher.nonce, "ciphertext": ciphertext, "tag": tag}
def decrypt(self, nonce: bytes, ciphertext: bytes, tag: bytes) -> str:
key = self.config.data["hashed_password"]
cipher = AES.new(key, self.mode, nonce=nonce)
return cipher.decrypt_and_verify(ciphertext, tag).decode()
@staticmethod
def encode_to_json_string(**kwargs: bytes) -> str:
"""
Convert bytes values to Base64 and create a JSON string.
Args:
**kwargs: Key-value pairs where values must be of type `bytes`.
Returns:
str: A JSON string with all `bytes` values Base64-encoded.
Raises:
ValueError: If a value is not of type `bytes`.
"""
json_data = {}
for key, value in kwargs.items():
if isinstance(value, bytes):
json_data[key] = base64.b64encode(value).decode("utf-8")
else:
raise ValueError(
f"Unsupported value type for key '{key}': {type(value)}. "
f"This method only supports 'bytes'."
)
return json.dumps(json_data)
@staticmethod
def decode_from_json_string(json_string: str) -> dict:
"""
Decode a JSON string where all values are Base64-encoded back to their original bytes.
Args:
json_string (str): A JSON string with Base64-encoded values.
Returns:
dict: A dictionary with the original keys and `bytes` values decoded from Base64.
Raises:
ValueError: If the JSON string is not valid or if decoding fails.
"""
# Parse the JSON string into a dictionary
json_data = json.loads(json_string)
decoded_data = {}
# Decode each Base64-encoded value back to bytes
for key, value in json_data.items():
if isinstance(value, str):
decoded_data[key] = base64.b64decode(value)
else:
raise ValueError(
f"Unsupported value type for key '{key}': {type(value)}. "
+ f"Expected 'str' for Base64 decoding."
)
return decoded_data
@staticmethod
def string_to_sha3_512_lowercase_hex(input_string: str) -> str:
"""
Convert a string to its lowercase hexadecimal SHA3-512 hash.
Args:
input_string (str): The input string to hash.
Returns:
str: The lowercase hexadecimal representation of the SHA3-512 hash.
"""
return hashlib.sha3_512(input_string.encode("utf-8")).hexdigest()