Spaces:
Running on Zero
Running on Zero
Download smishing_detector/utils/encryption.py from ExistedYear/ScamShield: direct link, hf CLI and curl.
- Browser
- Download file 2.66 kB
-
https://huggingface.co/spaces/ExistedYear/ScamShield/resolve/main/smishing_detector/utils/encryption.py
- Command line
-
hf download hf://spaces/ExistedYear/ScamShield/smishing_detector/utils/encryption.py
-
curl -L -o encryption.py https://huggingface.co/spaces/ExistedYear/ScamShield/resolve/main/smishing_detector/utils/encryption.py
2.66 kB
| """ | |
| utils/encryption.py β AES-256-CBC encrypt/decrypt for secure API communication. | |
| Shared key is stored in .env as SMS_ENCRYPTION_KEY (64-char hex = 32 bytes). | |
| Mobile encrypts SMS body with the same key before sending to /predict_secure. | |
| """ | |
| import os | |
| import base64 | |
| import secrets | |
| from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes | |
| from cryptography.hazmat.backends import default_backend | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| # 32-byte (256-bit) key from env β generate once with: | |
| # python -c "import os; print(os.urandom(32).hex())" | |
| def _load_key_hex() -> str: | |
| key_hex = os.getenv("SMS_ENCRYPTION_KEY") | |
| if not key_hex: | |
| # Fallback to known default so mobile and server stay in sync | |
| # when .env is not yet configured. Set SMS_ENCRYPTION_KEY in .env | |
| # before deploying to production. | |
| key_hex = "5fc5555dfd4b23ecfbfbfda273cb82eb5fdfb8b25c5b1357a2568d6afa1f472e" | |
| print("Warning: SMS_ENCRYPTION_KEY not set in .env; using built-in dev key.") | |
| if len(key_hex) != 64: | |
| raise ValueError("SMS_ENCRYPTION_KEY must be a 64-character hex string.") | |
| bytes.fromhex(key_hex) # validate it's valid hex | |
| return key_hex | |
| _KEY_HEX = _load_key_hex() | |
| def get_key() -> bytes: | |
| return bytes.fromhex(_KEY_HEX) | |
| def decrypt_message(encrypted_b64: str) -> str: | |
| """ | |
| Decrypt a base64-encoded AES-256-CBC ciphertext. | |
| Format: base64(IV[16] + ciphertext) | |
| Matching encrypt_message() in mobile src/utils/encryption.js | |
| """ | |
| data = base64.b64decode(encrypted_b64) | |
| iv = data[:16] | |
| ciphertext = data[16:] | |
| key = get_key() | |
| cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) | |
| decryptor = cipher.decryptor() | |
| padded = decryptor.update(ciphertext) + decryptor.finalize() | |
| # Remove PKCS7 padding | |
| pad_len = padded[-1] | |
| return padded[:-pad_len].decode("utf-8") | |
| def encrypt_message(plaintext: str) -> str: | |
| """ | |
| Encrypt a string with AES-256-CBC (for testing / server-to-client responses). | |
| Returns base64(IV[16] + ciphertext). | |
| """ | |
| key = get_key() | |
| iv = secrets.token_bytes(16) | |
| # PKCS7 padding | |
| raw = plaintext.encode("utf-8") | |
| pad = 16 - (len(raw) % 16) | |
| raw += bytes([pad] * pad) | |
| cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) | |
| encryptor = cipher.encryptor() | |
| ciphertext = encryptor.update(raw) + encryptor.finalize() | |
| return base64.b64encode(iv + ciphertext).decode("utf-8") | |
| def get_key_hex() -> str: | |
| """Return current key as hex β sent to client on /api/encryption-key.""" | |
| return _KEY_HEX | |