Skip to content

Commit 957c405

Browse files
committed
file name generation similar to java
1 parent b3f56e1 commit 957c405

File tree

1 file changed

+22
-36
lines changed

1 file changed

+22
-36
lines changed

src/firebolt/utils/file_operations.py

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
from base64 import b64decode, urlsafe_b64encode
1+
from base64 import b64decode, b64encode, urlsafe_b64encode
22
from hashlib import sha256
33
from typing import Optional
44

55
from cryptography.fernet import Fernet, InvalidToken
66
from cryptography.hazmat.backends import default_backend # type: ignore
7-
from cryptography.hazmat.primitives import hashes, padding # type: ignore
8-
from cryptography.hazmat.primitives.ciphers import ( # type: ignore
9-
Cipher,
10-
algorithms,
11-
modes,
12-
)
7+
from cryptography.hazmat.primitives import hashes # type: ignore
8+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM # type: ignore
139
from cryptography.hazmat.primitives.kdf.pbkdf2 import (
1410
PBKDF2HMAC, # type: ignore
1511
)
@@ -76,39 +72,29 @@ def generate_salt() -> str:
7672

7773

7874
def generate_encrypted_file_name(cache_key: str, encryption_key: str) -> str:
79-
"""Generate encrypted file name from cache key using AES encryption.
75+
"""Generate encrypted file name from cache key using AES-GCM encryption.
76+
77+
This implementation matches the Java EncryptionService to ensure compatibility.
8078
8179
Args:
8280
cache_key (str): The cache key to encrypt
8381
encryption_key (str): The encryption key
8482
8583
Returns:
86-
str: Base64URL encoded AES encrypted filename ending in .txt
84+
str: Base64 encoded AES-GCM encrypted filename
8785
"""
88-
# Derive a 256-bit key from the encryption_key using PBKDF2
89-
kdf = PBKDF2HMAC(
90-
algorithm=hashes.SHA256(),
91-
salt=b"firebolt_cache_salt", # Fixed salt for deterministic key derivation
92-
length=32, # 256 bits
93-
iterations=10000,
94-
backend=default_backend(),
95-
)
96-
aes_key = kdf.derive(encryption_key.encode("utf-8"))
97-
98-
# Pad the cache_key to be a multiple of 16 bytes (AES block size)
99-
padder = padding.PKCS7(128).padder()
100-
padded_data = padder.update(cache_key.encode("utf-8"))
101-
padded_data += padder.finalize()
102-
103-
# Use a fixed IV for deterministic encryption
104-
# (same input always produces same output)
105-
# This is acceptable for cache file names where we need deterministic results
106-
iv = sha256(cache_key.encode("utf-8")).digest()[:16]
107-
108-
# Encrypt the padded cache_key
109-
cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv), backend=default_backend())
110-
encryptor = cipher.encryptor()
111-
encrypted_data = encryptor.update(padded_data) + encryptor.finalize()
112-
113-
# Base64URL encode the encrypted data and add .txt extension
114-
return urlsafe_b64encode(encrypted_data).decode("ascii").rstrip("=") + ".txt"
86+
# Derive AES key using SHA-256
87+
key_hash = sha256(encryption_key.encode("utf-8")).digest()
88+
aes_key = key_hash[:32] # Use first 32 bytes for AES-256
89+
90+
# Generate deterministic nonce
91+
nonce_input = (encryption_key + encryption_key).encode("utf-8")
92+
nonce_hash = sha256(nonce_input).digest()
93+
nonce = nonce_hash[:12] # AES-GCM nonce should be 12 bytes
94+
95+
# Encrypt using AES-GCM
96+
aesgcm = AESGCM(aes_key)
97+
encrypted_data = aesgcm.encrypt(nonce, cache_key.encode("utf-8"), None)
98+
99+
# Base64 encode
100+
return b64encode(encrypted_data).decode("ascii")

0 commit comments

Comments
 (0)