# How FreeLLMAPI Encrypts API Keys: AES-256-GCM Implementation Explained

> Discover how FreeLLMAPI secures API keys with robust AES-256-GCM encryption. Learn about their secure key management and protect your sensitive data.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: deep-dive
- Published: 2026-08-28

---

**FreeLLMAPI uses AES-256-GCM encryption with a 256-bit key derived from the `ENCRYPTION_KEY` environment variable to protect all stored API keys and proxy URLs.**

The open-source FreeLLMAPI project implements military-grade symmetric encryption for sensitive credential storage. According to the tashfeenahmed/freellmapi source code, every API key undergoes authenticated encryption before persistence, combining confidentiality with integrity verification through Galois/Counter Mode.

## AES-256-GCM Encryption in FreeLLMAPI

The encryption layer resides in **[`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts)**, which exports `encrypt` and `decrypt` functions built on Node.js's native `crypto` module.

### Encryption Algorithm Details

The implementation follows NIST-recommended parameters for GCM:

- **Algorithm**: AES-256-GCM
- **Key size**: 256 bits (32 bytes)
- **IV size**: 128 bits (16 bytes), randomly generated per encryption
- **Authentication tag**: 128 bits (16 bytes), fixed length

The `encrypt` function constructs a cipher instance using:

```typescript
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);

```

The resulting ciphertext, IV, and authentication tag are stored across three columns in the SQLite `api_keys` table: `encrypted_key`, `iv`, and `auth_tag`.

### Decryption and Integrity Verification

The `decrypt` function enforces a fixed 16-byte GCM tag length to prevent tag-truncation attacks. It reconstructs the decipher from stored components and validates the authentication tag before returning plaintext:

```typescript
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);

```

## Key Management Architecture

### Production Key Source

In production environments, the 32-byte encryption key is derived from the `ENCRYPTION_KEY` environment variable. This variable must contain a 64-character hexadecimal string representing 32 bytes of key material.

### Development Fallback

Non-production deployments automatically generate a cryptographically secure fallback key if `ENCRYPTION_KEY` is unset. This key is persisted to a file named `.encryption-key` adjacent to the SQLite database, enabling consistent encryption across development restarts without manual configuration.

## Practical Code Examples

### Encrypting and Storing an API Key

```typescript
import { encrypt, decrypt } from './lib/crypto.js';

// Encrypt a raw API key before storing it
const rawKey = 'sk-xxxxxxxxxxxxxxxxxxxx';
const { encrypted, iv, authTag } = encrypt(rawKey);

// Store `encrypted`, `iv`, and `authTag` in the `api_keys` table
db.prepare(`
  INSERT INTO api_keys (encrypted_key, iv, auth_tag, provider)
  VALUES (?, ?, ?, ?)
`).run(encrypted, iv, authTag, 'openai');

```

### Retrieving and Decrypting for Use

```typescript
// Later, retrieve and decrypt
const stored = db.prepare(`
  SELECT encrypted_key, iv, auth_tag 
  FROM api_keys 
  WHERE id = ?
`).get(keyId);

const apiKey = decrypt(stored.encrypted_key, stored.iv, stored.auth_tag);
console.log(apiKey); // => 'sk-xxxxxxxxxxxxxxxxxxxx'

```

## Key Files in the Encryption Implementation

| File | Purpose |
|------|---------|
| [`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts) | Core encryption/decryption utilities, key initialization, and masking logic |
| [`server/src/routes/keys.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/keys.ts) | API endpoint that receives raw keys, encrypts via `encrypt`, and persists them |
| [`server/src/routes/media.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/media.ts) | Demonstrates retrieval and decryption of stored keys for downstream LLM requests |
| [`server/src/lib/key-proxy.js`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/key-proxy.js) | Encrypts proxy URLs using the identical AES-256-GCM routine |

## Summary

- **FreeLLMAPI uses AES-256-GCM** for authenticated encryption of all API keys and proxy URLs
- The implementation in **[`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts)** enforces 256-bit keys, random 16-byte IVs, and 16-byte authentication tags
- Production deployments require the `ENCRYPTION_KEY` environment variable as a 64-character hex string
- Development environments auto-generate fallback keys stored in `.encryption-key`
- Three-part storage (ciphertext, IV, auth tag) enables secure decryption with integrity verification

## Frequently Asked Questions

### What encryption algorithm does FreeLLMAPI use for API keys?

FreeLLMAPI uses **AES-256-GCM**. This is an authenticated encryption mode that provides both confidentiality and integrity verification, implemented in [`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts) using Node.js native crypto primitives.

### How is the encryption key managed in FreeLLMAPI?

Production deployments supply a 256-bit key via the `ENCRYPTION_KEY` environment variable as 64 hexadecimal characters. In development, FreeLLMAPI automatically generates and persists a secure fallback key to a `.encryption-key` file beside the database.

### Where does FreeLLMAPI store encrypted API keys?

Encrypted API keys are stored in an SQLite database table named `api_keys` with three columns: `encrypted_key` (ciphertext), `iv` (16-byte initialization vector), and `auth_tag` (16-byte GCM authentication tag).

### Does FreeLLMAPI encrypt anything besides API keys?

Yes. The same AES-256-GCM implementation in [`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts) is reused for proxy URL encryption, as seen in [`server/src/lib/key-proxy.js`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/key-proxy.js), ensuring consistent protection for all sensitive configuration data.