How CloddsBot Handles Credential Encryption: AES-256-GCM Implementation Guide
CloddsBot protects trading credentials using AES-256-GCM encryption with scrypt key derivation, storing encrypted blobs in SQLite with automatic key rotation and comprehensive audit logging.
Effective credential encryption is critical for any automated trading system handling sensitive API keys. The open-source CloddsBot repository (alsk1992/CloddsBot) implements a defense-in-depth approach to credential encryption, combining authenticated encryption, secure key derivation, and database-backed audit trails. This article examines the complete implementation from master key generation to runtime credential access.
Encryption Architecture Overview
The credential encryption system in CloddsBot operates across two primary modules. The Credentials Manager (src/credentials/index.ts) handles encryption/decryption operations and credential lifecycle management, while the Secret Store (src/trading/secrets.ts) manages database persistence, key rotation, and audit logging. Together they ensure that plaintext credentials never touch the disk.
Master Key Management
CloddsBot relies on a single master encryption key supplied via the CLODDS_CREDENTIAL_KEY environment variable.
Automatic Key Generation
If the environment variable is missing at startup, the core entry point in src/index.ts auto-generates a cryptographically secure 32-byte hex key. The system stores this key in process.env for the current runtime and attempts to persist it to ~/.clodds/.env for subsequent executions.
Runtime Validation
When CLODDS_CREDENTIAL_KEY is absent, the Credentials Manager logs a warning and disables encryption operations. This fail-safe mechanism prevents accidental storage of plaintext credentials by causing credential-dependent operations to fail fast.
AES-256-GCM Encryption Implementation
The encryption workflow in src/credentials/index.ts follows industry best practices for authenticated encryption.
Key Derivation and Cipher Initialization
For each encryption operation, the system generates a random 16-byte salt and 12-byte IV. It derives a 256-bit encryption key using crypto.scryptSync(masterKey, salt, 32), then initializes the cipher with crypto.createCipheriv('aes-256-gcm', ...).
Payload Structure
The resulting encrypted payload uses a versioned format prefixed with v2. The final stored string concatenates four components separated by colons: the version marker (v2), the hexadecimal salt, the hexadecimal IV, the authentication tag, and the ciphertext. This format enables forward compatibility and algorithm agility.
Legacy Decryption Support
The decrypt function in src/credentials/index.ts detects legacy credentials by checking for the version prefix. Credentials stored without the v2 marker trigger the legacy decryption path using AES-256-CBC, ensuring seamless migration from earlier versions without breaking existing user data.
Database Storage Schema
Encrypted credentials reside in the secrets table created by createSecretStore in src/trading/secrets.ts. The table stores credentials as JSON strings under the encrypted_data column, linked to user identifiers and provider names (e.g., "binance").
Credential Access Flow
The Credentials Manager exposes two primary methods for credential handling.
Storing Credentials
The setCredentials method accepts a user ID, provider name, and plain credential object. It serializes the object to JSON, encrypts it using the encrypt function, and persists the blob via db.createTradingCredentials or db.updateTradingCredentials.
Retrieving Credentials
The getCredentials method queries the database for the encrypted blob, invokes decrypt to recover the plaintext JSON, parses it into a typed object, and returns it. If decryption fails due to key mismatches or corruption, the method logs the error and returns null.
Master Key Rotation
The Secret Store provides a rotateKey(newMasterKey) method implemented in src/trading/secrets.ts. This function iterates through every row in the secrets table, decrypts each credential with the current master key, re-encrypts it with the new key, and updates the database in-place. After processing all rows, it updates the in-memory master key reference and logs the rotation event.
Security Controls and Audit Logging
Every write, read, delete, and rotation operation generates an audit entry in the secrets_audit table. These entries enable administrators to trace credential access patterns, detect unauthorized retrieval attempts, and verify key rotation completion.
Practical Implementation Examples
The following examples demonstrate working with the credential encryption system.
Storing trading credentials:
import { createCredentialsManager } from './credentials';
import { Database } from './db';
const db = new Database();
const credMgr = createCredentialsManager(db);
await credMgr.setCredentials(
'user-123',
'binance',
{ apiKey: 'my-api-key', secretKey: 'my-secret' }
);
Retrieving decrypted credentials:
const binanceCreds = await credMgr.getCredentials<BinanceCredentials>(
'user-123',
'binance'
);
if (binanceCreds) {
// Use decrypted credentials for API calls
}
Rotating the master encryption key:
import { createSecretStore } from './trading/secrets';
const db = new Database();
const oldKey = process.env.CLODDS_CREDENTIAL_KEY!;
const newKey = 'new-hex-encoded-32-byte-key-string-here';
const secretStore = await createSecretStore(db, oldKey);
await secretStore.rotateKey(newKey);
process.env.CLODDS_CREDENTIAL_KEY = newKey;
Summary
- CloddsBot uses AES-256-GCM authenticated encryption with scrypt key derivation for all credential storage.
- The master key derives from the
CLODDS_CREDENTIAL_KEYenvironment variable, with automatic generation and persistence if missing. - Encrypted credentials follow a versioned format (
v2:salt:iv:tag:ciphertext) supporting legacy AES-256-CBC fallback. - The Credentials Manager (
src/credentials/index.ts) and Secret Store (src/trading/secrets.ts) handle encryption operations and database persistence. - Built-in key rotation capability decrypts and re-encrypts all credentials without service interruption.
- Comprehensive audit logging in
secrets_audittracks every access and modification.
Frequently Asked Questions
What encryption algorithm does CloddsBot use?
CloddsBot implements AES-256-GCM (Galois/Counter Mode) for authenticated encryption. This provides both confidentiality and integrity verification through built-in authentication tags. The system derives keys using scrypt with a random 16-byte salt to resist brute-force attacks.
How does CloddsBot handle missing encryption keys?
If CLODDS_CREDENTIAL_KEY is not set at startup, the system auto-generates a secure 32-byte hex key in src/index.ts and attempts to save it to ~/.clodds/.env. During runtime, if the key remains unavailable, the Credentials Manager disables encryption and fails credential operations to prevent plaintext storage.
Can I rotate the encryption key without losing existing credentials?
Yes. The rotateKey method in src/trading/secrets.ts iterates through all stored secrets, decrypts them with the current master key, re-encrypts with the new key, and updates the database atomically. This operation maintains full data integrity while updating the encryption key.
Does CloddsBot support migrating from older encryption formats?
Yes. The decryption logic in src/credentials/index.ts automatically detects legacy AES-256-CBC encrypted credentials (version 1) by the absence of the v2 prefix and falls back to the legacy decryption path, ensuring seamless backward compatibility.
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 →