# What Encryption Is Used for Credential Storage in Craft Agents?

> Craft Agents secures credentials at rest with AES-256-GCM encryption. Learn how hardware-bound keys and authenticated encryption protect your data's confidentiality and integrity.

- Repository: [Craft Ai Agents/craft-agents-oss](https://github.com/craft-ai-agents/craft-agents-oss)
- Tags: internals
- Published: 2026-07-04

---

**Craft Agents uses AES-256-GCM (Advanced Encryption Standard with Galois/Counter Mode) to encrypt all credentials at rest, combining hardware-bound key derivation and authenticated encryption to ensure both confidentiality and integrity.**

Craft Agents, the open-source framework maintained in the `craft-ai-agents/craft-agents-oss` repository, protects sensitive authentication data using industry-standard cryptographic primitives. All user credentials—including OAuth tokens, API keys, and bearer tokens—are stored in a dedicated encrypted file at `~/.craft-agent/credentials.enc`. The implementation relies on **AES-256-GCM** encryption to prevent unauthorized access while detecting tampering through cryptographic authentication tags.

## AES-256-GCM Encryption Architecture

The credential storage system implements a layered security model that binds encryption keys to the specific host machine while using authenticated encryption to protect data integrity.

### Encrypted File Layout

The credential file follows a structured binary format defined in [`packages/shared/src/credentials/backends/secure-storage.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts). The file begins with a **64-byte header** containing a magic string (`"CRAFT01\0"`), reserved flags, and a **32-byte PBKDF2 salt**. Following the header, the encrypted payload stores the JSON-encoded credential data using a random **12-byte initialization vector (IV)** and a **16-byte authentication tag** appended to the ciphertext. This format ensures that decryption can only succeed with both the correct key and the original authentication parameters. See the header documentation at [lines 15-24](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts#L15-L24) for the complete specification.

### Machine-Specific Key Derivation

Rather than storing keys in plaintext, Craft Agents derives the 256-bit AES key from stable machine identifiers using **PBKDF2** (Password-Based Key Derivation Function 2). The derivation process uses:

- **100,000 iterations** of PBKDF2 with SHA-256
- A **32-byte salt** stored in the file header
- A hardware-bound identifier: hardware UUID on macOS, `MachineGuid` on Windows, or `/var/lib/dbus/machine-id` on Linux

The key generation logic resides in `SecureStorageBackend.getEncryptionKey()` at [lines 22-28](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts#L22-L28). This machine-binding prevents simple copy-paste attacks, as moving the encrypted file to another device renders the data inaccessible.

### Authenticated Encryption Implementation

The encryption layer uses Node.js crypto primitives to implement AES-256-GCM. During encryption, `createCipheriv('aes-256-gcm', key, iv)` generates a cipher stream, and `cipher.getAuthTag()` produces the 16-byte authentication tag. For decryption, `SecureStorageBackend.tryDecrypt()` ([lines 64-71](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts#L64-L71)) uses `createDecipheriv('aes-256-gcm', key, iv)` and verifies the tag via `decipher.setAuthTag()` before recovering plaintext. If the authentication tag fails verification, the decryption aborts, indicating potential tampering.

## Credential Storage Structure

The system supports multiple credential types—including global API keys, workspace-scoped OAuth tokens, and source-specific bearer tokens—all defined in [`packages/shared/src/credentials/types.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/types.ts) ([lines 1-5](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/types.ts#L1-L5)). These values are serialized to JSON and encrypted as a single payload, ensuring that all sensitive data remains protected under the AES-256-GCM envelope regardless of credential type.

## Migration and Corruption Handling

The `loadStoreSync()` function ([lines 41-55](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts#L41-L55)) implements resilience logic for legacy migrations. On initialization, the backend attempts decryption with the current machine-bound key derivation; if that fails, it falls back to a legacy hostname-based key (v1) to support upgrades from earlier versions. If both attempts fail, the system treats the file as corrupted and safely deletes it, preventing crash loops from invalid data.

## Secure Storage Implementation Example

The following example demonstrates how the `SecureStorageBackend` class encrypts credentials transparently:

```typescript
import { SecureStorageBackend } from './packages/shared/src/credentials/backends/secure-storage';
import { CredentialId, StoredCredential } from './packages/shared/src/credentials/types';

async function saveExample() {
  const backend = new SecureStorageBackend();
  const id: CredentialId = { type: 'source_oauth', workspaceId: 'ws-123', sourceId: 'slack' };
  const cred: StoredCredential = {
    value: 'xoxb-1234567890-abcdef',    // Slack bot token
    clientId: 'my-client-id',
    clientSecret: 'my-client-secret',
    source: 'native',
  };
  await backend.set(id, cred);
}

```

The `backend.set()` call automatically re-encrypts the entire credential store with AES-256-GCM and persists it to `~/.craft-agent/credentials.enc`, handling IV generation, authentication tagging, and key derivation internally.

## Summary

- **AES-256-GCM** provides authenticated encryption with 256-bit keys and tamper detection via 16-byte authentication tags.
- **PBKDF2 key derivation** uses 100,000 iterations and machine-specific identifiers (hardware UUID, MachineGuid, or dbus machine-id) to bind credentials to the host.
- **File format** includes a 64-byte header with salt storage and a payload containing IV, ciphertext, and authentication tag.
- **Resilience features** include legacy key fallback for migrations and safe deletion of corrupted stores.
- **Source locations**: Core logic in [`packages/shared/src/credentials/backends/secure-storage.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts) with type definitions in [`packages/shared/src/credentials/types.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/types.ts).

## Frequently Asked Questions

### What encryption algorithm does Craft Agents use for credential storage?

Craft Agents uses **AES-256-GCM** (Advanced Encryption Standard with Galois/Counter Mode). This algorithm provides both confidentiality through 256-bit encryption and integrity protection through built-in message authentication, preventing both unauthorized reading and undetected modification of stored credentials.

### How does Craft Agents derive the encryption key without storing it?

The system derives keys dynamically using **PBKDF2** with 100,000 iterations of SHA-256. The input combines a version string with a stable machine identifier—hardware UUID on macOS, `MachineGuid` on Windows, or `/var/lib/dbus/machine-id` on Linux. This approach ensures the encryption key never exists in persistent storage and cannot be recreated on a different machine.

### What happens if the credentials file is moved to another computer or becomes corrupted?

If the file is moved to another machine, decryption fails because the hardware-derived key differs. The `loadStoreSync()` function attempts a fallback to legacy hostname-based keys for migration purposes, but if both attempts fail, the system treats the file as corrupted and safely deletes it. This prevents crash loops while maintaining security.

### Where is the encryption implementation located in the source code?

The encryption logic resides in [`packages/shared/src/credentials/backends/secure-storage.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/backends/secure-storage.ts), specifically within the `SecureStorageBackend` class. Key methods include `getEncryptionKey()` (lines 22-28) for key derivation, `tryDecrypt()` (lines 64-71) for authenticated decryption, and `loadStoreSync()` (lines 41-55) for file handling. Credential type definitions are in [`packages/shared/src/credentials/types.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/credentials/types.ts) (lines 1-5).