@@ -16,8 +16,6 @@ package ecdsa
16
16
17
17
import (
18
18
"crypto"
19
- "crypto/aes"
20
- "crypto/cipher"
21
19
"crypto/ecdh"
22
20
"crypto/elliptic"
23
21
"crypto/internal/boring"
@@ -131,14 +129,24 @@ func bigIntEqual(a, b *big.Int) bool {
131
129
return subtle .ConstantTimeCompare (a .Bytes (), b .Bytes ()) == 1
132
130
}
133
131
134
- // Sign signs digest with priv, reading randomness from rand. The opts argument
135
- // is not currently used but, in keeping with the crypto.Signer interface,
136
- // should be the hash function used to digest the message.
132
+ // Sign signs a hash (which should be the result of hashing a larger message
133
+ // with opts.HashFunc()) using the private key, priv. If the hash is longer than
134
+ // the bit-length of the private key's curve order, the hash will be truncated
135
+ // to that length. It returns the ASN.1 encoded signature, like [SignASN1].
137
136
//
138
- // This method implements crypto.Signer, which is an interface to support keys
139
- // where the private part is kept in, for example, a hardware module. Common
140
- // uses can use the [SignASN1] function in this package directly.
137
+ // If rand is not nil, the signature is randomized. Most applications should use
138
+ // [crypto/rand.Reader] as rand. Note that the returned signature does not
139
+ // depend deterministically on the bytes read from rand, and may change between
140
+ // calls and/or between versions.
141
+ //
142
+ // If rand is nil, Sign will produce a deterministic signature according to RFC
143
+ // 6979. When producing a deterministic signature, opts.HashFunc() must be the
144
+ // function used to produce digest and priv.Curve must be one of
145
+ // [elliptic.P224], [elliptic.P256], [elliptic.P384], or [elliptic.P521].
141
146
func (priv * PrivateKey ) Sign (rand io.Reader , digest []byte , opts crypto.SignerOpts ) ([]byte , error ) {
147
+ if rand == nil {
148
+ return signRFC6979 (priv , digest , opts )
149
+ }
142
150
return SignASN1 (rand , priv , digest )
143
151
}
144
152
@@ -205,34 +213,66 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
205
213
}
206
214
boring .UnreachableExceptTests ()
207
215
208
- csprng , err := mixedCSPRNG (rand , priv , hash )
216
+ switch priv .Curve .Params () {
217
+ case elliptic .P224 ().Params ():
218
+ return signFIPS (ecdsa .P224 (), priv , rand , hash )
219
+ case elliptic .P256 ().Params ():
220
+ return signFIPS (ecdsa .P256 (), priv , rand , hash )
221
+ case elliptic .P384 ().Params ():
222
+ return signFIPS (ecdsa .P384 (), priv , rand , hash )
223
+ case elliptic .P521 ().Params ():
224
+ return signFIPS (ecdsa .P521 (), priv , rand , hash )
225
+ default :
226
+ return signLegacy (priv , rand , hash )
227
+ }
228
+ }
229
+
230
+ func signFIPS [P ecdsa.Point [P ]](c * ecdsa.Curve [P ], priv * PrivateKey , rand io.Reader , hash []byte ) ([]byte , error ) {
231
+ // privateKeyToFIPS is very slow in FIPS mode because it performs a
232
+ // Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache
233
+ // it or attach it to the PrivateKey.
234
+ k , err := privateKeyToFIPS (c , priv )
209
235
if err != nil {
210
236
return nil , err
211
237
}
238
+ // Always using SHA-512 instead of the hash that computed hash is
239
+ // technically a violation of draft-irtf-cfrg-det-sigs-with-noise-04 but in
240
+ // our API we don't get to know what it was, and this has no security impact.
241
+ sig , err := ecdsa .Sign (c , sha512 .New , k , rand , hash )
242
+ if err != nil {
243
+ return nil , err
244
+ }
245
+ return encodeSignature (sig .R , sig .S )
246
+ }
212
247
248
+ func signRFC6979 (priv * PrivateKey , hash []byte , opts crypto.SignerOpts ) ([]byte , error ) {
249
+ if opts == nil {
250
+ return nil , errors .New ("ecdsa: Sign called with nil opts" )
251
+ }
252
+ h := opts .HashFunc ()
253
+ if h .Size () != len (hash ) {
254
+ return nil , errors .New ("ecdsa: hash length does not match hash function" )
255
+ }
213
256
switch priv .Curve .Params () {
214
257
case elliptic .P224 ().Params ():
215
- return signFIPS (ecdsa .P224 (), priv , csprng , hash )
258
+ return signFIPSDeterministic (ecdsa .P224 (), h , priv , hash )
216
259
case elliptic .P256 ().Params ():
217
- return signFIPS (ecdsa .P256 (), priv , csprng , hash )
260
+ return signFIPSDeterministic (ecdsa .P256 (), h , priv , hash )
218
261
case elliptic .P384 ().Params ():
219
- return signFIPS (ecdsa .P384 (), priv , csprng , hash )
262
+ return signFIPSDeterministic (ecdsa .P384 (), h , priv , hash )
220
263
case elliptic .P521 ().Params ():
221
- return signFIPS (ecdsa .P521 (), priv , csprng , hash )
264
+ return signFIPSDeterministic (ecdsa .P521 (), h , priv , hash )
222
265
default :
223
- return signLegacy ( priv , csprng , hash )
266
+ return nil , errors . New ( "ecdsa: curve not supported by deterministic signatures" )
224
267
}
225
268
}
226
269
227
- func signFIPS [P ecdsa.Point [P ]](c * ecdsa.Curve [P ], priv * PrivateKey , csprng io.Reader , hash []byte ) ([]byte , error ) {
228
- // privateKeyToFIPS is very slow in FIPS mode because it performs a
229
- // Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache
230
- // it or attach it to the PrivateKey.
270
+ func signFIPSDeterministic [P ecdsa.Point [P ]](c * ecdsa.Curve [P ], hashFunc crypto.Hash , priv * PrivateKey , hash []byte ) ([]byte , error ) {
231
271
k , err := privateKeyToFIPS (c , priv )
232
272
if err != nil {
233
273
return nil , err
234
274
}
235
- sig , err := ecdsa .Sign (c , k , csprng , hash )
275
+ sig , err := ecdsa .SignDeterministic (c , hashFunc . New , k , hash )
236
276
if err != nil {
237
277
return nil , err
238
278
}
@@ -266,61 +306,6 @@ func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) {
266
306
})
267
307
}
268
308
269
- // mixedCSPRNG returns a CSPRNG that mixes entropy from rand with the message
270
- // and the private key, to protect the key in case rand fails. This is
271
- // equivalent in security to RFC 6979 deterministic nonce generation, but still
272
- // produces randomized signatures.
273
- func mixedCSPRNG (rand io.Reader , priv * PrivateKey , hash []byte ) (io.Reader , error ) {
274
- // This implementation derives the nonce from an AES-CTR CSPRNG keyed by:
275
- //
276
- // SHA2-512(priv.D || entropy || hash)[:32]
277
- //
278
- // The CSPRNG key is indifferentiable from a random oracle as shown in
279
- // [Coron], the AES-CTR stream is indifferentiable from a random oracle
280
- // under standard cryptographic assumptions (see [Larsson] for examples).
281
- //
282
- // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf
283
- // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf
284
-
285
- // Get 256 bits of entropy from rand.
286
- entropy := make ([]byte , 32 )
287
- if _ , err := io .ReadFull (rand , entropy ); err != nil {
288
- return nil , err
289
- }
290
-
291
- // Initialize an SHA-512 hash context; digest...
292
- md := sha512 .New ()
293
- md .Write (priv .D .Bytes ()) // the private key,
294
- md .Write (entropy ) // the entropy,
295
- md .Write (hash ) // and the input hash;
296
- key := md .Sum (nil )[:32 ] // and compute ChopMD-256(SHA-512),
297
- // which is an indifferentiable MAC.
298
-
299
- // Create an AES-CTR instance to use as a CSPRNG.
300
- block , err := aes .NewCipher (key )
301
- if err != nil {
302
- return nil , err
303
- }
304
-
305
- // Create a CSPRNG that xors a stream of zeros with
306
- // the output of the AES-CTR instance.
307
- const aesIV = "IV for ECDSA CTR"
308
- return & cipher.StreamReader {
309
- R : zeroReader ,
310
- S : cipher .NewCTR (block , []byte (aesIV )),
311
- }, nil
312
- }
313
-
314
- type zr struct {}
315
-
316
- var zeroReader = zr {}
317
-
318
- // Read replaces the contents of dst with zeros. It is safe for concurrent use.
319
- func (zr ) Read (dst []byte ) (n int , err error ) {
320
- clear (dst )
321
- return len (dst ), nil
322
- }
323
-
324
309
// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
325
310
// public key, pub. Its return value records whether the signature is valid.
326
311
//
0 commit comments