aegis-lock
v2.1.0
Published
Database-agnostic client-side AES-256-GCM field-level encryption. Works with Supabase, MongoDB, or any database via pluggable adapters.
Downloads
322
Maintainers
Readme
aegis-lock
Database-agnostic client-side AES-256-GCM field-level encryption with Contextual Binding and Blind Indexing.
Encrypt sensitive fields before they leave the browser or server. Decrypt after select. Zero plaintext hits the wire or your database. Works with Supabase, MongoDB, or any database via custom adapters.
⚠️ SECURITY WARNING:
aegis-lockprovides the cryptographic primitives, but you are responsible for your keys. Never hardcodeCryptoKeyexports in your source code. Always use a secure Key Management Service (KMS) or strict, vault-backed environment variables to inject your keys at runtime.
Requirements
- Node.js 18+ (or any environment supporting the standard Web Crypto API, such as modern browsers, Cloudflare Workers, or Vercel Edge functions).
Install
npm install aegis-lockQuick Start — Supabase
import { createClient } from "@supabase/supabase-js";
import { AegisClient, SupabaseAdapter, generateKey, generateBidxKey, exportKey } from "aegis-lock";
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
const adapter = new SupabaseAdapter(supabase);
// Generate your master encryption key and searchable blind index key
const key = await generateKey();
const bidxKey = await generateBidxKey();
// Export and save these securely! e.g., await exportKey(key)
const aegis = new AegisClient({
adapter,
primaryKeyField: "record_id", // REQUIRED: Binds ciphertext to the row to prevent tampering
encryptedFields: {
secure_fields: ["encrypted_content", "ssn", "email"]
},
bidxFields: {
secure_fields: ["email"] // Optional: Creates an 'email_bidx' column for searching
}
}, key, bidxKey);
// 1. Insert — fields are auto-encrypted.
// Note: You MUST provide the primary key application-side!
await aegis.insert("secure_fields", {
record_id: "uuid-1234-5678",
email: "[email protected]",
encrypted_content: "Top secret",
});
// 2. Select — Aegis automatically hashes the email to search the 'email_bidx' column securely
const { data } = await aegis.select("secure_fields", {
column: "email",
value: "[email protected]"
});
// 3. Update — automatically re-encrypts with a new IV and updates the blind index
await aegis.update("secure_fields", {
record_id: "uuid-1234-5678", // Must include the primary key!
email: "[email protected]",
encrypted_content: "New secret"
});
// 4. Delete — Aegis automatically hashes the email to find the correct row to delete
await aegis.delete("secure_fields", {
column: "email",
value: "[email protected]"
});Quick Start — MongoDB
import { MongoClient } from "mongodb";
import { AegisClient, MongoDBAdapter, generateKey } from "aegis-lock";
import { v4 as uuidv4 } from "uuid";
const mongo = new MongoClient("mongodb://localhost:27017");
await mongo.connect();
const adapter = new MongoDBAdapter(mongo.db("myapp"));
const key = await generateKey();
const aegis = new AegisClient({
adapter,
primaryKeyField: "_id",
encryptedFields: {
users: ["ssn", "credit_card"]
}
}, key);
const newUserId = uuidv4();
// 1. Insert with a client-generated ID
await aegis.insert("users", {
_id: newUserId,
name: "Alice",
ssn: "123-45-6789"
});
// 2. Select by an unencrypted field
const { data } = await aegis.select("users", {
column: "name",
value: "Alice"
});
// data[0].ssn → "123-45-6789" (decrypted)
// 3. Update — automatically re-encrypts the SSN with a new IV
await aegis.update("users", {
_id: newUserId, // Must include the primary key!
name: "Alice",
ssn: "999-99-9999"
});
// 4. Delete — Removes the record from the database
await aegis.delete("users", {
column: "_id",
value: newUserId
});Custom Adapter
Implement the DatabaseAdapter interface for any database:
import { DatabaseAdapter } from "aegis-lock";
class MyAdapter implements DatabaseAdapter {
async insert(table: string, data: Record<string, unknown>) {
// your insert logic
return { data: [data], error: null };
}
async select(table: string, query?) {
// your select logic
return { data: [], error: null };
}
async update(table: string, data: Record<string, unknown>) {
// your update logic
return { data: [data], error: null };
}
async delete(table: string, query: { column: string; value: unknown }) {
// your delete logic
return { data: [], error: null };
}
}API
new AegisClient(config, key, bidxKey?)
config—AegisConfigobject:adapter: anyDatabaseAdapter(SupabaseAdapter,MongoDBAdapter, or custom)primaryKeyField:string(The ID field used for cryptographic contextual binding)encryptedFields:Record<tableName, fieldName[]>bidxFields: (Optional)Record<tableName, fieldName[]>
key—CryptoKeyfromgenerateKey()orimportKey()bidxKey— (Optional)CryptoKeyfromgenerateBidxKey()orimportKey()
AegisClient Methods
insert(table, data): Encrypts data and creates blind indexes before saving.select(table, query): Fetches and automatically decrypts data. Intercepts blind index queries.update(table, data): Re-encrypts modified fields with new IVs and updates blind indexes.delete(table, query): Intercepts queries to securely delete by blind-indexed fields.selectRaw(table, query): Bypasses decryption to return raw database records (useful for auditing or migrations).
Adapters
new SupabaseAdapter(supabaseClient)new MongoDBAdapter(mongoDb)
Crypto Utilities
generateKey()/generateBidxKey()exportKey(key)/importKey(base64)
How It Works (Security Architecture)
- Web Crypto API (AES-256-GCM): Runs natively in any modern browser or edge runtime.
- Field-Level IVs: Every single encrypted field gets a unique, mathematically random Initialization Vector (IV) stored as a composite string (
iv:ciphertext) to prevent keystream reuse attacks. - Contextual Binding (AAD): Ciphertexts are cryptographically bound to the row's
primaryKeyField. If an attacker copies an encrypted SSN from User A and pastes it into User B's row, the decryption will strictly fail. - Blind Indexing (HMAC-SHA256): Because AES-GCM is non-deterministic (the same text encrypts differently every time), you cannot query standard encrypted fields. If configured via
bidxFields, Aegis-Lock automatically generates deterministic, memory-aligned HMAC hashes. This allows you to search for exact matches (like looking up an email address) without exposing the plaintext to the database. - Database-agnostic: Swap adapters without changing your core application code.
License
MIT
