diff --git a/src/util.h b/src/util.h index 49af867a..c2add8ac 100644 --- a/src/util.h +++ b/src/util.h @@ -8,11 +8,17 @@ #define SECP256K1_UTIL_H #include "../include/secp256k1.h" +#include "checkmem.h" +#include #include #include #include #include +#if defined(_MSC_VER) +/* For SecureZeroMemory */ +#include +#endif #define STR_(x) #x #define STR(x) STR_(x) @@ -221,6 +227,34 @@ static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) { } } +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it + * is pretty efficient, because the compiler can still implement the memset() efficently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +#ifdef VERIFY + SECP256K1_CHECKMEM_UNDEFINE(ptr, len); +#endif +} + /** Semantics like memcmp. Variable-time. * * We use this to avoid possible compiler bugs with memcmp, e.g.