github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/whisper/whisperv5/message.go (about)

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