# How OmniRoute Secures and Encrypts API Keys: HMAC Validation and AES-256-GCM Explained

> Learn how OmniRoute secures API keys with HMAC validation for integrity and AES-256-GCM encryption for confidentiality. Protect your data effectively.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-09

---

**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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/apiKey.ts) for checksum generation and [`src/lib/db/encryption.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/apiKey.ts) follows this pattern:

```typescript
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```typescript
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/secretsValidator.ts). This module verifies that:

- `API_KEY_SECRET` is present and non-empty for checksum operations
- `STORAGE_ENCRYPTION_KEY` is 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_SECRET` can 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_SECRET` and `STORAGE_ENCRYPTION_KEY` at 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/secretsValidator.ts) typically prevents this scenario by aborting the process or triggering automatic generation via [`instrumentation-node.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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.