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, ¶ms.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, ¶ms.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 }