github.com/luckypickle/go-ethereum-vet@v1.14.2/whisper/whisperv6/message.go (about)

     1  // Copyright 2016 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.
    18  
    19  package whisperv6
    20  
    21  import (
    22  	"crypto/aes"
    23  	"crypto/cipher"
    24  	"crypto/ecdsa"
    25  	crand "crypto/rand"
    26  	"encoding/binary"
    27  	"errors"
    28  	mrand "math/rand"
    29  	"strconv"
    30  
    31  	"github.com/luckypickle/go-ethereum-vet/common"
    32  	"github.com/luckypickle/go-ethereum-vet/crypto"
    33  	"github.com/luckypickle/go-ethereum-vet/crypto/ecies"
    34  	"github.com/luckypickle/go-ethereum-vet/log"
    35  )
    36  
    37  // MessageParams specifies the exact way a message should be wrapped
    38  // into an Envelope.
    39  type MessageParams struct {
    40  	TTL      uint32
    41  	Src      *ecdsa.PrivateKey
    42  	Dst      *ecdsa.PublicKey
    43  	KeySym   []byte
    44  	Topic    TopicType
    45  	WorkTime uint32
    46  	PoW      float64
    47  	Payload  []byte
    48  	Padding  []byte
    49  }
    50  
    51  // SentMessage represents an end-user data packet to transmit through the
    52  // Whisper protocol. These are wrapped into Envelopes that need not be
    53  // understood by intermediate nodes, just forwarded.
    54  type sentMessage struct {
    55  	Raw []byte
    56  }
    57  
    58  // ReceivedMessage represents a data packet to be received through the
    59  // Whisper protocol and successfully decrypted.
    60  type ReceivedMessage struct {
    61  	Raw []byte
    62  
    63  	Payload   []byte
    64  	Padding   []byte
    65  	Signature []byte
    66  	Salt      []byte
    67  
    68  	PoW   float64          // Proof of work as described in the Whisper spec
    69  	Sent  uint32           // Time when the message was posted into the network
    70  	TTL   uint32           // Maximum time to live allowed for the message
    71  	Src   *ecdsa.PublicKey // Message recipient (identity used to decode the message)
    72  	Dst   *ecdsa.PublicKey // Message recipient (identity used to decode the message)
    73  	Topic TopicType
    74  
    75  	SymKeyHash   common.Hash // The Keccak256Hash of the key
    76  	EnvelopeHash common.Hash // Message envelope hash to act as a unique id
    77  }
    78  
    79  func isMessageSigned(flags byte) bool {
    80  	return (flags & signatureFlag) != 0
    81  }
    82  
    83  func (msg *ReceivedMessage) isSymmetricEncryption() bool {
    84  	return msg.SymKeyHash != common.Hash{}
    85  }
    86  
    87  func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
    88  	return msg.Dst != nil
    89  }
    90  
    91  // NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message.
    92  func NewSentMessage(params *MessageParams) (*sentMessage, error) {
    93  	const payloadSizeFieldMaxSize = 4
    94  	msg := sentMessage{}
    95  	msg.Raw = make([]byte, 1,
    96  		flagsLength+payloadSizeFieldMaxSize+len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
    97  	msg.Raw[0] = 0 // set all the flags to zero
    98  	msg.addPayloadSizeField(params.Payload)
    99  	msg.Raw = append(msg.Raw, params.Payload...)
   100  	err := msg.appendPadding(params)
   101  	return &msg, err
   102  }
   103  
   104  // addPayloadSizeField appends the auxiliary field containing the size of payload
   105  func (msg *sentMessage) addPayloadSizeField(payload []byte) {
   106  	fieldSize := getSizeOfPayloadSizeField(payload)
   107  	field := make([]byte, 4)
   108  	binary.LittleEndian.PutUint32(field, uint32(len(payload)))
   109  	field = field[:fieldSize]
   110  	msg.Raw = append(msg.Raw, field...)
   111  	msg.Raw[0] |= byte(fieldSize)
   112  }
   113  
   114  // getSizeOfPayloadSizeField returns the number of bytes necessary to encode the size of payload
   115  func getSizeOfPayloadSizeField(payload []byte) int {
   116  	s := 1
   117  	for i := len(payload); i >= 256; i /= 256 {
   118  		s++
   119  	}
   120  	return s
   121  }
   122  
   123  // appendPadding appends the padding specified in params.
   124  // If no padding is provided in params, then random padding is generated.
   125  func (msg *sentMessage) appendPadding(params *MessageParams) error {
   126  	if len(params.Padding) != 0 {
   127  		// padding data was provided by the Dapp, just use it as is
   128  		msg.Raw = append(msg.Raw, params.Padding...)
   129  		return nil
   130  	}
   131  
   132  	rawSize := flagsLength + getSizeOfPayloadSizeField(params.Payload) + len(params.Payload)
   133  	if params.Src != nil {
   134  		rawSize += signatureLength
   135  	}
   136  	odd := rawSize % padSizeLimit
   137  	paddingSize := padSizeLimit - odd
   138  	pad := make([]byte, paddingSize)
   139  	_, err := crand.Read(pad)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	if !validateDataIntegrity(pad, paddingSize) {
   144  		return errors.New("failed to generate random padding of size " + strconv.Itoa(paddingSize))
   145  	}
   146  	msg.Raw = append(msg.Raw, pad...)
   147  	return nil
   148  }
   149  
   150  // sign calculates and sets the cryptographic signature for the message,
   151  // also setting the sign flag.
   152  func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error {
   153  	if isMessageSigned(msg.Raw[0]) {
   154  		// this should not happen, but no reason to panic
   155  		log.Error("failed to sign the message: already signed")
   156  		return nil
   157  	}
   158  
   159  	msg.Raw[0] |= signatureFlag // it is important to set this flag before signing
   160  	hash := crypto.Keccak256(msg.Raw)
   161  	signature, err := crypto.Sign(hash, key)
   162  	if err != nil {
   163  		msg.Raw[0] &= (0xFF ^ signatureFlag) // clear the flag
   164  		return err
   165  	}
   166  	msg.Raw = append(msg.Raw, signature...)
   167  	return nil
   168  }
   169  
   170  // encryptAsymmetric encrypts a message with a public key.
   171  func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
   172  	if !ValidatePublicKey(key) {
   173  		return errors.New("invalid public key provided for asymmetric encryption")
   174  	}
   175  	encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
   176  	if err == nil {
   177  		msg.Raw = encrypted
   178  	}
   179  	return err
   180  }
   181  
   182  // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
   183  // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
   184  func (msg *sentMessage) encryptSymmetric(key []byte) (err error) {
   185  	if !validateDataIntegrity(key, aesKeyLength) {
   186  		return errors.New("invalid key provided for symmetric encryption, size: " + strconv.Itoa(len(key)))
   187  	}
   188  	block, err := aes.NewCipher(key)
   189  	if err != nil {
   190  		return err
   191  	}
   192  	aesgcm, err := cipher.NewGCM(block)
   193  	if err != nil {
   194  		return err
   195  	}
   196  	salt, err := generateSecureRandomData(aesNonceLength) // never use more than 2^32 random nonces with a given key
   197  	if err != nil {
   198  		return err
   199  	}
   200  	encrypted := aesgcm.Seal(nil, salt, msg.Raw, nil)
   201  	msg.Raw = append(encrypted, salt...)
   202  	return nil
   203  }
   204  
   205  // generateSecureRandomData generates random data where extra security is required.
   206  // The purpose of this function is to prevent some bugs in software or in hardware
   207  // from delivering not-very-random data. This is especially useful for AES nonce,
   208  // where true randomness does not really matter, but it is very important to have
   209  // a unique nonce for every message.
   210  func generateSecureRandomData(length int) ([]byte, error) {
   211  	x := make([]byte, length)
   212  	y := make([]byte, length)
   213  	res := make([]byte, length)
   214  
   215  	_, err := crand.Read(x)
   216  	if err != nil {
   217  		return nil, err
   218  	} else if !validateDataIntegrity(x, length) {
   219  		return nil, errors.New("crypto/rand failed to generate secure random data")
   220  	}
   221  	_, err = mrand.Read(y)
   222  	if err != nil {
   223  		return nil, err
   224  	} else if !validateDataIntegrity(y, length) {
   225  		return nil, errors.New("math/rand failed to generate secure random data")
   226  	}
   227  	for i := 0; i < length; i++ {
   228  		res[i] = x[i] ^ y[i]
   229  	}
   230  	if !validateDataIntegrity(res, length) {
   231  		return nil, errors.New("failed to generate secure random data")
   232  	}
   233  	return res, nil
   234  }
   235  
   236  // Wrap bundles the message into an Envelope to transmit over the network.
   237  func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
   238  	if options.TTL == 0 {
   239  		options.TTL = DefaultTTL
   240  	}
   241  	if options.Src != nil {
   242  		if err = msg.sign(options.Src); err != nil {
   243  			return nil, err
   244  		}
   245  	}
   246  	if options.Dst != nil {
   247  		err = msg.encryptAsymmetric(options.Dst)
   248  	} else if options.KeySym != nil {
   249  		err = msg.encryptSymmetric(options.KeySym)
   250  	} else {
   251  		err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
   252  	}
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  	envelope = NewEnvelope(options.TTL, options.Topic, msg)
   258  	if err = envelope.Seal(options); err != nil {
   259  		return nil, err
   260  	}
   261  	return envelope, nil
   262  }
   263  
   264  // decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
   265  // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
   266  func (msg *ReceivedMessage) decryptSymmetric(key []byte) error {
   267  	// symmetric messages are expected to contain the 12-byte nonce at the end of the payload
   268  	if len(msg.Raw) < aesNonceLength {
   269  		return errors.New("missing salt or invalid payload in symmetric message")
   270  	}
   271  	salt := msg.Raw[len(msg.Raw)-aesNonceLength:]
   272  
   273  	block, err := aes.NewCipher(key)
   274  	if err != nil {
   275  		return err
   276  	}
   277  	aesgcm, err := cipher.NewGCM(block)
   278  	if err != nil {
   279  		return err
   280  	}
   281  	decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-aesNonceLength], nil)
   282  	if err != nil {
   283  		return err
   284  	}
   285  	msg.Raw = decrypted
   286  	msg.Salt = salt
   287  	return nil
   288  }
   289  
   290  // decryptAsymmetric decrypts an encrypted payload with a private key.
   291  func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
   292  	decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
   293  	if err == nil {
   294  		msg.Raw = decrypted
   295  	}
   296  	return err
   297  }
   298  
   299  // ValidateAndParse checks the message validity and extracts the fields in case of success.
   300  func (msg *ReceivedMessage) ValidateAndParse() bool {
   301  	end := len(msg.Raw)
   302  	if end < 1 {
   303  		return false
   304  	}
   305  
   306  	if isMessageSigned(msg.Raw[0]) {
   307  		end -= signatureLength
   308  		if end <= 1 {
   309  			return false
   310  		}
   311  		msg.Signature = msg.Raw[end : end+signatureLength]
   312  		msg.Src = msg.SigToPubKey()
   313  		if msg.Src == nil {
   314  			return false
   315  		}
   316  	}
   317  
   318  	beg := 1
   319  	payloadSize := 0
   320  	sizeOfPayloadSizeField := int(msg.Raw[0] & SizeMask) // number of bytes indicating the size of payload
   321  	if sizeOfPayloadSizeField != 0 {
   322  		payloadSize = int(bytesToUintLittleEndian(msg.Raw[beg : beg+sizeOfPayloadSizeField]))
   323  		if payloadSize+1 > end {
   324  			return false
   325  		}
   326  		beg += sizeOfPayloadSizeField
   327  		msg.Payload = msg.Raw[beg : beg+payloadSize]
   328  	}
   329  
   330  	beg += payloadSize
   331  	msg.Padding = msg.Raw[beg:end]
   332  	return true
   333  }
   334  
   335  // SigToPubKey returns the public key associated to the message's
   336  // signature.
   337  func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
   338  	defer func() { recover() }() // in case of invalid signature
   339  
   340  	pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
   341  	if err != nil {
   342  		log.Error("failed to recover public key from signature", "err", err)
   343  		return nil
   344  	}
   345  	return pub
   346  }
   347  
   348  // hash calculates the SHA3 checksum of the message flags, payload size field, payload and padding.
   349  func (msg *ReceivedMessage) hash() []byte {
   350  	if isMessageSigned(msg.Raw[0]) {
   351  		sz := len(msg.Raw) - signatureLength
   352  		return crypto.Keccak256(msg.Raw[:sz])
   353  	}
   354  	return crypto.Keccak256(msg.Raw)
   355  }