mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/internal/fips140/drbg: avoid global lock on rand state
Having a global lock on the random state (used only in FIPS-140 mode) introduces contention in concurrent programs. Use an approximately per-P random state instead, using sync.Pool to manage per-P state. This code is important to land for the Go 1.24 release because it is part of the FIPS-140 module that will be validated and certified, so it will live for a long time. We otherwise wouldn't be able to correct this contention for at least a year, perhaps more. At the same time, the code is only used in the FIPS-140 mode, so there is no risk to normal programs. Fixes #71155. Change-Id: I6b779f15ddfdf232f608f5cda08f75906e58114f Reviewed-on: https://go-review.googlesource.com/c/go/+/641097 Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Filippo Valsorda <filippo@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
9a44df6675
commit
e966a2773c
2 changed files with 38 additions and 10 deletions
|
|
@ -13,8 +13,15 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mu sync.Mutex
|
var drbgs = sync.Pool{
|
||||||
var drbg *Counter
|
New: func() any {
|
||||||
|
var c *Counter
|
||||||
|
entropy.Depleted(func(seed *[48]byte) {
|
||||||
|
c = NewCounter(seed)
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Read fills b with cryptographically secure random bytes. In FIPS mode, it
|
// Read fills b with cryptographically secure random bytes. In FIPS mode, it
|
||||||
// uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
|
// uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
|
||||||
|
|
@ -33,14 +40,8 @@ func Read(b []byte) {
|
||||||
additionalInput := new([SeedSize]byte)
|
additionalInput := new([SeedSize]byte)
|
||||||
sysrand.Read(additionalInput[:16])
|
sysrand.Read(additionalInput[:16])
|
||||||
|
|
||||||
mu.Lock()
|
drbg := drbgs.Get().(*Counter)
|
||||||
defer mu.Unlock()
|
defer drbgs.Put(drbg)
|
||||||
|
|
||||||
if drbg == nil {
|
|
||||||
entropy.Depleted(func(seed *[48]byte) {
|
|
||||||
drbg = NewCounter(seed)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
size := min(len(b), maxRequestSize)
|
size := min(len(b), maxRequestSize)
|
||||||
|
|
|
||||||
27
src/crypto/internal/fips140/drbg/rand_test.go
Normal file
27
src/crypto/internal/fips140/drbg/rand_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2025 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 drbg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/internal/fips140"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkDBRG(b *testing.B) {
|
||||||
|
old := fips140.Enabled
|
||||||
|
defer func() {
|
||||||
|
fips140.Enabled = old
|
||||||
|
}()
|
||||||
|
fips140.Enabled = true
|
||||||
|
|
||||||
|
const N = 64
|
||||||
|
b.SetBytes(N)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
buf := make([]byte, N)
|
||||||
|
for pb.Next() {
|
||||||
|
Read(buf)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue