age-encryption
is a TypeScript
implementation of the age file encryption format.
It depends only on the noble cryptography libraries, and uses the Web Crypto API when available.
npm install age-encryption
age-encryption
is a modern ES Module with built-in types.
It's compiled for ES2022, and compatible with Node.js 18+, Bun, Deno, and all recent browsers.
import * as age from "age-encryption"
const identity = await age.generateIdentity()
const recipient = await age.identityToRecipient(identity)
console.log(identity)
console.log(recipient)
const e = new age.Encrypter()
e.addRecipient(recipient)
const ciphertext = await e.encrypt("Hello, age!")
const d = new age.Decrypter()
d.addIdentity(identity)
const out = await d.decrypt(ciphertext, "text")
console.log(out)
age encrypted files (the inputs of Decrypter.decrypt
and outputs of
Encrypter.encrypt
) are binary files, of type Uint8Array
. There is an official ASCII
"armor" format, based on PEM, which provides a way to encode an encrypted file as text.
import * as age from "age-encryption"
const identity = await age.generateIdentity()
const recipient = await age.identityToRecipient(identity)
console.log(identity)
console.log(recipient)
const e = new age.Encrypter()
e.addRecipient(recipient)
const ciphertext = await e.encrypt("Hello, age!")
const armored = age.armor.encode(ciphertext)
console.log(armored)
// -----BEGIN AGE ENCRYPTED FILE-----
// YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0QXVkQmNwZ3ZzYnNRZDJP
// WlFId3hyeFNmRS9SdUVUTkFhY1FXSno5VUFBClNOSWhEbnhoK21TaEs3SWRGdklw
// OW9pdlBZbDg3SEVSQ1FZZHBvUS90YjgKLS0tIGRCVXNNWmdJS0ZkNlNZbStPZWh4
// N2FBNUJZdTFxMmYwVTEzUWwvTFVNeUkKrNZnrZjMlXvoCHz0FUS/bp9129XtSV1Q
// 2twDjjAOwgBtBYoji9gKWgOG4w==
// -----END AGE ENCRYPTED FILE-----
const d = new age.Decrypter()
d.addIdentity(identity)
const decoded = age.armor.decode(armored)
const out = await d.decrypt(decoded, "text")
console.log(out)
import { Encrypter, Decrypter } from "age-encryption"
const e = new Encrypter()
e.setPassphrase("burst-swarm-slender-curve-ability-various-crystal-moon-affair-three")
const ciphertext = await e.encrypt("Hello, age!")
const d = new Decrypter()
d.addPassphrase("burst-swarm-slender-curve-ability-various-crystal-moon-affair-three")
const out = await d.decrypt(ciphertext, "text")
console.log(out)
age-encryption
is compatible with modern bundlers such as esbuild.
To produce a classic library file that sets age
as a global variable, you can run
cd "$(mktemp -d)" && npm init -y && npm install esbuild age-encryption
npx esbuild --target=es2022 --bundle --minify --outfile=age.js --global-name=age age-encryption
or download a pre-built one from the Releases page.
Then, you can use it like this
<script src="age.js"></script>
<script>
(async () => {
const identity = await age.generateIdentity()
const recipient = await age.identityToRecipient(identity)
console.log(identity)
console.log(recipient)
const e = new age.Encrypter()
e.addRecipient(recipient)
const ciphertext = await e.encrypt("Hello, age!")
const d = new age.Decrypter()
d.addIdentity(identity)
const out = await d.decrypt(ciphertext, "text")
console.log(out)
})()
</script>
You can use a CryptoKey as an identity. It must have an algorithm
of X25519
,
and support the deriveBits
key usage. It doesn't need to be extractable.
const keyPair = await crypto.subtle.generateKey({ name: "X25519" }, false, ["deriveBits"])
const identity = (keyPair as CryptoKeyPair).privateKey
const recipient = await age.identityToRecipient(identity)
console.log(recipient)
const e = new age.Encrypter()
e.addRecipient(recipient)
const file = await e.encrypt("age")
const d = new age.Decrypter()
d.addIdentity(identity)
const out = await d.decrypt(file, "text")
console.log(out)
You can implement the Recipient
and Identity
interfaces to use custom types
as recipients and identities.
This lets you use use remote APIs and secrets managers to wrap files keys, and interoperate with age plugins.