Lightweight application-level field encryption (ALFE) for Node.js/Mongoose and MongoDB.
Transparent encrypt/decrypt on write/read, HMAC blind index for exact-match queries, multi-DEK envelope encryption with key rotation, multi-KMS/SM-crypto support, and 100% interoperability with the Java LightCrypto-Link ecosystem.
npm install lightcrypto-link-node- Configure a CMK provider (local hex key, Azure Key Vault, or Alibaba Cloud KMS).
- Define schema with
encrypt: trueand optionallyblindIndex: true. - Use Mongoose normally — encryption/decryption is automatic.
Deep docs are in docs:
- Configuration — env vars, secret managers, CMK provider setup
- Architecture — envelope encryption, key vault format, rotation
- CMK Provider — custom provider interface and built-in providers
- Type Mapping — Java ↔ Node.js type compatibility
- Troubleshooting — common errors, security, limitations
- Transparent field encryption via Mongoose plugin (pre-save/post-find hooks)
- Blind indexing for exact-match queries (HMAC-SHA-256)
- Multiple algorithms: AES-256-GCM (default), AES-256-CBC, SM4-CBC (China compliance)
- Structured type encryption: whole-object (
DOC), whole-array (COL), element-level array encryption - Nested path encryption for sub-documents and array elements (e.g.,
address.street,items[].price) - Encryption mode control:
AUTO(default),ELEMENT,WHOLE - Per-entity DEK versioning and rotation
- Pluggable CMK providers: Local, Azure Key Vault, Alibaba Cloud KMS
- Zero third-party crypto dependencies (native Node.js
crypto) - BSON format compatible with Java LightCrypto-Link (DOC, COL, MAP type markers)
npm install lightcrypto-link-nodeCloud KMS (optional):
# Azure Key Vault
npm install @azure/keyvault-keys @azure/identity
# Alibaba Cloud KMS
npm install @alicloud/kms20160120 @alicloud/openapi-clientLocal symmetric CMK:
const { LocalCmkProvider } = require('lightcrypto-link-node');
const cmkProvider = new LocalCmkProvider('your-64-char-hex-cmk-key');See docs/configuration.md for Azure Key Vault, Alibaba Cloud KMS, and environment variable setup.
const mongoose = require('mongoose');
const { lclCryptoPlugin, KeyVaultService, prepareEncryptedSchema } = require('lightcrypto-link-node');
const keyVaultService = new KeyVaultService({
connection: mongoose.connection,
cmkProvider,
cacheTtl: 3600000 // 1 hour
});
const userSchema = new mongoose.Schema(prepareEncryptedSchema({
name: { type: String },
phone: { type: String, encrypt: true, blindIndex: true },
ssn: { type: String, encrypt: true }
}));
userSchema.plugin(lclCryptoPlugin, {
keyVaultService,
entityName: 'User',
algorithm: 'AES_256_GCM'
});
const User = mongoose.model('User', userSchema);// Encryption is automatic on save
const user = new User({ name: 'John', phone: '13800138000', ssn: '123-45-6789' });
await user.save();
// Decryption is automatic on find
const found = await User.findById(user._id);
console.log(found.phone); // '13800138000'
// Blind index queries work transparently
const result = await User.findOne({ phone: '13800138000' });| Option | Type | Description |
|---|---|---|
encrypt: true |
Boolean | Enable encryption for this field |
blindIndex: true |
Boolean | Enable blind index for exact-match queries |
fieldName: string |
String | Custom field name for blind index (cross-entity sharing) |
mode: string |
String | Encryption mode: AUTO (default), ELEMENT, WHOLE |
| Field Type | AUTO (default) | ELEMENT | WHOLE |
|---|---|---|---|
| Scalar (String, Number, etc.) | field-level | field-level | field-level |
| Sub-document (POJO) | whole-object (DOC) |
error | whole-object (DOC) |
| Array of scalars | element-level | element-level | whole-array (COL) |
| Array of sub-docs | whole-array (COL) |
error | whole-array (COL) |
// Whole-object encryption (DOC) — sub-document Schema instance
const addressSchema = new mongoose.Schema({ street: String, city: String });
const userSchema = new mongoose.Schema(prepareEncryptedSchema({
name: String,
address: { type: addressSchema, encrypt: true } // AUTO → DOC
}));
// Element-level encryption — scalar array
tags: { type: [String], encrypt: true } // AUTO → element-level
// Whole-array encryption (COL) — explicit mode
tags: { type: [String], encrypt: true, mode: 'WHOLE' } // → COL
// Nested path encryption — encrypt specific fields within sub-documents
address: {
street: { type: String, encrypt: true }, // only street encrypted, city visible
city: String
}
// Nested path in array elements — items[].price encrypted per-element
items: [{ sku: String, price: { type: Number, encrypt: true } }]await keyVaultService.rotateDek('User');
keyVaultService.flushCache();For behavior details, see docs/architecture.md.
Use ProgrammaticCryptoService for manual encryption/decryption outside Mongoose — raw driver queries, aggregation pipelines, migration scripts, and DTO encryption:
const { ProgrammaticCryptoService, KeyVaultService, LocalCmkProvider } = require('lightcrypto-link-node');
const keyVaultService = new KeyVaultService({ connection, cmkProvider });
const programmatic = new ProgrammaticCryptoService({ keyVaultService, algorithm: 'AES_256_GCM' });
// Encrypt a scalar value
const subDoc = await programmatic.encryptValue('13800138000', 'User');
// → { _e: 1, _k: 'v1-abcd1234', _a: 'AES_256_GCM', _t: 'STR', c: <Buffer> }
// Decrypt a sub-document
const plaintext = await programmatic.decryptValue(subDoc);
// → '13800138000'
// Decrypt fields in a raw document (e.g., from aggregation or db.collection.find())
const rawDoc = await db.collection('users').findOne({ name: 'Alice' });
await programmatic.decryptDocument(rawDoc, 'User', ['phone', 'ssn']);
// rawDoc.phone and rawDoc.ssn are now plaintextFor low-level field operations (without key vault integration), use FieldCryptoService:
const { FieldCryptoService } = require('lightcrypto-link-node');
const fieldService = new FieldCryptoService();
const encrypted = fieldService.encryptField(value, fieldName, dek, hmacKey, kid, algorithm);
const decrypted = fieldService.decryptField(encrypted, dek, hmacKey, algorithm);See examples/ for runnable demos:
node examples/basic-crud.js # CRUD with blind index
node examples/multi-algorithm.js # AES-GCM, AES-CBC, SM4-CBC
node examples/key-rotation.js # DEK rotation
node examples/config-from-env.js # Configuration sources
node examples/programmatic-encrypt.js # Programmatic encrypt/decrypt API
node examples/azure-kms.js # Azure Key Vault
node examples/alibaba-kms.js # Alibaba Cloud KMSlightcrypto-link-node/
├── src/
│ ├── crypto/ # Encryptor implementations (AES-GCM, AES-CBC, SM4-CBC)
│ ├── service/ # KeyVaultService, FieldCryptoService, TypeSerializer
│ ├── provider/ # CMK providers (Local, Azure, Alibaba)
│ ├── plugin/ # Mongoose plugin and query rewriter
│ ├── model/ # KeyVaultDocument schema
│ ├── config/ # LclConfig (multi-source loader)
│ └── index.js # Public API exports
├── test/
│ ├── unit/
│ ├── integration/
│ └── interoperability/
├── docs/ # Detailed documentation
├── examples/ # Runnable examples
└── openspec/ # OpenSpec change proposals
- Node.js: 22.x (recommended), 24.x
- Mongoose: 8.x, 9.x
- MongoDB: 5.0+, 6.0+, 7.0+, 8.0+
- Java LightCrypto-Link: BSON format compatible (DOC, COL, MAP type markers). Note: MAP encryption from Node.js is not yet supported; MAP decryption from Java-encrypted documents works.