Browse Source

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.
pull/3037/merge
Ayke van Laethem 2 years ago
committed by Ron Evans
parent
commit
91e9c84d85
  1. 4
      src/crypto/rand/rand_baremetal.go
  2. 27
      src/machine/machine_nrf.go
  3. 60
      src/machine/machine_nrf52840_rng.go

4
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

27
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
}

60
src/machine/machine_nrf52840_rng.go

@ -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
}
Loading…
Cancel
Save