import { type Bytes } from './bytes.js'; /** * The sealed blob is self-describing: * * [0..3) magic "CHL" 3 bytes * [3] version 1 byte * [4..8) recipient key id 4 bytes * [8..73) ephemeral pubkey 65 bytes, raw uncompressed P-256 * [73..85) IV 12 bytes * [85..] ciphertext + tag AES-GCM * * Self-contained on purpose. Nothing about a sealed file needs a sidecar * field, a database column or a flag on the sink, which means a queue can hold * sealed and unsealed items at once — during a rollout, or after turning the * feature off — and each is handled on its own terms. * * A literal magic rather than a bare version byte, because `decrypt` has to be * safe to point at anything: a plain JPEG opens with `0xFF`, which as a version * number is both wrong and larger than any this library will issue for a long * time. Three bytes that no image format begins with is the difference between * passing unsealed data through and refusing it. */ export declare const MAGIC: Uint8Array; export declare const VERSION = 1; export declare const KEY_ID_BYTES = 4; export declare const EPK_BYTES = 65; export declare const IV_BYTES = 12; export declare const TAG_BYTES = 16; export declare const HEADER_BYTES: number; export interface Header { version: number; keyId: Bytes; epk: Bytes; iv: Bytes; } export declare function writeHeader(header: Omit): Bytes; /** * Null when these bytes were never sealed, which is not an error — it is how * an unencrypted item in a mixed queue is recognised and passed through. */ export declare function readHeader(bytes: Bytes): Header | null; /** * An `inspect` guard that refuses any body which is not sealed. * * This is how "encrypted deployment" becomes a property of the server rather * than a promise the sender makes. If the recipient key is stripped out of the * URL fragment in transit, the uploader's page has nothing to seal with — and * without this, the plaintext is accepted and stored with nobody the wiser. * Here the body is refused before the sink is ever called. * * Pair it with `requireSeal` on the upload session, which refuses the same case * up front so the person is told before sending a file rather than after. * * ```ts * createHandler({ broker, sink, inspect: sealedOnly() }); * ``` * * Two limits, neither hideable. It cannot check the *payload* format — that is * the whole point of encryption, so `inspect` cannot do both jobs. And it stops * accidental plaintext, not a forgery: anyone can prepend these four bytes to * junk, exactly as they could seal to a key nobody holds. No server that cannot * decrypt can tell the difference. */ export declare function sealedOnly(): (head: Uint8Array) => 'bad-type' | null; export declare function sameKeyId(a: Uint8Array, b: Uint8Array): boolean; /** * First four bytes of SHA-256 over the raw public key. * * Not a security control — it only lets a dashboard say "sealed to a key this * device no longer has" instead of "failed to decrypt". Four bytes collide * roughly once in four billion, and a collision costs one misleading label * before the AEAD refuses anyway. */ export declare function keyIdFor(publicKeyRaw: Uint8Array): Promise; //# sourceMappingURL=format.d.ts.map