age-encryption
Version:
<p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://github.com/FiloSottile/age/blob/main/logo/logo_white.svg"> <source media="(prefers-color-scheme: light)" srcset="https://github.com/FiloSottile/a
48 lines (47 loc) • 1.69 kB
JavaScript
import { base64 } from "@scure/base";
/**
* Encode an age encrypted file using the ASCII armor format, a strict subset of
* PEM that starts with `-----BEGIN AGE ENCRYPTED FILE-----`.
*
* @param file - The raw encrypted file (returned by {@link Encrypter.encrypt}).
*
* @returns The ASCII armored file, with a final newline.
*/
export function encode(file) {
const lines = [];
lines.push("-----BEGIN AGE ENCRYPTED FILE-----\n");
for (let i = 0; i < file.length; i += 48) {
let end = i + 48;
if (end > file.length)
end = file.length;
lines.push(base64.encode(file.subarray(i, end)) + "\n");
}
lines.push("-----END AGE ENCRYPTED FILE-----\n");
return lines.join("");
}
/**
* Decode an age encrypted file from the ASCII armor format, a strict subset of
* PEM that starts with `-----BEGIN AGE ENCRYPTED FILE-----`.
*
* Extra whitespace before and after the file is ignored, and newlines can be
* CRLF or LF, but otherwise the format is parsed strictly.
*
* @param file - The ASCII armored file.
*
* @returns The raw encrypted file (to be passed to {@link Decrypter.decrypt}).
*/
export function decode(file) {
const lines = file.trim().replaceAll("\r\n", "\n").split("\n");
if (lines[0] !== "-----BEGIN AGE ENCRYPTED FILE-----") {
throw Error("invalid header");
}
if (lines[lines.length - 1] !== "-----END AGE ENCRYPTED FILE-----") {
throw Error("invalid footer");
}
lines.shift();
lines.pop();
if (lines.some((l, i) => i === lines.length - 1 ? l.length > 64 : l.length !== 64)) {
throw Error("line too long");
}
return base64.decode(lines.join(""));
}