Encrypt environment variables synchronously using X25519 and AES-GCM.
(envs: List[EnvVar], public_key_hex: str)
| 75 | |
| 76 | |
| 77 | def encrypt_env_vars_sync(envs: List[EnvVar], public_key_hex: str) -> str: |
| 78 | """Encrypt environment variables synchronously using X25519 and AES-GCM.""" |
| 79 | # Prepare environment data as JSON |
| 80 | env_dict = {"env": [{"key": env.key, "value": env.value} for env in envs]} |
| 81 | env_json = json.dumps(env_dict).encode("utf-8") |
| 82 | |
| 83 | # Generate private key and derive public key |
| 84 | private_key = X25519PrivateKey.generate() |
| 85 | public_key = private_key.public_key() |
| 86 | |
| 87 | # Get public key bytes (32 bytes for X25519) |
| 88 | public_key_bytes = public_key.public_bytes( |
| 89 | encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw |
| 90 | ) |
| 91 | |
| 92 | # Generate shared secret |
| 93 | remote_public_key = X25519PublicKey.from_public_bytes(hex_to_bytes(public_key_hex)) |
| 94 | shared_secret = private_key.exchange(remote_public_key) |
| 95 | |
| 96 | # Encrypt the data using AES-GCM |
| 97 | aesgcm = AESGCM(shared_secret) |
| 98 | iv = secrets.token_bytes(12) # 12 bytes IV for GCM |
| 99 | encrypted_data = aesgcm.encrypt(iv, env_json, None) |
| 100 | |
| 101 | # Combine all components: public_key + iv + encrypted_data |
| 102 | result = public_key_bytes + iv + encrypted_data |
| 103 | |
| 104 | return bytes_to_hex(result) |