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