Allow to use hash in Sign*/Verify*
Sometimes having a whole buffer in memory isn't desired. New interface allows us to provide hashes instead.
This commit is contained in:
parent
e9d1b1884c
commit
225b24f7f4
4 changed files with 65 additions and 10 deletions
21
ecdsa.go
21
ecdsa.go
|
@ -124,11 +124,17 @@ func hashBytes(data []byte) []byte {
|
|||
// Verify verifies the signature of msg using the public key pub. It returns
|
||||
// nil only if signature is valid.
|
||||
func Verify(pub *ecdsa.PublicKey, msg, sig []byte) error {
|
||||
if r, s := unmarshalXY(sig); r == nil || s == nil {
|
||||
return ErrCannotUnmarshal
|
||||
} else if pub == nil {
|
||||
return VerifyHash(pub, hashBytes(msg), sig)
|
||||
}
|
||||
|
||||
// VerifyHash verifies the signature of msg using it's hash the public key pub.
|
||||
// It returns nil only if signature is valid.
|
||||
func VerifyHash(pub *ecdsa.PublicKey, msgHash, sig []byte) error {
|
||||
if pub == nil {
|
||||
return ErrEmptyPublicKey
|
||||
} else if !ecdsa.Verify(pub, hashBytes(msg), r, s) {
|
||||
} else if r, s := unmarshalXY(sig); r == nil || s == nil {
|
||||
return ErrCannotUnmarshal
|
||||
} else if !ecdsa.Verify(pub, msgHash, r, s) {
|
||||
return errors.Wrapf(ErrInvalidSignature, "%0x : %0x", r, s)
|
||||
}
|
||||
|
||||
|
@ -140,7 +146,12 @@ func Verify(pub *ecdsa.PublicKey, msg, sig []byte) error {
|
|||
// will be truncated to that length. It returns the signature as slice bytes.
|
||||
// The security of the private key depends on the entropy of rand.
|
||||
func Sign(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) {
|
||||
x, y, err := ecdsa.Sign(rand.Reader, key, hashBytes(msg))
|
||||
return SignHash(key, hashBytes(msg))
|
||||
}
|
||||
|
||||
// SignHash signs message using it's hash and private key.
|
||||
func SignHash(key *ecdsa.PrivateKey, msgHash []byte) ([]byte, error) {
|
||||
x, y, err := ecdsa.Sign(rand.Reader, key, msgHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
|
@ -125,6 +126,17 @@ func TestSignVerify(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
t.Run("using prepared hash", func(t *testing.T) {
|
||||
var (
|
||||
data = []byte("Hello world")
|
||||
sum = sha512.Sum512(data)
|
||||
key = test.DecodeKey(0)
|
||||
)
|
||||
sig, err := SignHash(key, sum[:])
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, VerifyHash(&key.PublicKey, sum[:], sig))
|
||||
})
|
||||
|
||||
t.Run("low level", func(t *testing.T) {
|
||||
var (
|
||||
data = []byte("Hello world")
|
||||
|
|
22
rfc6979.go
22
rfc6979.go
|
@ -34,10 +34,16 @@ func hashBytesRFC6979(data []byte) []byte {
|
|||
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
|
||||
// to the byte-length of the subgroup. This function does not perform that.
|
||||
func SignRFC6979(key *ecdsa.PrivateKey, msg []byte) ([]byte, error) {
|
||||
return SignRFC6979Hash(key, hashBytesRFC6979(msg))
|
||||
}
|
||||
|
||||
// SignRFC6979Hash signs sha256 hash of the message using the private key.
|
||||
func SignRFC6979Hash(key *ecdsa.PrivateKey, msgHash []byte) ([]byte, error) {
|
||||
if key == nil {
|
||||
return nil, ErrEmptyPrivateKey
|
||||
}
|
||||
r, s := rfc6979.SignECDSA(key, hashBytesRFC6979(msg), sha256.New)
|
||||
|
||||
r, s := rfc6979.SignECDSA(key, msgHash, sha256.New)
|
||||
rBytes, sBytes := r.Bytes(), s.Bytes()
|
||||
signature := make([]byte, RFC6979SignatureSize)
|
||||
|
||||
|
@ -73,3 +79,17 @@ func VerifyRFC6979(key *ecdsa.PublicKey, msg, sig []byte) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyRFC6979 verifies the signature of msg using the public key. It
|
||||
// return nil only if signature is valid.
|
||||
func VerifyRFC6979Hash(key *ecdsa.PublicKey, msgHash, sig []byte) error {
|
||||
if key == nil {
|
||||
return ErrEmptyPublicKey
|
||||
} else if r, s, err := decodeSignature(sig); err != nil {
|
||||
return err
|
||||
} else if !ecdsa.Verify(key, msgHash, r, s) {
|
||||
return ErrWrongSignature
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
|
@ -63,12 +64,23 @@ func TestRFC6979(t *testing.T) {
|
|||
{ // Generated by Go
|
||||
sig := data[offset : offset+RFC6979SignatureSize]
|
||||
|
||||
{ // SignRFC6979
|
||||
res, err := SignRFC6979(key, body)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, sig, res, "step: %d, %02x", i, res)
|
||||
|
||||
require.NoErrorf(t, VerifyRFC6979(pub, body, sig), "step: %d", i)
|
||||
}
|
||||
{ // SignRFC6979Hash
|
||||
sum := sha256.Sum256(body)
|
||||
res, err := SignRFC6979Hash(key, sum[:])
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, sig, res, "step: %d, %02x", i, res)
|
||||
|
||||
require.NoErrorf(t, VerifyRFC6979Hash(pub, sum[:], sig), "step: %d", i)
|
||||
}
|
||||
offset += RFC6979SignatureSize
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue