| // 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]. |
| // |
| // 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. |
| // |
| // [FIPS 186-5]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf |
| package ecdsa |
| |
| import ( |
| "crypto" |
| "crypto/ecdh" |
| "crypto/elliptic" |
| "crypto/internal/boring" |
| "crypto/internal/boring/bbig" |
| "crypto/internal/fips140/ecdsa" |
| "crypto/internal/fips140/nistec" |
| "crypto/internal/fips140cache" |
| "crypto/internal/fips140hash" |
| "crypto/internal/fips140only" |
| "crypto/internal/randutil" |
| "crypto/sha512" |
| "crypto/subtle" |
| "errors" |
| "io" |
| "math/big" |
| |
| "golang.org/x/crypto/cryptobyte" |
| "golang.org/x/crypto/cryptobyte/asn1" |
| ) |
| |
| // PublicKey represents an ECDSA public key. |
| type PublicKey struct { |
| elliptic.Curve |
| |
| // X, Y are the coordinates of the public key point. |
| // |
| // Deprecated: modifying the raw coordinates can produce invalid keys, and may |
| // invalidate internal optimizations; moreover, [big.Int] methods are not |
| // suitable for operating on cryptographic values. To encode and decode |
| // PublicKey values, use [PublicKey.Bytes] and [ParseUncompressedPublicKey] |
| // or [crypto/x509.MarshalPKIXPublicKey] and [crypto/x509.ParsePKIXPublicKey]. |
| // For ECDH, use [crypto/ecdh]. For lower-level elliptic curve operations, |
| // use a third-party module like filippo.io/nistec. |
| 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 (k *PublicKey) ECDH() (*ecdh.PublicKey, error) { |
| c := curveToECDH(k.Curve) |
| if c == nil { |
| return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh") |
| } |
| if !k.Curve.IsOnCurve(k.X, k.Y) { |
| return nil, errors.New("ecdsa: invalid public key") |
| } |
| return c.NewPublicKey(elliptic.Marshal(k.Curve, k.X, k.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 (pub *PublicKey) Equal(x crypto.PublicKey) bool { |
| xx, ok := x.(*PublicKey) |
| if !ok { |
| return false |
| } |
| return bigIntEqual(pub.X, xx.X) && bigIntEqual(pub.Y, xx.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. |
| pub.Curve == xx.Curve |
| } |
| |
| // ParseUncompressedPublicKey parses a public key encoded as an uncompressed |
| // point according to SEC 1, Version 2.0, Section 2.3.3 (also known as the X9.62 |
| // uncompressed format). It returns an error if the point is not in uncompressed |
| // form, is not on the curve, or is the point at infinity. |
| // |
| // curve must be one of [elliptic.P224], [elliptic.P256], [elliptic.P384], or |
| // [elliptic.P521], or ParseUncompressedPublicKey returns an error. |
| // |
| // ParseUncompressedPublicKey accepts the same format as |
| // [ecdh.Curve.NewPublicKey] does for NIST curves, but returns a [PublicKey] |
| // instead of an [ecdh.PublicKey]. |
| // |
| // Note that public keys are more commonly encoded in DER (or PEM) format, which |
| // can be parsed with [crypto/x509.ParsePKIXPublicKey] (and [encoding/pem]). |
| func ParseUncompressedPublicKey(curve elliptic.Curve, data []byte) (*PublicKey, error) { |
| if len(data) < 1 || data[0] != 4 { |
| return nil, errors.New("ecdsa: invalid uncompressed public key") |
| } |
| switch curve { |
| case elliptic.P224(): |
| return parseUncompressedPublicKey(ecdsa.P224(), curve, data) |
| case elliptic.P256(): |
| return parseUncompressedPublicKey(ecdsa.P256(), curve, data) |
| case elliptic.P384(): |
| return parseUncompressedPublicKey(ecdsa.P384(), curve, data) |
| case elliptic.P521(): |
| return parseUncompressedPublicKey(ecdsa.P521(), curve, data) |
| default: |
| return nil, errors.New("ecdsa: curve not supported by ParseUncompressedPublicKey") |
| } |
| } |
| |
| func parseUncompressedPublicKey[P ecdsa.Point[P]](c *ecdsa.Curve[P], curve elliptic.Curve, data []byte) (*PublicKey, error) { |
| k, err := ecdsa.NewPublicKey(c, data) |
| if err != nil { |
| return nil, err |
| } |
| return publicKeyFromFIPS(curve, k) |
| } |
| |
| // Bytes encodes the public key as an uncompressed point according to SEC 1, |
| // Version 2.0, Section 2.3.3 (also known as the X9.62 uncompressed format). |
| // It returns an error if the public key is invalid. |
| // |
| // PublicKey.Curve must be one of [elliptic.P224], [elliptic.P256], |
| // [elliptic.P384], or [elliptic.P521], or Bytes returns an error. |
| // |
| // Bytes returns the same format as [ecdh.PublicKey.Bytes] does for NIST curves. |
| // |
| // Note that public keys are more commonly encoded in DER (or PEM) format, which |
| // can be generated with [crypto/x509.MarshalPKIXPublicKey] (and [encoding/pem]). |
| func (pub *PublicKey) Bytes() ([]byte, error) { |
| switch pub.Curve { |
| case elliptic.P224(): |
| return publicKeyBytes(ecdsa.P224(), pub) |
| case elliptic.P256(): |
| return publicKeyBytes(ecdsa.P256(), pub) |
| case elliptic.P384(): |
| return publicKeyBytes(ecdsa.P384(), pub) |
| case elliptic.P521(): |
| return publicKeyBytes(ecdsa.P521(), pub) |
| default: |
| return nil, errors.New("ecdsa: curve not supported by PublicKey.Bytes") |
| } |
| } |
| |
| func publicKeyBytes[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey) ([]byte, error) { |
| k, err := publicKeyToFIPS(c, pub) |
| if err != nil { |
| return nil, err |
| } |
| return k.Bytes(), nil |
| } |
| |
| // PrivateKey represents an ECDSA private key. |
| type PrivateKey struct { |
| PublicKey |
| |
| // D is the private scalar value. |
| // |
| // Deprecated: modifying the raw value can produce invalid keys, and may |
| // invalidate internal optimizations; moreover, [big.Int] methods are not |
| // suitable for operating on cryptographic values. To encode and decode |
| // PrivateKey values, use [PrivateKey.Bytes] and [ParseRawPrivateKey] or |
| // [crypto/x509.MarshalPKCS8PrivateKey] and [crypto/x509.ParsePKCS8PrivateKey]. |
| // For ECDH, use [crypto/ecdh]. |
| 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 (k *PrivateKey) ECDH() (*ecdh.PrivateKey, error) { |
| c := curveToECDH(k.Curve) |
| if c == nil { |
| return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh") |
| } |
| size := (k.Curve.Params().N.BitLen() + 7) / 8 |
| if k.D.BitLen() > size*8 { |
| return nil, errors.New("ecdsa: invalid private key") |
| } |
| return c.NewPrivateKey(k.D.FillBytes(make([]byte, size))) |
| } |
| |
| func curveToECDH(c elliptic.Curve) ecdh.Curve { |
| switch c { |
| 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 (priv *PrivateKey) Public() crypto.PublicKey { |
| return &priv.PublicKey |
| } |
| |
| // Equal reports whether priv and x have the same value. |
| // |
| // See [PublicKey.Equal] for details on how Curve is compared. |
| func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool { |
| xx, ok := x.(*PrivateKey) |
| if !ok { |
| return false |
| } |
| return priv.PublicKey.Equal(&xx.PublicKey) && bigIntEqual(priv.D, xx.D) |
| } |
| |
| // bigIntEqual reports whether a and b are equal leaking only their bit length |
| // through timing side-channels. |
| func bigIntEqual(a, b *big.Int) bool { |
| return subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1 |
| } |
| |
| // ParseRawPrivateKey parses a private key encoded as a fixed-length big-endian |
| // integer, according to SEC 1, Version 2.0, Section 2.3.6 (sometimes referred |
| // to as the raw format). It returns an error if the value is not reduced modulo |
| // the curve's order, or if it's zero. |
| // |
| // curve must be one of [elliptic.P224], [elliptic.P256], [elliptic.P384], or |
| // [elliptic.P521], or ParseRawPrivateKey returns an error. |
| // |
| // ParseRawPrivateKey accepts the same format as [ecdh.Curve.NewPrivateKey] does |
| // for NIST curves, but returns a [PrivateKey] instead of an [ecdh.PrivateKey]. |
| // |
| // Note that private keys are more commonly encoded in ASN.1 or PKCS#8 format, |
| // which can be parsed with [crypto/x509.ParseECPrivateKey] or |
| // [crypto/x509.ParsePKCS8PrivateKey] (and [encoding/pem]). |
| func ParseRawPrivateKey(curve elliptic.Curve, data []byte) (*PrivateKey, error) { |
| switch curve { |
| case elliptic.P224(): |
| return parseRawPrivateKey(ecdsa.P224(), nistec.NewP224Point, curve, data) |
| case elliptic.P256(): |
| return parseRawPrivateKey(ecdsa.P256(), nistec.NewP256Point, curve, data) |
| case elliptic.P384(): |
| return parseRawPrivateKey(ecdsa.P384(), nistec.NewP384Point, curve, data) |
| case elliptic.P521(): |
| return parseRawPrivateKey(ecdsa.P521(), nistec.NewP521Point, curve, data) |
| default: |
| return nil, errors.New("ecdsa: curve not supported by ParseRawPrivateKey") |
| } |
| } |
| |
| func parseRawPrivateKey[P ecdsa.Point[P]](c *ecdsa.Curve[P], newPoint func() P, curve elliptic.Curve, data []byte) (*PrivateKey, error) { |
| q, err := newPoint().ScalarBaseMult(data) |
| if err != nil { |
| return nil, err |
| } |
| k, err := ecdsa.NewPrivateKey(c, data, q.Bytes()) |
| if err != nil { |
| return nil, err |
| } |
| return privateKeyFromFIPS(curve, k) |
| } |
| |
| // Bytes encodes the private key as a fixed-length big-endian integer according |
| // to SEC 1, Version 2.0, Section 2.3.6 (sometimes referred to as the raw |
| // format). It returns an error if the private key is invalid. |
| // |
| // PrivateKey.Curve must be one of [elliptic.P224], [elliptic.P256], |
| // [elliptic.P384], or [elliptic.P521], or Bytes returns an error. |
| // |
| // Bytes returns the same format as [ecdh.PrivateKey.Bytes] does for NIST curves. |
| // |
| // Note that private keys are more commonly encoded in ASN.1 or PKCS#8 format, |
| // which can be generated with [crypto/x509.MarshalECPrivateKey] or |
| // [crypto/x509.MarshalPKCS8PrivateKey] (and [encoding/pem]). |
| func (priv *PrivateKey) Bytes() ([]byte, error) { |
| switch priv.Curve { |
| case elliptic.P224(): |
| return privateKeyBytes(ecdsa.P224(), priv) |
| case elliptic.P256(): |
| return privateKeyBytes(ecdsa.P256(), priv) |
| case elliptic.P384(): |
| return privateKeyBytes(ecdsa.P384(), priv) |
| case elliptic.P521(): |
| return privateKeyBytes(ecdsa.P521(), priv) |
| default: |
| return nil, errors.New("ecdsa: curve not supported by PrivateKey.Bytes") |
| } |
| } |
| |
| func privateKeyBytes[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey) ([]byte, error) { |
| k, err := privateKeyToFIPS(c, priv) |
| if err != nil { |
| return nil, err |
| } |
| return k.Bytes(), nil |
| } |
| |
| // 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 (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { |
| if rand == nil { |
| return signRFC6979(priv, digest, opts) |
| } |
| return SignASN1(rand, priv, digest) |
| } |
| |
| // 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 GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) { |
| randutil.MaybeReadByte(rand) |
| |
| if boring.Enabled && rand == boring.RandReader { |
| x, y, d, err := boring.GenerateKeyECDSA(c.Params().Name) |
| if err != nil { |
| return nil, err |
| } |
| return &PrivateKey{PublicKey: PublicKey{Curve: c, X: bbig.Dec(x), Y: bbig.Dec(y)}, D: bbig.Dec(d)}, nil |
| } |
| boring.UnreachableExceptTests() |
| |
| switch c.Params() { |
| case elliptic.P224().Params(): |
| return generateFIPS(c, ecdsa.P224(), rand) |
| case elliptic.P256().Params(): |
| return generateFIPS(c, ecdsa.P256(), rand) |
| case elliptic.P384().Params(): |
| return generateFIPS(c, ecdsa.P384(), rand) |
| case elliptic.P521().Params(): |
| return generateFIPS(c, ecdsa.P521(), rand) |
| default: |
| return generateLegacy(c, rand) |
| } |
| } |
| |
| func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) { |
| if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { |
| return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") |
| } |
| privateKey, err := ecdsa.GenerateKey(c, rand) |
| if err != nil { |
| return nil, err |
| } |
| return privateKeyFromFIPS(curve, privateKey) |
| } |
| |
| // 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 SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) { |
| randutil.MaybeReadByte(rand) |
| |
| if boring.Enabled && rand == boring.RandReader { |
| b, err := boringPrivateKey(priv) |
| if err != nil { |
| return nil, err |
| } |
| return boring.SignMarshalECDSA(b, hash) |
| } |
| boring.UnreachableExceptTests() |
| |
| switch priv.Curve.Params() { |
| case elliptic.P224().Params(): |
| return signFIPS(ecdsa.P224(), priv, rand, hash) |
| case elliptic.P256().Params(): |
| return signFIPS(ecdsa.P256(), priv, rand, hash) |
| case elliptic.P384().Params(): |
| return signFIPS(ecdsa.P384(), priv, rand, hash) |
| case elliptic.P521().Params(): |
| return signFIPS(ecdsa.P521(), priv, rand, hash) |
| default: |
| return signLegacy(priv, rand, hash) |
| } |
| } |
| |
| func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) { |
| if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { |
| return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") |
| } |
| k, err := privateKeyToFIPS(c, priv) |
| if err != nil { |
| return nil, err |
| } |
| // 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. |
| sig, err := ecdsa.Sign(c, sha512.New, k, rand, hash) |
| if err != nil { |
| return nil, err |
| } |
| return encodeSignature(sig.R, sig.S) |
| } |
| |
| func signRFC6979(priv *PrivateKey, hash []byte, opts crypto.SignerOpts) ([]byte, error) { |
| if opts == nil { |
| return nil, errors.New("ecdsa: Sign called with nil opts") |
| } |
| h := opts.HashFunc() |
| if h.Size() != len(hash) { |
| return nil, errors.New("ecdsa: hash length does not match hash function") |
| } |
| switch priv.Curve.Params() { |
| case elliptic.P224().Params(): |
| return signFIPSDeterministic(ecdsa.P224(), h, priv, hash) |
| case elliptic.P256().Params(): |
| return signFIPSDeterministic(ecdsa.P256(), h, priv, hash) |
| case elliptic.P384().Params(): |
| return signFIPSDeterministic(ecdsa.P384(), h, priv, hash) |
| case elliptic.P521().Params(): |
| return signFIPSDeterministic(ecdsa.P521(), h, priv, hash) |
| default: |
| return nil, errors.New("ecdsa: curve not supported by deterministic signatures") |
| } |
| } |
| |
| func signFIPSDeterministic[P ecdsa.Point[P]](c *ecdsa.Curve[P], hashFunc crypto.Hash, priv *PrivateKey, hash []byte) ([]byte, error) { |
| k, err := privateKeyToFIPS(c, priv) |
| if err != nil { |
| return nil, err |
| } |
| h := fips140hash.UnwrapNew(hashFunc.New) |
| if fips140only.Enabled && !fips140only.ApprovedHash(h()) { |
| return nil, errors.New("crypto/ecdsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") |
| } |
| sig, err := ecdsa.SignDeterministic(c, h, k, hash) |
| if err != nil { |
| return nil, err |
| } |
| return encodeSignature(sig.R, sig.S) |
| } |
| |
| func encodeSignature(r, s []byte) ([]byte, error) { |
| var b cryptobyte.Builder |
| b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { |
| addASN1IntBytes(b, r) |
| addASN1IntBytes(b, s) |
| }) |
| return b.Bytes() |
| } |
| |
| // addASN1IntBytes encodes in ASN.1 a positive integer represented as |
| // a big-endian byte slice with zero or more leading zeroes. |
| func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) { |
| for len(bytes) > 0 && bytes[0] == 0 { |
| bytes = bytes[1:] |
| } |
| if len(bytes) == 0 { |
| b.SetError(errors.New("invalid integer")) |
| return |
| } |
| b.AddASN1(asn1.INTEGER, func(c *cryptobyte.Builder) { |
| if bytes[0]&0x80 != 0 { |
| c.AddUint8(0) |
| } |
| c.AddBytes(bytes) |
| }) |
| } |
| |
| // 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 VerifyASN1(pub *PublicKey, hash, sig []byte) bool { |
| if boring.Enabled { |
| key, err := boringPublicKey(pub) |
| if err != nil { |
| return false |
| } |
| return boring.VerifyECDSA(key, hash, sig) |
| } |
| boring.UnreachableExceptTests() |
| |
| switch pub.Curve.Params() { |
| case elliptic.P224().Params(): |
| return verifyFIPS(ecdsa.P224(), pub, hash, sig) |
| case elliptic.P256().Params(): |
| return verifyFIPS(ecdsa.P256(), pub, hash, sig) |
| case elliptic.P384().Params(): |
| return verifyFIPS(ecdsa.P384(), pub, hash, sig) |
| case elliptic.P521().Params(): |
| return verifyFIPS(ecdsa.P521(), pub, hash, sig) |
| default: |
| return verifyLegacy(pub, hash, sig) |
| } |
| } |
| |
| func verifyFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey, hash, sig []byte) bool { |
| r, s, err := parseSignature(sig) |
| if err != nil { |
| return false |
| } |
| k, err := publicKeyToFIPS(c, pub) |
| if err != nil { |
| return false |
| } |
| if err := ecdsa.Verify(c, k, hash, &ecdsa.Signature{R: r, S: s}); err != nil { |
| return false |
| } |
| return true |
| } |
| |
| func parseSignature(sig []byte) (r, s []byte, err error) { |
| var inner cryptobyte.String |
| input := cryptobyte.String(sig) |
| if !input.ReadASN1(&inner, asn1.SEQUENCE) || |
| !input.Empty() || |
| !inner.ReadASN1Integer(&r) || |
| !inner.ReadASN1Integer(&s) || |
| !inner.Empty() { |
| return nil, nil, errors.New("invalid ASN.1") |
| } |
| return r, s, nil |
| } |
| |
| func publicKeyFromFIPS(curve elliptic.Curve, pub *ecdsa.PublicKey) (*PublicKey, error) { |
| x, y, err := pointToAffine(curve, pub.Bytes()) |
| if err != nil { |
| return nil, err |
| } |
| return &PublicKey{Curve: curve, X: x, Y: y}, nil |
| } |
| |
| func privateKeyFromFIPS(curve elliptic.Curve, priv *ecdsa.PrivateKey) (*PrivateKey, error) { |
| pub, err := publicKeyFromFIPS(curve, priv.PublicKey()) |
| if err != nil { |
| return nil, err |
| } |
| return &PrivateKey{PublicKey: *pub, D: new(big.Int).SetBytes(priv.Bytes())}, nil |
| } |
| |
| func publicKeyToFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey) (*ecdsa.PublicKey, error) { |
| Q, err := pointFromAffine(pub.Curve, pub.X, pub.Y) |
| if err != nil { |
| return nil, err |
| } |
| return ecdsa.NewPublicKey(c, Q) |
| } |
| |
| var privateKeyCache fips140cache.Cache[PrivateKey, ecdsa.PrivateKey] |
| |
| func privateKeyToFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey) (*ecdsa.PrivateKey, error) { |
| Q, err := pointFromAffine(priv.Curve, priv.X, priv.Y) |
| if err != nil { |
| return nil, err |
| } |
| return privateKeyCache.Get(priv, func() (*ecdsa.PrivateKey, error) { |
| return ecdsa.NewPrivateKey(c, priv.D.Bytes(), Q) |
| }, func(k *ecdsa.PrivateKey) bool { |
| return subtle.ConstantTimeCompare(k.PublicKey().Bytes(), Q) == 1 && |
| leftPadBytesEqual(k.Bytes(), priv.D.Bytes()) |
| }) |
| } |
| |
| func leftPadBytesEqual(a, b []byte) bool { |
| if len(a) < len(b) { |
| a, b = b, a |
| } |
| if len(a) > len(b) { |
| x := make([]byte, 0, 66 /* enough for a P-521 private key */) |
| x = append(x, make([]byte, len(a)-len(b))...) |
| x = append(x, b...) |
| b = x |
| } |
| return subtle.ConstantTimeCompare(a, b) == 1 |
| } |
| |
| // pointFromAffine is used to convert the PublicKey to a nistec SetBytes input. |
| func pointFromAffine(curve elliptic.Curve, x, y *big.Int) ([]byte, error) { |
| bitSize := curve.Params().BitSize |
| // Reject values that would not get correctly encoded. |
| if x.Sign() < 0 || y.Sign() < 0 { |
| return nil, errors.New("negative coordinate") |
| } |
| if x.BitLen() > bitSize || y.BitLen() > bitSize { |
| return nil, errors.New("overflowing coordinate") |
| } |
| // Encode the coordinates and let SetBytes reject invalid points. |
| byteLen := (bitSize + 7) / 8 |
| buf := make([]byte, 1+2*byteLen) |
| buf[0] = 4 // uncompressed point |
| x.FillBytes(buf[1 : 1+byteLen]) |
| y.FillBytes(buf[1+byteLen : 1+2*byteLen]) |
| return buf, nil |
| } |
| |
| // pointToAffine is used to convert a nistec Bytes encoding to a PublicKey. |
| func pointToAffine(curve elliptic.Curve, p []byte) (x, y *big.Int, err error) { |
| if len(p) == 1 && p[0] == 0 { |
| // This is the encoding of the point at infinity. |
| return nil, nil, errors.New("ecdsa: public key point is the infinity") |
| } |
| byteLen := (curve.Params().BitSize + 7) / 8 |
| x = new(big.Int).SetBytes(p[1 : 1+byteLen]) |
| y = new(big.Int).SetBytes(p[1+byteLen:]) |
| return x, y, nil |
| } |