@mediagato/crypto
v0.1.0
Published
End-to-end encryption primitives — AES-256-GCM with PBKDF2-derived keys. Web Crypto everywhere (browser, modern Node, Cloudflare Workers, Deno, Bun). Originally lifted from TabbJam's bookmark-sync crypto layer.
Downloads
48
Maintainers
Readme
@mediagato/crypto
End-to-end encryption primitives for MEDiAGATO products. AES-256-GCM authenticated encryption with PBKDF2-derived keys (600k iterations, OWASP 2023+ recommendation).
Built on Web Crypto, runs identically in:
- Browsers (extension popups, content scripts, web pages)
- Modern Node (>=19, where
globalThis.crypto.subtleis native) - Cloudflare Workers / Pages Functions
- Deno, Bun
Why
Two MEDiAGATO products needed E2E encryption: TabbJam's bookmark sync (shipped to Chrome Web Store) and Mr. Mags's upcoming sync tier. Carving out the primitive once means both consume the same audited code, neither has to reinvent, and any future product gets a battle-tested base.
Install
npm i @mediagato/cryptoUse
import { encrypt, decrypt } from '@mediagato/crypto';
const blob = await encrypt(
{ hello: 'world' },
'correct-horse-battery-staple'
);
// blob = { ciphertext, iv, salt, checksum }
const original = await decrypt(
blob.ciphertext, blob.iv, blob.salt, blob.checksum,
'correct-horse-battery-staple'
);
// original = { hello: 'world' }The salt is derived once on first encrypt — pass it back as the third argument to subsequent encrypt() calls if you want the same derived key (so a server can de-duplicate or version blobs without seeing plaintext).
The IV is fresh every call — never reuse one with the same key. Encrypting the same plaintext twice with the same passphrase + salt produces different ciphertext but decrypts to the same value.
The checksum is a SHA-256 of the plaintext, verified post-decrypt. AES-GCM already authenticates, so a tampered ciphertext won't decrypt at all; the checksum is a belt-and-suspenders against bugs at the storage layer.
Browser global
For drop-in use inside MV3 extensions (where you might not want a bundler), the module also assigns globalThis.MediagatoCrypto = { encrypt, decrypt, deriveKey } — same surface as the named exports.
What it isn't
Not a library for arbitrary cryptographic protocols. Just symmetric encryption of JSON values with a user-held passphrase. If you need asymmetric key exchange, signatures, or anything beyond "encrypt this blob, decrypt it later," reach for libsodium-wrappers or tweetnacl instead.
License
MIT — see LICENSE.
