mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
[noise] Use the clamp bit of the spare key as its ready flag
A clamped X25519 private key always has bit 254 set, so byte 31 of the slot says whether a key is present and a wiped slot reads empty; the separate flag and its padding go, leaving the slot at exactly 64 bytes.
This commit is contained in:
@@ -29,39 +29,33 @@ void NoiseContext::load_psk(psk_t &out) const {
|
||||
#ifdef USE_NOISE_SPARE_EPHEMERAL
|
||||
static constexpr size_t PRIVATE_KEY_SIZE = 32;
|
||||
static constexpr size_t PUBLIC_KEY_SIZE = 32;
|
||||
// Private key then public key
|
||||
static uint8_t
|
||||
spare_ephemeral[PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
bool spare_ephemeral_ready = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static_assert(PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE == SPARE_EPHEMERAL_SIZE);
|
||||
uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
void prepare_spare_ephemeral() {
|
||||
// A partial fill must never look ready
|
||||
spare_ephemeral_ready = false;
|
||||
uint8_t *private_key = spare_ephemeral;
|
||||
uint8_t *public_key = spare_ephemeral + PRIVATE_KEY_SIZE;
|
||||
// Same steps as noise-c's curve25519 keygen; on failure the slot stays
|
||||
// empty and the handshake generates its own key
|
||||
// Same steps as noise-c's curve25519 keygen; the clamp sets the ready bit,
|
||||
// a failure wipes the slot so the handshake generates its own key
|
||||
if (!random_bytes(private_key, PRIVATE_KEY_SIZE)) {
|
||||
sodium_memzero(spare_ephemeral, sizeof(spare_ephemeral));
|
||||
return;
|
||||
}
|
||||
private_key[0] &= 0xF8;
|
||||
private_key[PRIVATE_KEY_SIZE - 1] = (private_key[PRIVATE_KEY_SIZE - 1] & 0x7F) | 0x40;
|
||||
if (crypto_scalarmult_curve25519_base(public_key, private_key) != 0) {
|
||||
sodium_memzero(spare_ephemeral, sizeof(spare_ephemeral));
|
||||
return;
|
||||
}
|
||||
spare_ephemeral_ready = true;
|
||||
}
|
||||
|
||||
int consume_spare_ephemeral(NoiseHandshakeState *state) {
|
||||
if (!spare_ephemeral_ready) {
|
||||
if (!has_spare_ephemeral()) {
|
||||
return 0;
|
||||
}
|
||||
// noise-c keeps its own copy, so the slot is wiped either way
|
||||
int err = noise_handshakestate_set_local_ephemeral(state, spare_ephemeral, PRIVATE_KEY_SIZE,
|
||||
spare_ephemeral + PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE);
|
||||
sodium_memzero(spare_ephemeral, sizeof(spare_ephemeral));
|
||||
spare_ephemeral_ready = false;
|
||||
return err;
|
||||
}
|
||||
#endif // USE_NOISE_SPARE_EPHEMERAL
|
||||
|
||||
@@ -46,9 +46,12 @@ const LogString *noise_err_to_logstr(int err);
|
||||
// ESP8266), refilled by the api server while idle and consumed by the next
|
||||
// handshake of any noise transport; an empty slot means the handshake
|
||||
// generates its own key.
|
||||
extern bool spare_ephemeral_ready; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// Polled every api loop tick, so it must inline
|
||||
inline bool has_spare_ephemeral() { return spare_ephemeral_ready; }
|
||||
// Private key then public key; zero when empty
|
||||
static constexpr size_t SPARE_EPHEMERAL_SIZE = 64;
|
||||
extern uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// Polled every api loop tick, so it must inline. A clamped X25519 private key
|
||||
// always has bit 254 set, so that byte doubles as the ready flag.
|
||||
inline bool has_spare_ephemeral() { return (spare_ephemeral[31] & 0x40) != 0; }
|
||||
/// Fill the slot; blocks for the base point multiply
|
||||
void prepare_spare_ephemeral();
|
||||
/// Hand the slot's key pair to a handshake that has not started and wipe the
|
||||
|
||||
Reference in New Issue
Block a user