hybrid-crypto-express
v1.0.0
Published
Lightweight hybrid (RSA + AES-GCM) encryption for Node.js and Express microservices
Maintainers
Readme
hybrid-crypto-express
Lightweight hybrid encryption for Node.js and Express: RSA-OAEP for key exchange and AES-256-GCM for payloads. Zero dependencies, uses only Node.js crypto. Suited for microservices and APIs that need optional end-to-end encryption.
Security
- RSA-OAEP (2048-bit, SHA-256) for encrypting the ephemeral AES key
- AES-256-GCM (12-byte IV, 16-byte auth tag) for request/response bodies
- Session keys stored server-side with configurable TTL; no key reuse across sessions
- Constant-time safe where applicable via Node
crypto
Install
npm install hybrid-crypto-expressServer (Express)
const express = require('express');
const {
HybridCrypto,
decryptRequest,
encryptResponse,
registerCryptoRoutes
} = require('hybrid-crypto-express');
const app = express();
const hybridCrypto = new HybridCrypto({
sessionExpiryMs: 5 * 60 * 1000 // 5 min
});
// 1) Decrypt encrypted requests (must run before body parser for encrypted paths)
app.use(decryptRequest(hybridCrypto, {
skipPaths: ['/health', '/', '/api/crypto/public-key', '/api/crypto/handshake']
}));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(express.json({ limit: '10mb' }));
// 2) Crypto endpoints + optional test route
registerCryptoRoutes(app, hybridCrypto, { testRoute: true });
// 3) Encrypt responses when client sends X-Encrypted: true
app.use(encryptResponse(hybridCrypto));
app.get('/health', (req, res) => {
res.json({ status: 'ok', encryption: true });
});
app.post('/api/secure-action', (req, res) => {
// req.body is decrypted when request was encrypted
res.json({ received: req.body });
});
app.listen(3000);Client (Node or microservice)
const { HybridCryptoClient } = require('hybrid-crypto-express');
const client = new HybridCryptoClient('my-service-id');
async function run() {
await client.handshake('http://localhost:3000');
const payload = { userId: 1, action: 'submit' };
const encrypted = client.encryptPayload(payload);
const res = await fetch('http://localhost:3000/api/secure-action', {
method: 'POST',
headers: client.getEncryptedRequestHeaders(),
body: JSON.stringify(encrypted)
});
const body = await res.json();
if (body.encrypted) {
const decrypted = client.decryptPayload(body);
console.log(decrypted);
} else {
console.log(body);
}
}
run();API
Server
HybridCrypto(options?)sessionExpiryMs– session TTL (default 5 min)rsaModulusLength– default 2048
decryptRequest(hybridCrypto, options?)- Decrypts body when
X-Encrypted: trueandX-Client-IDare set. options.skipPaths– paths that skip decryption (default includes/api/crypto/public-key,/api/crypto/handshake).
- Decrypts body when
encryptResponse(hybridCrypto)- Wraps
res.jsonto encrypt when same headers are present.
- Wraps
registerCryptoRoutes(app, hybridCrypto, options?)- Adds
GET /api/crypto/public-keyandPOST /api/crypto/handshake. options.pathPrefix– default'/api/crypto'.options.testRoute– addPOST /api/crypto/test.
- Adds
Client
HybridCryptoClient(clientId?)handshake(baseUrl, fetchOptions?)– fetch public key, send encrypted AES key, establish session.encryptPayload(data)– returns{ ciphertext, iv, authTag }.decryptPayload(encrypted)– expects{ ciphertext, iv, authTag }.getEncryptedRequestHeaders()–X-Client-ID,X-Encrypted: true,Content-Type.
getPublicKey(baseUrl, fetchOptions?)– one-off fetch of server public key.
Subpath imports
const { HybridCrypto } = require('hybrid-crypto-express/server');
const { HybridCryptoClient } = require('hybrid-crypto-express/client');
const { decryptRequest, encryptResponse, registerCryptoRoutes } = require('hybrid-crypto-express/middleware');CORS
Allow these headers so clients can use encryption:
X-Client-ID,X-Encrypted,X-Encryption-Type- Expose:
X-Encrypted,X-Encryption-Algorithm,X-Session-Expiry
License
MIT
