From dda778eda7ad9b94acf14c3c91c1c29e711e170f Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Dec 2014 14:17:32 +0100 Subject: [PATCH] Updated whisper messages to new crypto api + added tests --- whisper/envelope.go | 20 ++++++++++++++++ whisper/main.go | 2 +- whisper/message.go | 18 +++++++++----- whisper/messages_test.go | 51 ++++++++++++++++++++++++++++++++++++++++ whisper/whisper.go | 9 +++---- 5 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 whisper/messages_test.go diff --git a/whisper/envelope.go b/whisper/envelope.go index eb80098ad..359fa1568 100644 --- a/whisper/envelope.go +++ b/whisper/envelope.go @@ -2,7 +2,9 @@ package whisper import ( "bytes" + "crypto/ecdsa" "encoding/binary" + "fmt" "io" "time" @@ -59,6 +61,24 @@ func (self *Envelope) Seal(pow time.Duration) { self.proveWork(pow) } +func (self *Envelope) Open(prv *ecdsa.PrivateKey) (*Message, error) { + data := self.Data + if data[0] > 0 && len(data) < 66 { + return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < 66") + } + + if data[0] > 0 { + payload, err := crypto.Decrypt(prv, data[66:]) + if err != nil { + return nil, fmt.Errorf("unable to open envelope. Decrypt failed: %v", err) + } + + return NewMessage(payload), nil + } + + return NewMessage(data[1:]), nil +} + func (self *Envelope) proveWork(dura time.Duration) { var bestBit int d := make([]byte, 64) diff --git a/whisper/main.go b/whisper/main.go index 3868f604f..80050d899 100644 --- a/whisper/main.go +++ b/whisper/main.go @@ -19,7 +19,7 @@ func main() { pub, sec := secp256k1.GenerateKeyPair() - whisper := whisper.New(pub, sec) + whisper := whisper.New(sec) srv := p2p.Server{ MaxPeers: 10, diff --git a/whisper/message.go b/whisper/message.go index 408b9f7df..8ce5d880b 100644 --- a/whisper/message.go +++ b/whisper/message.go @@ -1,6 +1,7 @@ package whisper import ( + "crypto/ecdsa" "time" "github.com/ethereum/go-ethereum/crypto" @@ -20,13 +21,17 @@ func (self *Message) hash() []byte { return crypto.Sha3(append([]byte{self.Flags}, self.Payload...)) } -func (self *Message) sign(key []byte) (err error) { +func (self *Message) sign(key *ecdsa.PrivateKey) (err error) { self.Flags = 1 self.Signature, err = crypto.Sign(self.hash(), key) return } -func (self *Message) Encrypt(from, to []byte) (err error) { +func (self *Message) Recover() *ecdsa.PublicKey { + return crypto.SigToPub(self.hash(), self.Signature) +} + +func (self *Message) Encrypt(from *ecdsa.PrivateKey, to *ecdsa.PublicKey) (err error) { err = self.sign(from) if err != nil { return err @@ -45,13 +50,14 @@ func (self *Message) Bytes() []byte { } type Opts struct { - From, To []byte // private(sender), public(receiver) key - Ttl time.Duration - Topics [][]byte + From *ecdsa.PrivateKey + To *ecdsa.PublicKey + Ttl time.Duration + Topics [][]byte } func (self *Message) Seal(pow time.Duration, opts Opts) (*Envelope, error) { - if len(opts.To) > 0 && len(opts.From) > 0 { + if opts.To != nil && opts.From != nil { if err := self.Encrypt(opts.From, opts.To); err != nil { return nil, err } diff --git a/whisper/messages_test.go b/whisper/messages_test.go new file mode 100644 index 000000000..cba103011 --- /dev/null +++ b/whisper/messages_test.go @@ -0,0 +1,51 @@ +package whisper + +import ( + "bytes" + "crypto/elliptic" + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/crypto" +) + +func TestSign(t *testing.T) { + prv, _ := crypto.GenerateKey() + msg := NewMessage([]byte("hello world")) + msg.sign(prv) + + pubKey := msg.Recover() + p1 := elliptic.Marshal(crypto.S256(), prv.PublicKey.X, prv.PublicKey.Y) + p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) + + if !bytes.Equal(p1, p2) { + t.Error("recovered pub key did not match") + } +} + +func TestMessageEncryptDecrypt(t *testing.T) { + prv1, _ := crypto.GenerateKey() + prv2, _ := crypto.GenerateKey() + + data := []byte("hello world") + msg := NewMessage(data) + envelope, err := msg.Seal(DefaultPow, Opts{ + From: prv1, + To: &prv2.PublicKey, + }) + if err != nil { + fmt.Println(err) + t.FailNow() + } + + msg1, err := envelope.Open(prv2) + if err != nil { + fmt.Println(err) + t.FailNow() + } + + if !bytes.Equal(msg1.Payload, data) { + fmt.Println("encryption error. data did not match") + t.FailNow() + } +} diff --git a/whisper/whisper.go b/whisper/whisper.go index b4e37b959..4d7a2a23e 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -2,11 +2,13 @@ package whisper import ( "bytes" + "crypto/ecdsa" "errors" "fmt" "sync" "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" "gopkg.in/fatih/set.v0" ) @@ -39,7 +41,7 @@ const ( const DefaultTtl = 50 * time.Second type Whisper struct { - pub, sec []byte + key *ecdsa.PrivateKey protocol p2p.Protocol mmu sync.RWMutex @@ -49,10 +51,9 @@ type Whisper struct { quit chan struct{} } -func New(pub, sec []byte) *Whisper { +func New(sec []byte) *Whisper { whisper := &Whisper{ - pub: pub, - sec: sec, + key: crypto.ToECDSA(sec), messages: make(map[Hash]*Envelope), expiry: make(map[uint32]*set.SetNonTS), quit: make(chan struct{}),