Purpose
This policy defines approved cryptographic algorithms, key management practices, and security requirements for cryptographic operations across Maelstrom AI’s two platforms — Provii (privacy-preserving age verification) and downpipes (no-custody backup and disaster recovery for the Cloudflare data layer).
The two platforms have distinct cryptographic profiles:
- Provii uses zero knowledge proofs, commitments and signatures to verify age without exposing personal data; Maelstrom operates the Provii verification infrastructure and manages the associated signing keys.
- downpipes seals customer backups with post-quantum hybrid encryption under customer-held keys, in the customer’s own Cloudflare account. Because downpipes is no-custody, the keys that protect backup contents are generated and held by the customer and are not Maelstrom-managed; Maelstrom holds only two vendor-side signing keys (licence and update — see Key Management). Maelstrom’s own Cloudflare estate is backed up by our own production instance of downpipes, in which Maelstrom holds the operator keys (we dogfood our own product).
The Provii-specific standards below (zero knowledge proofs, commitments, credential signatures) apply to the Provii platform; the downpipes Cryptography section sets out the downpipes profile. Shared standards — transport encryption, data at rest, hashing, key management discipline — apply to both platforms.
Cryptographic Standards
Zero knowledge Proofs
Algorithm: Groth16 Curve: BLS12-381 pairing-friendly elliptic curve Library: bellman 0.14 Use: Age verification proofs
Rationale: Industry-standard, well-audited, optimal proof size
Commitments
Algorithm: Pedersen commitments Curve: Jubjub (embedded in BLS12-381) Library: jubjub 0.10 Use: Hiding date-of-birth in credentials; commitment opened inside ZKP circuit
Rationale: Perfectly hiding, computationally binding; compatible with Groth16 circuit over BLS12-381
Digital Signatures
Credential Signing:
- Algorithm: RedJubjub (custom variant)
- Curve: Jubjub (embedded in BLS12-381)
- Library: redjubjub 0.8
- Use: Issuer signs age credentials
Issuer Attestation:
- Algorithm: Ed25519
- Library: ed25519-dalek 2.x
- Use: Issuers sign attestation payloads proving user identity verification
API Authentication:
- Algorithm: HMAC-SHA256
- Key size: 256 bits minimum
- Use: Expert relying party API authentication (provii-verifier, provii-issuer); also used in provii-verifier hosted mode for session token signing and internal service communication (hosted mode RP auth uses pk_ keys + Origin validation)
WebAuthn Verification:
- Algorithm: ECDSA over P-256 (NIST curve)
- Library: @simplewebauthn/server (TypeScript, admin-portal)
- Use: WebAuthn passkey verification in admin-portal
API Key Hashing
Algorithm: Argon2id (RFC 9106) Library: argon2 0.5 Use: Hashing API keys at rest in provii-verifier and provii-issuer; designed so that stored key material cannot feasibly be reversed
Envelope Encryption
Algorithm: AES-256-GCM Library: aes-gcm 0.10 Use: Envelope encryption of HMAC secrets at rest in KV storage; Master Encryption Key (MEK) held in Cloudflare Secrets Store, Data Encryption Keys (DEK) stored alongside encrypted secrets
Hashing
Approved Algorithms:
- BLAKE2 / BLAKE2s (preferred for ZKP)
- SHA-256 (API authentication, checksums)
- SHA-384 (SRI hashes for browser artifacts)
Prohibited: MD5, SHA-1 (cryptographically broken)
Exception: HMAC-SHA1 is permitted exclusively for YubiKey officer authentication in the provii-issuer. This hardware-enforced constraint cannot be changed as YubiKey 5 series implements HMAC-SHA1 in firmware. The HMAC construction mitigates SHA-1’s collision weaknesses.
Transport Encryption
TLS 1.3 preferred for all external communications
- Minimum: TLS 1.2 (permitted if TLS 1.3 unavailable)
- Cloudflare handles TLS termination
- Certificate management: Automatic (Cloudflare Universal SSL)
Data at Rest
Full disk encryption required:
- macOS: FileVault (AES-256)
- Windows: BitLocker (AES-256)
- Linux: LUKS (AES-256)
Cloudflare KV:
- Encrypted at rest by Cloudflare
- Transparent to applications
downpipes Cryptography
downpipes is no-custody backup and disaster recovery for the Cloudflare data layer. The backup engine runs in the customer’s own Cloudflare account, under the customer’s own keys; Maelstrom holds no customer keys, data or Cloudflare tokens. This section sets out the cryptography specific to downpipes.
Archive Sealing
Algorithm: Post-quantum hybrid encryption Use: Sealing backup archives before they leave the source tenant Where: In the customer’s own Cloudflare account, by the in-tenant engine
The engine reads sources (Workers KV, D1, R2, Secrets Store and zone/account configuration surfaces) and seals each archive with post-quantum hybrid encryption before fanning it out (3-2-1) to two or more customer-controlled destinations. Archives are sealed under customer-held keys; no archive is readable by anyone without those keys.
Customer-Held Keys (No-Custody)
Because downpipes is no-custody, the keys that protect backup contents are generated and held by the customer, not by Maelstrom. They are not Maelstrom assets and are not managed under the Key Management section below.
Key set (customer-held):
- Break-glass key
- Operational key(s)
- Archive-signer key
Generation: Customer-generated via a guided in-browser key ceremony
Storage: Offline, by the customer — guidance provided for encrypted USB, password manager, or Shamir split; a printed recovery sheet is produced during the ceremony
Posture: Default two-recipient posture, with a strict break-glass-only opt-out
Recovery: The MIT-licensed downpipe offline reader restores from archive bytes plus the customer’s offline key alone — no vendor, no network
No-custody boundary. Maelstrom cannot decrypt, recover or rotate customer downpipes keys — by design. Safeguarding the break-glass, operational and archive-signer keys is a complementary user-entity control (CUEC) borne by the customer.
Vendor-Side Signing Keys
Maelstrom holds exactly two vendor-side signing keys for downpipes. Neither protects customer data; both are documented in the Asset Register (CRYPTO-008, CRYPTO-009).
downpipes Licence Signer:
- Use: Signs downpipes licence tokens issued by the vendor-operated control-plane
- Storage: Cloudflare Secrets Store (control-plane)
- Failure mode: Fail-open — a forged, missing or expired licence degrades to the free tier and never gates backup or restore, so compromise is contained
downpipes Update Signer:
- Use: Signs engine update artefacts for the signature-pinned update channel (
updates.downpipes.io) - Storage: Held offline by the operator; never deployed to any Worker
- Verification: The engine verifies the update signature against a pinned public key before applying; updates are pulled (never pushed), canary-gated with automatic rollback, and there is no phone-home
Maelstrom’s Own Estate (Dogfooding)
Maelstrom’s entire Cloudflare estate is backed up by our own production instance of downpipes (we run downpipes as a customer of our own product). In that deployment Maelstrom holds the operator keys (break-glass, operational, archive-signer), created through the same in-browser key ceremony and stored offline; archives are sealed with post-quantum hybrid encryption and fanned out 3-2-1 to Maelstrom-controlled destinations. See Cloudflare Backup Evidence.
Key Management
This section governs the cryptographic keys Maelstrom manages: Provii signing keys and HMAC secrets, API tokens, and the two downpipes vendor-side signers (Licence Signer, Update Signer — see Vendor-Side Signing Keys). Customer-held downpipes keys (break-glass, operational, archive-signer) are no-custody and out of scope here — see Customer-Held Keys (No-Custody).
Signing Key Lifecycle
Generation:
- Generated using cryptographically secure random number generator
- Offline generation preferred
- Ceremony documented (who, when, how)
- Verification key published to JWKS
Storage:
- Production: Cloudflare Workers KV with AES-256-GCM envelope encryption; Master Encryption Key (MEK/KEK) held in Cloudflare Secrets Store, separate from encrypted signing keys
- Backup: Encrypted offline storage (physical security)
- Never in source code or logs
Rotation:
- Schedule: Annually
- Trigger: On compromise or suspected compromise
- Process: Generate new key, update JWKS, mark old key status as Deprecated in KV storage
- Grace period: 30 days for relying parties to update
Destruction:
- Cryptographic erasure (overwrite with random data)
- Physical destruction for offline backups (after retention period)
HMAC Secrets
Generation: Cryptographically secure random (256 bits minimum) Storage: Cloudflare KV with AES-256-GCM envelope encryption; Master Encryption Keys held in Cloudflare Secrets Store Rotation: Annually or on compromise Distribution: Secure channel only (never email)
API Keys
Cloudflare API Tokens:
- Scoped minimally (specific permissions only)
- Stored in GitHub Secrets (for CI/CD) or password manager
- Rotation: Annually or on suspected compromise
GitHub Personal Access Tokens:
- Scoped to required repos/actions only
- Expiration: 90 days maximum
- Stored in password manager
- Rotation: At expiration or on compromise
Cryptographic Implementation
Development Guidelines
Use established libraries:
- Never implement cryptography from scratch
- Use well-audited, maintained libraries
- Keep dependencies updated
Approved Libraries (Rust):
- bellman, bls12_381, jubjub, redjubjub (ZKP and signature primitives)
- ed25519-dalek (Ed25519 attestation signatures)
- blake2, sha2, sha1 (sha1 for YubiKey HMAC only)
- hmac, hkdf (HMAC-SHA256 authentication, key derivation)
- aes-gcm (AES-256-GCM envelope encryption for secrets at rest)
- argon2 (Argon2id for API key hashing)
- subtle (constant-time comparisons)
- zeroize (secret memory erasure)
- rand, rand_core, getrandom (cryptographically secure random)
- p256, ecdsa (P-256 ECDSA primitives, available for future use)
Approved Libraries (JavaScript/TypeScript):
- @simplewebauthn/server (WebAuthn passkey verification in admin-portal)
- Web Crypto API (browser)
- Node.js crypto module
Testing
Required for cryptographic code:
- Unit tests (correctness)
- Property-based tests (proptest)
- Fuzzing (cargo-fuzz)
- Known-answer tests (test vectors)
Never:
- Use weak RNGs for crypto (Math.random, etc.)
- Implement custom crypto without expert review
- Disable crypto for debugging
Quantum Resistance
The two platforms sit at different points on the post-quantum curve:
Provii — current primitives (Groth16/BLS12-381, RedJubjub, Pedersen commitments, Ed25519) are NOT quantum-resistant.
- Monitoring: Track NIST post-quantum standardisation
- Timeline: Plan migration when post-quantum standards mature
- Estimated: 2030-2035 timeframe for practical quantum threat
- Near-term: BLS12-381 provides 128-bit security, sufficient for foreseeable future
- Migration plan: see the Post-Quantum Cryptography Roadmap
downpipes — backup archives are already sealed with post-quantum hybrid encryption (see Archive Sealing), mitigating the store-now-decrypt-later threat to backed-up data under the no-custody model.
Compliance
- Australian Signals Directorate (ASD) guidance reviewed
- NIST SP 800-series consulted
- Industry best practices followed
Related Documents
- provii-crypto documentation
- Statement of Applicability - Control A.8.24 (Use of Cryptography)
- Access Control Policy
- Post-Quantum Cryptography Roadmap - Provii PQC migration plan
- Asset Register - CRYPTO-008/009 (downpipes vendor-side signers)
- Cloudflare Backup Evidence - downpipes dogfooding evidence
Document Information
- Version. 1.2
- Effective Date. 2025-01-13
- Last Updated. 2026-06-19
- Owner. ISMS Owner
- Maintained By. Cryptography Specialist
- Review Frequency. Annually
- Next Review. 2026-11-21
- Classification. Public
- Change History. v1.2 (2026-06-19) — downpipes added as second in-scope platform; the legacy backup worker retired in favour of self-hosted downpipes.