///
import type { Key, KeyPair, KeyPairLocked, PublicKey, PrivateKey, RecoveryCode, Signature, PasswordHash, PasswordSalt, BufferLocked, RecoveryCodeLocked, PasswordOpsLimit, PasswordMemLimit } from './types.js';
import type { NodeId } from '../ids/types.js';
import type { PolykeyWorkerManager } from '../workers/types.js';
import type { FileSystem, ObjectEmpty } from '../types.js';
import Logger from '@matrixai/logger';
import { createDestroyStartStop } from '@matrixai/async-init';
import { Lock } from '@matrixai/async-locks';
interface KeyRing extends createDestroyStartStop.CreateDestroyStartStop {
}
declare class KeyRing {
static createKeyRing({ keysPath, passwordOpsLimit, passwordMemLimit, strictMemoryLock, workerManager, fs, logger, ...startOptions }: {
keysPath: string;
password: string;
passwordOpsLimit?: PasswordOpsLimit;
passwordMemLimit?: PasswordMemLimit;
strictMemoryLock?: boolean;
workerManager?: PolykeyWorkerManager;
fs?: FileSystem;
logger?: Logger;
fresh?: boolean;
} & ({} | {
recoveryCode: RecoveryCode;
} | {
privateKey: PrivateKey;
} | {
privateKeyPath: string;
})): Promise;
readonly keysPath: string;
readonly publicKeyPath: string;
readonly privateKeyPath: string;
readonly dbKeyPath: string;
readonly strictMemoryLock: boolean;
protected logger: Logger;
protected fs: FileSystem;
protected workerManager?: PolykeyWorkerManager;
protected _keyPair?: KeyPairLocked;
protected _dbKey?: BufferLocked;
protected passwordHash?: Readonly<{
hash: BufferLocked;
salt: BufferLocked;
}>;
protected passwordOpsLimit?: PasswordOpsLimit;
protected passwordMemLimit?: PasswordMemLimit;
protected _recoveryCodeData?: RecoveryCodeLocked;
protected rotateLock: Lock;
constructor({ keysPath, workerManager, passwordOpsLimit, passwordMemLimit, strictMemoryLock, fs, logger, }: {
keysPath: string;
workerManager?: PolykeyWorkerManager;
passwordOpsLimit?: PasswordOpsLimit;
passwordMemLimit?: PasswordMemLimit;
strictMemoryLock: boolean;
fs: FileSystem;
logger: Logger;
});
setWorkerManager(workerManager: PolykeyWorkerManager): void;
unsetWorkerManager(): void;
start(options: {
password: string;
fresh?: boolean;
} & (ObjectEmpty | {
recoveryCode: RecoveryCode;
} | {
privateKey: PrivateKey;
} | {
privateKeyPath: string;
})): Promise;
stop(): Promise;
destroy(): Promise;
get keyPair(): KeyPairLocked;
get dbKey(): BufferLocked;
get recoveryCode(): RecoveryCode | undefined;
getNodeId(): NodeId;
/**
* Warning: this is intended to be a slow operation to prevent brute force
* attacks
*/
checkPassword(password: string): Promise;
/**
* Changes the root key pair password.
* This will re-wrap the private key.
* The password is the new password.
* This does not require the old password because
* if the `KeyRing` is ready, that means the agent is unlocked
* at least from the perspective of the `KeyRing`.
* If an external client intends to change the password,
* they must be authenticated first.
*/
changePassword(password: string): Promise;
/**
* Rotates the key pair.
* This generates a new recovery code and new key pair.
* The DB key is not rotated, it is just re-encrypted with the new key pair.
* The key pair is wrapped with the new password.
*/
rotateKeyPair(password: string, rotateHook?: (keyPairNew: KeyPair, keyPairOld: KeyPair, recoveryCodeNew: RecoveryCode, recoveryCodeOld?: RecoveryCode) => any): Promise;
/**
* Encrypt to a public key.
* The `authenticated` option is used to determine whether to use
* the static root key pair. By default it will use generate an ephemeral key pair.
* Neither ensures forward secrecy. However ephemeral key pair provides one-way
* forward secrecy.
* If it is important that the receiver can authenticate the sender, consider doing
* `sign-then-encrypt`, by adding a signature into the plain text being sent.
*/
encrypt(receiverPublicKey: PublicKey, plainText: Buffer, authenticated?: boolean): Buffer;
/**
* Decrypt data sent to this key pair
* Note that this does not automatically authenticate the sender.
*/
decrypt(cipherText: Buffer): Buffer | undefined;
sign(data: Buffer): Signature;
verify(publicKey: PublicKey, data: Buffer, signature: Signature): boolean;
/**
* Sets up the root key pair.
* If the root key pair already exists:
* - If password is supplied, the key pair is decrypted with the password.
* The key pair is returned without the recovery code.
* - If password and recovery code is supplied, then the key pair will be
* recovered.
* The recovery code is used to derive a key pair that is checked against
* the existing key pair.
* If the key pairs match, then the derived key pair is encrypted with
* the password.
* The key pair is returned without the recovery code.
* - Private key and private key path is ignored, and this is handled the
* same as if only the password was supplied.
* If the root key pair does not exist:
* - If password is supplied, then recovery code and key pair is generated.
* The key pair is encrypted with the password.
* The key pair and recovery code will be returned.
* - If password and recovery code is supplied, then it will be used for key pair generation.
* The key pair is encrypted with the password.
* The key pair and recovery code will be returned.
* - If password and private key is supplied, then key pair will be derived from the private key.
* The key pair is encrypted with the password.
* The key pair is returned without the recovery code.
*/
protected setupKeyPair(options: {
password: string;
} | {
password: string;
recoveryCode: RecoveryCode;
} | {
password: string;
privateKey: PrivateKey;
} | {
password: string;
privateKeyPath: string;
}): Promise<[KeyPair, RecoveryCode | undefined]>;
/**
* Only the private key is necessary.
* We can derive the public key from the private key.
*/
protected existsKeyPair(): Promise;
protected existsPublicKey(): Promise;
protected existsPrivateKey(): Promise;
/**
* Reads the key pair from the filesystem.
* This only needs to read the private key as the public key is derived.
* The private key is expected to be stored in a flattened JWE format.
*/
protected readKeyPair(password: string): Promise;
/**
* Reads the public key from the filesystem.
* The public key is expected to be stored in a flattened JWE format.
*/
protected readPublicKey(publicKeyPath?: string): Promise;
/**
* Reads the private key from the filesystem.
* The private key is expected to be stored in a flattened JWE format.
*/
protected readPrivateKey(password: string, privateKeyPath?: string): Promise;
/**
* Writes the root key pair to the filesystem.
* The public key will be stored in JWK format.
* The private key will be stored in flattened JWE format.
* This first writes the public key and private key to `.tmp` files.
* Then proceeds to atomically rename the files together.
* The files should be updated together to ensure consistency.
*/
protected writeKeyPair(keyPair: KeyPair, password: string): Promise;
/**
* Generates the root key pair.
* If recovery code is passed in, it is used as a deterministic seed.
*/
protected generateKeyPair(recoveryCode?: RecoveryCode): Promise;
protected recoverKeyPair(recoveryCode: RecoveryCode): Promise;
/**
* Setup the DB key.
* This is the data encryption key for the rest of PK.
* This is what makes PK a hybrid cryptosystem.
*/
protected setupDbKey(keyPair: KeyPair): Promise;
/**
* Checks the existence of the DB key path.
* This checks if the file can be read and written.
* If the file does not exist, this returns `false`.
* If the file does exist but it cannot be read or written, then
* this will throw `ErrorDBKeyRead`.
*/
protected existsDbKey(): Promise;
/**
* Reads the DB key from the filesystem.
* The DB key is expected to be stored in flattened JWE format.
* The DB key is expected to be encrypted with our ECIES.
*/
protected readDbKey(keyPair: KeyPair, dbKeyPath?: string): Promise;
/**
* Writes the DB key from the filesystem.
* The DB key will be stored in flattened JWE format.
* The DB key will be encrypted with our ECIES.
*/
protected writeDbKey(dbKey: Key, publicKey: PublicKey): Promise;
/**
* Generates the DB key.
* This is 256 bit key.
*/
protected generateDbKey(): Key;
/**
* This sets up a password hash in-memory.
* This is used to check if the password is correct.
* The returned buffers are guaranteed to unpooled and memory-locked.
* This means the underlying `ArrayBuffer` is safely transferrable.
*/
protected setupPasswordHash(password: string): Promise<[PasswordHash, PasswordSalt]>;
}
export default KeyRing;