node-crypto

Opinionated AES-256-GCM encryption and decryption for serializable JavaScript objects, built on Node's crypto module.

Library
npm
v1.2.3
8stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
23/100Needs Attention
Development Activity16
Maintenance0
Community16
Maturity60
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
55/100Fair
Architecture65
Code Quality78
Innovation40
Learning Curve35

@elastic/node-crypto is a small TypeScript library, maintained by Elastic, that encrypts and decrypts any JSON-serializable value (strings, numbers, booleans, arrays, objects) using a fixed, strong set of cryptographic choices: AES-256-GCM for encryption, PBKDF2 (SHA-512, 10,000 iterations) for key derivation from a passphrase, a per-call random salt and IV, and an authentication tag to detect tampering. None of these parameters are configurable by the caller, which is the point — it removes the most common way consumer code accidentally weakens its own encryption.

The module exports a single factory function, makeCryptoWith({ encryptionKey }), which returns an object exposing encrypt/decrypt (Promise-based, using Node’s async crypto.pbkdf2) and encryptSync/decryptSync (using crypto.pbkdf2Sync) — the same guarantees in both blocking and non-blocking form. Every encrypted payload embeds its own salt, IV, and auth tag alongside the ciphertext, base64-encoded as a single string, so decrypting only requires the original passphrase and the stored output.

What You Get

  • A makeCryptoWith(opts) factory that binds an encryption passphrase once and returns ready-to-use encrypt/decrypt functions
  • Both Promise-based (encrypt/decrypt) and synchronous (encryptSync/decryptSync) variants backed by the same algorithm
  • Support for any JSON-serializable input — strings, numbers, booleans, arrays, and plain objects — round-tripped exactly via JSON.stringify/JSON.parse
  • Optional Additional Authenticated Data (AAD) on both encrypt and decrypt to bind ciphertext to a context string without encrypting it
  • Self-contained ciphertext output — salt, IV, and GCM auth tag are packed into the same base64 string, so no side-channel state needs to be stored separately
  • Full TypeScript type definitions shipped with the package (CryptoOptions, Crypto, EncryptOutput)

Common Use Cases

  • Encrypting secrets (API keys, credentials, tokens) at rest inside a Kibana or Node.js backend configuration store
  • Protecting serialized session or state objects before persisting them to a database or cache
  • Adding tamper-evidence to values passed between services by supplying an AAD tied to the request context
  • Replacing ad hoc crypto module usage in a codebase with a single, audited, opinionated implementation to avoid inconsistent algorithm choices across call sites

Under The Hood

Architecture The entire module lives in one file, src/crypto.ts, built around a factory-function pattern: makeCryptoWith(opts) validates its CryptoOptions once and closes over the encryptionKey, returning a Crypto object with four methods that share the same private helpers (_generateSalt, _generateIV, _generateKey/_generateKeySync, _serialize, module-level encrypt/decrypt). The async and sync code paths are intentionally parallel rather than deduplicated — the async variants use crypto.pbkdf2 wrapped in a Promise while the sync variants call crypto.pbkdf2Sync directly — trading a small amount of duplication for keeping each path simple to read in isolation. Because the module is a thin, deliberately non-extensible wrapper, the load-bearing abstraction is the fixed byte layout of the output (salt + IV + auth tag + ciphertext, in that order); the README’s own maintainer notes flag that changing any encryption parameter changes this layout and requires a major version bump, which is the project’s real architectural contract with its consumers.

Tech Stack Written in TypeScript (5.1) with zero runtime dependencies — it calls Node’s built-in crypto module directly rather than any third-party crypto package. The dev toolchain is tsc for compilation to lib/, jest/ts-jest for tests, and tslint (with tslint-config-prettier/tslint-plugin-prettier) for linting, alongside a retire audit step wired into npm test. CI is configured via a .travis.yml targeting Node stable, 10, and 8, with Codecov coverage upload on success — there is no GitHub Actions workflow in the repository, so Travis (largely inactive for open source projects today) appears to be the only configured CI path.

Code Quality The test suite (src/crypto.test.ts, ~280 lines) is thorough for the module’s scope: it exercises encrypt/decrypt round-trips across strings, numbers, booleans, arrays, and objects, covers both the async and sync APIs, tests AAD success and mismatch behavior, and asserts that missing encryptionKey and non-serializable input throw. Types are precise and exported (CryptoOptions, Crypto, EncryptOutput) rather than left as any. The lint tooling (tslint) is deprecated upstream in favor of ESLint, which is a maintenance-debt signal even though the rules themselves (via tslint-config-prettier) are reasonable. No inline comments beyond the top-of-file doc block, which is adequate given the code’s small size and self-explanatory helper names.

What Makes It Unique The library isn’t technically novel — AES-256-GCM with PBKDF2 key derivation is a standard, well-documented construction — but its value is the opinionation: callers cannot choose a weaker cipher, a low iteration count, or reuse a salt, because none of those are exposed as options. That constraint, plus bundling the salt/IV/tag into the ciphertext itself, makes it a drop-in way to get a single consistent encryption behavior across many call sites in a larger codebase, which is exactly the problem it was built to solve inside Elastic’s own products.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search