From 91e9c84d85c466a63a1630026608705bd0a7b264 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 15 Sep 2022 17:25:34 +0200 Subject: [PATCH] nrf: make GetRNG available to all chips All nrf chips have a cryptographically secure RNG on board. Therefore, I've made the code more portable so that it works on all nrf chips. I did remove a number of exported functions. I am of the opinion that these should only be made available once we have an agreed upon API for multiple chips. People who want to have greater control over the RNG should use the device/nrf package directly instead. I have also changed the behavior to always enable digital error correction. Enabling it seems like a more conservative (and secure) default to me. Again, people who would like to have it disabled can use the device/nrf package directly. --- src/crypto/rand/rand_baremetal.go | 4 +- src/machine/machine_nrf.go | 27 +++++++++++++ src/machine/machine_nrf52840_rng.go | 60 ----------------------------- 3 files changed, 29 insertions(+), 62 deletions(-) delete mode 100644 src/machine/machine_nrf52840_rng.go diff --git a/src/crypto/rand/rand_baremetal.go b/src/crypto/rand/rand_baremetal.go index fe9fea2a..e4103684 100644 --- a/src/crypto/rand/rand_baremetal.go +++ b/src/crypto/rand/rand_baremetal.go @@ -1,5 +1,5 @@ -//go:build nrf52840 || stm32 || (sam && atsamd51) || (sam && atsame5x) -// +build nrf52840 stm32 sam,atsamd51 sam,atsame5x +//go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x) +// +build nrf stm32 sam,atsamd51 sam,atsame5x package rand diff --git a/src/machine/machine_nrf.go b/src/machine/machine_nrf.go index 43a680ae..c291821c 100644 --- a/src/machine/machine_nrf.go +++ b/src/machine/machine_nrf.go @@ -350,3 +350,30 @@ func (i2c *I2C) readByte() (byte, error) { i2c.Bus.EVENTS_RXDREADY.Set(0) return byte(i2c.Bus.RXD.Get()), nil } + +var rngStarted = false + +// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. +// According to Nordic's documentation, the random output is suitable for cryptographic purposes. +func GetRNG() (ret uint32, err error) { + // There's no apparent way to check the status of the RNG peripheral's task, so simply start it + // to avoid deadlocking while waiting for output. + if !rngStarted { + nrf.RNG.TASKS_START.Set(1) + nrf.RNG.SetCONFIG_DERCEN(nrf.RNG_CONFIG_DERCEN_Enabled) + rngStarted = true + } + + // The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return. + for i := 0; i < 4; i++ { + // Wait for data to be ready. + for nrf.RNG.EVENTS_VALRDY.Get() == 0 { + } + // Append random byte to output. + ret = (ret << 8) ^ nrf.RNG.GetVALUE() + // Unset the EVENTS_VALRDY register to avoid reading the same random output twice. + nrf.RNG.EVENTS_VALRDY.Set(0) + } + + return ret, nil +} diff --git a/src/machine/machine_nrf52840_rng.go b/src/machine/machine_nrf52840_rng.go deleted file mode 100644 index 1d4eba04..00000000 --- a/src/machine/machine_nrf52840_rng.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build nrf52840 -// +build nrf52840 - -package machine - -import ( - "device/nrf" -) - -// Implementation based on Nordic Semiconductor's nRF52840 documentation version 1.7 found here: -// https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.7.pdf - -// SetRNGBiasCorrection configures the RNG peripheral's bias correction mechanism. Note that when -// bias correction is enabled, the peripheral is slower to produce random values. -func SetRNGBiasCorrection(enabled bool) { - var val uint32 - if enabled { - val = nrf.RNG_CONFIG_DERCEN_Enabled - } - nrf.RNG.SetCONFIG_DERCEN(val) -} - -// RNGBiasCorrectionEnabled determines whether the RNG peripheral's bias correction mechanism is -// enabled or not. -func RNGBiasCorrectionEnabled() bool { - return nrf.RNG.GetCONFIG_DERCEN() == nrf.RNG_CONFIG_DERCEN_Enabled -} - -// StartRNG starts the RNG peripheral core. This is automatically called by GetRNG, but can be -// manually called for interacting with the RNG peripheral directly. -func StartRNG() { - nrf.RNG.SetTASKS_START(nrf.RNG_TASKS_START_TASKS_START_Trigger) -} - -// StopRNG stops the RNG peripheral core. This is not called automatically. It may make sense to -// manually disable RNG peripheral for power conservation. -func StopRNG() { - nrf.RNG.SetTASKS_STOP(nrf.RNG_TASKS_STOP_TASKS_STOP_Trigger) -} - -// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. -// According to Nordic's documentation, the random output is suitable for cryptographic purposes. -func GetRNG() (ret uint32, err error) { - // There's no apparent way to check the status of the RNG peripheral's task, so simply start it - // to avoid deadlocking while waiting for output. - StartRNG() - - // The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return. - for i := 0; i < 4; i++ { - // Wait for data to be ready. - for nrf.RNG.GetEVENTS_VALRDY() == nrf.RNG_EVENTS_VALRDY_EVENTS_VALRDY_NotGenerated { - } - // Append random byte to output. - ret = (ret << 8) ^ nrf.RNG.GetVALUE() - // Unset the EVENTS_VALRDY register to avoid reading the same random output twice. - nrf.RNG.SetEVENTS_VALRDY(nrf.RNG_EVENTS_VALRDY_EVENTS_VALRDY_NotGenerated) - } - - return ret, nil -}