aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMateusz Poliwczak <mpoliwczak34@gmail.com>2026-02-20 10:56:04 +0100
committerMateusz Poliwczak <mpoliwczak34@gmail.com>2026-02-23 12:41:28 -0800
commitfe080173033908f0f69b2dbf4a7ba1eaaea194bf (patch)
tree332e08d7efd69653f65f4450645e7ccb10766b25 /src
parent4e693d1ec52c86b262ac23f0d6cee6b60fef4fb0 (diff)
downloadgo-fe080173033908f0f69b2dbf4a7ba1eaaea194bf.tar.xz
crypto/rand: remove exported fields in the default Reader
Uses a clever trick with embeddeding such that, the Reader is 0-byte and does not have any exported fields. This change is not really a must, but I think it is better not to have any exported fields that could be accessed with reflect or such. Change-Id: Ib2e0b71d1e56b74a608601c98a81c8646a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/747460 Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/crypto/internal/fips140/drbg/rand.go16
-rw-r--r--src/crypto/internal/fips140only/fips140only.go7
-rw-r--r--src/crypto/internal/fips140only/random_fips140v1.0.go17
-rw-r--r--src/crypto/internal/fips140only/random_fips140v1.28.go16
-rw-r--r--src/crypto/internal/rand/rand.go16
-rw-r--r--src/crypto/internal/rand/random_fips140v1.0.go20
-rw-r--r--src/crypto/internal/rand/random_fips140v1.28.go19
-rw-r--r--src/crypto/rand/rand_test.go24
8 files changed, 113 insertions, 22 deletions
diff --git a/src/crypto/internal/fips140/drbg/rand.go b/src/crypto/internal/fips140/drbg/rand.go
index 949e74ac60..44284f93d8 100644
--- a/src/crypto/internal/fips140/drbg/rand.go
+++ b/src/crypto/internal/fips140/drbg/rand.go
@@ -124,14 +124,22 @@ func SetTestingReader(r io.Reader) {
// [crypto/rand.Reader], used to recognize it when passed to
// APIs that accept a rand io.Reader.
//
-// Any Reader that implements this interface is assumed to
-// call [Read] as its Read method.
-type DefaultReader interface{ defaultReader() }
+// Any [io.Reader] that embeds this type is assumed to
+// call [Read] as its [io.Reader.Read] method.
+type DefaultReader struct{}
+
+func (d DefaultReader) defaultReader() {}
+
+// IsDefaultReader reports whether the r embeds the [DefaultReader] type.
+func IsDefaultReader(r io.Reader) bool {
+ _, ok := r.(interface{ defaultReader() })
+ return ok
+}
// ReadWithReader uses Reader to fill b with cryptographically secure random
// bytes. It is intended for use in APIs that expose a rand io.Reader.
func ReadWithReader(r io.Reader, b []byte) error {
- if _, ok := r.(DefaultReader); ok {
+ if IsDefaultReader(r) {
Read(b)
return nil
}
diff --git a/src/crypto/internal/fips140only/fips140only.go b/src/crypto/internal/fips140only/fips140only.go
index 1b0a4be6ba..a8d840b170 100644
--- a/src/crypto/internal/fips140only/fips140only.go
+++ b/src/crypto/internal/fips140only/fips140only.go
@@ -6,12 +6,10 @@ package fips140only
import (
"crypto/fips140"
- "crypto/internal/fips140/drbg"
"crypto/internal/fips140/sha256"
"crypto/internal/fips140/sha3"
"crypto/internal/fips140/sha512"
"hash"
- "io"
)
// Enforced reports whether FIPS 140-only mode is enabled and enforced, in which non-approved
@@ -28,8 +26,3 @@ func ApprovedHash(h hash.Hash) bool {
return false
}
}
-
-func ApprovedRandomReader(r io.Reader) bool {
- _, ok := r.(drbg.DefaultReader)
- return ok
-}
diff --git a/src/crypto/internal/fips140only/random_fips140v1.0.go b/src/crypto/internal/fips140only/random_fips140v1.0.go
new file mode 100644
index 0000000000..f402f308bc
--- /dev/null
+++ b/src/crypto/internal/fips140only/random_fips140v1.0.go
@@ -0,0 +1,17 @@
+// Copyright 2026 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 fips140v1.0 || fips140v1.26
+
+package fips140only
+
+import (
+ "crypto/internal/fips140/drbg"
+ "io"
+)
+
+func ApprovedRandomReader(r io.Reader) bool {
+ _, ok := r.(drbg.DefaultReader)
+ return ok
+}
diff --git a/src/crypto/internal/fips140only/random_fips140v1.28.go b/src/crypto/internal/fips140only/random_fips140v1.28.go
new file mode 100644
index 0000000000..b03b9ef537
--- /dev/null
+++ b/src/crypto/internal/fips140only/random_fips140v1.28.go
@@ -0,0 +1,16 @@
+// Copyright 2026 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 !(fips140v1.0 || fips140v1.26)
+
+package fips140only
+
+import (
+ "crypto/internal/fips140/drbg"
+ "io"
+)
+
+func ApprovedRandomReader(r io.Reader) bool {
+ return drbg.IsDefaultReader(r)
+}
diff --git a/src/crypto/internal/rand/rand.go b/src/crypto/internal/rand/rand.go
index 29648b9f38..00e736a579 100644
--- a/src/crypto/internal/rand/rand.go
+++ b/src/crypto/internal/rand/rand.go
@@ -13,9 +13,11 @@ import (
_ "unsafe"
)
-type reader struct {
- drbg.DefaultReader
-}
+// defaultReader aliases [drbg.DefaultReader], so that [reader]
+// does not have an exported DefaultReader field.
+type defaultReader = drbg.DefaultReader
+
+type reader struct{ defaultReader }
func (r reader) Read(b []byte) (n int, err error) {
if boring.Enabled {
@@ -63,11 +65,3 @@ func CustomReader(r io.Reader) io.Reader {
}
return Reader
}
-
-// IsDefaultReader reports whether r is the default [crypto/rand.Reader].
-//
-// If true, the Read method of r can be assumed to call [drbg.Read].
-func IsDefaultReader(r io.Reader) bool {
- _, ok := r.(drbg.DefaultReader)
- return ok
-}
diff --git a/src/crypto/internal/rand/random_fips140v1.0.go b/src/crypto/internal/rand/random_fips140v1.0.go
new file mode 100644
index 0000000000..7314157443
--- /dev/null
+++ b/src/crypto/internal/rand/random_fips140v1.0.go
@@ -0,0 +1,20 @@
+// Copyright 2026 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 fips140v1.0 || fips140v1.26
+
+package rand
+
+import (
+ "crypto/internal/fips140/drbg"
+ "io"
+)
+
+// IsDefaultReader reports whether r is the default [crypto/rand.Reader].
+//
+// If true, the Read method of r can be assumed to call [drbg.Read].
+func IsDefaultReader(r io.Reader) bool {
+ _, ok := r.(drbg.DefaultReader)
+ return ok
+}
diff --git a/src/crypto/internal/rand/random_fips140v1.28.go b/src/crypto/internal/rand/random_fips140v1.28.go
new file mode 100644
index 0000000000..b9dafecff6
--- /dev/null
+++ b/src/crypto/internal/rand/random_fips140v1.28.go
@@ -0,0 +1,19 @@
+// Copyright 2026 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 !(fips140v1.0 || fips140v1.26)
+
+package rand
+
+import (
+ "crypto/internal/fips140/drbg"
+ "io"
+)
+
+// IsDefaultReader reports whether r is the default [crypto/rand.Reader].
+//
+// If true, the Read method of r can be assumed to call [drbg.Read].
+func IsDefaultReader(r io.Reader) bool {
+ return drbg.IsDefaultReader(r)
+}
diff --git a/src/crypto/rand/rand_test.go b/src/crypto/rand/rand_test.go
index 3bb3d5f1ac..13e4a65db2 100644
--- a/src/crypto/rand/rand_test.go
+++ b/src/crypto/rand/rand_test.go
@@ -8,10 +8,12 @@ import (
"bytes"
"compress/flate"
"crypto/internal/cryptotest"
+ "crypto/internal/rand"
"errors"
"internal/testenv"
"io"
"os"
+ "reflect"
"sync"
"testing"
)
@@ -213,3 +215,25 @@ func benchmarkRead(b *testing.B, size int) {
}
}
}
+
+func TestDefaultReader(t *testing.T) {
+ if !rand.IsDefaultReader(Reader) {
+ t.Error("rand.IsDefaultReader(Reader) == False")
+ }
+
+ typ := reflect.ValueOf(Reader).Type()
+ for method := range typ.Methods() {
+ if method.Name == "Read" {
+ continue
+ }
+ if method.IsExported() {
+ t.Fatal("unexpected exported method")
+ }
+ }
+
+ for field := range typ.Fields() {
+ if field.IsExported() {
+ t.Fatal("unexpected exported field")
+ }
+ }
+}