@supercat1337/aes-gcm
v2.0.2
Published
AES-GCM encryption for browser using Web Crypto API. Supports strings, files, Web Workers, and chunked multipart encryption.
Maintainers
Readme
AES-GCM Encryption Library for JavaScript (ESM)
A modern, zero-dependency JavaScript library for AES-GCM encryption using the Web Crypto API.
Supports ArrayBuffer, Uint8Array, string, File/Blob objects, and multi‑part (chunked) file encryption.
All cryptographic operations can be offloaded to Web Workers to keep the main thread responsive.
✨ Features
- ✅ AES‑GCM 256 – industry standard authenticated encryption
- ✅ Web Workers – encrypt/decrypt without blocking UI
- ✅ Parallel Multipart Processing – concurrent chunk processing with a worker pool for fast, non-blocking large file encryption
- ✅ High-Level Password API – automated salt/key derivation and secure serialization out of the box
- ✅ File encryption – single file or chunked (multi‑part) for large files
- ✅ Ultra-fast Base64 – native-level encoding/decoding using
FileReaderwithout call-stack memory limits - ✅ Zero dependencies – uses only Web Crypto API
- ✅ TypeScript ready – JSDoc annotated +
.d.tsgeneration - ✅ Tree‑shakeable ESM – import only what you need
📦 Installation
npm install @supercat1337/aes-gcmOr use directly in the browser:
<script type="module">
import { encryptBytes, decryptBytes } from './dist/aes-gcm.esm.js';
</script>🚀 Quick Start
Encrypt / Decrypt a string
import {
encryptBytes,
decryptBytes,
generateRawSecret,
stringToBuffer,
bufferToString,
} from 'aes-gcm';
// 1. Generate a random 32‑byte key
const rawKey = generateRawSecret();
// 2. Data to encrypt
const plaintext = 'Hello, world!';
const plainBytes = stringToBuffer(plaintext);
// 3. Encrypt
const encrypted = await encryptBytes(plainBytes, rawKey);
// 4. Decrypt
const decryptedBytes = await decryptBytes(encrypted, rawKey);
const decryptedText = bufferToString(decryptedBytes);
console.log(decryptedText); // "Hello, world!"Using Web Workers
import { WorkerEncrypt, WorkerDecrypt, generateRawSecret, stringToBuffer } from 'aes-gcm';
const rawKey = generateRawSecret();
const workerEnc = new WorkerEncrypt();
const workerDec = new WorkerDecrypt();
const encrypted = await workerEnc.encrypt({
data: stringToBuffer('secret'),
rawSecret: rawKey,
});
const decrypted = await workerDec.decrypt({
data: encrypted,
rawSecret: rawKey,
});
workerEnc.worker.terminate();
workerDec.worker.terminate();📚 API Reference
🔐 Core Encryption
| Function | Description |
| -------------------------------------------------------------------------- | --------------------------------------------------- |
| encryptBytes(bytes: Uint8Array, rawKey: Uint8Array): Promise<Uint8Array> | Encrypts data. Returns IV + ciphertext + authTag. |
| decryptBytes(bytes: Uint8Array, rawKey: Uint8Array): Promise<Uint8Array> | Decrypts data. |
🔑 Key Management
| Function | Description |
| ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| generateRawSecret(): Uint8Array | Generates a cryptographically random 32‑byte key. |
| createCryptoKey(secret?: string \| Uint8Array): Promise<CryptoKey> | Imports a raw key or generates a new one. |
| exportSecret(cryptoKey: CryptoKey): Promise<string> | Exports key as Base64URL string. |
| exportRawSecret(cryptoKey: CryptoKey): Promise<Uint8Array> | Exports key as raw bytes. |
| exportJwk(cryptoKey: CryptoKey): Promise<JsonWebKey> | Exports key as JWK. |
| createMasterKeyFromPassword(password: string): Promise<CryptoKey> | Derives a master key using PBKDF2 (no salt yet). |
| derivedKeyFromMasterKey(masterKey: CryptoKey, salt: Uint8Array, iterations?: number): Promise<CryptoKey> | Derives a child AES‑GCM key. |
| generateSalt(): Uint8Array | Generates a 16‑byte random salt. |
🔒 Password-Based Encryption (High-Level)
If you don't want to manage salts, iterations, and binary concatenation manually, use the simplified password API. It automatically derives keys and packages everything into a transportable format:
import { encryptWithPassword, decryptWithPassword } from '@supercat1337/aes-gcm';
const data = new TextEncoder().encode('Secret message');
const password = 'my-secure-password';
// 1. Encrypt (automatically manages PBKDF2 salt and metadata internally)
const packedBytes = await encryptWithPassword(data, password, {
iterations: 600000, // optional, default 600000
hash: 'SHA-256', // optional, default 'SHA-256' (supports SHA-384, SHA-512)
});
// 2. Decrypt
const decryptedBytes = await decryptWithPassword(packedBytes, password);
const originalText = new TextDecoder().decode(decryptedBytes);
console.log(originalText); // 'Secret message'📁 File Encryption
Single File (whole file in memory)
import { SingleFileEncryptor, SingleFileDecryptor } from 'aes-gcm';
// Encrypt
const file = fileInput.files[0];
const encryptor = new SingleFileEncryptor(file, rawKey);
const encryptedData = await encryptor.encrypt(); // Uint8Array
// save encryptedData as .enc file
encryptor.terminate();
// Decrypt
const decryptor = new SingleFileDecryptor(encryptedFileBlob, rawKey);
const metadata = await decryptor.decryptMetaData(); // { fileName, fileSize, fileType }
const content = await decryptor.decryptContent(); // Uint8Array
// reassemble Blob and download
decryptor.terminate();Multi‑Part (chunked) – for large files
import { MultipartFileEncryptor, MultipartFileDecryptor } from 'aes-gcm';
// Encrypt (file split into chunks of 512 KB)
const encryptor = new MultipartFileEncryptor(file, rawKey, 512);
const encryptedMeta = await encryptor.encryptMetaData();
const encryptedChunks = [];
for (let i = 0; i < encryptor.totalChunks; i++) {
encryptedChunks.push(await encryptor.encryptChunk(i));
}
encryptor.terminate();
// Decrypt
const decryptor = new MultipartFileDecryptor(encryptedMeta, encryptedChunks, rawKey);
const decryptedBlob = await decryptor.decrypt();
// decryptedBlob is the original file🛠️ Utilities
| Function | Description |
| ------------------------------------------------------ | ------------------------------------------------ |
| stringToBuffer(str: string): Uint8Array | UTF‑8 encode string. |
| bufferToString(buf: Uint8Array): string | UTF‑8 decode. |
| bufferToBase64(buf: ArrayBuffer): Promise<string> | Convert to standard base64. |
| bufferToBase64URL(buf: ArrayBuffer): Promise<string> | Convert to base64url (RFC 4648). |
| base64URLToBuffer(base64url: string): Uint8Array | Decode base64url to bytes. |
| bjson(obj: object): Uint8Array | Binary JSON (8‑byte length prefix + JSON UTF‑8). |
| bjsonParse(bytes: Uint8Array): object | Parse binary JSON. |
⚙️ Web Worker Classes
Both WorkerEncrypt and WorkerDecrypt accept { data: Uint8Array|Blob, rawSecret: Uint8Array } and return a Promise<Uint8Array>.
They automatically transfer ArrayBuffer ownership for zero‑copy performance.
Always call
.terminate()when done to free the worker thread.
🔒 Security Notes
- The library uses AES‑GCM with 256‑bit keys, 12‑byte random IV, and 128‑bit authentication tag – following current best practices.
- Keys are never logged or exposed unintentionally.
- For passwords, always use
PBKDF2with a high iteration count (e.g. 600 000) and a random salt. - The library does not implement any obfuscation or “custom encryption” – only standard Web Crypto.
- ⚠️ When encrypting extremely large files (≥1 GB) with
SingleFileEncryptor, the entire file is loaded into memory. UseMultipartFileEncryptorfor such cases.
🧪 Examples
Run any example locally (after building):
npm run build
cd example/basic-string
npx serveAvailable examples:
basic-string/– encrypt/decrypt a string, export/import keyworker-string/– using Web Workerssimple-encrypt/– directencryptBytes/decryptByteskey-formats/– raw, base64url, JWK conversionssingle-file/– encrypt/decrypt a file (one chunk)multipart/– split large file into encrypted chunks and reassemble
📄 License
MIT © [Albert Bazaleev]
