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┌──────────┬──────────┬─────────────────────────────────┬──────────────┐
693versionkey typepayload'0a' trailer694│ (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