2024-11-16 16:38:07 +01:00
|
|
|
// Copyright 2024 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
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2024-11-20 09:03:35 -05:00
|
|
|
"crypto/internal/fips140"
|
|
|
|
|
"crypto/internal/fips140/bigmod"
|
|
|
|
|
"crypto/internal/fips140/drbg"
|
|
|
|
|
"crypto/internal/fips140/nistec"
|
2024-11-16 16:38:07 +01:00
|
|
|
"errors"
|
|
|
|
|
"io"
|
|
|
|
|
"sync"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// PrivateKey and PublicKey are not generic to make it possible to use them
|
|
|
|
|
// in other types without instantiating them with a specific point type.
|
|
|
|
|
// They are tied to one of the Curve types below through the curveID field.
|
|
|
|
|
|
|
|
|
|
type PrivateKey struct {
|
|
|
|
|
pub PublicKey
|
2024-12-13 16:59:20 +01:00
|
|
|
d []byte // bigmod.(*Nat).Bytes output (same length as the curve order)
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (priv *PrivateKey) Bytes() []byte {
|
|
|
|
|
return priv.d
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (priv *PrivateKey) PublicKey() *PublicKey {
|
|
|
|
|
return &priv.pub
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type PublicKey struct {
|
|
|
|
|
curve curveID
|
|
|
|
|
q []byte // uncompressed nistec Point.Bytes output
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pub *PublicKey) Bytes() []byte {
|
|
|
|
|
return pub.q
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type curveID string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
p224 curveID = "P-224"
|
|
|
|
|
p256 curveID = "P-256"
|
|
|
|
|
p384 curveID = "P-384"
|
|
|
|
|
p521 curveID = "P-521"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Curve[P Point[P]] struct {
|
|
|
|
|
curve curveID
|
|
|
|
|
newPoint func() P
|
|
|
|
|
ordInverse func([]byte) ([]byte, error)
|
|
|
|
|
N *bigmod.Modulus
|
|
|
|
|
nMinus2 []byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Point is a generic constraint for the [nistec] Point types.
|
|
|
|
|
type Point[P any] interface {
|
|
|
|
|
*nistec.P224Point | *nistec.P256Point | *nistec.P384Point | *nistec.P521Point
|
|
|
|
|
Bytes() []byte
|
|
|
|
|
BytesX() ([]byte, error)
|
|
|
|
|
SetBytes([]byte) (P, error)
|
|
|
|
|
ScalarMult(P, []byte) (P, error)
|
|
|
|
|
ScalarBaseMult([]byte) (P, error)
|
|
|
|
|
Add(p1, p2 P) P
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func precomputeParams[P Point[P]](c *Curve[P], order []byte) {
|
|
|
|
|
var err error
|
|
|
|
|
c.N, err = bigmod.NewModulus(order)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
two, _ := bigmod.NewNat().SetBytes([]byte{2}, c.N)
|
|
|
|
|
c.nMinus2 = bigmod.NewNat().ExpandFor(c.N).Sub(two, c.N).Bytes(c.N)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func P224() *Curve[*nistec.P224Point] { return _P224() }
|
|
|
|
|
|
|
|
|
|
var _P224 = sync.OnceValue(func() *Curve[*nistec.P224Point] {
|
|
|
|
|
c := &Curve[*nistec.P224Point]{
|
|
|
|
|
curve: p224,
|
|
|
|
|
newPoint: nistec.NewP224Point,
|
|
|
|
|
}
|
|
|
|
|
precomputeParams(c, p224Order)
|
|
|
|
|
return c
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var p224Order = []byte{
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
|
|
|
|
|
0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
|
|
|
|
|
0x5c, 0x5c, 0x2a, 0x3d,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func P256() *Curve[*nistec.P256Point] { return _P256() }
|
|
|
|
|
|
|
|
|
|
var _P256 = sync.OnceValue(func() *Curve[*nistec.P256Point] {
|
|
|
|
|
c := &Curve[*nistec.P256Point]{
|
|
|
|
|
curve: p256,
|
|
|
|
|
newPoint: nistec.NewP256Point,
|
|
|
|
|
ordInverse: nistec.P256OrdInverse,
|
|
|
|
|
}
|
|
|
|
|
precomputeParams(c, p256Order)
|
|
|
|
|
return c
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var p256Order = []byte{
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
|
|
|
|
|
0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51}
|
|
|
|
|
|
|
|
|
|
func P384() *Curve[*nistec.P384Point] { return _P384() }
|
|
|
|
|
|
|
|
|
|
var _P384 = sync.OnceValue(func() *Curve[*nistec.P384Point] {
|
|
|
|
|
c := &Curve[*nistec.P384Point]{
|
|
|
|
|
curve: p384,
|
|
|
|
|
newPoint: nistec.NewP384Point,
|
|
|
|
|
}
|
|
|
|
|
precomputeParams(c, p384Order)
|
|
|
|
|
return c
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var p384Order = []byte{
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf,
|
|
|
|
|
0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a,
|
|
|
|
|
0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73}
|
|
|
|
|
|
|
|
|
|
func P521() *Curve[*nistec.P521Point] { return _P521() }
|
|
|
|
|
|
|
|
|
|
var _P521 = sync.OnceValue(func() *Curve[*nistec.P521Point] {
|
|
|
|
|
c := &Curve[*nistec.P521Point]{
|
|
|
|
|
curve: p521,
|
|
|
|
|
newPoint: nistec.NewP521Point,
|
|
|
|
|
}
|
|
|
|
|
precomputeParams(c, p521Order)
|
|
|
|
|
return c
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var p521Order = []byte{0x01, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa,
|
|
|
|
|
0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b,
|
|
|
|
|
0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0,
|
|
|
|
|
0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae,
|
|
|
|
|
0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09}
|
|
|
|
|
|
|
|
|
|
func NewPrivateKey[P Point[P]](c *Curve[P], D, Q []byte) (*PrivateKey, error) {
|
2024-11-20 09:03:35 -05:00
|
|
|
fips140.RecordApproved()
|
2024-11-16 17:44:17 +01:00
|
|
|
pub, err := NewPublicKey(c, Q)
|
2024-11-16 16:38:07 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
d, err := bigmod.NewNat().SetBytes(D, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-11-16 17:44:17 +01:00
|
|
|
priv := &PrivateKey{pub: *pub, d: d.Bytes(c.N)}
|
2024-11-17 18:38:29 +01:00
|
|
|
if err := fipsPCT(c, priv); err != nil {
|
|
|
|
|
// This can happen if the application went out of its way to make an
|
|
|
|
|
// ecdsa.PrivateKey with a mismatching PublicKey.
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-11-16 17:44:17 +01:00
|
|
|
return priv, nil
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewPublicKey[P Point[P]](c *Curve[P], Q []byte) (*PublicKey, error) {
|
2024-11-16 17:44:17 +01:00
|
|
|
// SetBytes checks that Q is a valid point on the curve, and that its
|
|
|
|
|
// coordinates are reduced modulo p, fulfilling the requirements of SP
|
|
|
|
|
// 800-89, Section 5.3.2.
|
2024-11-16 16:38:07 +01:00
|
|
|
_, err := c.newPoint().SetBytes(Q)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-11-16 17:44:17 +01:00
|
|
|
return &PublicKey{curve: c.curve, q: Q}, nil
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GenerateKey generates a new ECDSA private key pair for the specified curve.
|
|
|
|
|
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
|
2024-11-20 09:03:35 -05:00
|
|
|
fips140.RecordApproved()
|
2024-11-16 23:45:05 +01:00
|
|
|
|
|
|
|
|
k, Q, err := randomPoint(c, func(b []byte) error {
|
2024-12-11 14:50:00 +01:00
|
|
|
return drbg.ReadWithReader(rand, b)
|
2024-11-16 23:45:05 +01:00
|
|
|
})
|
2024-11-16 16:38:07 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-11-16 23:45:05 +01:00
|
|
|
|
2024-11-16 17:44:17 +01:00
|
|
|
priv := &PrivateKey{
|
2024-11-16 16:38:07 +01:00
|
|
|
pub: PublicKey{
|
|
|
|
|
curve: c.curve,
|
|
|
|
|
q: Q.Bytes(),
|
|
|
|
|
},
|
|
|
|
|
d: k.Bytes(c.N),
|
2024-11-16 17:44:17 +01:00
|
|
|
}
|
2024-11-17 18:38:29 +01:00
|
|
|
if err := fipsPCT(c, priv); err != nil {
|
|
|
|
|
// This clearly can't happen, but FIPS 140-3 mandates that we check it.
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2024-11-16 17:44:17 +01:00
|
|
|
return priv, nil
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-16 17:44:17 +01:00
|
|
|
// randomPoint returns a random scalar and the corresponding point using a
|
|
|
|
|
// procedure equivalent to FIPS 186-5, Appendix A.2.2 (ECDSA Key Pair Generation
|
2024-11-16 23:45:05 +01:00
|
|
|
// by Rejection Sampling) and to Appendix A.3.2 (Per-Message Secret Number
|
|
|
|
|
// Generation of Private Keys by Rejection Sampling) or Appendix A.3.3
|
|
|
|
|
// (Per-Message Secret Number Generation for Deterministic ECDSA) followed by
|
|
|
|
|
// Step 5 of Section 6.4.1.
|
|
|
|
|
func randomPoint[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmod.Nat, p P, err error) {
|
2024-11-16 16:38:07 +01:00
|
|
|
for {
|
|
|
|
|
b := make([]byte, c.N.Size())
|
2024-11-16 23:45:05 +01:00
|
|
|
if err := generate(b); err != nil {
|
|
|
|
|
return nil, nil, err
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-16 23:45:05 +01:00
|
|
|
// Take only the leftmost bits of the generated random value. This is
|
|
|
|
|
// both necessary to increase the chance of the random value being in
|
|
|
|
|
// the correct range and to match the specification. It's unfortunate
|
|
|
|
|
// that we need to do a shift instead of a mask, but see the comment on
|
|
|
|
|
// rightShift.
|
|
|
|
|
//
|
|
|
|
|
// These are the most dangerous lines in the package and maybe in the
|
|
|
|
|
// library: a single bit of bias in the selection of nonces would likely
|
2024-11-16 16:38:07 +01:00
|
|
|
// lead to key recovery, but no tests would fail. Look but DO NOT TOUCH.
|
|
|
|
|
if excess := len(b)*8 - c.N.BitLen(); excess > 0 {
|
|
|
|
|
// Just to be safe, assert that this only happens for the one curve that
|
|
|
|
|
// doesn't have a round number of bits.
|
2024-11-16 23:45:05 +01:00
|
|
|
if c.curve != p521 {
|
2024-11-16 16:38:07 +01:00
|
|
|
panic("ecdsa: internal error: unexpectedly masking off bits")
|
|
|
|
|
}
|
2024-11-16 23:45:05 +01:00
|
|
|
b = rightShift(b, excess)
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-16 17:44:17 +01:00
|
|
|
// FIPS 186-5, Appendix A.4.2 makes us check x <= N - 2 and then return
|
|
|
|
|
// x + 1. Note that it follows that 0 < x + 1 < N. Instead, SetBytes
|
|
|
|
|
// checks that k < N, and we explicitly check 0 != k. Since k can't be
|
|
|
|
|
// negative, this is strictly equivalent. None of this matters anyway
|
|
|
|
|
// because the chance of selecting zero is cryptographically negligible.
|
|
|
|
|
if k, err := bigmod.NewNat().SetBytes(b, c.N); err == nil && k.IsZero() == 0 {
|
|
|
|
|
p, err := c.newPoint().ScalarBaseMult(k.Bytes(c.N))
|
|
|
|
|
return k, p, err
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if testingOnlyRejectionSamplingLooped != nil {
|
|
|
|
|
testingOnlyRejectionSamplingLooped()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// testingOnlyRejectionSamplingLooped is called when rejection sampling in
|
|
|
|
|
// randomPoint rejects a candidate for being higher than the modulus.
|
|
|
|
|
var testingOnlyRejectionSamplingLooped func()
|
|
|
|
|
|
|
|
|
|
// Signature is an ECDSA signature, where r and s are represented as big-endian
|
2024-12-13 16:59:20 +01:00
|
|
|
// byte slices of the same length as the curve order.
|
2024-11-16 16:38:07 +01:00
|
|
|
type Signature struct {
|
|
|
|
|
R, S []byte
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-16 23:45:05 +01:00
|
|
|
// Sign signs a hash (which shall be the result of hashing a larger message with
|
|
|
|
|
// the hash function H) 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.
|
2024-11-20 09:03:35 -05:00
|
|
|
func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
|
2024-11-16 16:38:07 +01:00
|
|
|
if priv.pub.curve != c.curve {
|
|
|
|
|
return nil, errors.New("ecdsa: private key does not match curve")
|
|
|
|
|
}
|
2024-11-20 09:03:35 -05:00
|
|
|
fips140.RecordApproved()
|
2024-11-16 17:44:17 +01:00
|
|
|
fipsSelfTest()
|
2024-11-16 23:45:05 +01:00
|
|
|
|
|
|
|
|
// Random ECDSA is dangerous, because a failure of the RNG would immediately
|
|
|
|
|
// leak the private key. Instead, we use a "hedged" approach, as specified
|
|
|
|
|
// in draft-irtf-cfrg-det-sigs-with-noise-04, Section 4. This has also the
|
|
|
|
|
// advantage of closely resembling Deterministic ECDSA.
|
|
|
|
|
|
|
|
|
|
Z := make([]byte, len(priv.d))
|
2024-12-11 14:50:00 +01:00
|
|
|
if err := drbg.ReadWithReader(rand, Z); err != nil {
|
|
|
|
|
return nil, err
|
2024-11-16 23:45:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6
|
|
|
|
|
// for the FIPS compliance of this method. In short Z is entropy from the
|
|
|
|
|
// main DRBG, of length 3/2 of security_strength, so the nonce is optional
|
|
|
|
|
// per SP 800-90Ar1, Section 8.6.7, and the rest is a personalization
|
|
|
|
|
// string, which per SP 800-90Ar1, Section 8.7.1 may contain secret
|
|
|
|
|
// information.
|
|
|
|
|
drbg := newDRBG(h, Z, nil, blockAlignedPersonalizationString{priv.d, bits2octets(c, hash)})
|
|
|
|
|
|
|
|
|
|
return sign(c, priv, drbg, hash)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SignDeterministic signs a hash (which shall be the result of hashing a
|
|
|
|
|
// larger message with the hash function H) 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. This applies Deterministic ECDSA as
|
|
|
|
|
// specified in FIPS 186-5 and RFC 6979.
|
2024-11-20 09:03:35 -05:00
|
|
|
func SignDeterministic[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, hash []byte) (*Signature, error) {
|
2024-11-16 23:45:05 +01:00
|
|
|
if priv.pub.curve != c.curve {
|
|
|
|
|
return nil, errors.New("ecdsa: private key does not match curve")
|
|
|
|
|
}
|
2024-11-20 09:03:35 -05:00
|
|
|
fips140.RecordApproved()
|
2024-11-16 23:45:05 +01:00
|
|
|
fipsSelfTestDeterministic()
|
|
|
|
|
drbg := newDRBG(h, priv.d, bits2octets(c, hash), nil) // RFC 6979, Section 3.3
|
|
|
|
|
return sign(c, priv, drbg, hash)
|
2024-11-16 18:31:41 +01:00
|
|
|
}
|
2024-11-16 16:38:07 +01:00
|
|
|
|
2024-11-16 23:45:05 +01:00
|
|
|
// bits2octets as specified in FIPS 186-5, Appendix B.2.4 or RFC 6979,
|
|
|
|
|
// Section 2.3.4. See RFC 6979, Section 3.5 for the rationale.
|
|
|
|
|
func bits2octets[P Point[P]](c *Curve[P], hash []byte) []byte {
|
|
|
|
|
e := bigmod.NewNat()
|
|
|
|
|
hashToNat(c, e, hash)
|
|
|
|
|
return e.Bytes(c.N)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func signGeneric[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
|
2024-11-16 17:44:17 +01:00
|
|
|
// FIPS 186-5, Section 6.4.1
|
2024-11-16 16:38:07 +01:00
|
|
|
|
2024-11-16 23:45:05 +01:00
|
|
|
k, R, err := randomPoint(c, func(b []byte) error {
|
|
|
|
|
drbg.Generate(b)
|
|
|
|
|
return nil
|
|
|
|
|
})
|
2024-11-16 16:38:07 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// kInv = k⁻¹
|
|
|
|
|
kInv := bigmod.NewNat()
|
|
|
|
|
inverse(c, kInv, k)
|
|
|
|
|
|
|
|
|
|
Rx, err := R.BytesX()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
r, err := bigmod.NewNat().SetOverflowingBytes(Rx, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The spec wants us to retry here, but the chance of hitting this condition
|
|
|
|
|
// on a large prime-order group like the NIST curves we support is
|
|
|
|
|
// cryptographically negligible. If we hit it, something is awfully wrong.
|
|
|
|
|
if r.IsZero() == 1 {
|
|
|
|
|
return nil, errors.New("ecdsa: internal error: r is zero")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e := bigmod.NewNat()
|
|
|
|
|
hashToNat(c, e, hash)
|
|
|
|
|
|
|
|
|
|
s, err := bigmod.NewNat().SetBytes(priv.d, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
s.Mul(r, c.N)
|
|
|
|
|
s.Add(e, c.N)
|
|
|
|
|
s.Mul(kInv, c.N)
|
|
|
|
|
|
|
|
|
|
// Again, the chance of this happening is cryptographically negligible.
|
|
|
|
|
if s.IsZero() == 1 {
|
|
|
|
|
return nil, errors.New("ecdsa: internal error: s is zero")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &Signature{r.Bytes(c.N), s.Bytes(c.N)}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// inverse sets kInv to the inverse of k modulo the order of the curve.
|
|
|
|
|
func inverse[P Point[P]](c *Curve[P], kInv, k *bigmod.Nat) {
|
|
|
|
|
if c.ordInverse != nil {
|
|
|
|
|
kBytes, err := c.ordInverse(k.Bytes(c.N))
|
|
|
|
|
// Some platforms don't implement ordInverse, and always return an error.
|
|
|
|
|
if err == nil {
|
|
|
|
|
_, err := kInv.SetBytes(kBytes, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic("ecdsa: internal error: ordInverse produced an invalid value")
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate the inverse of s in GF(N) using Fermat's method
|
|
|
|
|
// (exponentiation modulo P - 2, per Euler's theorem)
|
|
|
|
|
kInv.Exp(k, c.nMinus2, c.N)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hashToNat sets e to the left-most bits of hash, according to
|
2024-11-16 17:44:17 +01:00
|
|
|
// FIPS 186-5, Section 6.4.1, point 2 and Section 6.4.2, point 3.
|
2024-11-16 16:38:07 +01:00
|
|
|
func hashToNat[P Point[P]](c *Curve[P], e *bigmod.Nat, hash []byte) {
|
|
|
|
|
// ECDSA asks us to take the left-most log2(N) bits of hash, and use them as
|
|
|
|
|
// an integer modulo N. This is the absolute worst of all worlds: we still
|
|
|
|
|
// have to reduce, because the result might still overflow N, but to take
|
|
|
|
|
// the left-most bits for P-521 we have to do a right shift.
|
|
|
|
|
if size := c.N.Size(); len(hash) >= size {
|
|
|
|
|
hash = hash[:size]
|
|
|
|
|
if excess := len(hash)*8 - c.N.BitLen(); excess > 0 {
|
2024-11-16 23:45:05 +01:00
|
|
|
hash = rightShift(hash, excess)
|
2024-11-16 16:38:07 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_, err := e.SetOverflowingBytes(hash, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic("ecdsa: internal error: truncated hash is too long")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-16 23:45:05 +01:00
|
|
|
// rightShift implements the right shift necessary for bits2int, which takes the
|
|
|
|
|
// leftmost bits of either the hash or HMAC_DRBG output.
|
|
|
|
|
//
|
|
|
|
|
// Note how taking the rightmost bits would have been as easy as masking the
|
|
|
|
|
// first byte, but we can't have nice things.
|
|
|
|
|
func rightShift(b []byte, shift int) []byte {
|
|
|
|
|
if shift <= 0 || shift >= 8 {
|
|
|
|
|
panic("ecdsa: internal error: shift can only be by 1 to 7 bits")
|
|
|
|
|
}
|
|
|
|
|
b = bytes.Clone(b)
|
|
|
|
|
for i := len(b) - 1; i >= 0; i-- {
|
|
|
|
|
b[i] >>= shift
|
|
|
|
|
if i > 0 {
|
|
|
|
|
b[i] |= b[i-1] << (8 - shift)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return b
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-16 16:38:07 +01:00
|
|
|
// Verify verifies the signature, sig, of hash (which should be the result of
|
|
|
|
|
// hashing a larger message) using the public key, pub. If the hash is longer
|
|
|
|
|
// than the bit-length of the private key's curve order, the hash will be
|
|
|
|
|
// truncated to that length.
|
|
|
|
|
//
|
|
|
|
|
// 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 Verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
|
|
|
|
|
if pub.curve != c.curve {
|
|
|
|
|
return errors.New("ecdsa: public key does not match curve")
|
|
|
|
|
}
|
2024-11-20 09:03:35 -05:00
|
|
|
fips140.RecordApproved()
|
2024-11-16 17:44:17 +01:00
|
|
|
fipsSelfTest()
|
2024-11-16 18:31:41 +01:00
|
|
|
return verify(c, pub, hash, sig)
|
|
|
|
|
}
|
2024-11-16 16:38:07 +01:00
|
|
|
|
2024-11-16 18:31:41 +01:00
|
|
|
func verifyGeneric[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
|
2024-11-16 17:44:17 +01:00
|
|
|
// FIPS 186-5, Section 6.4.2
|
|
|
|
|
|
2024-11-16 16:38:07 +01:00
|
|
|
Q, err := c.newPoint().SetBytes(pub.q)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r, err := bigmod.NewNat().SetBytes(sig.R, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if r.IsZero() == 1 {
|
|
|
|
|
return errors.New("ecdsa: invalid signature: r is zero")
|
|
|
|
|
}
|
|
|
|
|
s, err := bigmod.NewNat().SetBytes(sig.S, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if s.IsZero() == 1 {
|
|
|
|
|
return errors.New("ecdsa: invalid signature: s is zero")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e := bigmod.NewNat()
|
|
|
|
|
hashToNat(c, e, hash)
|
|
|
|
|
|
|
|
|
|
// w = s⁻¹
|
|
|
|
|
w := bigmod.NewNat()
|
|
|
|
|
inverse(c, w, s)
|
|
|
|
|
|
|
|
|
|
// p₁ = [e * s⁻¹]G
|
|
|
|
|
p1, err := c.newPoint().ScalarBaseMult(e.Mul(w, c.N).Bytes(c.N))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
// p₂ = [r * s⁻¹]Q
|
|
|
|
|
p2, err := Q.ScalarMult(Q, w.Mul(r, c.N).Bytes(c.N))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
// BytesX returns an error for the point at infinity.
|
|
|
|
|
Rx, err := p1.Add(p1, p2).BytesX()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v, err := bigmod.NewNat().SetOverflowingBytes(Rx, c.N)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if v.Equal(r) != 1 {
|
|
|
|
|
return errors.New("ecdsa: signature did not verify")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|