Added encryption for messages better API for sealing messages

This commit is contained in:
obscuren 2014-12-10 00:03:50 +01:00
parent 87adff7e18
commit 984c7e6689
4 changed files with 90 additions and 23 deletions

View File

@ -16,8 +16,8 @@ const (
) )
type Envelope struct { type Envelope struct {
Expiry int32 // Whisper protocol specifies int32, really should be int64 Expiry uint32 // Whisper protocol specifies int32, really should be int64
Ttl int32 // ^^^^^^ Ttl uint32 // ^^^^^^
Topics [][]byte Topics [][]byte
Data []byte Data []byte
Nonce uint32 Nonce uint32
@ -52,11 +52,11 @@ func (self *Envelope) Hash() Hash {
func NewEnvelope(ttl time.Duration, topics [][]byte, data *Message) *Envelope { func NewEnvelope(ttl time.Duration, topics [][]byte, data *Message) *Envelope {
exp := time.Now().Add(ttl) exp := time.Now().Add(ttl)
return &Envelope{int32(exp.Unix()), int32(ttl.Seconds()), topics, data.Bytes(), 0, Hash{}} return &Envelope{uint32(exp.Unix()), uint32(ttl.Seconds()), topics, data.Bytes(), 0, Hash{}}
} }
func (self *Envelope) Seal() { func (self *Envelope) Seal(pow time.Duration) {
self.proveWork(DefaultPow) self.proveWork(pow)
} }
func (self *Envelope) proveWork(dura time.Duration) { func (self *Envelope) proveWork(dura time.Duration) {

View File

@ -1,5 +1,11 @@
package whisper package whisper
import (
"time"
"github.com/ethereum/go-ethereum/crypto"
)
type Message struct { type Message struct {
Flags byte Flags byte
Signature []byte Signature []byte
@ -10,6 +16,49 @@ func NewMessage(payload []byte) *Message {
return &Message{Flags: 0, Payload: payload} return &Message{Flags: 0, Payload: payload}
} }
func (self *Message) hash() []byte {
return crypto.Sha3(append([]byte{self.Flags}, self.Payload...))
}
func (self *Message) sign(key []byte) (err error) {
self.Flags = 1
self.Signature, err = crypto.Sign(self.hash(), key)
return
}
func (self *Message) Encrypt(from, to []byte) (err error) {
err = self.sign(from)
if err != nil {
return err
}
self.Payload, err = crypto.Encrypt(to, self.Payload)
if err != nil {
return err
}
return nil
}
func (self *Message) Bytes() []byte { func (self *Message) Bytes() []byte {
return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...) return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...)
} }
type Opts struct {
From, To []byte // private(sender), public(receiver) key
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 err := self.Encrypt(opts.From, opts.To); err != nil {
return nil, err
}
}
envelope := NewEnvelope(DefaultTtl, opts.Topics, self)
envelope.Seal(pow)
return envelope, nil
}

View File

@ -2,6 +2,7 @@ package whisper
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@ -35,7 +36,7 @@ const (
envelopesMsg = 0x01 envelopesMsg = 0x01
) )
const defaultTtl = 50 * time.Second const DefaultTtl = 50 * time.Second
type Whisper struct { type Whisper struct {
pub, sec []byte pub, sec []byte
@ -43,7 +44,7 @@ type Whisper struct {
mmu sync.RWMutex mmu sync.RWMutex
messages map[Hash]*Envelope messages map[Hash]*Envelope
expiry map[int32]*set.SetNonTS expiry map[uint32]*set.SetNonTS
quit chan struct{} quit chan struct{}
} }
@ -53,12 +54,18 @@ func New(pub, sec []byte) *Whisper {
pub: pub, pub: pub,
sec: sec, sec: sec,
messages: make(map[Hash]*Envelope), messages: make(map[Hash]*Envelope),
expiry: make(map[int32]*set.SetNonTS), expiry: make(map[uint32]*set.SetNonTS),
quit: make(chan struct{}), quit: make(chan struct{}),
} }
go whisper.update() go whisper.update()
whisper.Send(defaultTtl, nil, NewMessage([]byte("Hello world. This is whisper-go"))) msg := NewMessage([]byte(fmt.Sprintf("Hello world. This is whisper-go. Incase you're wondering; the time is %v", time.Now())))
envelope, _ := msg.Seal(DefaultPow, Opts{
Ttl: DefaultTtl,
})
if err := whisper.Send(envelope); err != nil {
fmt.Println(err)
}
// p2p whisper sub protocol handler // p2p whisper sub protocol handler
whisper.protocol = p2p.Protocol{ whisper.protocol = p2p.Protocol{
@ -75,17 +82,14 @@ func (self *Whisper) Stop() {
close(self.quit) close(self.quit)
} }
func (self *Whisper) Send(ttl time.Duration, topics [][]byte, data *Message) { func (self *Whisper) Send(envelope *Envelope) error {
envelope := NewEnvelope(ttl, topics, data) return self.add(envelope)
envelope.Seal()
self.add(envelope)
} }
// Main handler for passing whisper messages to whisper peer objects // Main handler for passing whisper messages to whisper peer objects
func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error { func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
wpeer := NewPeer(self, peer, ws) wpeer := NewPeer(self, peer, ws)
// init whisper peer (handshake/status) // initialise whisper peer (handshake/status)
if err := wpeer.init(); err != nil { if err := wpeer.init(); err != nil {
return err return err
} }
@ -106,22 +110,37 @@ func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
continue continue
} }
self.add(envelope) if err := self.add(envelope); err != nil {
// TODO Punish peer here. Invalid envelope.
peer.Infoln(err)
}
wpeer.addKnown(envelope) wpeer.addKnown(envelope)
} }
} }
// takes care of adding envelopes to the messages pool. At this moment no sanity checks are being performed. // takes care of adding envelopes to the messages pool. At this moment no sanity checks are being performed.
func (self *Whisper) add(envelope *Envelope) { func (self *Whisper) add(envelope *Envelope) error {
if !envelope.valid() {
return errors.New("invalid pow for envelope")
}
self.mmu.Lock() self.mmu.Lock()
defer self.mmu.Unlock() defer self.mmu.Unlock()
fmt.Println("add", envelope) hash := envelope.Hash()
self.messages[envelope.Hash()] = envelope self.messages[hash] = envelope
if self.expiry[envelope.Expiry] == nil { if self.expiry[envelope.Expiry] == nil {
self.expiry[envelope.Expiry] = set.NewNonTS() self.expiry[envelope.Expiry] = set.NewNonTS()
} }
self.expiry[envelope.Expiry].Add(envelope.Hash())
if !self.expiry[envelope.Expiry].Has(hash) {
self.expiry[envelope.Expiry].Add(hash)
// TODO notify listeners (given that we had any ...)
}
fmt.Println("add", envelope)
return nil
} }
func (self *Whisper) update() { func (self *Whisper) update() {
@ -141,7 +160,7 @@ func (self *Whisper) expire() {
self.mmu.Lock() self.mmu.Lock()
defer self.mmu.Unlock() defer self.mmu.Unlock()
now := int32(time.Now().Unix()) now := uint32(time.Now().Unix())
for then, hashSet := range self.expiry { for then, hashSet := range self.expiry {
if then > now { if then > now {
continue continue

View File

@ -33,8 +33,7 @@ const (
MsgGetPeersTy = 0x04 MsgGetPeersTy = 0x04
MsgPeersTy = 0x05 MsgPeersTy = 0x05
MsgStatusTy = 0x10 MsgStatusTy = 0x10
//MsgGetTxsTy = 0x11
MsgTxTy = 0x12 MsgTxTy = 0x12
MsgGetBlockHashesTy = 0x13 MsgGetBlockHashesTy = 0x13
MsgBlockHashesTy = 0x14 MsgBlockHashesTy = 0x14