import type CryptoLib from '../../interfaces/CryptoLib.mjs'; import type { DeviceSecretKeys, Encrypted, PrivateKey, PublicKey, SecretKeysString, Signature, SigningPublicKey, SigningSecretKey, SymmetricKey } from '../../interfaces/CryptoLib.mjs'; /** * Creates the device's signing keypair. * @returns The Ed25519 keypair, base64 encoded. */ export declare const createSigningKeyPair: () => { signingSecretKey: SigningSecretKey; signingPublicKey: SigningPublicKey; }; /** * Creates a X25519 keypair -- the device's own, or an ephemeral one per seal. * @returns The keypair, base64 encoded. */ export declare const createEncryptionKeyPair: () => { privateKey: PrivateKey; publicKey: PublicKey; }; /** * Recovers the signing public key from the secret key. * * Public keys are derived on unlock rather than stored, exactly as the RSA * layer derived them from the private key: a stored copy is one more field that * can disagree with the key material it claims to describe. * @param signingSecretKey - The device's Ed25519 secret key. * @returns The matching public key. * @throws {CryptoError} If the secret key is malformed. */ export declare const signingPublicKeyFromSecret: (signingSecretKey: SigningSecretKey) => SigningPublicKey; /** * Recovers the encryption public key from the secret key. * @param privateKey - The device's X25519 secret key. * @returns The matching public key. * @throws {CryptoError} If the secret key is malformed. */ export declare const encryptionPublicKeyFromSecret: (privateKey: PrivateKey) => PublicKey; /** * Signs a message with the device's signing key. * @param signingSecretKey - The device's Ed25519 secret key. * @param message - The canonical message to sign, from canonical.mts. * @returns The base64 encoded signature. * @throws {CryptoError} If the secret key is malformed. */ export declare const signMessage: (signingSecretKey: SigningSecretKey, message: string) => Signature; /** * Verifies a signature against a public key. * * Returns false for every failure, malformed input included, and never throws: * its callers are deciding whether to drop a message that arrived from the * network, and a thrown error there would separate "bad signature" from "bad * base64" for whoever is probing. * @param signingPublicKey - The claimed sender's Ed25519 public key. * @param message - The canonical message the signature should cover. * @param signature - The base64 encoded signature. * @returns Whether the signature is valid. */ export declare const verifyMessage: (signingPublicKey: SigningPublicKey, message: string, signature: Signature) => boolean; /** * Derives the seal key on the sending side, from a keypair that exists for * this one message. * * The ephemeral half is what buys the forward secrecy the RSA wrap never had: * recovering a device's long-term secret key does not decrypt traffic captured * earlier, because the other half of every past exchange was discarded as soon * as it was used. * @param ephemeralKeyPair - The per-message keypair, from createEncryptionKeyPair. * @param ephemeralKeyPair.privateKey - Its secret half, discarded after this call. * @param ephemeralKeyPair.publicKey - Its public half, sent with the ciphertext. * @param recipientPublicKey - The recipient's long-term X25519 public key. * @returns The derived AES-256 key, base64 encoded. * @throws {CryptoError} If either key is malformed. */ export declare const deriveSealKeyForSender: (ephemeralKeyPair: { privateKey: PrivateKey; publicKey: PublicKey; }, recipientPublicKey: PublicKey) => SymmetricKey; /** * Derives the same key on the receiving side. * * The recipient's own public key is recomputed from its secret key rather than * taken from the message: the info has to describe who the sender sealed TO, * and a value the sender chose could name someone else. * @param privateKey - This device's long-term X25519 secret key. * @param ephemeralPublicKey - The per-message public key from the ciphertext. * @returns The derived AES-256 key, base64 encoded. * @throws {CryptoError} If either key is malformed. */ export declare const deriveSealKeyForRecipient: (privateKey: PrivateKey, ephemeralPublicKey: PublicKey) => SymmetricKey; /** * Seals a message to a public key, using the provider's own AES-GCM. * * The asymmetric half is shared; the symmetric half is the caller's, which is * why this takes the provider rather than living inside one. Both providers * therefore produce byte-compatible seals without either of them owning the * curve code. * @param crypto - The provider whose encryptSymmetric to use. * @param publicKey - The recipient's X25519 public key. * @param plainText - The text to seal. * @returns A promise resolving to the sealed text. * @throws {CryptoError} If the public key is malformed. */ export declare const sealTo: (crypto: Pick, publicKey: PublicKey, plainText: T) => Promise>; /** * Opens a message sealed to this device. * * Every failure is the same CryptoError with the same message -- a malformed * ephemeral key, a wrong recipient, a tampered tag, a v1 blob. Which one it was * is exactly what an attacker probing the sync path wants told. * @param crypto - The provider whose decryptSymmetric to use. * @param privateKey - This device's X25519 secret key. * @param encryptedText - The sealed text. * @returns A promise resolving to the decrypted text. * @throws {CryptoError} If the seal cannot be opened, for any reason. */ export declare const openSeal: (crypto: Pick, privateKey: PrivateKey, encryptedText: Encrypted) => Promise; /** * Serialises a device's secret keys for sealing at rest. * @param secretKeys - The two secret keys. * @returns The JSON to seal. */ export declare const serialiseSecretKeys: (secretKeys: DeviceSecretKeys) => SecretKeysString; /** * Reads a device's secret keys back after their seal has been opened. * * The seal authenticates these bytes, so this is not a trust boundary -- it is * the check that a vault written by a build with a different idea of the shape * fails loudly here rather than several calls later, where the error would name * a curve instead of a vault. * @param serialised - The JSON from inside the seal. * @returns The two secret keys. * @throws {CryptoError} If the JSON is not a pair of keys. */ export declare const parseSecretKeys: (serialised: string) => DeviceSecretKeys;