github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/whisper/message.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Contains the Whisper protocol Message element. For formal details please see 18 // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages. 19 20 package whisper 21 22 import ( 23 "crypto/ecdsa" 24 "math/rand" 25 "time" 26 27 "github.com/ethereumproject/go-ethereum/common" 28 "github.com/ethereumproject/go-ethereum/crypto" 29 "github.com/ethereumproject/go-ethereum/logger" 30 "github.com/ethereumproject/go-ethereum/logger/glog" 31 ) 32 33 // Message represents an end-user data packet to transmit through the Whisper 34 // protocol. These are wrapped into Envelopes that need not be understood by 35 // intermediate nodes, just forwarded. 36 type Message struct { 37 Flags byte // First bit is signature presence, rest reserved and should be random 38 Signature []byte 39 Payload []byte 40 41 Sent time.Time // Time when the message was posted into the network 42 TTL time.Duration // Maximum time to live allowed for the message 43 44 To *ecdsa.PublicKey // Message recipient (identity used to decode the message) 45 Hash common.Hash // Message envelope hash to act as a unique id 46 } 47 48 // Options specifies the exact way a message should be wrapped into an Envelope. 49 type Options struct { 50 From *ecdsa.PrivateKey 51 To *ecdsa.PublicKey 52 TTL time.Duration 53 Topics []Topic 54 } 55 56 // NewMessage creates and initializes a non-signed, non-encrypted Whisper message. 57 func NewMessage(payload []byte) *Message { 58 // Construct an initial flag set: no signature, rest random 59 flags := byte(rand.Intn(256)) 60 flags &= ^signatureFlag 61 62 // Assemble and return the message 63 return &Message{ 64 Flags: flags, 65 Payload: payload, 66 Sent: time.Now(), 67 } 68 } 69 70 // Wrap bundles the message into an Envelope to transmit over the network. 71 // 72 // pow (Proof Of Work) controls how much time to spend on hashing the message, 73 // inherently controlling its priority through the network (smaller hash, bigger 74 // priority). 75 // 76 // The user can control the amount of identity, privacy and encryption through 77 // the options parameter as follows: 78 // - options.From == nil && options.To == nil: anonymous broadcast 79 // - options.From != nil && options.To == nil: signed broadcast (known sender) 80 // - options.From == nil && options.To != nil: encrypted anonymous message 81 // - options.From != nil && options.To != nil: encrypted signed message 82 func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error) { 83 // Use the default TTL if non was specified 84 if options.TTL == 0 { 85 options.TTL = DefaultTTL 86 } 87 self.TTL = options.TTL 88 89 // Sign and encrypt the message if requested 90 if options.From != nil { 91 if err := self.sign(options.From); err != nil { 92 return nil, err 93 } 94 } 95 if options.To != nil { 96 if err := self.encrypt(options.To); err != nil { 97 return nil, err 98 } 99 } 100 // Wrap the processed message, seal it and return 101 envelope := NewEnvelope(options.TTL, options.Topics, self) 102 envelope.Seal(pow) 103 104 return envelope, nil 105 } 106 107 // sign calculates and sets the cryptographic signature for the message , also 108 // setting the sign flag. 109 func (self *Message) sign(key *ecdsa.PrivateKey) (err error) { 110 self.Flags |= signatureFlag 111 self.Signature, err = crypto.Sign(self.hash(), key) 112 return 113 } 114 115 // Recover retrieves the public key of the message signer. 116 func (self *Message) Recover() *ecdsa.PublicKey { 117 defer func() { recover() }() // in case of invalid signature 118 119 // Short circuit if no signature is present 120 if self.Signature == nil { 121 return nil 122 } 123 // Otherwise try and recover the signature 124 pub, err := crypto.SigToPub(self.hash(), self.Signature) 125 if err != nil { 126 glog.V(logger.Error).Infof("Could not get public key from signature: %v", err) 127 return nil 128 } 129 return pub 130 } 131 132 // encrypt encrypts a message payload with a public key. 133 func (self *Message) encrypt(key *ecdsa.PublicKey) (err error) { 134 self.Payload, err = crypto.Encrypt(key, self.Payload) 135 return 136 } 137 138 // decrypt decrypts an encrypted payload with a private key. 139 func (self *Message) decrypt(key *ecdsa.PrivateKey) error { 140 cleartext, err := crypto.Decrypt(key, self.Payload) 141 if err == nil { 142 self.Payload = cleartext 143 } 144 return err 145 } 146 147 // hash calculates the SHA3 checksum of the message flags and payload. 148 func (self *Message) hash() []byte { 149 return crypto.Keccak256(append([]byte{self.Flags}, self.Payload...)) 150 } 151 152 // bytes flattens the message contents (flags, signature and payload) into a 153 // single binary blob. 154 func (self *Message) bytes() []byte { 155 return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...) 156 }