- TypeScript 100%
| src | ||
| tests | ||
| .gitignore | ||
| .npmrc | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| README.md | ||
| tsconfig.json | ||
| tsdown.config.ts | ||
minicrypt
Simple TypeScript library for symmetric encryption.
Provides four authenticated encryption ciphers:
- AES-256-GCM — Standard, widely supported, hardware-accelerated
- AES-256-GCM-SIV — Nonce-misuse-resistant variant of AES-GCM
- ChaCha20-Poly1305 — Fast software cipher, used in TLS 1.3 and WireGuard
- XChaCha20-Poly1305 — Extended-nonce variant, safe with random nonces
Warning
This library is designed for encryption/decryption of data, not for hashing or storing passwords. Use a dedicated password-hashing function (Argon2id, bcrypt, scrypt) for password storage.
Installation
pnpm add minicrypt
Important
The
keyparameter is not an encryption key — it is a secret string that gets derived into a 256-bit key via HKDF-SHA256 (RFC 5869) with domain separation. Use a high-entropy secret (e.g.,crypto.randomBytes(32)hex-encoded, or a strong passphrase). Low-entropy secrets like"my-password"are trivially brute-forced — HKDF is a key-derivation function, not a password hasher. If you need to use a user-provided password, hash it through Argon2id / scrypt / bcrypt first, then use the result as the key.
Usage
AES-256-GCM
Standard, widely supported, hardware-accelerated (AES-NI).
import { encrypt, decrypt } from "minicrypt/aes-256-gcm";
import crypto from "crypto";
// Generate a high-entropy secret
const key = crypto.randomBytes(32).toString("hex");
const encrypted = await encrypt({ key, data: "Hello, World!" });
const decrypted = await decrypt({ key, data: encrypted });
AES-256-GCM-SIV
Nonce-misuse-resistant: if a nonce is reused, only reveals whether plaintexts are identical.
import { encrypt, decrypt } from "minicrypt/aes-256-gcm-siv";
import crypto from "crypto";
const key = crypto.randomBytes(32).toString("hex");
const encrypted = await encrypt({ key, data: "Hello, World!" });
const decrypted = await decrypt({ key, data: encrypted });
ChaCha20-Poly1305
Standard 12-byte nonce variant used in TLS 1.3, WireGuard, and SSH.
import { encrypt, decrypt } from "minicrypt/chacha20-poly1305";
import crypto from "crypto";
const key = crypto.randomBytes(32).toString("hex");
const encrypted = await encrypt({ key, data: "Hello, World!" });
const decrypted = await decrypt({ key, data: encrypted });
XChaCha20-Poly1305
Extended 24-byte nonce — safe to use with randomly generated nonces.
import { encrypt, decrypt } from "minicrypt/xchacha20-poly1305";
import crypto from "crypto";
const key = crypto.randomBytes(32).toString("hex");
const encrypted = await encrypt({ key, data: "Hello, World!" });
const decrypted = await decrypt({ key, data: encrypted });
API
All modules export the same async interface:
encrypt(options: CryptoOptions): Promise<string>
- options.key — The secret string used as HKDF-SHA256 input key material
- options.data — The plaintext string to encrypt
- Returns — Hex-encoded ciphertext with embedded nonce and auth tag
decrypt(options: CryptoOptions): Promise<string>
- options.key — The secret string (must match the one used for encryption)
- options.data — The hex-encoded ciphertext to decrypt
- Returns — The decrypted plaintext string
- Throws — If decryption fails (wrong key or tampered data)
Choosing a Cipher
| Cipher | Nonce Size | Best For |
|---|---|---|
| AES-256-GCM | 12 bytes | General purpose, hardware acceleration |
| AES-256-GCM-SIV | 12 bytes | When nonce uniqueness isn't guaranteed |
| ChaCha20-Poly1305 | 12 bytes | Software-only environments, mobile |
| XChaCha20-Poly1305 | 24 bytes | Random nonces, high-volume encryption |
Development
# Install dependencies
pnpm install
# Run tests
pnpm test
# Build library
pnpm build
# Type check
pnpm typecheck
Credits
- Uses @noble/ciphers for AEAD cipher implementations
- Uses @noble/hashes for HKDF-SHA256 key derivation
License
MIT