@@ -16,8 +16,6 @@ package ecdsa
1616
1717import (
1818 "crypto"
19- "crypto/aes"
20- "crypto/cipher"
2119 "crypto/ecdh"
2220 "crypto/elliptic"
2321 "crypto/internal/boring"
@@ -131,14 +129,24 @@ func bigIntEqual(a, b *big.Int) bool {
131129 return subtle .ConstantTimeCompare (a .Bytes (), b .Bytes ()) == 1
132130}
133131
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].
137136//
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].
141146func (priv * PrivateKey ) Sign (rand io.Reader , digest []byte , opts crypto.SignerOpts ) ([]byte , error ) {
147+ if rand == nil {
148+ return signRFC6979 (priv , digest , opts )
149+ }
142150 return SignASN1 (rand , priv , digest )
143151}
144152
@@ -205,34 +213,66 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
205213 }
206214 boring .UnreachableExceptTests ()
207215
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 )
209235 if err != nil {
210236 return nil , err
211237 }
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+ }
212247
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+ }
213256 switch priv .Curve .Params () {
214257 case elliptic .P224 ().Params ():
215- return signFIPS (ecdsa .P224 (), priv , csprng , hash )
258+ return signFIPSDeterministic (ecdsa .P224 (), h , priv , hash )
216259 case elliptic .P256 ().Params ():
217- return signFIPS (ecdsa .P256 (), priv , csprng , hash )
260+ return signFIPSDeterministic (ecdsa .P256 (), h , priv , hash )
218261 case elliptic .P384 ().Params ():
219- return signFIPS (ecdsa .P384 (), priv , csprng , hash )
262+ return signFIPSDeterministic (ecdsa .P384 (), h , priv , hash )
220263 case elliptic .P521 ().Params ():
221- return signFIPS (ecdsa .P521 (), priv , csprng , hash )
264+ return signFIPSDeterministic (ecdsa .P521 (), h , priv , hash )
222265 default :
223- return signLegacy ( priv , csprng , hash )
266+ return nil , errors . New ( "ecdsa: curve not supported by deterministic signatures" )
224267 }
225268}
226269
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 ) {
231271 k , err := privateKeyToFIPS (c , priv )
232272 if err != nil {
233273 return nil , err
234274 }
235- sig , err := ecdsa .Sign (c , k , csprng , hash )
275+ sig , err := ecdsa .SignDeterministic (c , hashFunc . New , k , hash )
236276 if err != nil {
237277 return nil , err
238278 }
@@ -266,61 +306,6 @@ func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) {
266306 })
267307}
268308
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-
324309// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
325310// public key, pub. Its return value records whether the signature is valid.
326311//
0 commit comments