Commit cce61d3c authored by Viktor Trón's avatar Viktor Trón Committed by GitHub

crypto: add ECDH shared secret support, in memory variant (#727)

parent 957c077c
// Copyright 2020 The Swarm 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 crypto
import (
"crypto/ecdsa"
"errors"
)
// DH is an interface allowing to generate shared keys for public key
// using a salt from a known private key
// TODO: implement clef support beside in-memory
type DH interface {
SharedKey(public *ecdsa.PublicKey, salt []byte) ([]byte, error)
}
type defaultDH struct {
key *ecdsa.PrivateKey
}
// NewDH returns an ECDH shared secret key generation seeded with in-memory private key
func NewDH(key *ecdsa.PrivateKey) DH {
return &defaultDH{key}
}
// SharedKey creates ECDH shared secret using the in-memory key as private key and the given public key
// and hashes it with the salt to return the shared key
// safety warning: this method is not meant to be exposed as it does not validate private and public keys
// are on the same curve
func (dh *defaultDH) SharedKey(pub *ecdsa.PublicKey, salt []byte) ([]byte, error) {
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, dh.key.D.Bytes())
if x == nil {
return nil, errors.New("shared secret is point at infinity")
}
return LegacyKeccak256(append(x.Bytes(), salt...))
}
// Copyright 2020 The Swarm 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 crypto_test
import (
"bytes"
"crypto/ecdsa"
"crypto/rand"
"encoding/hex"
"io"
"testing"
"github.com/btcsuite/btcd/btcec"
"github.com/ethersphere/bee/pkg/crypto"
)
func TestECDHCorrect(t *testing.T) {
key0, err := crypto.GenerateSecp256k1Key()
if err != nil {
t.Fatal(err)
}
dh0 := crypto.NewDH(key0)
key1, err := crypto.GenerateSecp256k1Key()
if err != nil {
t.Fatal(err)
}
dh1 := crypto.NewDH(key1)
salt := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
t.Fatal(err)
}
sk0, err := dh0.SharedKey(&key1.PublicKey, salt)
if err != nil {
t.Fatal(err)
}
sk1, err := dh1.SharedKey(&key0.PublicKey, salt)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(sk0, sk1) {
t.Fatal("shared secrets do not match")
}
}
func TestSharedKey(t *testing.T) {
data, err := hex.DecodeString("c786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa")
if err != nil {
t.Fatal(err)
}
privKey, err := crypto.DecodeSecp256k1PrivateKey(data)
if err != nil {
t.Fatal(err)
}
data, err = hex.DecodeString("0271e574ad8f6a6c998c84c27df18124fddd906aba9d852150da4223edde14044f")
if err != nil {
t.Fatal(err)
}
pubkey, err := btcec.ParsePubKey(data, btcec.S256())
if err != nil {
t.Fatal(err)
}
salt, err := hex.DecodeString("cb7e692f211f8ae4f858ff56ce8a4fc0e40bae1a36f8283f0ceb6bb4be133f1e")
if err != nil {
t.Fatal(err)
}
dh := crypto.NewDH(privKey)
sk, err := dh.SharedKey((*ecdsa.PublicKey)(pubkey), salt)
if err != nil {
t.Fatal(err)
}
expectedSKHex := "9edbd3beeb48c090158ccb82d679c5ea2bcb74850d34fe55c10b32e16b822007"
expectedSK, err := hex.DecodeString(expectedSKHex)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(sk, expectedSK) {
t.Fatalf("incorrect shared key: expected %v, got %x", expectedSK, sk)
}
}
......@@ -30,9 +30,17 @@ const (
type Key []byte
type Interface interface {
type Encryptor interface {
Encrypt(data []byte) ([]byte, error)
}
type Decryptor interface {
Decrypt(data []byte) ([]byte, error)
}
type Interface interface {
Encryptor
Decryptor
Reset()
}
......
......@@ -20,10 +20,10 @@ import (
"bytes"
crand "crypto/rand"
"encoding/hex"
"github.com/ethersphere/bee/pkg/encryption"
"math/rand"
"testing"
"github.com/ethersphere/bee/pkg/encryption"
"github.com/ethersphere/bee/pkg/swarm"
"golang.org/x/crypto/sha3"
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment