github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/signencrypt/codec_test.go (about) 1 package signencrypt 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "fmt" 7 "io" 8 "strings" 9 "testing" 10 11 "golang.org/x/crypto/nacl/secretbox" 12 13 "github.com/keybase/client/go/kbcrypto" 14 "github.com/keybase/go-crypto/ed25519" 15 "github.com/stretchr/testify/require" 16 ) 17 18 var plaintextInputs = []string{ 19 "", 20 "1", 21 "short", 22 strings.Repeat("long", 1000000), 23 } 24 25 type arbitraryMsg struct { 26 Message string `codec:"m" json:"m"` 27 } 28 type arbitraryNested struct { 29 Fun arbitraryMsg `codec:"f" json:"f"` 30 Boring arbitraryMsg `codec:"b" json:"b"` 31 } 32 33 var associatedDataInputs = []interface{}{ 34 "", 35 nil, 36 map[string]map[float64]map[string]string{"first": {2.22000222: {"third": "fourth"}}}, 37 strings.Repeat("long", 1000000), 38 arbitraryNested{ 39 Fun: arbitraryMsg{Message: "🤠"}, 40 Boring: arbitraryMsg{Message: "📄"}, 41 }, 42 } 43 44 func zeroSecretboxKey() SecretboxKey { 45 var key [SecretboxKeySize]byte // all zeroes 46 return &key 47 } 48 49 func zeroNonce() Nonce { 50 var nonce [NonceSize]byte // all zeroes 51 return &nonce 52 } 53 54 func zeroChunkNonce(chunkNum uint64) SecretboxNonce { 55 return makeChunkNonce(zeroNonce(), chunkNum) 56 } 57 58 func zeroVerifyKey() VerifyKey { 59 var key [ed25519.PublicKeySize]byte 60 // Generated from libsodium's crypto_sign_seed_keypair with a zero seed. 61 copy(key[:], ";j'\xbc\xce\xb6\xa4-b\xa3\xa8\xd0*o\rse2\x15w\x1d\xe2C\xa6:\xc0H\xa1\x8bY\xda)") 62 return &key 63 } 64 65 func zeroSignKey() SignKey { 66 var key [ed25519.PrivateKeySize]byte 67 // Generated from libsodium's crypto_sign_seed_keypair with a zero seed. 68 copy(key[:], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;j'\xbc\xce\xb6\xa4-b\xa3\xa8\xd0*o\rse2\x15w\x1d\xe2C\xa6:\xc0H\xa1\x8bY\xda)") 69 return &key 70 } 71 72 func testingPrefix() kbcrypto.SignaturePrefix { 73 return kbcrypto.SignaturePrefixTesting 74 } 75 76 func zeroEncoder() *Encoder { 77 return NewEncoder(zeroSecretboxKey(), zeroSignKey(), testingPrefix(), zeroNonce()) 78 } 79 80 func zeroDecoder() *Decoder { 81 return NewDecoder(zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroNonce()) 82 } 83 84 func zeroSealWhole(plaintext []byte) []byte { 85 return SealWhole(plaintext, zeroSecretboxKey(), zeroSignKey(), testingPrefix(), zeroNonce()) 86 } 87 88 func zeroOpenWhole(plaintext []byte) ([]byte, error) { 89 return OpenWhole(plaintext, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroNonce()) 90 } 91 92 func zeroSealWithAssociatedData(plaintext []byte, associatedData interface{}) []byte { 93 res, err := SealWithAssociatedData(plaintext, associatedData, zeroSecretboxKey(), zeroSignKey(), testingPrefix(), zeroNonce()) 94 if err != nil { 95 // this should never actually error 96 panic(err) 97 } 98 return res 99 } 100 101 func zeroOpenWithAssociatedData(plaintext []byte, associatedData interface{}) ([]byte, error) { 102 return OpenWithAssociatedData(plaintext, associatedData, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroNonce()) 103 } 104 105 func assertErrorType(t *testing.T, err error, expectedType ErrorType) { 106 if err == nil { 107 t.Fatal("expected an error, but error was nil") 108 } 109 concreteError, ok := err.(Error) 110 if !ok { 111 t.Fatal("failed to cast to Error") 112 } 113 if concreteError.Type != expectedType { 114 t.Fatalf("expected error type %d but found %d", expectedType, concreteError.Type) 115 } 116 } 117 118 func TestPacketRoundtrips(t *testing.T) { 119 for index, input := range plaintextInputs { 120 // Vary the chunk number, just for fun. 121 chunkNum := uint64(index) 122 sealed := sealPacket( 123 []byte(input), 124 zeroSecretboxKey(), 125 zeroSignKey(), 126 testingPrefix(), 127 zeroChunkNonce(chunkNum)) 128 129 opened, err := openPacket( 130 sealed, 131 zeroSecretboxKey(), 132 zeroVerifyKey(), 133 testingPrefix(), 134 zeroChunkNonce(chunkNum)) 135 if err != nil { 136 t.Fatal(err) 137 } 138 if !bytes.Equal([]byte(input), opened) { 139 t.Fatal("opened bytes don't equal the input") 140 } 141 142 if int64(len(sealed)) != getPacketLen(int64(len(input))) { 143 t.Fatalf("Expected len %d but found %d", getPacketLen(int64(len(input))), len(sealed)) 144 } 145 } 146 } 147 148 func TestWholeRoundtrips(t *testing.T) { 149 for _, input := range plaintextInputs { 150 sealed := zeroSealWhole([]byte(input)) 151 opened, err := zeroOpenWhole(sealed) 152 if err != nil { 153 t.Fatal(err) 154 } 155 if !bytes.Equal([]byte(input), opened) { 156 t.Fatal("opened bytes don't equal the input") 157 } 158 159 if int64(len(sealed)) != GetSealedSize(int64(len(input))) { 160 t.Fatalf("Expected len %d but found %d", GetSealedSize(int64(len(input))), len(sealed)) 161 } 162 } 163 } 164 165 func TestByteAtATimeRoundtrips(t *testing.T) { 166 for _, input := range plaintextInputs { 167 encoder := zeroEncoder() 168 var sealed []byte 169 for i := 0; i < len(input); i++ { 170 output := encoder.Write([]byte{input[i]}) 171 sealed = append(sealed, output...) 172 } 173 lastOutput := encoder.Finish() 174 sealed = append(sealed, lastOutput...) 175 176 var opened []byte 177 decoder := zeroDecoder() 178 for i := 0; i < len(sealed); i++ { 179 output, err := decoder.Write([]byte{sealed[i]}) 180 if err != nil { 181 t.Fatal(err) 182 } 183 opened = append(opened, output...) 184 } 185 lastOutput, err := decoder.Finish() 186 if err != nil { 187 t.Fatal(err) 188 } 189 opened = append(opened, lastOutput...) 190 if !bytes.Equal([]byte(input), opened) { 191 t.Fatal("opened bytes don't equal the input") 192 } 193 194 if int64(len(sealed)) != GetSealedSize(int64(len(input))) { 195 t.Fatalf("Expected len %d but found %d", GetSealedSize(int64(len(input))), len(sealed)) 196 } 197 } 198 } 199 200 func TestReaderWrapperRoundtrips(t *testing.T) { 201 for _, input := range plaintextInputs { 202 inputBuffer := bytes.NewBuffer([]byte(input)) 203 encodingReader := NewEncodingReader( 204 zeroSecretboxKey(), 205 zeroSignKey(), 206 testingPrefix(), 207 zeroNonce(), 208 inputBuffer) 209 encoded, err := io.ReadAll(encodingReader) 210 if err != nil { 211 t.Fatalf("errors shouldn't be possible for encoding: %s", err) 212 } 213 encodedBuffer := bytes.NewBuffer(encoded) 214 decodingReader := NewDecodingReader( 215 zeroSecretboxKey(), 216 zeroVerifyKey(), 217 testingPrefix(), 218 zeroNonce(), 219 encodedBuffer) 220 decoded, err := io.ReadAll(decodingReader) 221 if err != nil { 222 t.Fatalf("error during decoding: %s", err) 223 } 224 if !bytes.Equal([]byte(input), decoded) { 225 t.Fatal("decoded bytes don't equal the input") 226 } 227 if int64(len(encoded)) != GetSealedSize(int64(len(input))) { 228 t.Fatalf("Expected encoded len %d but found %d", GetSealedSize(int64(len(input))), len(encoded)) 229 } 230 } 231 } 232 233 func TestBadSecretbox(t *testing.T) { 234 // Test several different cases. First, a secretbox that's too short to even 235 // contain an authenticator (just one byte for the secretbox). 236 shortPacket := []byte{0xc6, 0, 0, 0, 1, 42} 237 _, err := openPacket(shortPacket, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroChunkNonce(0)) 238 assertErrorType(t, err, BadSecretbox) 239 240 // Then also test a secretbox that's long enough to be real, but has an 241 // invalid authenticator (just a bunch of constant bytes). 242 badAuthenticatorPacket := []byte{0xc6, 0, 0, 0, 100} 243 for i := 0; i < 100; i++ { 244 badAuthenticatorPacket = append(badAuthenticatorPacket, 42) 245 } 246 _, err = openPacket(badAuthenticatorPacket, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroChunkNonce(0)) 247 assertErrorType(t, err, BadSecretbox) 248 249 // Test a correct packet opened with the wrong chunk number. 250 var rightChunkNum uint64 = 5 251 var wrongChunkNum uint64 = 6 252 correctPacket := sealPacket([]byte{}, zeroSecretboxKey(), zeroSignKey(), testingPrefix(), zeroChunkNonce(rightChunkNum)) 253 _, err = openPacket(correctPacket, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroChunkNonce(wrongChunkNum)) 254 assertErrorType(t, err, BadSecretbox) 255 } 256 257 func TestShortSignature(t *testing.T) { 258 // Signatures are 64 bytes, so this slice is too short to be one. 259 shortSignedChunk := []byte{1, 2, 3, 4, 5, 6, 7} 260 var chunkNum uint64 = 999 261 chunkNonce := makeChunkNonce(zeroNonce(), chunkNum) 262 packet := secretbox.Seal(nil, shortSignedChunk, chunkNonce, zeroSecretboxKey()) 263 _, err := openPacket(packet, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroChunkNonce(chunkNum)) 264 assertErrorType(t, err, ShortSignature) 265 } 266 267 func TestInvalidSignature(t *testing.T) { 268 // A chunk that's long enough to contain a signature, but isn't valid (just 269 // a bunch of zeroes). 270 invalidSignedChunk := bytes.Repeat([]byte{42}, 100) 271 var chunkNum uint64 = 999 272 chunkNonce := makeChunkNonce(zeroNonce(), chunkNum) 273 packet := secretbox.Seal(nil, invalidSignedChunk, chunkNonce, zeroSecretboxKey()) 274 _, err := openPacket(packet, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), zeroChunkNonce(chunkNum)) 275 assertErrorType(t, err, BadSignature) 276 } 277 278 func TestErrorsReturnedFromDecoder(t *testing.T) { 279 // We need bad bytes long enough to trigger an open. This indirectly tests 280 // that the exact packet length is enough for that. 281 badPacket := bytes.Repeat([]byte{0}, int(getPacketLen(DefaultPlaintextChunkLength))) 282 decoder := zeroDecoder() 283 _, err := decoder.Write(badPacket) 284 assertErrorType(t, err, BadSecretbox) 285 286 // Make sure we get the same error again for any subsequent writes, even 287 // empty ones. 288 _, err = decoder.Write([]byte{}) 289 assertErrorType(t, err, BadSecretbox) 290 291 // And also for Finish(). 292 _, err = decoder.Finish() 293 assertErrorType(t, err, BadSecretbox) 294 295 // And make sure we get the same error independently for an all at once 296 // decode. 297 _, err = zeroOpenWhole(badPacket) 298 assertErrorType(t, err, BadSecretbox) 299 } 300 301 func TestErrorsReturnedFromDecoderDuringFinish(t *testing.T) { 302 // There are two errors that might have to be returned by OpenWhole. This 303 // tests the second path, where an error occurs first during Finish(). 304 badSealed := zeroSealWhole([]byte("foobar")) 305 // Flip the very last bit. 306 badSealed[len(badSealed)-1] ^= 1 307 _, err := zeroOpenWhole(badSealed) 308 assertErrorType(t, err, BadSecretbox) 309 } 310 311 func throwawayBuffer() []byte { 312 var buf [4096]byte 313 return buf[:] 314 } 315 316 // Similar to TestErrorsReturnedFromDecoder above, but for the reader. 317 func TestErrorsReturnedFromDecodingReader(t *testing.T) { 318 badPacket := bytes.Repeat([]byte{0}, int(getPacketLen(DefaultPlaintextChunkLength))) 319 reader := NewDecodingReader( 320 zeroSecretboxKey(), 321 zeroVerifyKey(), 322 testingPrefix(), 323 zeroNonce(), 324 bytes.NewBuffer(badPacket)) 325 n, err := reader.Read(throwawayBuffer()) 326 require.Equal(t, n, 0) 327 assertErrorType(t, err, BadSecretbox) 328 329 // Make sure we get the same error again for any subsequent reads, even 330 // empty ones. 331 n, err = reader.Read(throwawayBuffer()) 332 require.Equal(t, n, 0) 333 assertErrorType(t, err, BadSecretbox) 334 } 335 336 // Similar to TestErrorsReturnedFromDecoderDuringFinish above, but for the reader. 337 func TestErrorsReturnedFromReadingDecoderDuringFinish(t *testing.T) { 338 badSealed := zeroSealWhole([]byte("foobar")) 339 // Flip the very last bit. 340 badSealed[len(badSealed)-1] ^= 1 341 reader := NewDecodingReader( 342 zeroSecretboxKey(), 343 zeroVerifyKey(), 344 testingPrefix(), 345 zeroNonce(), 346 bytes.NewBuffer(badSealed)) 347 n, err := reader.Read(throwawayBuffer()) 348 require.Equal(t, n, 0) 349 assertErrorType(t, err, BadSecretbox) 350 } 351 352 func TestReencryptedPacketFails(t *testing.T) { 353 // Make sure that a packet can't be (legitimately) decrypted and then 354 // (illegitimately) reencrypted for another symmetric key, or with any 355 // other modified encryption metadata. This isn't proof that someone can't 356 // break the format in some clever way, but it's a sanity check that we're 357 // preventing at least the attacks we think we are. 358 359 // First create a valid packet. 360 var originalChunkNum uint64 // = 0, but lint doesn't let us write it :p 361 originalNonce := zeroNonce() 362 originalEncryptionKey := zeroSecretboxKey() 363 originalSignKey := zeroSignKey() 364 originalVerifyKey := zeroVerifyKey() 365 packet := sealPacket([]byte("foo"), originalEncryptionKey, originalSignKey, testingPrefix(), makeChunkNonce(originalNonce, originalChunkNum)) 366 367 // Now strip off the outer layer of encryption, as a recipient would. 368 originalChunkNonce := makeChunkNonce(originalNonce, originalChunkNum) 369 unboxedSig, valid := secretbox.Open(nil, packet, originalChunkNonce, originalEncryptionKey) 370 if !valid { 371 t.Fatal("expected this secretbox to open cleanly") 372 } 373 374 // Here's the attack: reencrypt the packet under a *different* key. 375 newEncryptionKey := zeroSecretboxKey() 376 newEncryptionKey[0] = 42 377 rekeyedPacket := secretbox.Seal(nil, unboxedSig, originalChunkNonce, newEncryptionKey) 378 379 // This new packet will have a bad secretbox if someone tries to decrypt it 380 // with the old key, of course. 381 _, err := openPacket(rekeyedPacket, originalEncryptionKey, originalVerifyKey, testingPrefix(), makeChunkNonce(originalNonce, originalChunkNum)) 382 assertErrorType(t, err, BadSecretbox) 383 384 // And here's the part we really care about: If someone tries to decrypt 385 // the packet with the *new* key, unboxing will succeed, but it should now 386 // give a bad *signature* error. This is the whole point of asserting the 387 // symmetric key inside the sig. 388 _, err = openPacket(rekeyedPacket, newEncryptionKey, originalVerifyKey, testingPrefix(), makeChunkNonce(originalNonce, originalChunkNum)) 389 assertErrorType(t, err, BadSignature) 390 391 // Another test along the same lines: it should also be a signature error if the chunk number changes. 392 var newChunkNum uint64 = 1 393 newChunkNumNonce := makeChunkNonce(originalNonce, newChunkNum) 394 renumberedPacket := secretbox.Seal(nil, unboxedSig, newChunkNumNonce, originalEncryptionKey) 395 _, err = openPacket(renumberedPacket, originalEncryptionKey, originalVerifyKey, testingPrefix(), makeChunkNonce(originalNonce, newChunkNum)) 396 assertErrorType(t, err, BadSignature) 397 398 // And: it should be a signature error if the caller's nonce changes. 399 newNonce := zeroNonce() 400 newNonce[0] = 42 401 newChunkNonce := makeChunkNonce(newNonce, originalChunkNum) 402 renoncedPacket := secretbox.Seal(nil, unboxedSig, newChunkNonce, originalEncryptionKey) 403 _, err = openPacket(renoncedPacket, originalEncryptionKey, originalVerifyKey, testingPrefix(), makeChunkNonce(newNonce, originalChunkNum)) 404 assertErrorType(t, err, BadSignature) 405 } 406 407 func TestTruncatedFails(t *testing.T) { 408 // Another sanity check test. This isn't proof that truncation is always 409 // detectable, but it exercises the simplest cases. 410 411 // One full packet's worth and then a little bit more. 412 plaintext := bytes.Repeat([]byte{0}, int(DefaultPlaintextChunkLength+42)) 413 sealed := zeroSealWhole(plaintext) 414 415 // Try truncating in the middle of a packet. 416 truncated := sealed[:999] 417 _, err := zeroOpenWhole(truncated) 418 assertErrorType(t, err, BadSecretbox) 419 420 // And try truncating at the first packet boundary. We still expect a 421 // BadSecretbox error, because secretbox.Open will fail on an empty slice. 422 packetLen := getPacketLen(DefaultPlaintextChunkLength) 423 truncated = sealed[:packetLen] 424 _, err = zeroOpenWhole(truncated) 425 assertErrorType(t, err, BadSecretbox) 426 } 427 428 func TestPacketSwapInOneMessageFails(t *testing.T) { 429 // Another sanity check test. This isn't proof that swapping is always 430 // detectable, but it exercises the simplest cases. 431 432 // Two full packets' worth. 433 plaintext := bytes.Repeat([]byte{0}, int(DefaultPlaintextChunkLength*2)) 434 sealed := zeroSealWhole(plaintext) 435 436 // Swap the first two packets. Make sure to make *copies* of both packets, 437 // or else the second swap will be a no-op. 438 packetLen := getPacketLen(DefaultPlaintextChunkLength) 439 packet1 := append([]byte{}, sealed[:packetLen]...) 440 packet2 := append([]byte{}, sealed[packetLen:2*packetLen]...) 441 copy(sealed, packet2) 442 copy(sealed[packetLen:], packet1) 443 444 // This should break both decoding. 445 _, err := zeroOpenWhole(sealed) 446 assertErrorType(t, err, BadSecretbox) 447 } 448 449 func TestPacketSwapBetweenMessagesFails(t *testing.T) { 450 // Another sanity check test. This isn't proof that swapping is always 451 // detectable, but it exercises the simplest cases. 452 453 // One full packet's worth and then a little bit more. 454 plaintext1 := bytes.Repeat([]byte{1}, int(DefaultPlaintextChunkLength+42)) 455 sealed1 := zeroSealWhole(plaintext1) 456 457 // Encrypt another same plaintext with a different nonce. (If we used the 458 // same nonce, packet swapping *would* be possible, not to mention all the 459 // crypto would be ruined.) 460 plaintext2 := bytes.Repeat([]byte{2}, int(DefaultPlaintextChunkLength+42)) 461 var nonce2 [16]byte 462 nonce2[0] = 42 463 sealed2 := SealWhole(plaintext2, zeroSecretboxKey(), zeroSignKey(), testingPrefix(), &nonce2) 464 465 // Swap the first packet between them. Make sure to make *copies* and not 466 // just slices, or else the second swap will be a no-op. 467 packetLen := getPacketLen(DefaultPlaintextChunkLength) 468 firstPacket1 := append([]byte{}, sealed1[:packetLen]...) 469 firstPacket2 := append([]byte{}, sealed2[:packetLen]...) 470 copy(sealed1, firstPacket2) 471 copy(sealed2, firstPacket1) 472 473 // This should break both messages. 474 _, err := zeroOpenWhole(sealed1) 475 assertErrorType(t, err, BadSecretbox) 476 _, err = OpenWhole(sealed2, zeroSecretboxKey(), zeroVerifyKey(), testingPrefix(), &nonce2) 477 assertErrorType(t, err, BadSecretbox) 478 } 479 480 // This type returns a random error the first time you Read from it, and then 481 // defers to the inner reader for every read after that. 482 type FakeIOErrorReader struct { 483 inner io.Reader 484 returnedErrorAlready bool 485 } 486 487 var _ io.Reader = (*FakeIOErrorReader)(nil) 488 489 var fakeErrorString = "random error for the first read" 490 491 func (f *FakeIOErrorReader) Read(buf []byte) (int, error) { 492 if !f.returnedErrorAlready { 493 f.returnedErrorAlready = true 494 return 0, fmt.Errorf(fakeErrorString) 495 } 496 return f.inner.Read(buf) 497 } 498 499 func TestTransientIOErrorsInReaderWrappers(t *testing.T) { 500 // If our DecodingReader gets a decryption error, it'll give up and fail 501 // forever. But if either reader gets an IO error from its inner reader, it 502 // should be willing to retry. Simulate this case on both ends, with a 503 // FakeIOErrorReader that returns a Read error one time and then returns 504 // real bytes on subsequent calls. 505 506 plaintext := []byte("foo") 507 plaintextBuf := bytes.NewBuffer(plaintext) 508 fakePlaintextErrorReader := &FakeIOErrorReader{inner: plaintextBuf} 509 encodingReader := NewEncodingReader( 510 zeroSecretboxKey(), 511 zeroSignKey(), 512 testingPrefix(), 513 zeroNonce(), 514 fakePlaintextErrorReader) 515 516 // The first read is an error. 517 n, err := encodingReader.Read(throwawayBuffer()) 518 if n != 0 { 519 t.Fatalf("Expected 0 bytes, but received %d", n) 520 } 521 if err.Error() != fakeErrorString { 522 t.Fatalf("Expected a fake error, but found: %s", err) 523 } 524 525 // Subsequent reads should succeed. 526 encoded, err := io.ReadAll(encodingReader) 527 if err != nil { 528 t.Fatalf("no more errors expected during encoding, but found: %s", err) 529 } 530 531 // Similar test for the decoder. 532 encodedBuffer := bytes.NewBuffer(encoded) 533 fakeCiphertextErrorReader := &FakeIOErrorReader{inner: encodedBuffer} 534 decodingReader := NewDecodingReader( 535 zeroSecretboxKey(), 536 zeroVerifyKey(), 537 testingPrefix(), 538 zeroNonce(), 539 fakeCiphertextErrorReader) 540 541 // Again, the first read is an error. 542 n, err = decodingReader.Read(throwawayBuffer()) 543 if n != 0 { 544 t.Fatalf("Expected 0 bytes, but received %d", n) 545 } 546 if err.Error() != fakeErrorString { 547 t.Fatalf("Expected a fake error, but found: %s", err) 548 } 549 550 // And again, subsequent reads should succeed. 551 decoded, err := io.ReadAll(decodingReader) 552 if err != nil { 553 t.Fatalf("no more errors expected during decoding, but found: %s", err) 554 } 555 if !bytes.Equal(plaintext, decoded) { 556 t.Fatal("decoded bytes don't equal the input") 557 } 558 } 559 560 func shouldPanic(t *testing.T, f func()) { 561 defer func() { 562 err := recover() 563 require.NotNil(t, err) 564 }() 565 f() 566 } 567 568 func TestCoverageHacks(t *testing.T) { 569 // Deliberately hit lines that don't/can't come up in normal execution. 570 571 err := NewError(BadSecretbox, "blah blah blah") 572 _ = err.Error() 573 574 encoder := Encoder{} 575 encoder.ChangePlaintextChunkLenForTesting(42) 576 // Try to seal a packet longer than the internal buffer. 577 shouldPanic(t, func() { 578 encoder.sealOnePacket(999) 579 }) 580 // Try to Finish with too much data in the buffer. 581 encoder.buf = bytes.Repeat([]byte{0}, 999) 582 shouldPanic(t, func() { 583 encoder.Finish() 584 }) 585 586 decoder := Decoder{} 587 decoder.ChangePlaintextChunkLenForTesting(42) 588 // Try to open a packet longer than the internal buffer. 589 shouldPanic(t, func() { 590 _, _ = decoder.openOnePacket(999) 591 }) 592 // Try to Finish with too much data in the buffer. 593 decoder.buf = bytes.Repeat([]byte{0}, 999) 594 shouldPanic(t, func() { 595 _, _ = decoder.Finish() 596 }) 597 } 598 599 func TestNullInPrefix(t *testing.T) { 600 encoder := NewEncoder(zeroSecretboxKey(), zeroSignKey(), kbcrypto.SignaturePrefix("Keybase-bad-prefix\x00"), zeroNonce()) 601 encoder.Write([]byte("kaboom")) 602 shouldPanic(t, func() { 603 encoder.Finish() 604 }) 605 } 606 607 func TestPrefixDifference(t *testing.T) { 608 // Test that different prefixes fail verification 609 for index, input := range plaintextInputs { 610 // Vary the chunk number, just for fun. 611 chunkNum := uint64(index) 612 sealed := sealPacket( 613 []byte(input), 614 zeroSecretboxKey(), 615 zeroSignKey(), 616 testingPrefix(), 617 zeroChunkNonce(chunkNum)) 618 619 // Use the correct prefix 620 opened, err := openPacket( 621 sealed, 622 zeroSecretboxKey(), 623 zeroVerifyKey(), 624 testingPrefix(), 625 zeroChunkNonce(chunkNum)) 626 if err != nil { 627 t.Fatal(err) 628 } 629 if !bytes.Equal([]byte(input), opened) { 630 t.Fatal("opened bytes don't equal the input") 631 } 632 633 // Use the wrong prefix 634 _, err = openPacket( 635 sealed, 636 zeroSecretboxKey(), 637 zeroVerifyKey(), 638 testingPrefix()+"other", 639 zeroChunkNonce(chunkNum)) 640 assertErrorType(t, err, BadSignature) 641 } 642 } 643 644 func TestVectors(t *testing.T) { 645 if len(testVectors) < 1 { 646 t.Fatalf("missing test vectors") 647 } 648 649 for i, v := range testVectors { 650 if !v.chunked { 651 t.Fatalf("i%d: non-chunked tests not supported yet", i) 652 } 653 sealedRef, err := hex.DecodeString(v.sealedHex) 654 if err != nil { 655 t.Fatalf("i:%d sealedHex is invalid hex: %v", i, err) 656 } 657 658 // Test seal 659 encoder := zeroEncoder() 660 encoder.Write([]byte(v.plaintext)) 661 sealed := encoder.Finish() 662 if !bytes.Equal(sealedRef, sealed) { 663 t.Fatalf("i:%d sealed bytes not equal\n got: %x\nexpected: %x", i, sealed, sealedRef) 664 } 665 666 // Test open 667 decoder := zeroDecoder() 668 _, err = decoder.Write(sealedRef) 669 require.NoError(t, err) 670 opened, err := decoder.Finish() 671 if err != nil { 672 t.Fatalf("i:%d error opening: %v", i, err) 673 } 674 if !bytes.Equal([]byte(v.plaintext), opened) { 675 t.Fatalf("i:%d opened bytes not equal\n got: %x\nexpected: %x", i, opened, v.plaintext) 676 } 677 } 678 } 679 680 var testVectors = []struct { 681 chunked bool 682 plaintext string 683 sealedHex string 684 }{ 685 { 686 chunked: true, 687 plaintext: `The KID format 688 689 Version 1 of Keybase KIDs are 35-bytes long, and take the form: 690 691 ┌──────────┬──────────┬─────────────────────────────────┬──────────────┐ 692 │ version │ key type │ payload │ '0a' trailer │ 693 │ (1 byte) │ (1 byte) │ (32 bytes) │ (1 byte) │ 694 └──────────┴──────────┴─────────────────────────────────┴──────────────┘ 695 The fields are described as follows: 696 `, 697 sealedHex: `9c488f76be8f8f5eb84e37737017ce5dc92ea5c4752b6af99dd17df6f71d625252344511a903d0a8bfeac4574c52c1ecdfdba71beb95c8d9b60e0bd1bb4c4f83742d7b46c7d827c6a79397cd4dedd8a52d769e92798608a4389f46722f4f45391862a323f3006ec74f1b9d92d709291a17216119445b1dce49912f59b00eeb74af2e6779623de2b5d8e229bc2934dbf8d98c5dfd558dca8080fad3bf217e25f313ddaa3cc0cb193cd7561d8be207aa11b44822b6fd80dabcb817683883c44ee5cab7390ce13103cd098c5f7a9c2e36bf62462d163fbd78efb429e90f141d579f01eeeb33713c40b86069da04d53f9aa33ecadd7af28556573e76a11b88d27253cd90f743b3c8087bbdf18b1f3f3b8d1d7adc15f0a4021590812b822b9d38e6e79a59168dfb51be1ded8c47cc228b59d75ea1e1f61f7a26fb6d0e4992cffb0cf4709e3d9f9ad6252719fa795acc8f71bacf3e32bcf35b55f899d3768eb3dc5147eb96dd8c09f7818487bc5ab15d3d0ded506bc596a0a182236138010e28cda2e1dd63cf6706707888174562949bc6a75aa22823c4a82ecfec3ae30b1081465d46c3596c21017520f7ef2b63b7a7b733f2b32a7f00746dba953805048ef2af1cab77eb12c29227f42aaaedc2c394120fde461ab6c078b503fcaa73f20be05bef9c5e6718d49904295fc32f753316789cb61a65507ba8800eac82856dda77cfd961518887caeda8ccce8b16e2750911272daccff1c9a104a1481552d8340975ee6fe9c9e371a7053267b67ef97903d9f4a8071f85667f67cc09730e0789c3e230f529d1c4caeb047642e225063d5c305a1d03a1941c18f15b9e36692e41bf3340f1e9876db480974cbf41eedaaacd01ca6d62d270f4c8f0df25c1d781b1eaeac0b1d3887fd5e07f12c5bf576fe1e99471c8894f8981d0fb86e7ac860f9b2da2e0654520ac9b53cf3949a01d5866a06f7d8ad8865042d96d2cae118f9ab5980ada48a720e47b0ade9e984ef2e12904ca41ef30f2ff0464107042aca152ffd5b7081fd481fe76aa23f04d840f43a6e2f17ae5dea74298730c7ffce42bafe108cc70b5839a9ebb28cd8318d03529d680d75a68cc3dbf261c43eebc698bcf4c6f90`, 698 }, 699 } 700 701 func TestAssociatedData(t *testing.T) { 702 for _, associatedData := range associatedDataInputs { 703 for _, input := range plaintextInputs { 704 sealed := zeroSealWithAssociatedData([]byte(input), associatedData) 705 opened, err := zeroOpenWithAssociatedData(sealed, associatedData) 706 if err != nil { 707 t.Fatal(err) 708 } 709 if !bytes.Equal([]byte(input), opened) { 710 t.Fatal("opened bytes don't equal the input") 711 } 712 } 713 } 714 715 plaintext := "This is one time where television really fails to capture the true excitement of a large squirrel predicting the weather." 716 associatedData := "groundhog day" 717 sealed := zeroSealWithAssociatedData([]byte(plaintext), associatedData) 718 opened, err := zeroOpenWithAssociatedData(sealed, associatedData) 719 require.NoError(t, err) 720 require.Equal(t, opened, []byte(plaintext)) 721 // tweaking the associated data should fail to open 722 incorrectAssociatedData := "groundhog day 2, the repeatening" 723 opened, err = zeroOpenWithAssociatedData(sealed, incorrectAssociatedData) 724 require.True(t, bytes.Equal(opened, []byte{})) 725 assertErrorType(t, err, AssociatedDataMismatch) 726 }