mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-10-28 00:12:04 +00:00
41 lines
1.3 KiB
Python
41 lines
1.3 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
|
|
# TODO: Replace this Python implementation with a Rust/WASM module for
|
|
# critical cryptographic operations.
|
|
|
|
|
|
class InMemorySecret:
|
|
"""Store sensitive data encrypted in RAM using AES-GCM.
|
|
|
|
Zeroization is best-effort only; Python's memory management may retain
|
|
copies of the plaintext.
|
|
"""
|
|
|
|
def __init__(self, data: bytes) -> None:
|
|
if not isinstance(data, (bytes, bytearray)):
|
|
raise TypeError("data must be bytes")
|
|
self._key = AESGCM.generate_key(bit_length=128)
|
|
self._nonce = os.urandom(12)
|
|
self._cipher = AESGCM(self._key)
|
|
self._encrypted = self._cipher.encrypt(self._nonce, bytes(data), None)
|
|
|
|
def get_bytes(self) -> bytes:
|
|
"""Decrypt and return the plaintext bytes."""
|
|
if self._cipher is None:
|
|
raise RuntimeError("Secret has been wiped")
|
|
return self._cipher.decrypt(self._nonce, self._encrypted, None)
|
|
|
|
def wipe(self) -> None:
|
|
"""Zero out internal data."""
|
|
self._key = None
|
|
self._nonce = None
|
|
self._cipher = None
|
|
self._encrypted = None
|
|
|
|
def get_str(self) -> str:
|
|
"""Return the decrypted plaintext as a UTF-8 string."""
|
|
return self.get_bytes().decode("utf-8")
|