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  }