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