Skip to content

Commit 3c86848

Browse files
committed
fix: correctly handle calls for GetRNG() when being made from nrf devices with SoftDevice enabled.
Signed-off-by: deadprogram <[email protected]>
1 parent ee32c62 commit 3c86848

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

src/machine/machine_nrf.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,9 @@ func (i2c *I2C) signalStop() error {
318318

319319
var rngStarted = false
320320

321-
// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
321+
// getRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
322322
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
323-
func GetRNG() (ret uint32, err error) {
323+
func getRNG() (ret uint32, err error) {
324324
// There's no apparent way to check the status of the RNG peripheral's task, so simply start it
325325
// to avoid deadlocking while waiting for output.
326326
if !rngStarted {

src/machine/machine_nrf_bare.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build nrf && !softdevice
2+
3+
package machine
4+
5+
// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
6+
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
7+
func GetRNG() (ret uint32, err error) {
8+
return getRNG()
9+
}

src/machine/machine_nrf_sd.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//go:build nrf && softdevice
2+
3+
package machine
4+
5+
import (
6+
"device/arm"
7+
"device/nrf"
8+
9+
"errors"
10+
)
11+
12+
// avoid a heap allocation in GetRNG.
13+
var (
14+
softdeviceEnabled uint8
15+
bytesAvailable uint8
16+
buf [4]uint8
17+
18+
errNoSoftDeviceSupport = errors.New("rng: softdevice not supported on this device")
19+
errNotEnoughRandomData = errors.New("rng: not enough random data available")
20+
)
21+
22+
// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
23+
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
24+
func GetRNG() (ret uint32, err error) {
25+
// First check whether the SoftDevice is enabled.
26+
// sd_rand_application_bytes_available_get cannot be called when the SoftDevice is not enabled.
27+
arm.SVCall1(0x12, &softdeviceEnabled) // sd_softdevice_is_enabled
28+
29+
if softdeviceEnabled == 0 {
30+
return getRNG()
31+
}
32+
33+
// call into the SoftDevice to get random data bytes available
34+
switch nrf.Device {
35+
case "nrf51":
36+
// sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4
37+
arm.SVCall1(0x2B+4, &bytesAvailable)
38+
case "nrf52", "nrf52840", "nrf52833":
39+
// sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4
40+
arm.SVCall1(0x2C+4, &bytesAvailable)
41+
default:
42+
return 0, errNoSoftDeviceSupport
43+
}
44+
45+
if bytesAvailable < 4 {
46+
return 0, errNotEnoughRandomData
47+
}
48+
49+
switch nrf.Device {
50+
case "nrf51":
51+
// sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5
52+
arm.SVCall2(0x2B+5, &buf, 4)
53+
case "nrf52", "nrf52840", "nrf52833":
54+
// sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5
55+
arm.SVCall2(0x2C+5, &buf, 4)
56+
}
57+
58+
return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24, nil
59+
}

0 commit comments

Comments
 (0)