Skip to content

Commit

Permalink
Merge pull request ethereum#718 from karalabe/whisper-cleanup
Browse files Browse the repository at this point in the history
Whisper cleanup, part 2
  • Loading branch information
fjl committed Apr 17, 2015
2 parents d3ed328 + 4afc22b commit 4020258
Show file tree
Hide file tree
Showing 16 changed files with 899 additions and 356 deletions.
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

0 comments on commit 4020258

Please sign in to comment.