Files
palladum-lightning/common/hsm_secret.h
Rusty Russell 16ae5a4b50 common: trivial changes from review.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-10-26 12:37:58 +10:30

179 lines
5.7 KiB
C

#ifndef LIGHTNING_COMMON_HSM_SECRET_H
#define LIGHTNING_COMMON_HSM_SECRET_H
#include "config.h"
#include <bitcoin/privkey.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <sodium.h>
#include <sys/types.h>
/* Length constants for encrypted HSM secret files */
#define HS_HEADER_LEN crypto_secretstream_xchacha20poly1305_HEADERBYTES
#define HS_CIPHERTEXT_LEN \
(sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES)
#define ENCRYPTED_HSM_SECRET_LEN (HS_HEADER_LEN + HS_CIPHERTEXT_LEN)
enum hsm_secret_type {
HSM_SECRET_PLAIN = 0, /* Legacy 32-byte format */
HSM_SECRET_ENCRYPTED = 1, /* Legacy 73-byte encrypted format */
HSM_SECRET_MNEMONIC_NO_PASS = 2, /* Mnemonic without passphrase */
HSM_SECRET_MNEMONIC_WITH_PASS = 3, /* Mnemonic with passphrase */
HSM_SECRET_INVALID = 4, /* When all else fails, blame the user */
};
enum hsm_secret_error {
HSM_SECRET_OK = 0,
HSM_SECRET_ERR_PASSPHRASE_REQUIRED,
HSM_SECRET_ERR_PASSPHRASE_NOT_NEEDED,
HSM_SECRET_ERR_WRONG_PASSPHRASE,
HSM_SECRET_ERR_INVALID_MNEMONIC,
HSM_SECRET_ERR_ENCRYPTION_FAILED,
HSM_SECRET_ERR_SEED_DERIVATION_FAILED,
HSM_SECRET_ERR_INVALID_FORMAT,
HSM_SECRET_ERR_TERMINAL,
};
/**
* Represents the content of the hsm_secret file, either a raw seed or a mnemonic.
*/
struct hsm_secret {
enum hsm_secret_type type;
const u8 *secret_data; /* Variable length: 32 bytes (legacy) or 64 bytes (mnemonic) */
const char *mnemonic; /* NULL if not derived from mnemonic */
};
/**
* Check if this HSM secret is mnemonic-based (64-byte seed).
* Returns true for mnemonic-derived secrets, false for legacy 32-byte secrets.
*/
bool is_mnemonic_secret(size_t secret_len);
/**
* Check if we should use BIP86 derivation for this HSM secret.
* BIP86 was introduced alongside mnemonic support, so they're available together.
* Returns true if mnemonic-based secret is available, false otherwise.
*/
bool use_bip86_derivation(size_t secret_len);
/**
* Checks whether the hsm_secret data requires a passphrase to decrypt.
* Handles legacy, encrypted, and mnemonic-based formats.
*/
bool hsm_secret_needs_passphrase(const u8 *hsm_secret, size_t len);
/**
* Parse and decrypt an hsm_secret file.
*
* @ctx - a tal context
* @hsm_secret - raw file contents
* @len - length of file
* @passphrase - passphrase, or NULL if not needed
* @err - pointer to set error code on failure
*
* Returns parsed `struct hsm_secret` or NULL on error.
*/
struct hsm_secret *extract_hsm_secret(const tal_t *ctx,
const u8 *hsm_secret, size_t len,
const char *passphrase,
enum hsm_secret_error *err);
/**
* get_encryption_key - Derive encryption key from passphrase using Argon2.
* @ctx - tal context for allocation
* @passphrase - the passphrase to derive from
*
* Returns derived encryption key, or NULL on error.
* The returned key is memory-locked and has a destructor to clear it.
*/
struct secret *get_encryption_key(const tal_t *ctx, const char *passphrase);
/**
* Encrypt a given hsm_secret using a provided encryption key.
* @encryption_key - derived from passphrase (via Argon2)
* @hsm_secret - plaintext secret to encrypt
* @output - output buffer for encrypted data (must be ENCRYPTED_HSM_SECRET_LEN bytes)
*
* Returns true on success.
*/
bool encrypt_legacy_hsm_secret(const struct secret *encryption_key,
const struct secret *hsm_secret,
u8 *output);
/**
* Reads a passphrase from stdin, disabling terminal echo.
* Returns a newly allocated string on success, NULL on error.
* @ctx - tal context for allocation
* @err - on failure, this will be set to the error code
*
* Returns allocated passphrase or NULL on error.
*/
const char *read_stdin_pass(const tal_t *ctx, enum hsm_secret_error *err);
/**
* Convert error code to human-readable string.
* @err - the error code to convert
*
* Returns a string describing the error.
*/
const char *hsm_secret_error_str(enum hsm_secret_error err);
/**
* Detect the type of hsm_secret based on its content and length.
* @hsm_secret - raw file contents
* @len - length of file
*
* Returns the detected type.
*/
enum hsm_secret_type detect_hsm_secret_type(const u8 *hsm_secret, size_t len);
/**
* Reads a BIP39 mnemonic from stdin with validation.
* Returns a newly allocated string on success, NULL on error.
* @ctx - tal context for allocation
* @err - optional pointer to set error code on failure
*
* Returns tal-allocated mnemonic string or NULL on error.
*/
const char *read_stdin_mnemonic(const tal_t *ctx, enum hsm_secret_error *err);
/**
* Derive seed hash from mnemonic + passphrase.
* @mnemonic - the BIP39 mnemonic
* @passphrase - the passphrase (can be NULL)
* @seed_hash - output parameter for the derived seed hash
*
* Returns true on success, false on failure.
*/
bool derive_seed_hash(const char *mnemonic, const char *passphrase, struct sha256 *seed_hash);
/**
* Check if hsm_secret file is encrypted (legacy format only).
* @path - path to the hsm_secret file
*
* Returns 1 if encrypted, 0 if not encrypted, -1 on error.
*/
int is_legacy_hsm_secret_encrypted(const char *path);
/**
* Convert hsm_secret_type enum to human-readable string.
* @type - the hsm_secret_type to convert
*
* Returns a string describing the type.
*/
const char *format_type_name(enum hsm_secret_type type);
/**
* Derive encryption key from passphrase using Argon2.
* @ctx - tal context for allocation
* @passphrase - the passphrase to derive from
*
* Returns derived encryption key, or NULL on error.
* The returned key is memory-locked and has a destructor to clear it.
*/
struct secret *get_encryption_key(const tal_t *ctx, const char *passphrase);
#endif /* LIGHTNING_COMMON_HSM_SECRET_H */