export interface Keyring { current: string; keys: Record; /** * Which `enc1:` ciphertext rows are assumed to belong to. Defaults to * `RELAY_ENCRYPTION_LEGACY_KEY_ID` or "k1" if unset. */ legacyKeyId: string; } /** True if the keyring is loaded + has at least one key (encryption active). */ export declare function isEncryptionActive(): boolean; /** * v2.1 Phase 7p MED #2: eager startup validation for the keyring config. * * Pre-7p, keyring validation was purely lazy — `loadKeyring()` ran on first * encrypt/decrypt, and `getKeyringInfo()` swallowed errors as "encryption * inactive". Ambiguous configs (e.g. both `RELAY_ENCRYPTION_KEYRING` and * `RELAY_ENCRYPTION_KEY` set) let the daemon boot and only surfaced on the * first encrypted-column code path. The documented contract is "reject at * startup"; this makes the contract actually load-bearing. * * Called from `validateConfigAndEnv()` in src/config.ts. Throws on any * config error — multi-source, malformed JSON, bad key size, unreadable * path, etc. Returns silently when the config is valid (or when no * encryption is configured at all — that's a legitimate "plaintext mode" * choice, not an error). */ export declare function validateKeyringStrict(): void; /** Return keyring info suitable for dashboards — NEVER exposes raw keys. */ export declare function getKeyringInfo(): { current: string | null; known_key_ids: string[]; legacy_key_id: string; }; /** * ADR-0003 (v2.20.0): derive a purpose-bound subkey from the keyring's CURRENT * key via HKDF-SHA256, WITHOUT exposing the raw keyring key outside this module * (the raw AES keys never leave encryption.ts — callers get only a domain- * separated derivative). Used by the token-lookup index to key its HMAC so a * DB-only read cannot offline-match a stolen token list against `token_lookup`. * * `info` is the HKDF context string — pass a stable, unique domain label per * use (e.g. "bot-relay/token-lookup/v1"). Returns a 32-byte subkey, or `null` * when no keyring is configured (plaintext mode) — callers must have their own * no-keyring fallback. The subkey rotates with the keyring: derivation reads * `kr.current`, so a keyring rotation yields a new subkey (and the token-lookup * layer re-populates lazily on the O(N) fallback path — the same graceful * behavior as first-time migration). */ export declare function deriveKeyringSubkey(info: string): Buffer | null; /** * Whether `RELAY_ENCRYPTION_KEY` is being used — flag so callers can emit * the one-time deprecation warning at startup. */ export declare function isLegacyEnvKeyInUse(): boolean; /** Whether the runtime has opted into RELAY_LAZY_REENCRYPT (reserved signal). */ export declare function isLazyReencryptEnabled(): boolean; /** * Encrypt a plaintext string for at-rest storage. Emits the v2 versioned * prefix `enc:::` using the keyring's current key. * Returns plaintext unchanged when no keyring is configured. */ export declare function encryptContent(plaintext: string): string; /** * Decrypt an at-rest string. Handles v2 versioned (enc:key_id:...), * legacy v1 (enc1:...), and plaintext pass-through uniformly. READ paths * stay pure — no side effects, no writes. See the READ-paths-stay-pure design note "READ paths stay * pure" discipline note. */ export declare function decryptContent(stored: string | null): string | null; /** * Re-encrypt an existing ciphertext row with a target key_id. Used by * `relay re-encrypt` for the migration pipeline. Parses the input, decrypts * via its native key_id (handles both v2 and legacy v1 inputs), re-encrypts * with the target. * * The target key MUST be in the current keyring. Caller is responsible for * ensuring the source key is also resolvable (error will surface otherwise). */ export declare function reencryptRow(stored: string, toKeyId: string): string; /** * Reset cached state — used exclusively by tests that mutate the env * between cases. Not exported in the public API contract. */ export declare function _resetKeyringCacheForTests(): void; //# sourceMappingURL=encryption.d.ts.map