mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-16 12:22:40 +00:00
crypto: harden all crypto-sensitive memcmp + memset sites
Audit-driven sweep found additional compiler-optimization-sensitive patterns beyond the login password compare just fixed: P4.F3 (HIGH) — Utils::MACThenDecrypt verified packet MACs with plain memcmp. Runs on EVERY encrypted-then-MAC'd packet in the mesh; a timing oracle here lets attackers forge MACs byte-by-byte across the whole mesh layer. Replaced with constantTimeEqual. P4.F4 (MEDIUM) — Multiple memset(secret, 0, ...) calls on stack-resident crypto buffers (Ed25519 seed, ADC noise pool, AES key derived in extract_via_aes_ctr, HWINFO unique ID) were subject to dead-store elimination under -Os. GCC/Clang routinely elide these when the buffer is never read after; the wipe vanishes and the secret persists on stack until next call overwrites. Replaced with secureZeroize using volatile pointer writes. P4.F5 (LOW) — Identity::validatePrivateKey boot self-test compared shared secrets with plain memcmp. Boot-only, no attacker observation channel, but hygiene matters and the fix is one line. Also added secret-wipe for ss1/ss2 on all return paths. Promoted the local ct_memeq() previously added to RepeaterMesh.cpp into Utils::constantTimeEqual + Utils::secureZeroize (Utils.h/cpp) so the login compare and MAC compare share the same audited helper. Both helpers verified by Thumb-2 disassembly on rak3401_1watt: - constantTimeEqual: loop branches on iterator, accumulator load-modify-stored to stack every iteration, final return uses CLZ+LSR (no conditional branch on result). - secureZeroize: STRB.W to memory in a counted loop, not replaced with memset builtin and not eliminated.
This commit is contained in:
@@ -19,6 +19,21 @@ public:
|
||||
static int decrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
static int encryptThenMAC(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
static int MACThenDecrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len);
|
||||
|
||||
/* Constant-time byte-equality. Returns true iff every byte of `a`
|
||||
* matches `b`. No early exit — timing is independent of input,
|
||||
* defeating timing-leak attacks on MAC/password/secret compares.
|
||||
* `volatile` accumulator survives `-Os` LTO — disassembly-verified
|
||||
* on Cortex-M4 (rak3401_1watt). Pattern from rweather/arduinolibs. */
|
||||
static bool constantTimeEqual(const void *a, const void *b, size_t n);
|
||||
|
||||
/* Securely zero a buffer such that the compiler cannot elide the
|
||||
* writes as dead-store optimization. Uses volatile pointer writes —
|
||||
* standard idiom for clearing crypto secrets before stack unwind.
|
||||
* Use this for any buffer holding key material, seeds, or shared
|
||||
* secrets after their last use. */
|
||||
static void secureZeroize(void *buf, size_t n);
|
||||
|
||||
static void toHex(char *dest, const uint8_t *src, size_t len);
|
||||
static bool fromHex(uint8_t *dest, int dest_size, const char *src_hex);
|
||||
static bool isHexChar(char c);
|
||||
|
||||
Reference in New Issue
Block a user