aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorYawning Angel <yawning@schwanenlied.me>2021-11-11 07:59:45 +0000
committerYawning Angel <yawning@schwanenlied.me>2021-11-17 14:00:00 +0000
commit6bafa21bee56ccfbdf74f88bf7937a900a7d22d9 (patch)
tree382a1c9a2f4811bebdd953180684ee6e05827c64 /core
parent61c581baeb94ac73cbb25e93af2710d12e15f25c (diff)
crypto: Add rand_bytes
This adds `rand_bytes(dst: []byte)` which fills the destination buffer with entropy from the cryptographic random number generator. This takes the "simple is best" approach and just directly returns the OS CSPRNG output instead of doing anything fancy (a la OpenBSD's arc4random).
Diffstat (limited to 'core')
-rw-r--r--core/crypto/crypto.odin11
-rw-r--r--core/crypto/rand_generic.odin7
-rw-r--r--core/crypto/rand_linux.odin37
3 files changed, 55 insertions, 0 deletions
diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin
index ddcc5d367..35e88c5ed 100644
--- a/core/crypto/crypto.odin
+++ b/core/crypto/crypto.odin
@@ -39,3 +39,14 @@ compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> i
// iff v == 0, setting the sign-bit, which gets returned.
return int((u32(v)-1) >> 31)
}
+
+// rand_bytes fills the dst buffer with cryptographic entropy taken from
+// the system entropy source. This routine will block if the system entropy
+// source is not ready yet. All system entropy source failures are treated
+// as catastrophic, resulting in a panic.
+rand_bytes :: proc (dst: []byte) {
+ // zero-fill the buffer first
+ mem.zero_explicit(raw_data(dst), len(dst))
+
+ _rand_bytes(dst)
+}
diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin
new file mode 100644
index 000000000..98890b5b1
--- /dev/null
+++ b/core/crypto/rand_generic.odin
@@ -0,0 +1,7 @@
+package crypto
+
+when ODIN_OS != "linux" {
+ _rand_bytes :: proc (dst: []byte) {
+ unimplemented("crypto: rand_bytes not supported on this OS")
+ }
+}
diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin
new file mode 100644
index 000000000..4d1183757
--- /dev/null
+++ b/core/crypto/rand_linux.odin
@@ -0,0 +1,37 @@
+package crypto
+
+import "core:fmt"
+import "core:os"
+import "core:sys/unix"
+
+_MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1
+
+_rand_bytes :: proc (dst: []byte) {
+ dst := dst
+ l := len(dst)
+
+ for l > 0 {
+ to_read := min(l, _MAX_PER_CALL_BYTES)
+ ret := unix.sys_getrandom(raw_data(dst), to_read, 0)
+ if ret < 0 {
+ switch os.Errno(-ret) {
+ case os.EINTR:
+ // Call interupted by a signal handler, just retry the
+ // request.
+ continue
+ case os.ENOSYS:
+ // The kernel is apparently prehistoric (< 3.17 circa 2014)
+ // and does not support getrandom.
+ panic("crypto: getrandom not available in kernel")
+ case:
+ // All other failures are things that should NEVER happen
+ // unless the kernel interface changes (ie: the Linux
+ // developers break userland).
+ panic(fmt.tprintf("crypto: getrandom failed: %d", ret))
+ }
+ }
+
+ l -= ret
+ dst = dst[ret:]
+ }
+}