Cryptography Reference
Grizzly encrypts asset data with AES-256-GCM and wraps the resulting symmetric keys using RSA-4096 before storing them. Asset metadata integrity is protected through a separate AES-256-GCM signing scheme. This document covers the specific algorithms, key material, IV construction, and binary formats in enough detail to evaluate them, audit them, or present them to a security reviewer.
Algorithms at a Glance
| Purpose | Algorithm | Key Size | Notes |
|---|---|---|---|
| Data encryption | AES-256-GCM | 256-bit | 128-bit auth tag |
| Key wrapping | RSA-4096 | 4096-bit | PKCS1 public, PKCS8 private |
| Asset signing | AES-256-GCM | 256-bit | Binds a SHA-256 content hash |
| Content hashing | SHA-256 | — | Used during asset signing only |
AES-256-GCM
All asset data is encrypted using AES-256-GCM with a 32-byte key and a 128-bit authentication tag. GCM provides authenticated encryption, which means the ciphertext carries an integrity check that the decryption process must verify before returning any plaintext. If the authentication tag does not match, decryption fails rather than silently producing corrupted output. The authentication tag (16 bytes) is appended to the end of the ciphertext and stripped during decryption.
IV Construction
Each encryption operation uses a 96-bit (12-byte) nonce composed of two parts: a 72-bit (9-byte) cryptographically random prefix and a 24-bit (3-byte) incrementing counter. The random prefix is generated when a Key is first created. The counter starts at zero and increments with each encrypt call on that Key.
This construction follows NIST SP 800-38D guidance for deterministic IV generation. The 24-bit counter supports up to 16,777,216 unique nonces per prefix before exhaustion, but Key rotation limits the number of operations per Key to a configurable ceiling that sits well below that number in practice.
Key Rotation
Each Key on a KeyRing has a maxEncryptCount setting that controls how many encrypt operations it will serve before the KeyRing automatically rotates to a new Key. The platform default is 50,000 operations. NIST recommends rotating AES-256-GCM keys before 64 GB of data has been encrypted under a single key, so organizations encrypting large payloads should tune maxEncryptCount downward to stay within that boundary.
After a Key rotates, it is never used for new encryption but remains in the system so that previously encrypted data can still be decrypted. The platform tracks which Key was used for each encrypt operation, so decryption always resolves to the correct Key regardless of how many rotations have occurred on the KeyRing.
Key Wrapping: RSA-4096
Every AES-256 key generated by the platform is immediately encrypted using the RSA-4096 public key associated with its KeyRing before it is stored. Grizzly never persists a raw symmetric key. To decrypt any asset, the caller presents the private key, which the platform uses to unwrap the symmetric key and complete the decryption.
Public keys are stored in PEM PKCS1 format. Private keys default to PEM PKCS8 format and can optionally be encrypted at rest using a symmetric cipher and passphrase, which adds a second layer of protection if the key file is exposed. Organizations generating their own key pairs outside of Grizzly's tooling can produce compatible keys with OpenSSL:
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out public.pem
Organizations that manage their own RSA key pairs can destroy the private key to render all data encrypted under a given KeyRing permanently unrecoverable, which is useful for time-limited datasets, expired partner contracts, or regulatory data destruction requirements.
Asset Signing
Asset metadata is signed using a dedicated AES-256-GCM signing key that is separate from the data encryption key. When an asset is signed, the platform computes a SHA-256 hash of the serialized asset metadata and encrypts a payload containing that hash into the signature. The signing operation produces three outputs: an encrypted payload, a 12-byte random IV, and a reference identifier for the signing key.
Verification decrypts the payload using the original signing key and IV, then recomputes the SHA-256 hash of the current asset metadata. If the metadata has changed at all since signing, the hashes will not match and verification fails. If the ciphertext itself has been modified, the GCM authentication tag will reject decryption before the hash comparison is even reached.
A valid signature therefore proves two things independently: that the metadata content has not changed since signing (via the SHA-256 hash), and that the signature ciphertext has not been tampered with since it was produced (via the GCM auth tag).
Encrypted Output: The Header
When the platform encrypts data, it prepends a binary header to the ciphertext. The header carries the information needed to look up the correct Key for decryption and can embed the IV, a signed asset, or an asset ID as typed blocks.
Header layout (Version 1):
| Field | Size | Description |
|---|---|---|
| Version | 1 byte | Header version (currently 1) |
| Length | 2 bytes | Total header length, max 64 KB |
| Hash | 14 bytes | 6 bytes KeyRing ID + 8 bytes Key ID |
| Blocks | variable | Zero or more typed data blocks |
Each block contains a 1-byte type identifier, a 2-byte length field (max 64 KB of data per block), and the block payload. Three block types are defined:
| Type | Value | Contents |
|---|---|---|
| IV | 1 | The packed nonce (random prefix + counter) used during encryption |
| Asset | 2 | The signed asset payload |
| AssetId | 3 | The asset identifier string |
The 14-byte hash is returned as a standalone value in encrypt responses. Either the full header or the hash can be passed to the decrypt endpoint; the platform uses whichever is provided to resolve the KeyRing and Key, then decrypts accordingly.
Platform Capacity
The hash field in the header allocates 6 bytes to the KeyRing ID and 8 bytes to the Key ID. Those sizes set the theoretical upper bounds on scale:
- KeyRings: up to 281,474,976,710,656 (2^48), which is roughly 892,551 new KeyRings per minute sustained over 10 years.
- Keys per KeyRing: up to approximately 1.89 × 10^19 (2^64), which is roughly 974,904,028 new Keys per second sustained over 10 years.
These limits are inherent to the binary format and are not configurable.
Security Properties
AES-256-GCM with a 32-byte key provides 256-bit symmetric security against brute force. The GCM authentication tag detects any modification to ciphertext before decryption produces output, so a successful decryption is proof the data has not been altered in transit or at rest. RSA-4096 key wrapping means raw symmetric keys are never stored in plaintext and can only be recovered by whoever holds the corresponding private key. Each KeyRing uses a separate RSA key pair, so a key pair compromise is bounded to that KeyRing's data and does not affect others. Key rotation limits the volume of data exposed under any single symmetric key, and rotated keys are retained for decryption of existing data but are never reused for new encryption.