// Copyright 2011 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 ecdsa implements the Elliptic Curve Digital Signature Algorithm, as // defined in FIPS 186-5 and SEC 1, Version 2.0. // // Signatures generated by this package are not deterministic, but entropy is // mixed with the private key and the message, achieving the same level of // security in case of randomness source failure. // // Operations involving private keys are implemented using constant-time // algorithms, as long as an [elliptic.Curve] returned by [elliptic.P224], // [elliptic.P256], [elliptic.P384], or [elliptic.P521] is used.
package ecdsa import ( ) // PublicKey represents an ECDSA public key. type PublicKey struct { elliptic.Curve X, Y *big.Int } // Any methods implemented on PublicKey might need to also be implemented on // PrivateKey, as the latter embeds the former and will expose its methods. // ECDH returns k as a [ecdh.PublicKey]. It returns an error if the key is // invalid according to the definition of [ecdh.Curve.NewPublicKey], or if the // Curve is not supported by crypto/ecdh. func ( *PublicKey) () (*ecdh.PublicKey, error) { := curveToECDH(.Curve) if == nil { return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh") } if !.Curve.IsOnCurve(.X, .Y) { return nil, errors.New("ecdsa: invalid public key") } return .NewPublicKey(elliptic.Marshal(.Curve, .X, .Y)) } // Equal reports whether pub and x have the same value. // // Two keys are only considered to have the same value if they have the same Curve value. // Note that for example [elliptic.P256] and elliptic.P256().Params() are different // values, as the latter is a generic not constant time implementation. func ( *PublicKey) ( crypto.PublicKey) bool { , := .(*PublicKey) if ! { return false } return bigIntEqual(.X, .X) && bigIntEqual(.Y, .Y) && // Standard library Curve implementations are singletons, so this check // will work for those. Other Curves might be equivalent even if not // singletons, but there is no definitive way to check for that, and // better to err on the side of safety. .Curve == .Curve } // PrivateKey represents an ECDSA private key. type PrivateKey struct { PublicKey D *big.Int } // ECDH returns k as a [ecdh.PrivateKey]. It returns an error if the key is // invalid according to the definition of [ecdh.Curve.NewPrivateKey], or if the // Curve is not supported by [crypto/ecdh]. func ( *PrivateKey) () (*ecdh.PrivateKey, error) { := curveToECDH(.Curve) if == nil { return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh") } := (.Curve.Params().N.BitLen() + 7) / 8 if .D.BitLen() > *8 { return nil, errors.New("ecdsa: invalid private key") } return .NewPrivateKey(.D.FillBytes(make([]byte, ))) } func curveToECDH( elliptic.Curve) ecdh.Curve { switch { case elliptic.P256(): return ecdh.P256() case elliptic.P384(): return ecdh.P384() case elliptic.P521(): return ecdh.P521() default: return nil } } // Public returns the public key corresponding to priv. func ( *PrivateKey) () crypto.PublicKey { return &.PublicKey } // Equal reports whether priv and x have the same value. // // See [PublicKey.Equal] for details on how Curve is compared. func ( *PrivateKey) ( crypto.PrivateKey) bool { , := .(*PrivateKey) if ! { return false } return .PublicKey.Equal(&.PublicKey) && bigIntEqual(.D, .D) } // bigIntEqual reports whether a and b are equal leaking only their bit length // through timing side-channels. func bigIntEqual(, *big.Int) bool { return subtle.ConstantTimeCompare(.Bytes(), .Bytes()) == 1 } // Sign signs a hash (which should be the result of hashing a larger message // with opts.HashFunc()) using the private key, priv. If the hash is longer than // the bit-length of the private key's curve order, the hash will be truncated // to that length. It returns the ASN.1 encoded signature, like [SignASN1]. // // If rand is not nil, the signature is randomized. Most applications should use // [crypto/rand.Reader] as rand. Note that the returned signature does not // depend deterministically on the bytes read from rand, and may change between // calls and/or between versions. // // If rand is nil, Sign will produce a deterministic signature according to RFC // 6979. When producing a deterministic signature, opts.HashFunc() must be the // function used to produce digest and priv.Curve must be one of // [elliptic.P224], [elliptic.P256], [elliptic.P384], or [elliptic.P521]. func ( *PrivateKey) ( io.Reader, []byte, crypto.SignerOpts) ([]byte, error) { if == nil { return signRFC6979(, , ) } return SignASN1(, , ) } // GenerateKey generates a new ECDSA private key for the specified curve. // // Most applications should use [crypto/rand.Reader] as rand. Note that the // returned key does not depend deterministically on the bytes read from rand, // and may change between calls and/or between versions. func ( elliptic.Curve, io.Reader) (*PrivateKey, error) { randutil.MaybeReadByte() if boring.Enabled && == boring.RandReader { , , , := boring.GenerateKeyECDSA(.Params().Name) if != nil { return nil, } return &PrivateKey{PublicKey: PublicKey{Curve: , X: bbig.Dec(), Y: bbig.Dec()}, D: bbig.Dec()}, nil } boring.UnreachableExceptTests() switch .Params() { case elliptic.P224().Params(): return generateFIPS(, ecdsa.P224(), ) case elliptic.P256().Params(): return generateFIPS(, ecdsa.P256(), ) case elliptic.P384().Params(): return generateFIPS(, ecdsa.P384(), ) case elliptic.P521().Params(): return generateFIPS(, ecdsa.P521(), ) default: return generateLegacy(, ) } } func generateFIPS[ ecdsa.Point[]]( elliptic.Curve, *ecdsa.Curve[], io.Reader) (*PrivateKey, error) { if fips140only.Enabled && fips140only.ApprovedRandomReader() { return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") } , := ecdsa.GenerateKey(, ) if != nil { return nil, } return privateKeyFromFIPS(, ) } // errNoAsm is returned by signAsm and verifyAsm when the assembly // implementation is not available. var errNoAsm = errors.New("no assembly implementation available") // SignASN1 signs a hash (which should be the result of hashing a larger message) // using the private key, priv. If the hash is longer than the bit-length of the // private key's curve order, the hash will be truncated to that length. It // returns the ASN.1 encoded signature. // // The signature is randomized. Most applications should use [crypto/rand.Reader] // as rand. Note that the returned signature does not depend deterministically on // the bytes read from rand, and may change between calls and/or between versions. func ( io.Reader, *PrivateKey, []byte) ([]byte, error) { randutil.MaybeReadByte() if boring.Enabled && == boring.RandReader { , := boringPrivateKey() if != nil { return nil, } return boring.SignMarshalECDSA(, ) } boring.UnreachableExceptTests() switch .Curve.Params() { case elliptic.P224().Params(): return signFIPS(ecdsa.P224(), , , ) case elliptic.P256().Params(): return signFIPS(ecdsa.P256(), , , ) case elliptic.P384().Params(): return signFIPS(ecdsa.P384(), , , ) case elliptic.P521().Params(): return signFIPS(ecdsa.P521(), , , ) default: return signLegacy(, , ) } } func signFIPS[ ecdsa.Point[]]( *ecdsa.Curve[], *PrivateKey, io.Reader, []byte) ([]byte, error) { if fips140only.Enabled && !fips140only.ApprovedRandomReader() { return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") } // privateKeyToFIPS is very slow in FIPS mode because it performs a // Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache // it or attach it to the PrivateKey. , := privateKeyToFIPS(, ) if != nil { return nil, } // Always using SHA-512 instead of the hash that computed hash is // technically a violation of draft-irtf-cfrg-det-sigs-with-noise-04 but in // our API we don't get to know what it was, and this has no security impact. , := ecdsa.Sign(, sha512.New, , , ) if != nil { return nil, } return encodeSignature(.R, .S) } func signRFC6979( *PrivateKey, []byte, crypto.SignerOpts) ([]byte, error) { if == nil { return nil, errors.New("ecdsa: Sign called with nil opts") } := .HashFunc() if .Size() != len() { return nil, errors.New("ecdsa: hash length does not match hash function") } switch .Curve.Params() { case elliptic.P224().Params(): return signFIPSDeterministic(ecdsa.P224(), , , ) case elliptic.P256().Params(): return signFIPSDeterministic(ecdsa.P256(), , , ) case elliptic.P384().Params(): return signFIPSDeterministic(ecdsa.P384(), , , ) case elliptic.P521().Params(): return signFIPSDeterministic(ecdsa.P521(), , , ) default: return nil, errors.New("ecdsa: curve not supported by deterministic signatures") } } func signFIPSDeterministic[ ecdsa.Point[]]( *ecdsa.Curve[], crypto.Hash, *PrivateKey, []byte) ([]byte, error) { , := privateKeyToFIPS(, ) if != nil { return nil, } , := ecdsa.SignDeterministic(, .New, , ) if != nil { return nil, } return encodeSignature(.R, .S) } func encodeSignature(, []byte) ([]byte, error) { var cryptobyte.Builder .AddASN1(asn1.SEQUENCE, func( *cryptobyte.Builder) { addASN1IntBytes(, ) addASN1IntBytes(, ) }) return .Bytes() } // addASN1IntBytes encodes in ASN.1 a positive integer represented as // a big-endian byte slice with zero or more leading zeroes. func addASN1IntBytes( *cryptobyte.Builder, []byte) { for len() > 0 && [0] == 0 { = [1:] } if len() == 0 { .SetError(errors.New("invalid integer")) return } .AddASN1(asn1.INTEGER, func( *cryptobyte.Builder) { if [0]&0x80 != 0 { .AddUint8(0) } .AddBytes() }) } // VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the // public key, pub. Its return value records whether the signature is valid. // // The inputs are not considered confidential, and may leak through timing side // channels, or if an attacker has control of part of the inputs. func ( *PublicKey, , []byte) bool { if boring.Enabled { , := boringPublicKey() if != nil { return false } return boring.VerifyECDSA(, , ) } boring.UnreachableExceptTests() switch .Curve.Params() { case elliptic.P224().Params(): return verifyFIPS(ecdsa.P224(), , , ) case elliptic.P256().Params(): return verifyFIPS(ecdsa.P256(), , , ) case elliptic.P384().Params(): return verifyFIPS(ecdsa.P384(), , , ) case elliptic.P521().Params(): return verifyFIPS(ecdsa.P521(), , , ) default: return verifyLegacy(, , ) } } func verifyFIPS[ ecdsa.Point[]]( *ecdsa.Curve[], *PublicKey, , []byte) bool { , , := parseSignature() if != nil { return false } , := publicKeyToFIPS(, ) if != nil { return false } if := ecdsa.Verify(, , , &ecdsa.Signature{R: , S: }); != nil { return false } return true } func parseSignature( []byte) (, []byte, error) { var cryptobyte.String := cryptobyte.String() if !.ReadASN1(&, asn1.SEQUENCE) || !.Empty() || !.ReadASN1Integer(&) || !.ReadASN1Integer(&) || !.Empty() { return nil, nil, errors.New("invalid ASN.1") } return , , nil } func publicKeyFromFIPS( elliptic.Curve, *ecdsa.PublicKey) (*PublicKey, error) { , , := pointToAffine(, .Bytes()) if != nil { return nil, } return &PublicKey{Curve: , X: , Y: }, nil } func privateKeyFromFIPS( elliptic.Curve, *ecdsa.PrivateKey) (*PrivateKey, error) { , := publicKeyFromFIPS(, .PublicKey()) if != nil { return nil, } return &PrivateKey{PublicKey: *, D: new(big.Int).SetBytes(.Bytes())}, nil } func publicKeyToFIPS[ ecdsa.Point[]]( *ecdsa.Curve[], *PublicKey) (*ecdsa.PublicKey, error) { , := pointFromAffine(.Curve, .X, .Y) if != nil { return nil, } return ecdsa.NewPublicKey(, ) } func privateKeyToFIPS[ ecdsa.Point[]]( *ecdsa.Curve[], *PrivateKey) (*ecdsa.PrivateKey, error) { , := pointFromAffine(.Curve, .X, .Y) if != nil { return nil, } return ecdsa.NewPrivateKey(, .D.Bytes(), ) } // pointFromAffine is used to convert the PublicKey to a nistec SetBytes input. func pointFromAffine( elliptic.Curve, , *big.Int) ([]byte, error) { := .Params().BitSize // Reject values that would not get correctly encoded. if .Sign() < 0 || .Sign() < 0 { return nil, errors.New("negative coordinate") } if .BitLen() > || .BitLen() > { return nil, errors.New("overflowing coordinate") } // Encode the coordinates and let SetBytes reject invalid points. := ( + 7) / 8 := make([]byte, 1+2*) [0] = 4 // uncompressed point .FillBytes([1 : 1+]) .FillBytes([1+ : 1+2*]) return , nil } // pointToAffine is used to convert a nistec Bytes encoding to a PublicKey. func pointToAffine( elliptic.Curve, []byte) (, *big.Int, error) { if len() == 1 && [0] == 0 { // This is the encoding of the point at infinity. return nil, nil, errors.New("ecdsa: public key point is the infinity") } := (.Params().BitSize + 7) / 8 = new(big.Int).SetBytes([1 : 1+]) = new(big.Int).SetBytes([1+:]) return , , nil }