github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv5/message.go (about)

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