Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,6 @@ import (
"golang.org/x/crypto/ripemd160"
)

var secp256k1n *big.Int

func init() {
// specify the params for the s256 curve
ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256)
secp256k1n = common.String2Big("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")
}

func Sha3(data ...[]byte) []byte {
d := sha3.NewKeccak256()
for _, b := range data {
Expand Down Expand Up @@ -99,9 +91,9 @@ func ToECDSA(prv []byte) *ecdsa.PrivateKey {
}

priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = S256()
priv.PublicKey.Curve = secp256k1.S256()
priv.D = common.BigD(prv)
priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv)
priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv)
return priv
}

Expand All @@ -116,15 +108,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
if len(pub) == 0 {
return nil
}
x, y := elliptic.Unmarshal(S256(), pub)
return &ecdsa.PublicKey{S256(), x, y}
x, y := elliptic.Unmarshal(secp256k1.S256(), pub)
return &ecdsa.PublicKey{secp256k1.S256(), x, y}
}

func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(S256(), pub.X, pub.Y)
return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y)
}

// HexToECDSA parses a secp256k1 private key.
Expand Down Expand Up @@ -168,15 +160,15 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
}

func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(S256(), rand.Reader)
return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
}

func ValidateSignatureValues(v byte, r, s *big.Int) bool {
if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 {
return false
}
vint := uint32(v)
if r.Cmp(secp256k1n) < 0 && s.Cmp(secp256k1n) < 0 && (vint == 27 || vint == 28) {
if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) {
return true
} else {
return false
Expand All @@ -189,8 +181,8 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
return nil, err
}

x, y := elliptic.Unmarshal(S256(), s)
return &ecdsa.PublicKey{S256(), x, y}, nil
x, y := elliptic.Unmarshal(secp256k1.S256(), s)
return &ecdsa.PublicKey{secp256k1.S256(), x, y}, nil
}

func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
Expand Down
8 changes: 4 additions & 4 deletions crypto/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func TestValidateSignatureValues(t *testing.T) {
minusOne := big.NewInt(-1)
one := common.Big1
zero := common.Big0
secp256k1nMinus1 := new(big.Int).Sub(secp256k1n, common.Big1)
secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1)

// correct v,r,s
check(true, 27, one, one)
Expand All @@ -208,9 +208,9 @@ func TestValidateSignatureValues(t *testing.T) {
// correct sig with max r,s
check(true, 27, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit
check(false, 27, secp256k1n, secp256k1nMinus1)
check(false, 27, secp256k1nMinus1, secp256k1n)
check(false, 27, secp256k1n, secp256k1n)
check(false, 27, secp256k1.N, secp256k1nMinus1)
check(false, 27, secp256k1nMinus1, secp256k1.N)
check(false, 27, secp256k1.N, secp256k1.N)

// current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone
Expand Down
7 changes: 7 additions & 0 deletions crypto/ecies/asn1.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (
"fmt"
"hash"
"math/big"

"github.com/ethereum/go-ethereum/crypto/secp256k1"
)

var (
Expand Down Expand Up @@ -81,6 +83,7 @@ func doScheme(base, v []int) asn1.ObjectIdentifier {
type secgNamedCurve asn1.ObjectIdentifier

var (
secgNamedCurveS256 = secgNamedCurve{1, 3, 132, 0, 10}
secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
Expand Down Expand Up @@ -116,6 +119,8 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {

func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
switch {
case curve.Equal(secgNamedCurveS256):
return secp256k1.S256()
case curve.Equal(secgNamedCurveP256):
return elliptic.P256()
case curve.Equal(secgNamedCurveP384):
Expand All @@ -134,6 +139,8 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
return secgNamedCurveP384, true
case elliptic.P521():
return secgNamedCurveP521, true
case secp256k1.S256():
return secgNamedCurveS256, true
}

return nil, false
Expand Down
1 change: 1 addition & 0 deletions crypto/ecies/ecies.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b
if skLen+macLen > MaxSharedKeyLength(pub) {
return nil, ErrSharedKeyTooBig
}

x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
if x == nil {
return nil, ErrSharedKeyIsPointAtInfinity
Expand Down
121 changes: 108 additions & 13 deletions crypto/ecies/ecies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ package ecies

import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io/ioutil"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/crypto/secp256k1"
)

var dumpEnc bool
Expand Down Expand Up @@ -65,7 +70,6 @@ func TestKDF(t *testing.T) {
}
}

var skLen int
var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match")

// cmpParams compares a set of ECIES parameters. We assume, as per the
Expand Down Expand Up @@ -117,7 +121,7 @@ func TestSharedKey(t *testing.T) {
fmt.Println(err.Error())
t.FailNow()
}
skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2
skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2

prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
Expand All @@ -143,6 +147,44 @@ func TestSharedKey(t *testing.T) {
}
}

func TestSharedKeyPadding(t *testing.T) {
// sanity checks
prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9")
prv1 := hexKey("97a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16)
x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16)
y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16)
y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16)

if prv0.PublicKey.X.Cmp(x0) != 0 {
t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes())
}
if prv0.PublicKey.Y.Cmp(y0) != 0 {
t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes())
}
if prv1.PublicKey.X.Cmp(x1) != 0 {
t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes())
}
if prv1.PublicKey.Y.Cmp(y1) != 0 {
t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes())
}

// test shared secret generation
sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16)
if err != nil {
fmt.Println(err.Error())
}

sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16)
if err != nil {
t.Fatal(err.Error())
}

if !bytes.Equal(sk1, sk2) {
t.Fatal(ErrBadSharedKeys.Error())
}
}

// Verify that the key generation code fails when too much key data is
// requested.
func TestTooBigSharedKey(t *testing.T) {
Expand All @@ -158,13 +200,13 @@ func TestTooBigSharedKey(t *testing.T) {
t.FailNow()
}

_, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2)
_, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
fmt.Println("ecdh: shared key should be too large for curve")
t.FailNow()
}

_, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2)
_, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
fmt.Println("ecdh: shared key should be too large for curve")
t.FailNow()
Expand All @@ -176,25 +218,21 @@ func TestTooBigSharedKey(t *testing.T) {
func TestMarshalPublic(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
t.Fatalf("GenerateKey error: %s", err)
}

out, err := MarshalPublic(&prv.PublicKey)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
t.Fatalf("MarshalPublic error: %s", err)
}

pub, err := UnmarshalPublic(out)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
t.Fatalf("UnmarshalPublic error: %s", err)
}

if !cmpPublic(prv.PublicKey, *pub) {
fmt.Println("ecies: failed to unmarshal public key")
t.FailNow()
t.Fatal("ecies: failed to unmarshal public key")
}
}

Expand Down Expand Up @@ -304,9 +342,26 @@ func BenchmarkGenSharedKeyP256(b *testing.B) {
fmt.Println(err.Error())
b.FailNow()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
}
}
}

// Benchmark the generation of S256 shared keys.
func BenchmarkGenSharedKeyS256(b *testing.B) {
prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen)
_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
Expand Down Expand Up @@ -511,3 +566,43 @@ func TestBasicKeyValidation(t *testing.T) {
}
}
}

// Verify GenerateShared against static values - useful when
// debugging changes in underlying libs
func TestSharedKeyStatic(t *testing.T) {
prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad")
prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9")

skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2

sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}

sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
if err != nil {
fmt.Println(err.Error())
t.FailNow()
}

if !bytes.Equal(sk1, sk2) {
fmt.Println(ErrBadSharedKeys.Error())
t.FailNow()
}

sk, _ := hex.DecodeString("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62")
if !bytes.Equal(sk1, sk) {
t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1)
}
}

// TODO: remove after refactoring packages crypto and crypto/ecies
func hexKey(prv string) *PrivateKey {
priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = secp256k1.S256()
priv.D, _ = new(big.Int).SetString(prv, 16)
priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes())
return ImportECDSA(priv)
}
14 changes: 7 additions & 7 deletions crypto/ecies/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,12 @@ import (
"crypto/sha512"
"fmt"
"hash"
)

// The default curve for this package is the NIST P256 curve, which
// provides security equivalent to AES-128.
var DefaultCurve = elliptic.P256()
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)

var (
DefaultCurve = secp256k1.S256()
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
)
Expand Down Expand Up @@ -101,9 +100,10 @@ var (
)

var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
elliptic.P256(): ECIES_AES128_SHA256,
elliptic.P384(): ECIES_AES256_SHA384,
elliptic.P521(): ECIES_AES256_SHA512,
secp256k1.S256(): ECIES_AES128_SHA256,
elliptic.P256(): ECIES_AES128_SHA256,
elliptic.P384(): ECIES_AES256_SHA384,
elliptic.P521(): ECIES_AES256_SHA512,
}

func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
Expand Down
5 changes: 3 additions & 2 deletions crypto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/pborman/uuid"
)

Expand Down Expand Up @@ -137,7 +138,7 @@ func NewKey(rand io.Reader) *Key {
panic("key generation: could not read from random source: " + err.Error())
}
reader := bytes.NewReader(randBytes)
privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
if err != nil {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
}
Expand All @@ -155,7 +156,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
panic("key generation: could not read from random source: " + err.Error())
}
reader := bytes.NewReader(randBytes)
privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
if err != nil {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
}
Expand Down
Loading