Skip to content

Commit 3adcce5

Browse files
FiloSottilegopherbot
authored andcommitted
crypto: document non-determinism of GenerateKey
Fixes #58637 Change-Id: I9eb3905d5b35ea22e22e1d8eb8c33594eac487fc Reviewed-on: https://go-review.googlesource.com/c/go/+/505155 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Filippo Valsorda <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]>
1 parent 6dce882 commit 3adcce5

File tree

6 files changed

+47
-9
lines changed

6 files changed

+47
-9
lines changed

src/crypto/ecdh/ecdh.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ import (
1616
)
1717

1818
type Curve interface {
19-
// GenerateKey generates a new PrivateKey from rand.
19+
// GenerateKey generates a random PrivateKey.
20+
//
21+
// Most applications should use [crypto/rand.Reader] as rand. Note that the
22+
// returned key does not depend deterministically on the bytes read from rand,
23+
// and may change between calls and/or between versions.
2024
GenerateKey(rand io.Reader) (*PrivateKey, error)
2125

2226
// NewPrivateKey checks that key is valid and returns a PrivateKey.

src/crypto/ecdsa/ecdsa.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,11 @@ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp
150150
return SignASN1(rand, priv, digest)
151151
}
152152

153-
// GenerateKey generates a public and private key pair.
153+
// GenerateKey generates a new ECDSA private key for the specified curve.
154+
//
155+
// Most applications should use [crypto/rand.Reader] as rand. Note that the
156+
// returned key does not depend deterministically on the bytes read from rand,
157+
// and may change between calls and/or between versions.
154158
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
155159
randutil.MaybeReadByte(rand)
156160

@@ -245,6 +249,10 @@ var errNoAsm = errors.New("no assembly implementation available")
245249
// using the private key, priv. If the hash is longer than the bit-length of the
246250
// private key's curve order, the hash will be truncated to that length. It
247251
// returns the ASN.1 encoded signature.
252+
//
253+
// The signature is randomized. Most applications should use [crypto/rand.Reader]
254+
// as rand. Note that the returned signature does not depend deterministically on
255+
// the bytes read from rand, and may change between calls and/or between versions.
248256
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
249257
randutil.MaybeReadByte(rand)
250258

src/crypto/ed25519/ed25519.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (priv PrivateKey) Seed() []byte {
7676
return bytes.Clone(priv[:SeedSize])
7777
}
7878

79-
// Sign signs the given message with priv. rand is ignored.
79+
// Sign signs the given message with priv. rand is ignored and can be nil.
8080
//
8181
// If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
8282
// and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
@@ -132,6 +132,9 @@ func (o *Options) HashFunc() crypto.Hash { return o.Hash }
132132

133133
// GenerateKey generates a public/private key pair using entropy from rand.
134134
// If rand is nil, [crypto/rand.Reader] will be used.
135+
//
136+
// The output of this function is deterministic, and equivalent to reading
137+
// [SeedSize] bytes from rand, and passing them to [NewKeyFromSeed].
135138
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
136139
if rand == nil {
137140
rand = cryptorand.Reader

src/crypto/rsa/pkcs1v15.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ type PKCS1v15DecryptOptions struct {
3131
//
3232
// The random parameter is used as a source of entropy to ensure that
3333
// encrypting the same message twice doesn't result in the same
34-
// ciphertext.
34+
// ciphertext. Most applications should use [crypto/rand.Reader]
35+
// as random. Note that the returned ciphertext does not depend
36+
// deterministically on the bytes read from random, and may change
37+
// between calls and/or between versions.
3538
//
3639
// WARNING: use of this function to encrypt plaintexts other than
3740
// session keys is dangerous. Use RSA OAEP in new protocols.
@@ -79,7 +82,7 @@ func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, erro
7982
}
8083

8184
// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS #1 v1.5.
82-
// The random parameter is legacy and ignored, and it can be as nil.
85+
// The random parameter is legacy and ignored, and it can be nil.
8386
//
8487
// Note that whether this function returns an error or not discloses secret
8588
// information. If an attacker can cause this function to run repeatedly and
@@ -275,7 +278,7 @@ var hashPrefixes = map[crypto.Hash][]byte{
275278
// function. If hash is zero, hashed is signed directly. This isn't
276279
// advisable except for interoperability.
277280
//
278-
// The random parameter is legacy and ignored, and it can be as nil.
281+
// The random parameter is legacy and ignored, and it can be nil.
279282
//
280283
// This function is deterministic. Thus, if the set of possible
281284
// messages is small, an attacker may be able to build a map from

src/crypto/rsa/pss.go

+10
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,17 @@ var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be
285285
// digest must be the result of hashing the input message using the given hash
286286
// function. The opts argument may be nil, in which case sensible defaults are
287287
// used. If opts.Hash is set, it overrides hash.
288+
//
289+
// The signature is randomized depending on the message, key, and salt size,
290+
// using bytes from rand. Most applications should use [crypto/rand.Reader] as
291+
// rand.
288292
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, opts *PSSOptions) ([]byte, error) {
293+
// Note that while we don't commit to deterministic execution with respect
294+
// to the rand stream, we also don't apply MaybeReadByte, so per Hyrum's Law
295+
// it's probably relied upon by some. It's a tolerable promise because a
296+
// well-specified number of random bytes is included in the signature, in a
297+
// well-specified way.
298+
289299
if boring.Enabled && rand == boring.RandReader {
290300
bkey, err := boringPrivateKey(priv)
291301
if err != nil {

src/crypto/rsa/rsa.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,11 @@ func (priv *PrivateKey) Validate() error {
263263
return nil
264264
}
265265

266-
// GenerateKey generates an RSA keypair of the given bit size using the
267-
// random source random (for example, crypto/rand.Reader).
266+
// GenerateKey generates a random RSA private key of the given bit size.
267+
//
268+
// Most applications should use [crypto/rand.Reader] as rand. Note that the
269+
// returned key does not depend deterministically on the bytes read from rand,
270+
// and may change between calls and/or between versions.
268271
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
269272
return GenerateMultiPrimeKey(random, 2, bits)
270273
}
@@ -500,6 +503,7 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
500503
//
501504
// The random parameter is used as a source of entropy to ensure that
502505
// encrypting the same message twice doesn't result in the same ciphertext.
506+
// Most applications should use [crypto/rand.Reader] as random.
503507
//
504508
// The label parameter may contain arbitrary data that will not be encrypted,
505509
// but which gives important context to the message. For example, if a given
@@ -510,6 +514,12 @@ func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
510514
// The message must be no longer than the length of the public modulus minus
511515
// twice the hash length, minus a further 2.
512516
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
517+
// Note that while we don't commit to deterministic execution with respect
518+
// to the random stream, we also don't apply MaybeReadByte, so per Hyrum's
519+
// Law it's probably relied upon by some. It's a tolerable promise because a
520+
// well-specified number of random bytes is included in the ciphertext, in a
521+
// well-specified way.
522+
513523
if err := checkPub(pub); err != nil {
514524
return nil, err
515525
}
@@ -691,7 +701,7 @@ func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) {
691701
// Encryption and decryption of a given message must use the same hash function
692702
// and sha256.New() is a reasonable choice.
693703
//
694-
// The random parameter is legacy and ignored, and it can be as nil.
704+
// The random parameter is legacy and ignored, and it can be nil.
695705
//
696706
// The label parameter must match the value given when encrypting. See
697707
// EncryptOAEP for details.

0 commit comments

Comments
 (0)