refactor(core): originate random number always from sec/rng
What changed, and why it matters
This commit is a code cleanup that makes all random-number generation in the Trezor firmware core go through one dedicated secure path (sec/rng). It also moves the old insecure test-only random generator into a separate file so it is only used in emulators and tests, not in real hardware. The change reduces the risk that a real device accidentally uses a weak random source, but the commit itself does not claim to fix a specific active vulnerability.
Treat as a hardening/refactoring change rather than an urgent security patch. Review that USE_INSECURE_PRNG is never defined in production firmware builds and that all new call sites correctly include sec/rng.h. Continue normal QA and consider whether this refactor addresses any previously identified weak-randomness concerns.
Security signals we found
Centralizes randomness source to a single hardware-backed RNG path
Isolates insecure LCG PRNG under USE_INSECURE_PRNG for tests/emulators only
Removes weak random_buffer fallback from production RNG code paths
Adds FIPS-style continuous RNG checks (previous/current comparison) in STM32 driver
Updates many cryptographic secret-generation call sites to use sec/rng
Evidence from the diff
The refactor centralizes entropy requests on rng_fill_buffer()/rng_get() from core/embed/sec/rng and removes the weak random_buffer()/random32() fallbacks from production code paths. random_buffer is now implemented as a wrapper around rng_fill_buffer on STM32, and the insecure LCG-based implementation is isolated in crypto/rand_insecure.c under USE_INSECURE_PRNG. Call sites in prodtest, optiga, random_delays, storage salt, and MicroPython crypto modules are switched from rand.h to sec/rng.h. Legacy firmware and emulator/test builds are updated to include rand_insecure.c only where appropriate.
Changed components
core/embed/sec/rngcore/embed/sec/random_delayscore/embed/sec/storagecore/embed/sec/optigacore/embed/projects/prodtestcore/embed/upymod/modtrezorcryptocrypto/rand.c / rand_insecure.clegacy/rng.cbuild scripts: SConscript.*, MakefilesInspect captured patch +167 / −135
diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu
index ab4560d1..fe72c919 100644
--- a/core/SConscript.bootloader_emu
+++ b/core/SConscript.bootloader_emu
@@ -68,6 +68,7 @@ SOURCE_MOD_CRYPTO += [
'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c',
'vendor/trezor-crypto/memzero.c',
'vendor/trezor-crypto/rand.c',
+ 'vendor/trezor-crypto/rand_insecure.c',
'vendor/trezor-crypto/sha2.c',
]
diff --git a/core/SConscript.prodtest_emu b/core/SConscript.prodtest_emu
index b5790ac3..5daa3cf9 100644
--- a/core/SConscript.prodtest_emu
+++ b/core/SConscript.prodtest_emu
@@ -87,6 +87,7 @@ SOURCE_MOD_CRYPTO += [
'vendor/trezor-crypto/noise.c',
'vendor/trezor-crypto/nist256p1.c',
'vendor/trezor-crypto/rand.c',
+ 'vendor/trezor-crypto/rand_insecure.c',
'vendor/trezor-crypto/ripemd160.c',
'vendor/trezor-crypto/rfc6979.c',
'vendor/trezor-crypto/secp256k1.c',
diff --git a/core/SConscript.unix b/core/SConscript.unix
index 5f51ebf8..f553658b 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -149,6 +149,7 @@ SOURCE_MOD_CRYPTO += [
'vendor/trezor-crypto/nist256p1.c',
'vendor/trezor-crypto/pbkdf2.c',
'vendor/trezor-crypto/rand.c',
+ 'vendor/trezor-crypto/rand_insecure.c',
'vendor/trezor-crypto/rfc6979.c',
'vendor/trezor-crypto/ripemd160.c',
'vendor/trezor-crypto/secp256k1.c',
diff --git a/core/embed/projects/prodtest/cmd/prodtest_secrets.c b/core/embed/projects/prodtest/cmd/prodtest_secrets.c
index 6cef290a..087eea3f 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_secrets.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_secrets.c
@@ -28,7 +28,6 @@
#include "common.h"
#include "memzero.h"
-#include "rand.h"
#include "secbool.h"
#include "secure_channel.h"
@@ -222,7 +221,7 @@ static bool check_device_cert_chain(cli_t* cli, const uint8_t* chain,
}
uint8_t rnd[MLDSA_RNDBYTES] = {0};
- random_buffer(rnd, sizeof(rnd));
+ rng_fill_buffer(rnd, sizeof(rnd));
// The challenge is intentionally constant zero.
const uint8_t ENCODED_EMPTY_CONTEXT_STRING[] = {0, 0};
diff --git a/core/embed/sec/optiga/unix/optiga.c b/core/embed/sec/optiga/unix/optiga.c
index 3e0c2996..8d361ce5 100644
--- a/core/embed/sec/optiga/unix/optiga.c
+++ b/core/embed/sec/optiga/unix/optiga.c
@@ -21,11 +21,11 @@
#include <sec/optiga.h>
#include <sec/optiga_common.h>
+#include <sec/rng.h>
#include <sec/storage.h>
#include "ecdsa.h"
#include "nist256p1.h"
-#include "rand.h"
#if defined(TREZOR_MODEL_T2B1)
#include "certs/T2B1.h"
@@ -102,7 +102,7 @@ void optiga_set_sec_max(void) {}
uint32_t optiga_estimate_time_ms(storage_pin_op_t op) { return 0; }
bool optiga_random_buffer(uint8_t *dest, size_t size) {
- random_buffer(dest, size);
+ rng_fill_buffer(dest, size);
return true;
}
diff --git a/core/embed/sec/random_delays/stm32/random_delays.c b/core/embed/sec/random_delays/stm32/random_delays.c
index 74f1e675..caa4fcc7 100644
--- a/core/embed/sec/random_delays/stm32/random_delays.c
+++ b/core/embed/sec/random_delays/stm32/random_delays.c
@@ -22,10 +22,11 @@
#include <stdatomic.h>
#include <sec/random_delays.h>
+#include <sec/rng.h>
#include <sys/systimer.h>
+
#include "chacha_drbg.h"
#include "memzero.h"
-#include "rand.h"
#ifdef SECURE_MODE
@@ -43,7 +44,7 @@ static secbool rdi_disabled = sectrue;
static void drbg_init() {
uint8_t entropy[DRBG_TRNG_ENTROPY_LENGTH] = {0};
- random_buffer(entropy, sizeof(entropy));
+ rng_fill_buffer(entropy, sizeof(entropy));
chacha_drbg_init(&drbg_ctx, entropy, sizeof(entropy), NULL, 0);
memzero(entropy, sizeof(entropy));
@@ -54,7 +55,7 @@ static void drbg_reseed() {
ensure(drbg_initialized, NULL);
uint8_t entropy[DRBG_TRNG_ENTROPY_LENGTH] = {0};
- random_buffer(entropy, sizeof(entropy));
+ rng_fill_buffer(entropy, sizeof(entropy));
chacha_drbg_reseed(&drbg_ctx, entropy, sizeof(entropy), NULL, 0);
memzero(entropy, sizeof(entropy));
}
diff --git a/core/embed/sec/rng/inc/sec/rng.h b/core/embed/sec/rng/inc/sec/rng.h
index 893ae813..f526bbc6 100644
--- a/core/embed/sec/rng/inc/sec/rng.h
+++ b/core/embed/sec/rng/inc/sec/rng.h
@@ -31,13 +31,6 @@ void rng_init(void);
#endif
-/**
- * @brief Gets 32 bits of random data using from the hardware RNG.
- *
- * @return uint32_t Random data.
- */
-uint32_t rng_get(void);
-
/**
* @brief Fills a buffer with random bytes using the hardware RNG
*
@@ -50,6 +43,17 @@ uint32_t rng_get(void);
*/
void rng_fill_buffer(void* buffer, size_t buffer_size);
+/**
+ * @brief Gets 32 bits of random data using from the hardware RNG.
+ *
+ * @return uint32_t Random data.
+ */
+static inline uint32_t rng_get(void) {
+ uint32_t r = 0;
+ rng_fill_buffer((uint8_t*)&r, sizeof(r));
+ return r;
+}
+
/**
* @brief Fills a buffer with random bytes using the hardware RNG and
* combines it with other entropy sources (e.g., Optiga, Tropic) if
diff --git a/core/embed/sec/rng/rng_common.c b/core/embed/sec/rng/rng_common.c
index d370cc02..aea66e13 100644
--- a/core/embed/sec/rng/rng_common.c
+++ b/core/embed/sec/rng/rng_common.c
@@ -21,7 +21,7 @@
#include <sec/rng.h>
-#if SECURE_MODE
+#ifdef SECURE_MODE
#ifdef USE_OPTIGA
#include <sec/optiga.h>
@@ -34,21 +34,6 @@
#include "memzero.h"
#include "rand.h"
-void rng_fill_buffer(void* buffer, size_t buffer_size) {
- uint32_t* dst = (uint32_t*)buffer;
- size_t remaining = buffer_size;
-
- while (remaining >= sizeof(uint32_t)) {
- *dst++ = rng_get();
- remaining -= sizeof(uint32_t);
- }
-
- if (remaining > 0) {
- uint32_t r = rng_get();
- memcpy(dst, &r, remaining);
- }
-}
-
bool rng_fill_buffer_strong(void* buffer, size_t buffer_size) {
rng_fill_buffer(buffer, buffer_size);
@@ -88,23 +73,3 @@ bool rng_fill_buffer_strong(void* buffer, size_t buffer_size) {
}
#endif // SECURE_MODE
-
-#ifndef SECURE_MODE
-uint32_t rng_get(void) {
- uint32_t temp = 0;
- // Note: In non-secure mode we use rng_fill_buffer() since rng_get() is not
- // available as a smcall/syscall.
- rng_fill_buffer(&temp, sizeof(temp));
- return temp;
-}
-#endif // !SECURE_MODE
-
-#ifndef USE_INSECURE_PRNG
-// Re-implementation of random32() function declared in crypto/rand.h
-// to use MCU TRNG instead of crypto library PRNG.
-uint32_t random32(void) { return rng_get(); }
-#endif
-
-// Re-implementation of weak random_buffer() function defined in crypto/rand.c
-// to be the same as rng_fill_buffer() function.
-void random_buffer(uint8_t* buf, size_t len) { rng_fill_buffer(buf, len); }
diff --git a/core/embed/sec/rng/stm32/rng.c b/core/embed/sec/rng/stm32/rng.c
index b53acb4d..ce217566 100644
--- a/core/embed/sec/rng/stm32/rng.c
+++ b/core/embed/sec/rng/stm32/rng.c
@@ -27,7 +27,7 @@
#include "rand.h"
-#if SECURE_MODE
+#ifdef SECURE_MODE
void rng_init(void) {
// enable TRNG peripheral clock
@@ -37,17 +37,8 @@ void rng_init(void) {
RNG->CR = RNG_CR_RNGEN; // enable TRNG
}
-#ifdef USE_INSECURE_PRNG
-
-uint32_t rng_get(void) {
- // Uses PRNG implemented in crypto/rand.c
- return random32();
-}
-
-#else
-
-static uint32_t rng_read(const uint32_t previous,
- const uint32_t compare_previous) {
+static uint32_t rng_read_u32(const uint32_t previous,
+ const uint32_t compare_previous) {
uint32_t temp = previous;
do {
while ((RNG->SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) != RNG_SR_DRDY)
@@ -59,19 +50,36 @@ static uint32_t rng_read(const uint32_t previous,
return temp;
}
-uint32_t rng_get(void) {
+static uint32_t rng_get_u32(void) {
// reason for keeping history: RM0090 section 24.3.1 FIPS continuous random
// number generator test
static uint32_t previous = 0, current = 0;
if (previous == current) {
- previous = rng_read(previous, 0);
+ previous = rng_read_u32(previous, 0);
} else {
previous = current;
}
- current = rng_read(previous, 1);
+ current = rng_read_u32(previous, 1);
return current;
}
-#endif // USE_INSECURE_PRNG
+void rng_fill_buffer(void* buffer, size_t buffer_size) {
+ uint32_t* dst = (uint32_t*)buffer;
+ size_t remaining = buffer_size;
+
+ while (remaining >= sizeof(uint32_t)) {
+ *dst++ = rng_get_u32();
+ remaining -= sizeof(uint32_t);
+ }
+
+ if (remaining > 0) {
+ uint32_t r = rng_get_u32();
+ memcpy(dst, &r, remaining);
+ }
+}
#endif // SECURE_MODE
+
+// Implements random_buffer() function declared in crypto/rand.h
+// as a wrapper for rng_fill_buffer().
+void random_buffer(uint8_t* buf, size_t len) { rng_fill_buffer(buf, len); }
diff --git a/core/embed/sec/rng/unix/rng.c b/core/embed/sec/rng/unix/rng.c
index 18876dfb..18f9594f 100644
--- a/core/embed/sec/rng/unix/rng.c
+++ b/core/embed/sec/rng/unix/rng.c
@@ -23,25 +23,21 @@
#include "rand.h"
+void rng_fill_buffer(void* buffer, size_t buffer_size) {
#ifdef USE_INSECURE_PRNG
-uint32_t rng_get(void) {
- // Uses PRNG implemented in crypto/rand.c
- return random32();
-}
+ // Use PRNG implemented in crypto/rand_insecure.c
+ random_buffer((uint8_t*)buffer, buffer_size);
#else
-uint32_t rng_get(void) {
- static FILE *frand = NULL;
+ static FILE* frand = NULL;
if (!frand) {
frand = fopen("/dev/urandom", "r");
}
ensure(sectrue * (frand != NULL), "fopen failed");
- uint32_t r;
- ensure(sectrue * (sizeof(r) == fread(&r, 1, sizeof(r), frand)),
+ ensure(sectrue * (buffer_size == fread(buffer, 1, buffer_size, frand)),
"fread failed");
- return r;
-}
-#endif // USE_INSECURE_PRNG
+#endif
+}
diff --git a/core/embed/sec/storage/stm32f4/storage_salt.c b/core/embed/sec/storage/stm32f4/storage_salt.c
index ce3038fc..d3f89c91 100644
--- a/core/embed/sec/storage/stm32f4/storage_salt.c
+++ b/core/embed/sec/storage/stm32f4/storage_salt.c
@@ -22,10 +22,10 @@
#include <trezor_model.h>
#include <trezor_rtl.h>
+#include <sec/rng.h>
#include <sys/mpu.h>
#include <util/flash_otp.h>
-#include "rand.h"
#include "stm32f4xx_ll_utils.h"
#include "../storage_salt.h"
@@ -46,7 +46,7 @@ void storage_salt_get(storage_salt_t* salt) {
// set entropy in the OTP randomness block
if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
uint8_t rnd_bytes[FLASH_OTP_BLOCK_SIZE];
- random_buffer(rnd_bytes, FLASH_OTP_BLOCK_SIZE);
+ rng_fill_buffer(rnd_bytes, FLASH_OTP_BLOCK_SIZE);
ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, rnd_bytes,
FLASH_OTP_BLOCK_SIZE),
NULL);
diff --git a/core/embed/sec/storage/stm32u5/storage_salt.c b/core/embed/sec/storage/stm32u5/storage_salt.c
index d511676c..b2e258b3 100644
--- a/core/embed/sec/storage/stm32u5/storage_salt.c
+++ b/core/embed/sec/storage/stm32u5/storage_salt.c
@@ -22,11 +22,11 @@
#include <trezor_model.h>
#include <trezor_rtl.h>
+#include <sec/rng.h>
#include <sec/secret_keys.h>
#include <sys/mpu.h>
#include <util/flash_otp.h>
#include <util/image.h>
-#include "rand.h"
#include "stm32u5xx_ll_utils.h"
@@ -73,7 +73,7 @@ void storage_salt_get(storage_salt_t* salt) {
// set entropy in the OTP randomness block
if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
uint8_t rnd_bytes[FLASH_OTP_BLOCK_SIZE];
- random_buffer(rnd_bytes, FLASH_OTP_BLOCK_SIZE);
+ rng_fill_buffer(rnd_bytes, FLASH_OTP_BLOCK_SIZE);
ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, rnd_bytes,
FLASH_OTP_BLOCK_SIZE),
NULL);
diff --git a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-bip340.h b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-bip340.h
index 7c157b84..64d00bfb 100644
--- a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-bip340.h
+++ b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-bip340.h
@@ -19,9 +19,10 @@
#if USE_SECP256K1_ZKP
+#include <sec/rng.h>
+
#include "py/objstr.h"
-#include "rand.h"
#include "zkp_bip340.h"
/// package: trezorcrypto.bip340
@@ -34,7 +35,7 @@ STATIC mp_obj_t mod_trezorcrypto_bip340_generate_secret() {
vstr_t sk = {0};
vstr_init_len(&sk, 32);
for (;;) {
- random_buffer((uint8_t *)sk.buf, sk.len);
+ rng_fill_buffer((uint8_t *)sk.buf, sk.len);
// check whether secret > 0 && secret < curve_order
if (0 ==
memcmp(
diff --git a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-curve25519.h b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-curve25519.h
index 32199470..bc443cd5 100644
--- a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-curve25519.h
+++ b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-curve25519.h
@@ -17,12 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <sec/rng.h>
+
#include "py/objstr.h"
#include "ed25519-donna/ed25519.h"
-#include "rand.h"
-
/// package: trezorcrypto.curve25519
/// def generate_secret() -> bytes:
@@ -32,7 +32,7 @@
STATIC mp_obj_t mod_trezorcrypto_curve25519_generate_secret() {
vstr_t sk = {0};
vstr_init_len(&sk, 32);
- random_buffer((uint8_t *)sk.buf, sk.len);
+ rng_fill_buffer((uint8_t *)sk.buf, sk.len);
// taken from https://cr.yp.to/ecdh.html
sk.buf[0] &= 248;
sk.buf[31] &= 127;
diff --git a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-ed25519.h b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-ed25519.h
index 5e36360d..bb281171 100644
--- a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-ed25519.h
+++ b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-ed25519.h
@@ -17,13 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <sec/rng.h>
+
#include "py/objstr.h"
#include "ed25519-donna/ed25519-keccak.h"
#include "ed25519-donna/ed25519.h"
-#include "rand.h"
-
/// package: trezorcrypto.ed25519
/// def generate_secret() -> bytes:
@@ -33,7 +33,7 @@
STATIC mp_obj_t mod_trezorcrypto_ed25519_generate_secret() {
vstr_t sk = {0};
vstr_init_len(&sk, 32);
- random_buffer((uint8_t *)sk.buf, sk.len);
+ rng_fill_buffer((uint8_t *)sk.buf, sk.len);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &sk);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_ed25519_generate_secret_obj,
diff --git a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-nist256p1.h b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
index 133ff792..b04afd8d 100644
--- a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
+++ b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
@@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <sec/rng.h>
+
#include "py/objstr.h"
#include "ecdsa.h"
@@ -32,7 +34,7 @@ STATIC mp_obj_t mod_trezorcrypto_nist256p1_generate_secret() {
vstr_t sk = {0};
vstr_init_len(&sk, 32);
for (;;) {
- random_buffer((uint8_t *)sk.buf, sk.len);
+ rng_fill_buffer((uint8_t *)sk.buf, sk.len);
// check whether secret > 0 && secret < curve_order
if (0 ==
memcmp(
diff --git a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-secp256k1.h b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
index 6eeda3dc..2273f337 100644
--- a/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
+++ b/core/embed/upymod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
@@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <sec/rng.h>
+
#include "py/objstr.h"
#include "vendor/trezor-crypto/ecdsa.h"
@@ -32,7 +34,7 @@ STATIC mp_obj_t mod_trezorcrypto_secp256k1_generate_secret() {
vstr_t sk = {0};
vstr_init_len(&sk, 32);
for (;;) {
- random_buffer((uint8_t *)sk.buf, sk.len);
+ rng_fill_buffer((uint8_t *)sk.buf, sk.len);
// check whether secret > 0 && secret < curve_order
if (0 ==
memcmp(
diff --git a/crypto/Makefile b/crypto/Makefile
index aa1c6db4..c2257dd9 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -98,7 +98,7 @@ ifdef SMALL
CFLAGS += -DUSE_PRECOMPUTED_CP=0
endif
-SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c bip39_english.c pbkdf2.c base58.c base32.c
+SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c rand_insecure.c hmac.c bip32.c bip39.c bip39_english.c pbkdf2.c base58.c base32.c
SRCS += address.c
SRCS += script.c
SRCS += ripemd160.c
diff --git a/crypto/rand.c b/crypto/rand.c
index fe750397..ea0902d3 100644
--- a/crypto/rand.c
+++ b/crypto/rand.c
@@ -23,47 +23,6 @@
#include "rand.h"
-#ifdef USE_INSECURE_PRNG
-
-#pragma message( \
- "NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.")
-
-// The following code is not supposed to be used in a production environment.
-// It's included only to make the library testable.
-// The message above tries to prevent any accidental use outside of the test
-// environment.
-//
-// You are supposed to replace the random8() and random32() function with your
-// own secure code. There is also a possibility to replace the random_buffer()
-// function as it is defined as a weak symbol.
-
-static uint32_t seed = 0;
-
-void random_reseed(const uint32_t value) { seed = value; }
-
-uint32_t random32(void) {
- // Linear congruential generator from Numerical Recipes
- // https://en.wikipedia.org/wiki/Linear_congruential_generator
- seed = 1664525 * seed + 1013904223;
- return seed;
-}
-
-#endif /* USE_INSECURE_PRNG */
-
-//
-// The following code is platform independent
-//
-
-void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) {
- uint32_t r = 0;
- for (size_t i = 0; i < len; i++) {
- if (i % 4 == 0) {
- r = random32();
- }
- buf[i] = (r >> ((i % 4) * 8)) & 0xFF;
- }
-}
-
void random_xor(uint8_t *buf, size_t len) {
uint8_t r[4] = {0};
for (size_t i = 0; i < len; i++) {
diff --git a/crypto/rand.h b/crypto/rand.h
index 5dac98f6..b6da3fcf 100644
--- a/crypto/rand.h
+++ b/crypto/rand.h
@@ -27,9 +27,18 @@
#include <stdint.h>
#include <stdlib.h>
+#ifdef USE_INSECURE_PRNG
void random_reseed(const uint32_t value);
-uint32_t random32(void);
+#endif
+
void random_buffer(uint8_t *buf, size_t len);
+
+static inline uint32_t random32(void) {
+ uint32_t r = 0;
+ random_buffer((uint8_t *)&r, sizeof(r));
+ return r;
+}
+
void random_xor(uint8_t *buf, size_t len);
uint32_t random_uniform(uint32_t n);
diff --git a/crypto/rand_insecure.c b/crypto/rand_insecure.c
new file mode 100644
index 00000000..688bbbcd
--- /dev/null
+++ b/crypto/rand_insecure.c
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2013-2014 Tomas Dzetkulic
+ * Copyright (c) 2013-2014 Pavol Rusnak
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "rand.h"
+
+#ifdef USE_INSECURE_PRNG
+
+#pragma message( \
+ "NOT SUITABLE FOR PRODUCTION USE! Replace random_buffer() function with your own secure code.")
+
+static uint32_t seed = 0;
+
+void random_reseed(const uint32_t value) { seed = value; }
+
+static uint32_t lcg_get_u32(void) {
+ // Linear congruential generator from Numerical Recipes
+ // https://en.wikipedia.org/wiki/Linear_congruential_generator
+ seed = 1664525 * seed + 1013904223;
+ return seed;
+}
+
+void random_buffer(uint8_t *buf, size_t len) {
+ uint32_t r = 0;
+ for (size_t i = 0; i < len; i++) {
+ if (i % 4 == 0) {
+ r = lcg_get_u32();
+ }
+ buf[i] = (r >> ((i % 4) * 8)) & 0xFF;
+ }
+}
+
+#endif /* USE_INSECURE_PRNG */
diff --git a/legacy/firmware/Makefile b/legacy/firmware/Makefile
index 8210c5bf..d9dc3170 100644
--- a/legacy/firmware/Makefile
+++ b/legacy/firmware/Makefile
@@ -81,6 +81,9 @@ OBJS += ../vendor/trezor-crypto/nist256p1.o
OBJS += ../vendor/trezor-crypto/hmac_drbg.o
OBJS += ../vendor/trezor-crypto/rfc6979.o
OBJS += ../vendor/trezor-crypto/rand.o
+ifeq ($(EMULATOR),1)
+OBJS += ../vendor/trezor-crypto/rand_insecure.o
+endif
OBJS += ../vendor/trezor-crypto/memzero.o
OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.o
diff --git a/legacy/rng.c b/legacy/rng.c
index 45e576a8..e4e21e94 100644
--- a/legacy/rng.c
+++ b/legacy/rng.c
@@ -24,7 +24,7 @@
#include "rng.h"
#if !EMULATOR
-uint32_t random32(void) {
+static uint32_t rng_get_u32(void) {
static uint32_t last = 0, new = 0;
while (new == last) {
if ((RNG_SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) == RNG_SR_DRDY) {
@@ -34,4 +34,14 @@ uint32_t random32(void) {
last = new;
return new;
}
+
+void random_buffer(uint8_t *buf, size_t len) {
+ uint32_t r = 0;
+ for (size_t i = 0; i < len; i++) {
+ if (i % 4 == 0) {
+ r = rng_get_u32();
+ }
+ buf[i] = (r >> ((i % 4) * 8)) & 0xFF;
+ }
+}
#endif
diff --git a/storage/tests/c/Makefile b/storage/tests/c/Makefile
index 0349e9e9..b8cdc370 100644
--- a/storage/tests/c/Makefile
+++ b/storage/tests/c/Makefile
@@ -22,6 +22,7 @@ SRC += storage/storage_utils.c
SRC += storage/norcow.c
SRC += crypto/pbkdf2.c
SRC += crypto/rand.c
+SRC += crypto/rand_insecure.c
SRC += crypto/chacha20poly1305/rfc7539.c
SRC += crypto/chacha20poly1305/chacha20poly1305.c
SRC += crypto/chacha20poly1305/poly1305-donna.c
@@ -50,13 +51,25 @@ build_qw/crypto/chacha20poly1305/chacha_merged.o: $(BASE)crypto/chacha20poly1305
mkdir -p $(@D)
$(CC) $(CFLAGS) $(INC) -c $< -o $@
+# build object files from C sources with headers
build/%.o: $(BASE)%.c $(BASE)%.h
mkdir -p $(@D)
$(CC) $(CFLAGS) -DFLASH_BIT_ACCESS -DFLASH_BLOCK_WORDS=1 $(INC) -c $< -o $@
+# build object files from C sources without headers
+build/%.o: $(BASE)%.c
+ mkdir -p $(@D)
+ $(CC) $(CFLAGS) -DFLASH_BIT_ACCESS -DFLASH_BLOCK_WORDS=1 $(INC) -c $< -o $@
+
+# build object files from C sources with headers
build_qw/%.o: $(BASE)%.c $(BASE)%.h
mkdir -p $(@D)
$(CC) $(CFLAGS) -DFLASH_BLOCK_WORDS=4 $(INC) -c $< -o $@
+# build object files from C sources without headers
+build_qw/%.o: $(BASE)%.c
+ mkdir -p $(@D)
+ $(CC) $(CFLAGS) -DFLASH_BLOCK_WORDS=4 $(INC) -c $< -o $@
+
clean:
rm -f $(OUT) $(OUT_QW) $(OBJ) $(OBJ_QW)
diff --git a/storage/tests/c3/Makefile b/storage/tests/c3/Makefile
index 0be33676..b727fc20 100644
--- a/storage/tests/c3/Makefile
+++ b/storage/tests/c3/Makefile
@@ -19,6 +19,7 @@ SRC += storage/tests/c3/storage.c
SRC += storage/tests/c3/norcow.c
SRC += crypto/pbkdf2.c
SRC += crypto/rand.c
+SRC += crypto/rand_insecure.c
SRC += crypto/chacha20poly1305/rfc7539.c
SRC += crypto/chacha20poly1305/chacha20poly1305.c
SRC += crypto/chacha20poly1305/poly1305-donna.c
@@ -42,5 +43,9 @@ build/%.o: $(BASE)%.c $(BASE)%.h
mkdir -p $(@D)
$(CC) $(CFLAGS) $(INC) -c $< -o $@
+build/%.o: $(BASE)%.c
+ mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INC) -c $< -o $@
+
clean:
rm -f $(OUT) $(OBJ)
Why this scored 30/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.