How OmniRoute Secures and Encrypts API Keys: HMAC Validation and AES-256-GCM Explained
OmniRoute implements a dual-layer security model that combines HMAC-based CRC checksums for integrity validation and AES-256-GCM encryption for data at rest, ensuring both tamper detection and cryptographic confidentiality.
Understanding how API keys are secured and encrypted in OmniRoute reveals a defense-in-depth architecture addressing credential protection at every layer. The system utilizes environment-derived secrets and industry-standard cryptographic primitives spanning from startup validation to persistent storage. This implementation is distributed across critical modules including src/shared/utils/apiKey.ts for checksum generation and src/lib/db/encryption.ts for database-level encryption.
HMAC-Based Integrity Validation
Every API key generated by OmniRoute contains an embedded CRC8-style checksum computed using a secret HMAC value. This mechanism ensures that forged or tampered keys are immediately rejected during validation.
The API_KEY_SECRET Mechanism
The integrity system relies on API_KEY_SECRET, a required environment variable that seeds the checksum algorithm. According to the source code in instrumentation-node.ts, this secret is either supplied via environment configuration or automatically generated and persisted on first launch. If the secret is missing at runtime, the system emits a security warning and disables CRC validation.
The validator in src/shared/utils/secretsValidator.ts aborts server startup if required secrets are malformed or missing, ensuring cryptographic operations never execute with weak parameters.
PBKDF2-Based CRC Generation
The CRC checksum is generated using PBKDF2 as an HMAC-like construction, satisfying modern security scanning requirements while producing deterministic 8-character hexadecimal checksums. The implementation in src/shared/utils/apiKey.ts follows this pattern:
function generateCrc(machineId: string, keyId: string): string {
const secret = getApiKeySecret();
// PBKDF2 used as HMAC-like construction (CodeQL compliant)
return crypto
.pbkdf2Sync(machineId + keyId, secret, 1000, 32, "sha256")
.toString("hex")
.slice(0, 8);
}
export function generateApiKeyWithMachine(machineId: string) {
const keyId = generateKeyId(); // 6-character random identifier
const crc = generateCrc(machineId, keyId); // 8-character checksum
const key = `sk-${machineId}-${keyId}-${crc}`;
return { key, keyId };
}
The resulting API key follows the format sk-{machineId}-{keyId}-{crc}, where the CRC segment validates that the key was legitimately generated by an instance possessing the API_KEY_SECRET.
AES-256-GCM Encryption for At-Rest Data
While HMAC validation protects key integrity during transmission and validation, AES-256-GCM encryption protects credentials persisted to the SQLite database.
Storage Encryption Implementation
The encryption module at src/lib/db/encryption.ts handles all credential storage using authenticated encryption. The implementation uses a static salt combined with the STORAGE_ENCRYPTION_KEY environment variable to derive a 32-byte encryption key via scrypt:
const STATIC_SALT = "omniroute-field-encryption-v1";
export function encrypt(plaintext: string | null | undefined): string | null | undefined {
if (plaintext == null) return plaintext;
const key = crypto.scryptSync(process.env.STORAGE_ENCRYPTION_KEY!, STATIC_SALT, 32);
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
let encrypted = cipher.update(plaintext, "utf8", "hex");
encrypted += cipher.final("hex");
const authTag = cipher.getAuthTag().toString("hex");
// Format: enc:v1:{iv}:{ciphertext}:{authTag}
return `enc:v1:${iv.toString("hex")}:${encrypted}:${authTag}`;
}
Key Derivation and Salt Strategy
The encryption system utilizes scrypt for key derivation with a static application-specific salt (omniroute-field-encryption-v1). Each encryption operation generates a random 12-byte IV (Initialization Vector) to ensure ciphertext uniqueness. The enc:v1: prefix marks encrypted values, allowing the system to distinguish ciphertext from plaintext during decryption operations.
This design ensures that even with database read access, an attacker cannot decrypt stored refresh tokens or relay authentication blobs without the STORAGE_ENCRYPTION_KEY.
Startup Validation and Secret Lifecycle
Both cryptographic systems are validated early in the server lifecycle by src/shared/utils/secretsValidator.ts. This module verifies that:
API_KEY_SECRETis present and non-empty for checksum operationsSTORAGE_ENCRYPTION_KEYis available for database encryption- Generated secrets meet minimum entropy requirements
The validator aborts process startup if critical secrets are missing, preventing the server from running in a degraded security state.
Summary
- Tamper detection is implemented via HMAC-based CRC8 checksums generated with PBKDF2, ensuring only instances possessing
API_KEY_SECRETcan create valid API keys. - Confidentiality at rest is enforced through AES-256-GCM encryption using scrypt-derived keys and random IVs, protecting stored credentials in the SQLite database.
- Fail-secure defaults require both
API_KEY_SECRETandSTORAGE_ENCRYPTION_KEYat startup, with automatic generation available for the former during first launch. - CodeQL-compliant construction uses PBKDF2 as an HMAC alternative to satisfy static analysis tools while maintaining cryptographic strength.
Frequently Asked Questions
What happens if API_KEY_SECRET is not configured?
If API_KEY_SECRET is missing, OmniRoute emits a security warning to the console and disables CRC validation for API keys. However, the startup validator in src/shared/utils/secretsValidator.ts typically prevents this scenario by aborting the process or triggering automatic generation via instrumentation-node.ts on first launch.
How does OmniRoute encrypt stored provider credentials?
Provider refresh tokens and relay authentication blobs are encrypted using AES-256-GCM before being written to SQLite. The encryption function in src/lib/db/encryption.ts applies scrypt key derivation with a static salt, generates a random 12-byte IV for each operation, and stores the result in the format enc:v1:{iv}:{ciphertext}:{authTag}.
What cryptographic algorithms protect OmniRoute API keys?
OmniRoute uses PBKDF2-HMAC-SHA256 (1000 iterations, 32 bytes output) for generating the integrity checksums on API keys, and AES-256-GCM with scrypt key derivation for encrypting data at rest. The CRC checksum in API keys provides tamper detection without exposing the underlying secret.
Can encrypted database values be decrypted without the STORAGE_ENCRYPTION_KEY?
No. The STORAGE_ENCRYPTION_KEY is required to derive the decryption key via scrypt using the static salt defined in src/lib/db/encryption.ts. Without this environment variable, encrypted values in the database remain cryptographically secure and unreadable, even if an attacker gains direct database access.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →