Skip to content

Algorithm Documentation

adk-secure-sessions delegates all cryptographic operations to the pyca/cryptography library. No custom cryptographic primitives are implemented. This page documents the algorithms, parameters, and standards compliance for each registered encryption backend.

For how encrypted data is framed and identified, see the Envelope Protocol.

Algorithm Overview

The current release ships with two backends:

  • Fernet (backend ID 0x01) — AES-128-CBC + HMAC-SHA256 with two-phase key derivation (PBKDF2 + HKDF) for passphrase-based keys.
  • AES-256-GCM (backend ID 0x02) — AES-256-GCM authenticated encryption with 96-bit random nonces.

Fernet

Fernet provides authenticated encryption by combining AES-128-CBC for confidentiality with HMAC-SHA256 for integrity. Key material can be a pre-generated Fernet key or an arbitrary passphrase derived via a two-phase scheme: PBKDF2-HMAC-SHA256 at init time, followed by HKDF-SHA256 per operation.

Fernet keys are 256 bits (32 bytes), composed of two 128-bit halves:

  • Bytes 0 -- 15: HMAC-SHA256 signing key (message authentication)
  • Bytes 16 -- 31: AES-128-CBC encryption key (confidentiality)

This explains why the algorithm is called "AES-128-CBC" despite the overall key being 32 bytes — the 32 bytes are split, with only the second half used for AES encryption.

NIST/FIPS Compliance Mapping

Every cryptographic component maps to a published NIST or FIPS standard:

Component Algorithm Standard Reference
Block cipher AES-128-CBC FIPS 197 (AES) + NIST SP 800-38A (CBC mode) 128-bit key, CBC mode of operation
Message authentication HMAC-SHA256 FIPS 198-1 Keyed-hash message authentication code
Key derivation (extract) PBKDF2-HMAC-SHA256 NIST SP 800-132 Password-based key derivation
Key expansion (per-op) HKDF-SHA256 RFC 5869 / NIST SP 800-56C Rev. 2 HMAC-based extract-and-expand KDF
Initialization vector 128-bit random IV NIST SP 800-38A Per-message, generated by Fernet

FIPS 140-2 Certification

This library uses NIST-approved algorithms via pyca/cryptography, which builds on OpenSSL. FIPS 140-2 certification applies to the underlying cryptographic module (OpenSSL), not to libraries built on top of it. Organizations requiring FIPS 140-2 compliance should verify their deployment's OpenSSL build is FIPS-validated.

Component Details

AES-128-CBC (Confidentiality)

Advanced Encryption Standard with 128-bit keys in Cipher Block Chaining mode. Each message is encrypted with a fresh 128-bit random IV (initialization vector), generated by the Fernet implementation. Plaintext is PKCS7-padded to 16-byte block boundaries before encryption.

HMAC-SHA256 (Integrity)

Hash-based Message Authentication Code using SHA-256. Applied over the Fernet token's version, timestamp, IV, and ciphertext to detect tampering. The signing key (first 128 bits of the Fernet key) is independent of the encryption key.

PBKDF2-HMAC-SHA256 (Key Derivation — Extract Phase)

Password-Based Key Derivation Function 2 using HMAC-SHA256 as the pseudorandom function. Used at backend construction time to stretch an arbitrary passphrase into a 32-byte master key.

Current parameters:

Parameter Value Source
Hash function SHA-256 hashlib.pbkdf2_hmac("sha256", ...)
Iterations 600,000 _PBKDF2_ITERATIONS in backends/fernet.py
Salt b"adk-secure-sessions-fernet-v1" _PBKDF2_SALT in backends/fernet.py
Output length 32 bytes (256 bits) Master key for HKDF expansion

The iteration count meets the OWASP 2023 Password Storage Cheat Sheet recommendation of 600,000 for PBKDF2-HMAC-SHA256.

A legacy iteration count of 480,000 (_PBKDF2_ITERATIONS_LEGACY) is retained for backward-compatible decryption of data encrypted prior to version 3.2.

HKDF-SHA256 (Key Expansion — Per-Operation)

HMAC-based Extract-and-Expand Key Derivation Function (RFC 5869) using SHA-256. Used per encrypt/decrypt operation to derive a unique Fernet key from the PBKDF2-derived master key and a fresh random salt.

Parameters:

Parameter Value Source
Algorithm SHA-256 hashes.SHA256()
Salt 16 random bytes os.urandom(16) per operation
Info b"adk-fernet-v2" _HKDF_INFO in backends/fernet.py
Output length 32 bytes (256 bits) Base64url-encoded → Fernet key

HKDF completes in microseconds, making per-operation key derivation practical without the latency of repeated PBKDF2 calls.

Key Resolution

FernetBackend accepts keys as str or bytes and resolves them as follows:

  1. Valid Fernet key — if the input is a valid base64url-encoded 32-byte key, it is used directly (passthrough). No PBKDF2 derivation, no salt marker, no HKDF expansion.
  2. Arbitrary passphrase — the input is stretched via PBKDF2-HMAC-SHA256 (600,000 iterations) into a master key at init time. Each encrypt call generates a fresh 16-byte random salt and expands the master key via HKDF-SHA256 into a unique per-operation Fernet key.

Fernet Ciphertext Format

The ciphertext portion of the envelope (bytes 2+) depends on the key mode:

Passphrase mode (salted, v3.2+)

[0x01][salt: 16 bytes][fernet_token]
 ^--- SALT_MARKER
  • Byte 0: 0x01 salt marker, distinguishes from legacy format.
  • Bytes 1--16: Random salt used for HKDF expansion.
  • Bytes 17+: Standard Fernet token.

Direct-key mode / legacy passphrase mode (pre-3.2)

[fernet_token]

No marker byte. The entire blob is a standard Fernet token. Legacy passphrase data (encrypted with 480,000-iteration fixed-salt derivation) is decrypted transparently using a retained legacy Fernet instance.

Fernet Token Structure

A Fernet token contains: version byte (0x80), 8-byte big-endian timestamp, 16-byte random IV, AES-128-CBC ciphertext padded to 16-byte blocks, and a 32-byte HMAC-SHA256 authentication tag. See the Fernet Specification for the canonical format definition.

Async Implementation

All FernetBackend encrypt and decrypt operations are wrapped in asyncio.to_thread() because Fernet's underlying AES and HMAC computations are CPU-bound. This prevents blocking the async event loop in ADK agent pipelines.

Known Limitations

No FIPS 140-2 certification. The library uses NIST-approved algorithms but FIPS 140-2 certification belongs to the underlying cryptographic module (OpenSSL), not the application library. A FIPS deployment guide is planned for Phase 4.