From dda778eda7ad9b94acf14c3c91c1c29e711e170f Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
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{}),
-- 
GitLab