diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/crypto.go | 13 | ||||
-rw-r--r-- | crypto/crypto_test.go | 2 | ||||
-rw-r--r-- | crypto/ecies/ecies.go | 12 | ||||
-rw-r--r-- | crypto/ecies/ecies_test.go | 30 | ||||
-rw-r--r-- | crypto/secp256k1/secp256.go | 4 |
5 files changed, 52 insertions, 9 deletions
diff --git a/crypto/crypto.go b/crypto/crypto.go index 7d7623753..850be4da6 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -163,12 +163,21 @@ func GenerateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) } -func ValidateSignatureValues(v byte, r, s *big.Int) bool { +func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool { if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 { return false } vint := uint32(v) - if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { + // reject upper range of s values (ECDSA malleability) + // see discussion in secp256k1/libsecp256k1/include/secp256k1.h + if homestead && s.Cmp(secp256k1.HalfN) > 0 { + return false + } + // Frontier: allow s to be in full N range + if s.Cmp(secp256k1.N) >= 0 { + return false + } + if r.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { return true } else { return false diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index d5e19a4bb..1681c7fef 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -174,7 +174,7 @@ func TestLoadECDSAFile(t *testing.T) { func TestValidateSignatureValues(t *testing.T) { check := func(expected bool, v byte, r, s *big.Int) { - if ValidateSignatureValues(v, r, s) != expected { + if ValidateSignatureValues(v, r, s, false) != expected { t.Errorf("mismatch for v: %d r: %d s: %d want: %v", v, r, s, expected) } } diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 65dc5b38b..ee4285617 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -192,11 +192,9 @@ func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) { // messageTag computes the MAC of a message (called the tag) as per // SEC 1, 3.5. func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte { - if shared == nil { - shared = make([]byte, 0) - } mac := hmac.New(hash, km) mac.Write(msg) + mac.Write(shared) tag := mac.Sum(nil) return tag } @@ -243,9 +241,11 @@ func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, return } -// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. If -// the shared information parameters aren't being used, they should be -// nil. +// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. +// +// s1 and s2 contain shared information that is not part of the resulting +// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the +// shared information parameters aren't being used, they should be nil. func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) { params := pub.Params if params == nil { diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 6a0ea3f02..cb09061ce 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -408,6 +408,36 @@ func TestEncryptDecrypt(t *testing.T) { } } +func TestDecryptShared2(t *testing.T) { + prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) + if err != nil { + t.Fatal(err) + } + message := []byte("Hello, world.") + shared2 := []byte("shared data 2") + ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, shared2) + if err != nil { + t.Fatal(err) + } + + // Check that decrypting with correct shared data works. + pt, err := prv.Decrypt(rand.Reader, ct, nil, shared2) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(pt, message) { + t.Fatal("ecies: plaintext doesn't match message") + } + + // Decrypting without shared data or incorrect shared data fails. + if _, err = prv.Decrypt(rand.Reader, ct, nil, nil); err == nil { + t.Fatal("ecies: decrypting without shared data didn't fail") + } + if _, err = prv.Decrypt(rand.Reader, ct, nil, []byte("garbage")); err == nil { + t.Fatal("ecies: decrypting with incorrect shared data didn't fail") + } +} + // TestMarshalEncryption validates the encode/decode produces a valid // ECIES encryption key. func TestMarshalEncryption(t *testing.T) { diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 97b4bd8da..4999c5c95 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -58,10 +58,14 @@ import ( var ( context *C.secp256k1_context N *big.Int + HalfN *big.Int ) func init() { N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) + // N / 2 == 57896044618658097711785492504343953926418782139537452191302581570759080747168 + HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16) + // around 20 ms on a modern CPU. context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) |