aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2024-03-07 00:18:02 +0100
committerGopher Robot <gobot@golang.org>2024-03-19 20:02:21 +0000
commit99522de1c38e4915e061cd2dac7d34ee888c8318 (patch)
treeffa5113baa35d77f74e9f98d56a6f352b1cc0af8 /src
parent8f7df2256e271c8d8d170791c6cd90ba9cc69f5e (diff)
downloadgo-99522de1c38e4915e061cd2dac7d34ee888c8318.tar.xz
crypto/rand: use arc4random(3) on macOS and iOS
It's been good since Sierra: it never fails, it's faster, it's available on iOS (see #47812), and it still handles forks and reseeding. On a M2 with macOS 14.3.1: │ sec/op │ sec/op vs base │ Read/32-8 413.7n ± 3% 249.7n ± 3% -39.65% (p=0.000 n=10) Read/4K-8 7.097µ ± 6% 1.261µ ± 2% -82.24% (p=0.000 n=10) │ B/s │ B/s vs base │ Read/32-8 73.76Mi ± 3% 122.25Mi ± 3% +65.73% (p=0.000 n=10) Read/4K-8 550.5Mi ± 6% 3099.0Mi ± 2% +462.99% (p=0.000 n=10) arc4random(3) would be a good replacement for getentropy(2) on FreeBSD and NetBSD as well, but we don't get as easy access to libc there. Cq-Include-Trybots: luci.golang.try:gotip-darwin-amd64-longtest,gotip-darwin-amd64-nocgo,gotip-darwin-arm64_13,gotip-darwin-amd64_11,gotip-darwin-amd64_12,gotip-darwin-amd64_13,gotip-darwin-amd64_14 Change-Id: Ia76824853be92b4d1786e23592a1d2ef24d8907d Reviewed-on: https://go-review.googlesource.com/c/go/+/569655 Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/crypto/rand/rand.go15
-rw-r--r--src/crypto/rand/rand_darwin.go19
-rw-r--r--src/crypto/rand/rand_getentropy.go4
-rw-r--r--src/crypto/rand/rand_test.go19
-rw-r--r--src/internal/syscall/unix/arc4random_darwin.go24
-rw-r--r--src/internal/syscall/unix/asm_darwin.s1
-rw-r--r--src/internal/syscall/unix/getentropy_darwin.go28
-rw-r--r--src/internal/syscall/unix/getentropy_darwin.s9
8 files changed, 73 insertions, 46 deletions
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index d0dcc7cc71..d16d7a1c9c 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -11,13 +11,14 @@ import "io"
// Reader is a global, shared instance of a cryptographically
// secure random number generator.
//
-// On Linux, FreeBSD, Dragonfly, NetBSD and Solaris, Reader uses getrandom(2) if
-// available, /dev/urandom otherwise.
-// On OpenBSD and macOS, Reader uses getentropy(2).
-// On other Unix-like systems, Reader reads from /dev/urandom.
-// On Windows systems, Reader uses the ProcessPrng API.
-// On JS/Wasm, Reader uses the Web Crypto API.
-// On WASIP1/Wasm, Reader uses random_get from wasi_snapshot_preview1.
+// - On Linux, FreeBSD, Dragonfly, and Solaris, Reader uses getrandom(2)
+// if available, and /dev/urandom otherwise.
+// - On macOS and iOS, Reader uses arc4random_buf(3).
+// - On OpenBSD and NetBSD, Reader uses getentropy(2).
+// - On other Unix-like systems, Reader reads from /dev/urandom.
+// - On Windows, Reader uses the ProcessPrng API.
+// - On js/wasm, Reader uses the Web Crypto API.
+// - On wasip1/wasm, Reader uses random_get from wasi_snapshot_preview1.
var Reader io.Reader
// Read is a helper function that calls Reader.Read using io.ReadFull.
diff --git a/src/crypto/rand/rand_darwin.go b/src/crypto/rand/rand_darwin.go
new file mode 100644
index 0000000000..363ad69ec4
--- /dev/null
+++ b/src/crypto/rand/rand_darwin.go
@@ -0,0 +1,19 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import "internal/syscall/unix"
+
+func init() {
+ // arc4random_buf is the recommended application CSPRNG, accepts buffers of
+ // any size, and never returns an error.
+ //
+ // "The subsystem is re-seeded from the kernel random number subsystem on a
+ // regular basis, and also upon fork(2)." - arc4random(3)
+ //
+ // Note that despite its legacy name, it uses a secure CSPRNG (not RC4) in
+ // all supported macOS versions.
+ altGetRandom = func(b []byte) error { unix.ARC4Random(b); return nil }
+}
diff --git a/src/crypto/rand/rand_getentropy.go b/src/crypto/rand/rand_getentropy.go
index 210250411e..855716c83d 100644
--- a/src/crypto/rand/rand_getentropy.go
+++ b/src/crypto/rand/rand_getentropy.go
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build (darwin && !ios) || openbsd || netbsd
+//go:build openbsd || netbsd
package rand
import "internal/syscall/unix"
func init() {
- // getentropy(2) returns a maximum of 256 bytes per call
+ // getentropy(2) returns a maximum of 256 bytes per call.
altGetRandom = batched(unix.GetEntropy, 256)
}
diff --git a/src/crypto/rand/rand_test.go b/src/crypto/rand/rand_test.go
index e45f58e4e7..bbd4a86cda 100644
--- a/src/crypto/rand/rand_test.go
+++ b/src/crypto/rand/rand_test.go
@@ -41,3 +41,22 @@ func TestReadEmpty(t *testing.T) {
t.Fatalf("Read(nil) = %d, %v", n, err)
}
}
+
+func BenchmarkRead(b *testing.B) {
+ b.Run("32", func(b *testing.B) {
+ benchmarkRead(b, 32)
+ })
+ b.Run("4K", func(b *testing.B) {
+ benchmarkRead(b, 4<<10)
+ })
+}
+
+func benchmarkRead(b *testing.B, size int) {
+ b.SetBytes(int64(size))
+ buf := make([]byte, size)
+ for i := 0; i < b.N; i++ {
+ if _, err := Read(buf); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/src/internal/syscall/unix/arc4random_darwin.go b/src/internal/syscall/unix/arc4random_darwin.go
new file mode 100644
index 0000000000..a78204a355
--- /dev/null
+++ b/src/internal/syscall/unix/arc4random_darwin.go
@@ -0,0 +1,24 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+import (
+ "internal/abi"
+ "unsafe"
+)
+
+//go:cgo_import_dynamic libc_arc4random_buf arc4random_buf "/usr/lib/libSystem.B.dylib"
+
+func libc_arc4random_buf_trampoline()
+
+// ARC4Random calls the macOS arc4random_buf(3) function.
+func ARC4Random(p []byte) {
+ // macOS 11 and 12 abort if length is 0.
+ if len(p) == 0 {
+ return
+ }
+ syscall_syscall(abi.FuncPCABI0(libc_arc4random_buf_trampoline),
+ uintptr(unsafe.Pointer(unsafe.SliceData(p))), uintptr(len(p)), 0)
+}
diff --git a/src/internal/syscall/unix/asm_darwin.s b/src/internal/syscall/unix/asm_darwin.s
index 10d16ce87f..0b8efb1506 100644
--- a/src/internal/syscall/unix/asm_darwin.s
+++ b/src/internal/syscall/unix/asm_darwin.s
@@ -4,6 +4,7 @@
#include "textflag.h"
+TEXT ·libc_arc4random_buf_trampoline(SB),NOSPLIT,$0-0; JMP libc_arc4random_buf(SB)
TEXT ·libc_getaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getaddrinfo(SB)
TEXT ·libc_freeaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_freeaddrinfo(SB)
TEXT ·libc_getnameinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getnameinfo(SB)
diff --git a/src/internal/syscall/unix/getentropy_darwin.go b/src/internal/syscall/unix/getentropy_darwin.go
deleted file mode 100644
index 834099ffed..0000000000
--- a/src/internal/syscall/unix/getentropy_darwin.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build darwin && !ios
-
-package unix
-
-import (
- "internal/abi"
- "unsafe"
-)
-
-//go:cgo_import_dynamic libc_getentropy getentropy "/usr/lib/libSystem.B.dylib"
-
-func libc_getentropy_trampoline()
-
-// GetEntropy calls the macOS getentropy system call.
-func GetEntropy(p []byte) error {
- _, _, errno := syscall_syscall(abi.FuncPCABI0(libc_getentropy_trampoline),
- uintptr(unsafe.Pointer(&p[0])),
- uintptr(len(p)),
- 0)
- if errno != 0 {
- return errno
- }
- return nil
-}
diff --git a/src/internal/syscall/unix/getentropy_darwin.s b/src/internal/syscall/unix/getentropy_darwin.s
deleted file mode 100644
index f41e0fe97b..0000000000
--- a/src/internal/syscall/unix/getentropy_darwin.s
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build darwin && !ios
-
-#include "textflag.h"
-
-TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0; JMP libc_getentropy(SB)