Simplified the API a bit.

Also simplified the guts.
This commit is contained in:
Coda Hale 2014-10-02 20:48:18 -07:00
parent 94a733bbc3
commit 6a90f24967
5 changed files with 42 additions and 37 deletions

3
dsa.go
View file

@ -2,6 +2,7 @@ package rfc6979
import ( import (
"crypto/dsa" "crypto/dsa"
"hash"
"math/big" "math/big"
) )
@ -12,7 +13,7 @@ import (
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated // 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 // to the byte-length of the subgroup. This function does not perform that
// truncation itself. // truncation itself.
func SignDSA(priv *dsa.PrivateKey, hash []byte, alg HashFunc) (r, s *big.Int, err error) { func SignDSA(priv *dsa.PrivateKey, hash []byte, alg func() hash.Hash) (r, s *big.Int, err error) {
n := priv.Q.BitLen() n := priv.Q.BitLen()
if n&7 != 0 { if n&7 != 0 {
err = dsa.ErrInvalidPublicKey err = dsa.ErrInvalidPublicKey

View file

@ -1,4 +1,4 @@
package rfc6979 package rfc6979_test
import ( import (
"crypto/dsa" "crypto/dsa"
@ -6,14 +6,17 @@ import (
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"encoding/hex" "encoding/hex"
"hash"
"math/big" "math/big"
"testing" "testing"
"github.com/codahale/rfc6979"
) )
type dsaFixture struct { type dsaFixture struct {
name string name string
key *dsaKey key *dsaKey
alg HashFunc alg func() hash.Hash
message string message string
r, s string r, s string
} }
@ -239,7 +242,7 @@ func testDsaFixture(f *dsaFixture, t *testing.T) {
digest = digest[0:g] digest = digest[0:g]
} }
r, s, err := SignDSA(f.key.key, digest, f.alg) r, s, err := rfc6979.SignDSA(f.key.key, digest, f.alg)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return

View file

@ -3,25 +3,10 @@ package rfc6979
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"hash"
"math/big" "math/big"
) )
// copied from crypto/ecdsa
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
orderBits := c.Params().N.BitLen()
orderBytes := (orderBits + 7) / 8
if len(hash) > orderBytes {
hash = hash[:orderBytes]
}
ret := new(big.Int).SetBytes(hash)
excess := len(hash)*8 - orderBits
if excess > 0 {
ret.Rsh(ret, uint(excess))
}
return ret
}
// SignECDSA signs an arbitrary length hash (which should be the result of // SignECDSA signs an arbitrary length hash (which should be the result of
// hashing a larger message) using the private key, priv. It returns the // hashing a larger message) using the private key, priv. It returns the
// signature as a pair of integers. // signature as a pair of integers.
@ -29,7 +14,7 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated // 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 // to the byte-length of the subgroup. This function does not perform that
// truncation itself. // truncation itself.
func SignECDSA(priv *ecdsa.PrivateKey, hash []byte, alg HashFunc) (r, s *big.Int, err error) { func SignECDSA(priv *ecdsa.PrivateKey, hash []byte, alg func() hash.Hash) (r, s *big.Int, err error) {
c := priv.PublicKey.Curve c := priv.PublicKey.Curve
N := c.Params().N N := c.Params().N
@ -53,3 +38,19 @@ func SignECDSA(priv *ecdsa.PrivateKey, hash []byte, alg HashFunc) (r, s *big.Int
return return
} }
// copied from crypto/ecdsa
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
orderBits := c.Params().N.BitLen()
orderBytes := (orderBits + 7) / 8
if len(hash) > orderBytes {
hash = hash[:orderBytes]
}
ret := new(big.Int).SetBytes(hash)
excess := len(hash)*8 - orderBits
if excess > 0 {
ret.Rsh(ret, uint(excess))
}
return ret
}

View file

@ -1,4 +1,4 @@
package rfc6979 package rfc6979_test
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
@ -6,14 +6,17 @@ import (
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"hash"
"math/big" "math/big"
"testing" "testing"
"github.com/codahale/rfc6979"
) )
type ecdsaFixture struct { type ecdsaFixture struct {
name string name string
key *ecdsaKey key *ecdsaKey
alg HashFunc alg func() hash.Hash
message string message string
r, s string r, s string
} }
@ -425,7 +428,7 @@ func testEcsaFixture(f *ecdsaFixture, t *testing.T) {
digest = digest[0:g] digest = digest[0:g]
} }
r, s, err := SignECDSA(f.key.key, digest, f.alg) r, s, err := rfc6979.SignECDSA(f.key.key, digest, f.alg)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return

View file

@ -22,11 +22,8 @@ import (
"math/big" "math/big"
) )
// HashFunc is a function which provides a fresh Hash (e.g., sha256.New).
type HashFunc func() hash.Hash
// mac returns an HMAC of the given key and message. // mac returns an HMAC of the given key and message.
func (alg HashFunc) mac(k, m, buf []byte) []byte { func mac(alg func() hash.Hash, k, m, buf []byte) []byte {
h := hmac.New(alg, k) h := hmac.New(alg, k)
h.Write(m) h.Write(m)
return h.Sum(buf[:0]) return h.Sum(buf[:0])
@ -76,7 +73,7 @@ func bits2octets(in []byte, q *big.Int, qlen, rolen int) []byte {
var one = big.NewInt(1) var one = big.NewInt(1)
// https://tools.ietf.org/html/rfc6979#section-3.2 // https://tools.ietf.org/html/rfc6979#section-3.2
func generateSecret(q, x *big.Int, alg HashFunc, hash []byte, test func(*big.Int) bool) { func generateSecret(q, x *big.Int, alg func() hash.Hash, hash []byte, test func(*big.Int) bool) {
qlen := q.BitLen() qlen := q.BitLen()
holen := alg().Size() holen := alg().Size()
rolen := (qlen + 7) >> 3 rolen := (qlen + 7) >> 3
@ -89,25 +86,25 @@ func generateSecret(q, x *big.Int, alg HashFunc, hash []byte, test func(*big.Int
k := bytes.Repeat([]byte{0x00}, holen) k := bytes.Repeat([]byte{0x00}, holen)
// Step D // Step D
k = alg.mac(k, append(append(v, 0x00), bx...), k) k = mac(alg, k, append(append(v, 0x00), bx...), k)
// Step E // Step E
v = alg.mac(k, v, v) v = mac(alg, k, v, v)
// Step F // Step F
k = alg.mac(k, append(append(v, 0x01), bx...), k) k = mac(alg, k, append(append(v, 0x01), bx...), k)
// Step G // Step G
v = alg.mac(k, v, v) v = mac(alg, k, v, v)
// Step H // Step H
for { for {
// Step H1 // Step H1
t := make([]byte, 0) var t []byte
// Step H2 // Step H2
for len(t) < qlen/8 { for len(t) < qlen/8 {
v = alg.mac(k, v, v) v = mac(alg, k, v, v)
t = append(t, v...) t = append(t, v...)
} }
@ -116,7 +113,7 @@ func generateSecret(q, x *big.Int, alg HashFunc, hash []byte, test func(*big.Int
if secret.Cmp(one) >= 0 && secret.Cmp(q) < 0 && test(secret) { if secret.Cmp(one) >= 0 && secret.Cmp(q) < 0 && test(secret) {
return return
} }
k = alg.mac(k, append(v, 0x00), k) k = mac(alg, k, append(v, 0x00), k)
v = alg.mac(k, v, v) v = mac(alg, k, v, v)
} }
} }