/** * Encryption/decryption helpers for `.enc.cleobundle.tar.gz` bundles. * * Uses AES-256-GCM with a scrypt-derived key (Node built-in `node:crypto` only; * no native bindings). scrypt is memory-hard and NIST-approved. Argon2id (PHC * winner, spec §7.1) was the original target but adds a native binding * dependency that violates ADR-010. This module documents the trade-off: * scrypt with N=2^15 provides equivalent interactive-session security and full * cross-platform portability. * * Binary layout of an encrypted bundle: * [8] magic bytes "CLEOENC1" (0x43 0x4C 0x45 0x4F 0x45 0x4E 0x43 0x31) * [1] format version (0x01) * [7] reserved (zero-filled) * [32] scrypt salt (random, per-bundle) * [12] AES-256-GCM nonce (random, per-bundle) * [N] ciphertext (the tar.gz bytes) * [16] AES-256-GCM authentication tag * * Total fixed overhead: 76 bytes header + 16 bytes auth tag = 92 bytes. * * @task T345 * @epic T311 * @see ADR-038 §5 — opt-in encrypted backups for portable export/import * @module store/backup-crypto */ /** * Encrypts a plaintext tarball buffer with AES-256-GCM. * * A fresh random 32-byte salt and 12-byte nonce are generated for every call, * so two encryptions of the same plaintext produce different ciphertexts. * * Output binary layout: * ``` * Offset Length Field * 0 8 Magic bytes "CLEOENC1" * 8 1 Format version 0x01 * 9 7 Reserved (zeros) * 16 32 scrypt salt * 48 12 GCM nonce * 60 N Ciphertext * 60+N 16 GCM auth tag * ``` * * @param plaintext - Raw `.cleobundle.tar.gz` bytes to encrypt. * @param passphrase - User-supplied passphrase (must be non-empty). * @returns Encrypted bundle bytes ready to write as `.enc.cleobundle.tar.gz`. * @throws {Error} If `passphrase` is empty. * * @task T345 * @epic T311 */ export declare function encryptBundle(plaintext: Buffer, passphrase: string): Buffer; /** * Decrypts an `.enc.cleobundle.tar.gz` payload back to its original tar.gz bytes. * * Validates magic bytes, format version, and the AES-256-GCM authentication * tag. Any mismatch throws descriptively so callers can map to the correct * exit code (E_BUNDLE_DECRYPT = 70). * * @param encrypted - Full encrypted bundle bytes (as read from disk). * @param passphrase - User-supplied passphrase. * @returns Decrypted tar.gz bytes. * @throws {Error} `"decryptBundle: payload too short"` — buffer smaller than minimum. * @throws {Error} `"decryptBundle: magic mismatch (not a cleo encrypted bundle)"` — invalid magic. * @throws {Error} `"decryptBundle: unsupported version , expected 1"` — unknown version byte. * @throws {Error} `"decryptBundle: authentication failed (wrong passphrase or corrupted bundle)"` — GCM tag invalid. * * @task T345 * @epic T311 */ export declare function decryptBundle(encrypted: Buffer, passphrase: string): Buffer; /** * Tests whether a buffer starts with the CLEO encrypted bundle magic bytes * `"CLEOENC1"`. Reads only the first 8 bytes; does not validate any other * part of the header. * * Useful for detecting encrypted bundles before attempting decryption, e.g. * when deciding whether to prompt for a passphrase. * * @param header - At least 8 bytes from the start of the file (may be longer). * @returns `true` if the magic bytes match; `false` if the buffer is too short * or the magic does not match. * * @task T345 * @epic T311 */ export declare function isEncryptedBundle(header: Buffer): boolean; //# sourceMappingURL=backup-crypto.d.ts.map