Cryptographic operations for Proton Lumo's U2L (User-to-LLM) encryption.
Handles:
- AES-256-GCM encryption/decryption with Associated Data (AEAD)
- PGP encryption of the per-request AES key to Lumo's public key (via gpg)
The protocol: each request generates a fresh AES-256-GCM key. Message turns
are encrypted with this key using AD string lumo.request.{id}.turn.
The key itself is PGP-encrypted to Lumo's ECDH public key. Response chunks
arrive encrypted and are decrypted with the same key using AD string
lumo.response.{id}.chunk.
Summary
Functions
Decrypt base64-encoded AES-256-GCM ciphertext.
Decrypt a response chunk from Lumo.
Encrypt plaintext with AES-256-GCM.
Encrypt the AES request key to Lumo's PGP public key using gpg.
Encrypt a turn's content for Lumo U2L.
Generate a UUID v4 request ID.
Generate a random 32-byte AES-256-GCM key.
Check if gpg is available on the system.
Returns Lumo's production PGP public key.
Functions
@spec decrypt(binary(), <<_::256>>, binary() | nil) :: {:ok, binary()} | {:error, :decryption_failed | :invalid_base64}
Decrypt base64-encoded AES-256-GCM ciphertext.
Expects the format: base64(IV || ciphertext || tag).
@spec decrypt_chunk(binary(), binary(), String.t()) :: {:ok, binary()} | {:error, :decryption_failed}
Decrypt a response chunk from Lumo.
Uses AD string lumo.response.{request_id}.chunk.
Encrypt plaintext with AES-256-GCM.
Returns the concatenation of IV (12 bytes) + ciphertext + tag (16 bytes), base64-encoded.
Encrypt the AES request key to Lumo's PGP public key using gpg.
Returns {:ok, base64_encrypted_key} or {:error, reason}.
Requires gpg (GnuPG) to be installed. Uses a temporary homedir
to avoid polluting the user's keyring.
Encrypt a turn's content for Lumo U2L.
Uses AD string lumo.request.{request_id}.turn.
@spec generate_request_id() :: String.t()
Generate a UUID v4 request ID.
@spec generate_request_key() :: binary()
Generate a random 32-byte AES-256-GCM key.
@spec gpg_available?() :: boolean()
Check if gpg is available on the system.
@spec lumo_pub_key() :: String.t()
Returns Lumo's production PGP public key.