Skip to content

Commit

Permalink
Import deterministic ECDSA key generation code from Go 1.18 crypto/ec…
Browse files Browse the repository at this point in the history
…dsa package

Closes: cloudflare#61
  • Loading branch information
zhsj authored and ignatk committed Apr 18, 2023
1 parent 3875268 commit 51044cf
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 12 deletions.
62 changes: 62 additions & 0 deletions ecdsa/ecdsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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-4 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.
package ecdsa

// [FIPS 186-4] references ANSI X9.62-2005 for the bulk of the ECDSA algorithm.
// That standard is not freely available, which is a problem in an open source
// implementation, because not only the implementer, but also any maintainer,
// contributor, reviewer, auditor, and learner needs access to it. Instead, this
// package references and follows the equivalent [SEC 1, Version 2.0].
//
// [FIPS 186-4]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
// [SEC 1, Version 2.0]: https://www.secg.org/sec1-v2.pdf

import (
"crypto/ecdsa"
"crypto/elliptic"
"io"
"math/big"
)

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the order of the given
// curve using the procedure given in FIPS 186-4, Appendix B.5.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
params := c.Params()
// Note that for P-521 this will actually be 63 bits more than the order, as
// division rounds down, but the extra bit is inconsequential.
b := make([]byte, params.BitSize/8+8) // TODO: use params.N.BitLen()
_, err = io.ReadFull(rand, b)
if err != nil {
return
}

k = new(big.Int).SetBytes(b)
n := new(big.Int).Sub(params.N, one)
k.Mod(k, n)
k.Add(k, one)
return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*ecdsa.PrivateKey, error) {
k, err := randFieldElement(c, rand)
if err != nil {
return nil, err
}

priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = c
priv.D = k
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
return priv, nil
}
24 changes: 14 additions & 10 deletions gokey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import (
"golang.org/x/crypto/ed25519"
)

var (
passSpec = &PasswordSpec{16, 3, 3, 2, 1, ""}
)
var passSpec = &PasswordSpec{16, 3, 3, 2, 1, ""}

func TestGetPass(t *testing.T) {
pass1Seed1, err := GenerateEncryptedKeySeed("pass1")
Expand Down Expand Up @@ -163,13 +161,19 @@ func testGetKeyType(kt KeyType, t *testing.T) {
}

func TestGetKey(t *testing.T) {
testGetKeyType(EC256, t)
testGetKeyType(EC384, t)
testGetKeyType(EC521, t)
testGetKeyType(RSA2048, t)
testGetKeyType(RSA4096, t)
testGetKeyType(X25519, t)
testGetKeyType(ED25519, t)
for _, kt := range []KeyType{
EC256,
EC384,
EC521,
RSA2048,
RSA4096,
X25519,
ED25519,
} {
t.Run(kt.String(), func(t *testing.T) {
testGetKeyType(kt, t)
})
}
}

func TestGetKeyUnsafe(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions keygen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package gokey

import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"errors"
"io"
"strings"
"unicode"

deterministicEcdsaKeygen "github.com/cloudflare/gokey/ecdsa"
deterministicRsaKeygen "github.com/cloudflare/gokey/rsa"
"golang.org/x/crypto/ed25519"
)
Expand Down Expand Up @@ -184,7 +184,7 @@ func (keygen *KeyGen) generateEc(kt KeyType) (crypto.PrivateKey, error) {
return nil, errors.New("invalid EC key size requested")
}

return ecdsa.GenerateKey(curve, keygen.rng)
return deterministicEcdsaKeygen.GenerateKey(curve, keygen.rng)
}

func (keygen *KeyGen) generate25519(kt KeyType) (crypto.PrivateKey, error) {
Expand Down

0 comments on commit 51044cf

Please sign in to comment.