github.com/status-im/status-go@v1.1.0/waku/common/message_test.go (about)

     1  // Copyright 2019 The Waku Library Authors.
     2  //
     3  // The Waku library is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Lesser General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // (at your option) any later version.
     7  //
     8  // The Waku library is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty off
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    11  // GNU Lesser General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Lesser General Public License
    14  // along with the Waku library. If not, see <http://www.gnu.org/licenses/>.
    15  //
    16  // This software uses the go-ethereum library, which is licensed
    17  // under the GNU Lesser General Public Library, version 3 or any later.
    18  
    19  package common
    20  
    21  import (
    22  	"bytes"
    23  	"crypto/aes"
    24  	"crypto/cipher"
    25  	mrand "math/rand"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/stretchr/testify/require"
    30  
    31  	"github.com/ethereum/go-ethereum/common/hexutil"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/rlp"
    34  )
    35  
    36  func GenerateMessageParams() (*MessageParams, error) {
    37  	// set all the parameters except p.Dst and p.Padding
    38  
    39  	buf := make([]byte, 4)
    40  	mrand.Read(buf)       // nolint: gosec
    41  	sz := mrand.Intn(400) // nolint: gosec
    42  
    43  	var p MessageParams
    44  	p.PoW = 0.01
    45  	p.WorkTime = 1
    46  	p.TTL = uint32(mrand.Intn(1024)) // nolint: gosec
    47  	p.Payload = make([]byte, sz)
    48  	p.KeySym = make([]byte, AESKeyLength)
    49  	mrand.Read(p.Payload) // nolint: gosec
    50  	mrand.Read(p.KeySym)  // nolint: gosec
    51  	p.Topic = BytesToTopic(buf)
    52  
    53  	var err error
    54  	p.Src, err = crypto.GenerateKey()
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	return &p, nil
    60  }
    61  
    62  func singleMessageTest(t *testing.T, symmetric bool) {
    63  	params, err := GenerateMessageParams()
    64  	if err != nil {
    65  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
    66  	}
    67  
    68  	key, err := crypto.GenerateKey()
    69  	if err != nil {
    70  		t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err)
    71  	}
    72  
    73  	if !symmetric {
    74  		params.KeySym = nil
    75  		params.Dst = &key.PublicKey
    76  	}
    77  
    78  	text := make([]byte, 0, 512)
    79  	text = append(text, params.Payload...)
    80  
    81  	msg, err := NewSentMessage(params)
    82  	if err != nil {
    83  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
    84  	}
    85  	env, err := msg.Wrap(params, time.Now())
    86  	if err != nil {
    87  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
    88  	}
    89  
    90  	var decrypted *ReceivedMessage
    91  	if symmetric {
    92  		decrypted, err = env.OpenSymmetric(params.KeySym)
    93  	} else {
    94  		decrypted, err = env.OpenAsymmetric(key)
    95  	}
    96  
    97  	if err != nil {
    98  		t.Fatalf("failed to encrypt with seed %d: %s.", seed, err)
    99  	}
   100  
   101  	if !decrypted.ValidateAndParse() {
   102  		t.Fatalf("failed to validate with seed %d, symmetric = %v.", seed, symmetric)
   103  	}
   104  
   105  	if !bytes.Equal(text, decrypted.Payload) {
   106  		t.Fatalf("failed with seed %d: compare payload.", seed)
   107  	}
   108  	if !IsMessageSigned(decrypted.Raw[0]) {
   109  		t.Fatalf("failed with seed %d: unsigned.", seed)
   110  	}
   111  	if len(decrypted.Signature) != signatureLength {
   112  		t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature))
   113  	}
   114  	if !IsPubKeyEqual(decrypted.Src, &params.Src.PublicKey) {
   115  		t.Fatalf("failed with seed %d: signature mismatch.", seed)
   116  	}
   117  }
   118  
   119  func TestMessageEncryption(t *testing.T) {
   120  	InitSingleTest()
   121  
   122  	var symmetric bool
   123  	for i := 0; i < 256; i++ {
   124  		singleMessageTest(t, symmetric)
   125  		symmetric = !symmetric
   126  	}
   127  }
   128  
   129  func TestMessageWrap(t *testing.T) {
   130  	seed = int64(1777444222)
   131  	mrand.Seed(seed)
   132  	target := 128.0
   133  
   134  	params, err := GenerateMessageParams()
   135  	if err != nil {
   136  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   137  	}
   138  
   139  	msg, err := NewSentMessage(params)
   140  	if err != nil {
   141  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   142  	}
   143  	params.TTL = 1
   144  	params.WorkTime = 12
   145  	params.PoW = target
   146  	env, err := msg.Wrap(params, time.Now())
   147  	if err != nil {
   148  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   149  	}
   150  
   151  	pow := env.PoW()
   152  	if pow < target {
   153  		t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target)
   154  	}
   155  
   156  	// set PoW target too high, expect error
   157  	msg2, err := NewSentMessage(params)
   158  	if err != nil {
   159  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   160  	}
   161  	params.TTL = 1000000
   162  	params.WorkTime = 1
   163  	params.PoW = 10000000.0
   164  	_, err = msg2.Wrap(params, time.Now())
   165  	if err == nil {
   166  		t.Fatalf("unexpectedly reached the PoW target with seed %d.", seed)
   167  	}
   168  }
   169  
   170  func TestMessageSeal(t *testing.T) {
   171  	// this test depends on deterministic choice of seed (1976726903)
   172  	seed = int64(1976726903)
   173  	mrand.Seed(seed)
   174  
   175  	params, err := GenerateMessageParams()
   176  	if err != nil {
   177  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   178  	}
   179  
   180  	msg, err := NewSentMessage(params)
   181  	if err != nil {
   182  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   183  	}
   184  	params.TTL = 1
   185  
   186  	env := NewEnvelope(params.TTL, params.Topic, msg, time.Now())
   187  
   188  	env.Expiry = uint32(seed) // make it deterministic
   189  	target := 32.0
   190  	params.WorkTime = 4
   191  	params.PoW = target
   192  	err = env.Seal(params)
   193  	if err != nil {
   194  		t.Logf("failed to seal envelope: %s", err)
   195  	}
   196  
   197  	env.CalculatePoW(0)
   198  	pow := env.PoW()
   199  	if pow < target {
   200  		t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target)
   201  	}
   202  
   203  	// Seal should fail as WorkTime is significantly lower than PoW would require
   204  	params.WorkTime = 1
   205  	params.PoW = 1000000000.0
   206  	err = env.Seal(params)
   207  	require.EqualError(t, err, "failed to reach the PoW target, specified pow time (1 seconds) was insufficient")
   208  	env.CalculatePoW(0)
   209  	pow = env.PoW()
   210  	if pow < 2*target {
   211  		t.Fatalf("failed Wrap with seed %d: pow too small %f.", seed, pow)
   212  	}
   213  }
   214  
   215  func TestEnvelopeOpen(t *testing.T) {
   216  	InitSingleTest()
   217  
   218  	var symmetric bool
   219  	for i := 0; i < 32; i++ {
   220  		singleEnvelopeOpenTest(t, symmetric)
   221  		symmetric = !symmetric
   222  	}
   223  }
   224  
   225  func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
   226  	params, err := GenerateMessageParams()
   227  	if err != nil {
   228  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   229  	}
   230  
   231  	key, err := crypto.GenerateKey()
   232  	if err != nil {
   233  		t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err)
   234  	}
   235  
   236  	if !symmetric {
   237  		params.KeySym = nil
   238  		params.Dst = &key.PublicKey
   239  	}
   240  
   241  	text := make([]byte, 0, 512)
   242  	text = append(text, params.Payload...)
   243  
   244  	msg, err := NewSentMessage(params)
   245  	if err != nil {
   246  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   247  	}
   248  	env, err := msg.Wrap(params, time.Now())
   249  	if err != nil {
   250  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   251  	}
   252  
   253  	var f Filter
   254  	if symmetric {
   255  		f = Filter{KeySym: params.KeySym}
   256  	} else {
   257  		f = Filter{KeyAsym: key}
   258  	}
   259  	decrypted := env.Open(&f)
   260  	if decrypted == nil {
   261  		t.Fatalf("failed to open with seed %d.", seed)
   262  	}
   263  
   264  	if !bytes.Equal(text, decrypted.Payload) {
   265  		t.Fatalf("failed with seed %d: compare payload.", seed)
   266  	}
   267  	if !IsMessageSigned(decrypted.Raw[0]) {
   268  		t.Fatalf("failed with seed %d: unsigned.", seed)
   269  	}
   270  	if len(decrypted.Signature) != signatureLength {
   271  		t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature))
   272  	}
   273  	if !IsPubKeyEqual(decrypted.Src, &params.Src.PublicKey) {
   274  		t.Fatalf("failed with seed %d: signature mismatch.", seed)
   275  	}
   276  	if decrypted.isAsymmetricEncryption() == symmetric {
   277  		t.Fatalf("failed with seed %d: asymmetric %v vs. %v.", seed, decrypted.isAsymmetricEncryption(), symmetric)
   278  	}
   279  	if decrypted.isSymmetricEncryption() != symmetric {
   280  		t.Fatalf("failed with seed %d: symmetric %v vs. %v.", seed, decrypted.isSymmetricEncryption(), symmetric)
   281  	}
   282  	if !symmetric {
   283  		if decrypted.Dst == nil {
   284  			t.Fatalf("failed with seed %d: dst is nil.", seed)
   285  		}
   286  		if !IsPubKeyEqual(decrypted.Dst, &key.PublicKey) {
   287  			t.Fatalf("failed with seed %d: Dst.", seed)
   288  		}
   289  	}
   290  }
   291  
   292  func TestEncryptWithZeroKey(t *testing.T) {
   293  	InitSingleTest()
   294  
   295  	params, err := GenerateMessageParams()
   296  	if err != nil {
   297  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   298  	}
   299  	msg, err := NewSentMessage(params)
   300  	if err != nil {
   301  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   302  	}
   303  	params.KeySym = make([]byte, AESKeyLength)
   304  	_, err = msg.Wrap(params, time.Now())
   305  	if err == nil {
   306  		t.Fatalf("wrapped with zero key, seed: %d.", seed)
   307  	}
   308  
   309  	params, err = GenerateMessageParams()
   310  	if err != nil {
   311  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   312  	}
   313  	msg, err = NewSentMessage(params)
   314  	if err != nil {
   315  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   316  	}
   317  	params.KeySym = make([]byte, 0)
   318  	_, err = msg.Wrap(params, time.Now())
   319  	if err == nil {
   320  		t.Fatalf("wrapped with empty key, seed: %d.", seed)
   321  	}
   322  
   323  	params, err = GenerateMessageParams()
   324  	if err != nil {
   325  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   326  	}
   327  	msg, err = NewSentMessage(params)
   328  	if err != nil {
   329  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   330  	}
   331  	params.KeySym = nil
   332  	_, err = msg.Wrap(params, time.Now())
   333  	if err == nil {
   334  		t.Fatalf("wrapped with nil key, seed: %d.", seed)
   335  	}
   336  }
   337  
   338  func TestRlpEncode(t *testing.T) {
   339  	InitSingleTest()
   340  
   341  	params, err := GenerateMessageParams()
   342  	if err != nil {
   343  		t.Fatalf("failed GenerateMessageParams with seed %d: %s.", seed, err)
   344  	}
   345  	msg, err := NewSentMessage(params)
   346  	if err != nil {
   347  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   348  	}
   349  	env, err := msg.Wrap(params, time.Now())
   350  	if err != nil {
   351  		t.Fatalf("wrapped with zero key, seed: %d.", seed)
   352  	}
   353  
   354  	raw, err := rlp.EncodeToBytes(env)
   355  	if err != nil {
   356  		t.Fatalf("RLP encode failed: %s.", err)
   357  	}
   358  
   359  	var decoded Envelope
   360  	err = rlp.DecodeBytes(raw, &decoded)
   361  	if err != nil {
   362  		t.Fatalf("RLP decode failed: %s.", err)
   363  	}
   364  
   365  	he := env.Hash()
   366  	hd := decoded.Hash()
   367  
   368  	if he != hd {
   369  		t.Fatalf("Hashes are not equal: %x vs. %x", he, hd)
   370  	}
   371  }
   372  
   373  func singlePaddingTest(t *testing.T, padSize int) {
   374  	params, err := GenerateMessageParams()
   375  	if err != nil {
   376  		t.Fatalf("failed GenerateMessageParams with seed %d and sz=%d: %s.", seed, padSize, err)
   377  	}
   378  	params.Padding = make([]byte, padSize)
   379  	params.PoW = 0.0000000001
   380  	pad := make([]byte, padSize)
   381  	_, err = mrand.Read(pad) // nolint: gosec
   382  	if err != nil {
   383  		t.Fatalf("padding is not generated (seed %d): %s", seed, err)
   384  	}
   385  	n := copy(params.Padding, pad)
   386  	if n != padSize {
   387  		t.Fatalf("padding is not copied (seed %d): %s", seed, err)
   388  	}
   389  	msg, err := NewSentMessage(params)
   390  	if err != nil {
   391  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   392  	}
   393  	env, err := msg.Wrap(params, time.Now())
   394  	if err != nil {
   395  		t.Fatalf("failed to wrap, seed: %d and sz=%d.", seed, padSize)
   396  	}
   397  	f := Filter{KeySym: params.KeySym}
   398  	decrypted := env.Open(&f)
   399  	if decrypted == nil {
   400  		t.Fatalf("failed to open, seed and sz=%d: %d.", seed, padSize)
   401  	}
   402  	if !bytes.Equal(pad, decrypted.Padding) {
   403  		t.Fatalf("padding is not retireved as expected with seed %d and sz=%d:\n[%x]\n[%x].", seed, padSize, pad, decrypted.Padding)
   404  	}
   405  }
   406  
   407  func TestPadding(t *testing.T) {
   408  	InitSingleTest()
   409  
   410  	for i := 1; i < 260; i++ {
   411  		singlePaddingTest(t, i)
   412  	}
   413  
   414  	lim := 256 * 256
   415  	for i := lim - 5; i < lim+2; i++ {
   416  		singlePaddingTest(t, i)
   417  	}
   418  
   419  	for i := 0; i < 256; i++ {
   420  		n := mrand.Intn(256*254) + 256 // nolint: gosec
   421  		singlePaddingTest(t, n)
   422  	}
   423  
   424  	for i := 0; i < 256; i++ {
   425  		n := mrand.Intn(256*1024) + 256*256 // nolint: gosec
   426  		singlePaddingTest(t, n)
   427  	}
   428  }
   429  
   430  func TestPaddingAppendedToSymMessagesWithSignature(t *testing.T) {
   431  	params := &MessageParams{
   432  		Payload: make([]byte, 246),
   433  		KeySym:  make([]byte, AESKeyLength),
   434  	}
   435  
   436  	pSrc, err := crypto.GenerateKey()
   437  
   438  	if err != nil {
   439  		t.Fatalf("Error creating the signature key %v", err)
   440  		return
   441  	}
   442  	params.Src = pSrc
   443  
   444  	// Simulate a message with a payload just under 256 so that
   445  	// payload + flag + signature > 256. Check that the result
   446  	// is padded on the next 256 boundary.
   447  	msg := SentMessage{}
   448  	const payloadSizeFieldMinSize = 1
   449  	msg.Raw = make([]byte, flagsLength+payloadSizeFieldMinSize+len(params.Payload))
   450  
   451  	err = msg.appendPadding(params)
   452  
   453  	if err != nil {
   454  		t.Fatalf("Error appending padding to message %v", err)
   455  		return
   456  	}
   457  
   458  	if len(msg.Raw) != 512-signatureLength {
   459  		t.Errorf("Invalid size %d != 512", len(msg.Raw))
   460  	}
   461  }
   462  
   463  func TestAesNonce(t *testing.T) {
   464  	key := hexutil.MustDecode("0x03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31")
   465  	block, err := aes.NewCipher(key)
   466  	if err != nil {
   467  		t.Fatalf("NewCipher failed: %s", err)
   468  	}
   469  	aesgcm, err := cipher.NewGCM(block)
   470  	if err != nil {
   471  		t.Fatalf("NewGCM failed: %s", err)
   472  	}
   473  	// This is the most important single test in this package.
   474  	// If it fails, waku will not be working.
   475  	if aesgcm.NonceSize() != aesNonceLength {
   476  		t.Fatalf("Nonce size is wrong. This is a critical error. Apparently AES nonce size have changed in the new version of AES GCM package. Waku will not be working until this problem is resolved.")
   477  	}
   478  }
   479  
   480  func TestValidateAndParseSizeOfPayloadSize(t *testing.T) {
   481  	testCases := []struct {
   482  		Name string
   483  		Raw  []byte
   484  	}{
   485  		{
   486  			Name: "one byte of value 1",
   487  			Raw:  []byte{1},
   488  		},
   489  		{
   490  			Name: "two bytes of values 1 and 1",
   491  			Raw:  []byte{1, 1},
   492  		},
   493  	}
   494  
   495  	for _, tc := range testCases {
   496  		t.Run(tc.Name, func(t *testing.T) {
   497  			msg := ReceivedMessage{Raw: tc.Raw}
   498  			msg.ValidateAndParse()
   499  		})
   500  	}
   501  }