Encryption & Key Management
The portal's security model ensures that no plaintext identifiers or sensitive attributes are ever stored in the database. Every external identifier is either HMAC-hashed (irreversible, used for lookup) or AES-256-GCM encrypted (reversible, used for attribute retrieval). Three domain-separated cryptographic keys provide distinct protections, so the compromise of one key does not cascade to the others.
This design means that even an attacker with full read access to the database sees only opaque hashes and ciphertext. Recovering any meaningful data requires access to the corresponding key material, which is managed by a dedicated Key Management Service (KMS) and, in production, never leaves the HSM boundary.
Three-Key Architecture
The following diagram illustrates the three cryptographic keys and their roles within the portal:
Each key operates in its own domain. Key A and Key B are HMAC keys used exclusively for irreversible hashing of different identifier types, while Key C is a symmetric encryption key used for reversible encryption of sensitive payloads. This separation is fundamental to the security model.
Key Summary
| Key | Alias | Algorithm | Purpose | Reversible? |
|---|---|---|---|---|
| Key A | reconciliation:holder | HMAC-SHA256 | Hash wallet holder key fingerprints | No |
| Key B | reconciliation:institution | HMAC-SHA256 | Hash institutional identifiers (eduid) | No |
| Key C | reconciliation:encryption | AES-256-GCM | Encrypt sensitive data (claims, IDs) | Yes |
Key A and Key B are both HMAC-SHA256 keys, but they are entirely separate secrets. Using two distinct HMAC keys rather than one prevents cross-correlation between wallet-side identifiers and institution-side identifiers, even if one key is compromised.
Key C is a 256-bit AES key operating in Galois/Counter Mode (GCM), which provides both confidentiality and integrity. Every encryption operation generates a fresh random initialization vector (IV), so encrypting the same plaintext twice produces different ciphertext.
Why Domain Separation?
Using three keys instead of one provides defense in depth. Each compromise scenario is isolated:
-
If Key A is compromised: An attacker can compute holder key hashes and potentially match them against known public keys, but they cannot reverse institution hashes (protected by Key B) or decrypt any sensitive data (protected by Key C). The attacker gains no access to institutional identifiers or encrypted claims.
-
If Key B is compromised: An attacker can compute institution identifier hashes and potentially match them against known institutional IDs, but they cannot correlate those hashes with holder keys (protected by Key A) or decrypt any data (protected by Key C). The link between wallet holders and institutional accounts remains hidden.
-
If Key C is compromised: An attacker can decrypt encrypted data such as claims, institutional IDs, and auxiliary payloads, but they cannot correlate the hashed identifiers stored alongside that data with external identifiers (protected by Keys A and B). They can see what data exists but cannot easily determine which external identity it belongs to.
-
Full database access without any key: An attacker sees only meaningless hashes and ciphertext. No identifiers, no claims, no institutional IDs, and no way to correlate records with external systems.
Each key serves a fundamentally different purpose (lookup indexing vs. data protection), and domain separation prevents a single point of cryptographic failure. This architecture also supports independent key rotation schedules, different access control policies per key, and regulatory compliance requirements that may mandate separate key management for different data categories.
KMS Providers
The portal uses a pluggable Key Management Service (KMS) that supports multiple backends. The KMS abstraction layer means that application code never directly handles raw key material in production. Instead, it sends data to the KMS for cryptographic operations (HMAC, encrypt, decrypt), and the KMS performs those operations using its internally managed keys.
Software (Development)
For local development and testing, keys are generated and stored in a PKCS#12 keystore file on disk. This provider is straightforward to set up and requires no external infrastructure, but it offers no hardware protection for key material.
kms:
providers:
- id: "software"
type: "SOFTWARE"
config:
keystore-path: "data/keystore/auth-bridge.p12"
keystore-password-ref:
key: "KMS_KEYSTORE_PASSWORD"
The software KMS provider stores key material in a file on the local filesystem. This is acceptable for development and testing but is not recommended for production deployments. In production, use an HSM-backed provider such as Azure Key Vault or AWS KMS.
Azure Key Vault (Production)
For production deployments on Azure, the portal integrates with Azure Key Vault backed by HSM (Hardware Security Module) protection. Keys are generated inside the HSM and marked as non-exportable, meaning the raw key material never leaves the hardware boundary. All cryptographic operations (HMAC computation, AES-GCM encryption, AES-GCM decryption) are performed within the HSM itself.
Azure Key Vault also provides comprehensive audit logging, role-based access control (RBAC), and automatic key versioning. Access to the Key Vault is authenticated via Azure Managed Identity, eliminating the need for stored credentials.
AWS KMS (Production)
For deployments on AWS, the portal supports AWS Key Management Service, which provides similar HSM-backed key storage and management. Like Azure Key Vault, AWS KMS ensures that key material is non-exportable and that cryptographic operations occur within the HSM boundary. Access is controlled via IAM policies and CloudTrail provides audit logging.
Key Initialization
On first startup, the Auth Bridge service initializes the required keys if they do not already exist. The initialization process creates four keys:
-
JAR signing key (ES256/P-256): Used to sign OID4VP authorization request objects (JARs). The corresponding public key is published as a
did:jwkidentifier that wallets use to verify the verifier's identity. -
Key A (HMAC-SHA256): A 32-byte (256-bit) secret used exclusively for computing HMAC hashes of wallet holder key fingerprints. This key is used during the OID4VP verification flow when the holder's public key is extracted from the Verifiable Presentation.
-
Key B (HMAC-SHA256): A 32-byte (256-bit) secret used exclusively for computing HMAC hashes of institutional identifiers (such as the SURFconext
subclaim oreduperson_principal_name). This key is used during the reconciliation flow when the institution authenticates the user. -
Key C (AES-256-GCM): A 32-byte (256-bit) secret used for encrypting and decrypting all sensitive data that must be recoverable, including the actual eduid, canonical claims, reconciliation session data, and auxiliary data.
In production environments using Azure Key Vault, keys are pre-provisioned by infrastructure automation and marked as non-exportable. The initializer verifies that the expected keys exist and are accessible, but does not attempt to create them.
Next Steps
For detailed specifications of each key, including their algorithms, configuration parameters, and version management strategy, see Cryptographic Keys.
To understand how data is encrypted before persistence and decrypted on read, including the envelope encryption pattern and the zero-plaintext guarantee, see Encrypted Storage.