Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7b50190
whisper: separate out magic number from the code
karalabe Apr 13, 2015
9a53390
whisper: clean up and integrate topics
karalabe Apr 13, 2015
89358d2
whisper: start adding integration tests
karalabe Apr 13, 2015
cb707ba
whisper: push work in progress for bug report
karalabe Apr 13, 2015
4af7743
whisper: add utility functions for creating topics
karalabe Apr 14, 2015
5205b2f
whisper: fix anonymous broadcast drop, add broadcast tests
karalabe Apr 14, 2015
59bff46
whisper: general cleanups, documentation
karalabe Apr 14, 2015
e2b7498
whisper: add known message expiration to peers, cleanup
karalabe Apr 14, 2015
1a4cfc1
whisper, xeth/whisper, ui/qt/qwhispe: fix API polish breakages
karalabe Apr 14, 2015
f6efdd8
whisper: shorten constants to TTL and PoW
karalabe Apr 14, 2015
86372b2
whisper: add basic tests for the whiper peers
karalabe Apr 14, 2015
4fb7ab5
whisper: mock tests to use simulated peers
karalabe Apr 14, 2015
bcf4179
whisper: global message expiration tests, polishes
karalabe Apr 15, 2015
46ea193
whisper: remove some unneeded testing complexity
karalabe Apr 15, 2015
6ceb253
whisper: use async handshakes to handle blocking peers
karalabe Apr 15, 2015
ee6531c
whisper: remove dead code, rename a few constants
karalabe Apr 16, 2015
e5e91e9
whisper: track active peers, add peer cache expiry test
karalabe Apr 16, 2015
e5a03eb
whisper: don't issue signature warning if none present
karalabe Apr 16, 2015
bd14bd6
whisper: hide some internal types
karalabe Apr 17, 2015
4afc22b
whisper: cleanup lefover scoping
karalabe Apr 17, 2015
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
4 changes: 2 additions & 2 deletions ui/qt/qwhisper/whisper.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (self *Whisper) Post(payload []string, to, from string, topics []string, pr
TTL: time.Duration(ttl) * time.Second,
To: crypto.ToECDSAPub(common.FromHex(to)),
From: key,
Topics: whisper.TopicsFromString(topics...),
Topics: whisper.NewTopicsFromStrings(topics...),
})

if err != nil {
Expand Down Expand Up @@ -106,7 +106,7 @@ func filterFromMap(opts map[string]interface{}) (f whisper.Filter) {
if topicList, ok := opts["topics"].(*qml.List); ok {
var topics []string
topicList.Convert(&topics)
f.Topics = whisper.TopicsFromString(topics...)
f.Topics = whisper.NewTopicsFromStrings(topics...)
}

return
Expand Down
29 changes: 9 additions & 20 deletions whisper/envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ import (
type Envelope struct {
Expiry uint32 // Whisper protocol specifies int32, really should be int64
TTL uint32 // ^^^^^^
Topics [][]byte
Topics []Topic
Data []byte
Nonce uint32

hash common.Hash
hash common.Hash // Cached hash of the envelope to avoid rehashing every time
}

// NewEnvelope wraps a Whisper message with expiration and destination data
// included into an envelope for network forwarding.
func NewEnvelope(ttl time.Duration, topics [][]byte, msg *Message) *Envelope {
func NewEnvelope(ttl time.Duration, topics []Topic, msg *Message) *Envelope {
return &Envelope{
Expiry: uint32(time.Now().Add(ttl).Unix()),
TTL: uint32(ttl.Seconds()),
Expand Down Expand Up @@ -59,16 +59,6 @@ func (self *Envelope) Seal(pow time.Duration) {
}
}

// valid checks whether the claimed proof of work was indeed executed.
// TODO: Is this really useful? Isn't this always true?
func (self *Envelope) valid() bool {
d := make([]byte, 64)
copy(d[:32], self.rlpWithoutNonce())
binary.BigEndian.PutUint32(d[60:], self.Nonce)

return common.FirstBitSet(common.BigD(crypto.Sha3(d))) > 0
}

// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
func (self *Envelope) rlpWithoutNonce() []byte {
enc, _ := rlp.EncodeToBytes([]interface{}{self.Expiry, self.TTL, self.Topics, self.Data})
Expand All @@ -85,20 +75,19 @@ func (self *Envelope) Open(key *ecdsa.PrivateKey) (msg *Message, err error) {
}
data = data[1:]

if message.Flags&128 == 128 {
if len(data) < 65 {
return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < 65")
if message.Flags&signatureFlag == signatureFlag {
if len(data) < signatureLength {
return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < len(signature)")
}
message.Signature, data = data[:65], data[65:]
message.Signature, data = data[:signatureLength], data[signatureLength:]
}
message.Payload = data

// Short circuit if the encryption was requested
// Decrypt the message, if requested
if key == nil {
return message, nil
}
// Otherwise try to decrypt the message
message.Payload, err = crypto.Decrypt(key, message.Payload)
err = message.decrypt(key)
switch err {
case nil:
return message, nil
Expand Down
11 changes: 7 additions & 4 deletions whisper/filter.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// Contains the message filter for fine grained subscriptions.

package whisper

import "crypto/ecdsa"

// Filter is used to subscribe to specific types of whisper messages.
type Filter struct {
To *ecdsa.PublicKey
From *ecdsa.PublicKey
Topics [][]byte
Fn func(*Message)
To *ecdsa.PublicKey // Recipient of the message
From *ecdsa.PublicKey // Sender of the message
Topics []Topic // Topics to watch messages on
Fn func(*Message) // Handler in case of a match
}
4 changes: 2 additions & 2 deletions whisper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ func selfSend(shh *whisper.Whisper, payload []byte) error {
})
// Wrap the payload and encrypt it
msg := whisper.NewMessage(payload)
envelope, err := msg.Wrap(whisper.DefaultProofOfWork, whisper.Options{
envelope, err := msg.Wrap(whisper.DefaultPoW, whisper.Options{
From: id,
To: &id.PublicKey,
TTL: whisper.DefaultTimeToLive,
TTL: whisper.DefaultTTL,
})
if err != nil {
return fmt.Errorf("failed to seal message: %v", err)
Expand Down
26 changes: 19 additions & 7 deletions whisper/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ type Options struct {
From *ecdsa.PrivateKey
To *ecdsa.PublicKey
TTL time.Duration
Topics [][]byte
Topics []Topic
}

// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
func NewMessage(payload []byte) *Message {
// Construct an initial flag set: bit #1 = 0 (no signature), rest random
flags := byte(rand.Intn(128))
// Construct an initial flag set: no signature, rest random
flags := byte(rand.Intn(256))
flags &= ^signatureFlag

// Assemble and return the message
return &Message{
Expand All @@ -61,7 +62,7 @@ func NewMessage(payload []byte) *Message {
func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error) {
// Use the default TTL if non was specified
if options.TTL == 0 {
options.TTL = DefaultTimeToLive
options.TTL = DefaultTTL
}
// Sign and encrypt the message if requested
if options.From != nil {
Expand All @@ -84,7 +85,7 @@ func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error)
// sign calculates and sets the cryptographic signature for the message , also
// setting the sign flag.
func (self *Message) sign(key *ecdsa.PrivateKey) (err error) {
self.Flags |= 1 << 7
self.Flags |= signatureFlag
self.Signature, err = crypto.Sign(self.hash(), key)
return
}
Expand All @@ -93,6 +94,11 @@ func (self *Message) sign(key *ecdsa.PrivateKey) (err error) {
func (self *Message) Recover() *ecdsa.PublicKey {
defer func() { recover() }() // in case of invalid signature

// Short circuit if no signature is present
if self.Signature == nil {
return nil
}
// Otherwise try and recover the signature
pub, err := crypto.SigToPub(self.hash(), self.Signature)
if err != nil {
glog.V(logger.Error).Infof("Could not get public key from signature: %v", err)
Expand All @@ -102,8 +108,14 @@ func (self *Message) Recover() *ecdsa.PublicKey {
}

// encrypt encrypts a message payload with a public key.
func (self *Message) encrypt(to *ecdsa.PublicKey) (err error) {
self.Payload, err = crypto.Encrypt(to, self.Payload)
func (self *Message) encrypt(key *ecdsa.PublicKey) (err error) {
self.Payload, err = crypto.Encrypt(key, self.Payload)
return
}

// decrypt decrypts an encrypted payload with a private key.
func (self *Message) decrypt(key *ecdsa.PrivateKey) (err error) {
self.Payload, err = crypto.Decrypt(key, self.Payload)
return
}

Expand Down
24 changes: 12 additions & 12 deletions whisper/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ func TestMessageSimpleWrap(t *testing.T) {
payload := []byte("hello world")

msg := NewMessage(payload)
if _, err := msg.Wrap(DefaultProofOfWork, Options{}); err != nil {
if _, err := msg.Wrap(DefaultPoW, Options{}); err != nil {
t.Fatalf("failed to wrap message: %v", err)
}
if msg.Flags&128 != 0 {
t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 0)
if msg.Flags&signatureFlag != 0 {
t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, 0)
}
if len(msg.Signature) != 0 {
t.Fatalf("signature found for simple wrapping: 0x%x", msg.Signature)
Expand All @@ -36,13 +36,13 @@ func TestMessageCleartextSignRecover(t *testing.T) {
payload := []byte("hello world")

msg := NewMessage(payload)
if _, err := msg.Wrap(DefaultProofOfWork, Options{
if _, err := msg.Wrap(DefaultPoW, Options{
From: key,
}); err != nil {
t.Fatalf("failed to sign message: %v", err)
}
if msg.Flags&128 != 128 {
t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 1)
if msg.Flags&signatureFlag != signatureFlag {
t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, signatureFlag)
}
if bytes.Compare(msg.Payload, payload) != 0 {
t.Fatalf("payload mismatch after signing: have 0x%x, want 0x%x", msg.Payload, payload)
Expand All @@ -69,14 +69,14 @@ func TestMessageAnonymousEncryptDecrypt(t *testing.T) {
payload := []byte("hello world")

msg := NewMessage(payload)
envelope, err := msg.Wrap(DefaultProofOfWork, Options{
envelope, err := msg.Wrap(DefaultPoW, Options{
To: &key.PublicKey,
})
if err != nil {
t.Fatalf("failed to encrypt message: %v", err)
}
if msg.Flags&128 != 0 {
t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 0)
if msg.Flags&signatureFlag != 0 {
t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, 0)
}
if len(msg.Signature) != 0 {
t.Fatalf("signature found for anonymous message: 0x%x", msg.Signature)
Expand Down Expand Up @@ -104,15 +104,15 @@ func TestMessageFullCrypto(t *testing.T) {

payload := []byte("hello world")
msg := NewMessage(payload)
envelope, err := msg.Wrap(DefaultProofOfWork, Options{
envelope, err := msg.Wrap(DefaultPoW, Options{
From: fromKey,
To: &toKey.PublicKey,
})
if err != nil {
t.Fatalf("failed to encrypt message: %v", err)
}
if msg.Flags&128 != 128 {
t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 1)
if msg.Flags&signatureFlag != signatureFlag {
t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, signatureFlag)
}
if len(msg.Signature) == 0 {
t.Fatalf("no signature found for signed message")
Expand Down
Loading