github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv6/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 whisperv6
    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  	Salt      []byte
    65  
    66  	PoW   float64          // Proof of work as described in the Whisper spec
    67  	Sent  uint32           // Time when the message was posted into the network
    68  	TTL   uint32           // Maximum time to live allowed for the message
    69  	Src   *ecdsa.PublicKey // Message recipient (identity used to decode the message)
    70  	Dst   *ecdsa.PublicKey // Message recipient (identity used to decode the message)
    71  	Topic TopicType
    72  
    73  	SymKeyHash   common.Hash // The Keccak256Hash of the key, associated with the Topic
    74  	EnvelopeHash common.Hash // Message envelope hash to act as a unique id
    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  
   128  	if params.KeySym != nil {
   129  		rawSize += AESNonceLength
   130  	}
   131  	odd := rawSize % padSizeLimit
   132  
   133  	if len(params.Padding) != 0 {
   134  		padSize := len(params.Padding)
   135  		padLengthSize, err := getSizeOfLength(params.Padding)
   136  		if err != nil {
   137  			return err
   138  		}
   139  		totalPadSize := padSize + padLengthSize
   140  		buf := make([]byte, 8)
   141  		binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
   142  		buf = buf[:padLengthSize]
   143  		msg.Raw = append(msg.Raw, buf...)
   144  		msg.Raw = append(msg.Raw, params.Padding...)
   145  		msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size
   146  	} else if odd != 0 {
   147  		totalPadSize := padSizeLimit - odd
   148  		if totalPadSize > 255 {
   149  			// this algorithm is only valid if padSizeLimit < 256.
   150  			// if padSizeLimit will ever change, please fix the algorithm
   151  			// (please see also ReceivedMessage.extractPadding() function).
   152  			panic("please fix the padding algorithm before releasing new version")
   153  		}
   154  		buf := make([]byte, totalPadSize)
   155  		_, err := crand.Read(buf[1:])
   156  		if err != nil {
   157  			return err
   158  		}
   159  		if totalPadSize > 6 && !validateSymmetricKey(buf) {
   160  			return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
   161  		}
   162  		buf[0] = byte(totalPadSize)
   163  		msg.Raw = append(msg.Raw, buf...)
   164  		msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
   165  	}
   166  	return nil
   167  }
   168  
   169  // sign calculates and sets the cryptographic signature for the message,
   170  // also setting the sign flag.
   171  func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error {
   172  	if isMessageSigned(msg.Raw[0]) {
   173  		// this should not happen, but no reason to panic
   174  		log.Error("failed to sign the message: already signed")
   175  		return nil
   176  	}
   177  
   178  	msg.Raw[0] |= signatureFlag
   179  	hash := crypto.Keccak256(msg.Raw)
   180  	signature, err := crypto.Sign(hash, key)
   181  	if err != nil {
   182  		msg.Raw[0] &= ^signatureFlag // clear the flag
   183  		return err
   184  	}
   185  	msg.Raw = append(msg.Raw, signature...)
   186  	return nil
   187  }
   188  
   189  // encryptAsymmetric encrypts a message with a public key.
   190  func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
   191  	if !ValidatePublicKey(key) {
   192  		return errors.New("invalid public key provided for asymmetric encryption")
   193  	}
   194  	encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
   195  	if err == nil {
   196  		msg.Raw = encrypted
   197  	}
   198  	return err
   199  }
   200  
   201  // encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
   202  // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
   203  func (msg *sentMessage) encryptSymmetric(key []byte) (err error) {
   204  	if !validateSymmetricKey(key) {
   205  		return errors.New("invalid key provided for symmetric encryption")
   206  	}
   207  
   208  	block, err := aes.NewCipher(key)
   209  	if err != nil {
   210  		return err
   211  	}
   212  	aesgcm, err := cipher.NewGCM(block)
   213  	if err != nil {
   214  		return err
   215  	}
   216  
   217  	// never use more than 2^32 random nonces with a given key
   218  	salt := make([]byte, aesgcm.NonceSize())
   219  	_, err = crand.Read(salt)
   220  	if err != nil {
   221  		return err
   222  	} else if !validateSymmetricKey(salt) {
   223  		return errors.New("crypto/rand failed to generate salt")
   224  	}
   225  
   226  	msg.Raw = append(aesgcm.Seal(nil, salt, msg.Raw, nil), salt...)
   227  	return nil
   228  }
   229  
   230  // Wrap bundles the message into an Envelope to transmit over the network.
   231  func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
   232  	if options.TTL == 0 {
   233  		options.TTL = DefaultTTL
   234  	}
   235  	if options.Src != nil {
   236  		if err = msg.sign(options.Src); err != nil {
   237  			return nil, err
   238  		}
   239  	}
   240  	if options.Dst != nil {
   241  		err = msg.encryptAsymmetric(options.Dst)
   242  	} else if options.KeySym != nil {
   243  		err = msg.encryptSymmetric(options.KeySym)
   244  	} else {
   245  		err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
   246  	}
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  
   251  	envelope = NewEnvelope(options.TTL, options.Topic, msg)
   252  	if err = envelope.Seal(options); err != nil {
   253  		return nil, err
   254  	}
   255  	return envelope, nil
   256  }
   257  
   258  // decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
   259  // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
   260  func (msg *ReceivedMessage) decryptSymmetric(key []byte) error {
   261  	// In v6, symmetric messages are expected to contain the 12-byte
   262  	// "salt" at the end of the payload.
   263  	if len(msg.Raw) < AESNonceLength {
   264  		return errors.New("missing salt or invalid payload in symmetric message")
   265  	}
   266  	salt := msg.Raw[len(msg.Raw)-AESNonceLength:]
   267  
   268  	block, err := aes.NewCipher(key)
   269  	if err != nil {
   270  		return err
   271  	}
   272  	aesgcm, err := cipher.NewGCM(block)
   273  	if err != nil {
   274  		return err
   275  	}
   276  	if len(salt) != aesgcm.NonceSize() {
   277  		log.Error("decrypting the message", "AES salt size", len(salt))
   278  		return errors.New("wrong AES salt size")
   279  	}
   280  	decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-AESNonceLength], nil)
   281  	if err != nil {
   282  		return err
   283  	}
   284  	msg.Raw = decrypted
   285  	msg.Salt = salt
   286  	return nil
   287  }
   288  
   289  // decryptAsymmetric decrypts an encrypted payload with a private key.
   290  func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
   291  	decrypted, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, msg.Raw, nil, nil)
   292  	if err == nil {
   293  		msg.Raw = decrypted
   294  	}
   295  	return err
   296  }
   297  
   298  // Validate checks the validity and extracts the fields in case of success
   299  func (msg *ReceivedMessage) Validate() bool {
   300  	end := len(msg.Raw)
   301  	if end < 1 {
   302  		return false
   303  	}
   304  
   305  	if isMessageSigned(msg.Raw[0]) {
   306  		end -= signatureLength
   307  		if end <= 1 {
   308  			return false
   309  		}
   310  		msg.Signature = msg.Raw[end:]
   311  		msg.Src = msg.SigToPubKey()
   312  		if msg.Src == nil {
   313  			return false
   314  		}
   315  	}
   316  
   317  	padSize, ok := msg.extractPadding(end)
   318  	if !ok {
   319  		return false
   320  	}
   321  
   322  	msg.Payload = msg.Raw[1+padSize : end]
   323  	return true
   324  }
   325  
   326  // extractPadding extracts the padding from raw message.
   327  // although we don't support sending messages with padding size
   328  // exceeding 255 bytes, such messages are perfectly valid, and
   329  // can be successfully decrypted.
   330  func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
   331  	paddingSize := 0
   332  	sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes)
   333  	// could be zero -- it means no padding
   334  	if sz != 0 {
   335  		paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
   336  		if paddingSize < sz || paddingSize+1 > end {
   337  			return 0, false
   338  		}
   339  		msg.Padding = msg.Raw[1+sz : 1+paddingSize]
   340  	}
   341  	return paddingSize, true
   342  }
   343  
   344  // Recover retrieves the public key of the message signer.
   345  func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
   346  	defer func() { recover() }() // in case of invalid signature
   347  
   348  	pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
   349  	if err != nil {
   350  		log.Error("failed to recover public key from signature", "err", err)
   351  		return nil
   352  	}
   353  	return pub
   354  }
   355  
   356  // hash calculates the SHA3 checksum of the message flags, payload and padding.
   357  func (msg *ReceivedMessage) hash() []byte {
   358  	if isMessageSigned(msg.Raw[0]) {
   359  		sz := len(msg.Raw) - signatureLength
   360  		return crypto.Keccak256(msg.Raw[:sz])
   361  	}
   362  	return crypto.Keccak256(msg.Raw)
   363  }