github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/whisper/whisperv6/message.go (about)

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