mirror of
https://github.com/golang/go.git
synced 2026-04-02 09:20:29 +09:00
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>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
17
src/crypto/internal/fips140only/random_fips140v1.0.go
Normal file
17
src/crypto/internal/fips140only/random_fips140v1.0.go
Normal file
@@ -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
|
||||
}
|
||||
16
src/crypto/internal/fips140only/random_fips140v1.28.go
Normal file
16
src/crypto/internal/fips140only/random_fips140v1.28.go
Normal file
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
20
src/crypto/internal/rand/random_fips140v1.0.go
Normal file
20
src/crypto/internal/rand/random_fips140v1.0.go
Normal file
@@ -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
|
||||
}
|
||||
19
src/crypto/internal/rand/random_fips140v1.28.go
Normal file
19
src/crypto/internal/rand/random_fips140v1.28.go
Normal file
@@ -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)
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user