1// +build go1.9
2
3package s3crypto
4
5import (
6	"bytes"
7	"encoding/hex"
8	"encoding/json"
9	"fmt"
10	"io"
11	"io/ioutil"
12	"strings"
13	"testing"
14)
15
16// AES GCM
17func TestAES_GCM_NIST_gcmEncryptExtIV256_PTLen_128_Test_0(t *testing.T) {
18	iv, _ := hex.DecodeString("0d18e06c7c725ac9e362e1ce")
19	key, _ := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
20	plaintext, _ := hex.DecodeString("2db5168e932556f8089a0622981d017d")
21	expected, _ := hex.DecodeString("fa4362189661d163fcd6a56d8bf0405a")
22	tag, _ := hex.DecodeString("d636ac1bbedd5cc3ee727dc2ab4a9489")
23	aesgcmTest(t, iv, key, plaintext, expected, tag)
24}
25
26func TestAES_GCM_NIST_gcmEncryptExtIV256_PTLen_104_Test_3(t *testing.T) {
27	iv, _ := hex.DecodeString("4742357c335913153ff0eb0f")
28	key, _ := hex.DecodeString("e5a0eb92cc2b064e1bc80891faf1fab5e9a17a9c3a984e25416720e30e6c2b21")
29	plaintext, _ := hex.DecodeString("8499893e16b0ba8b007d54665a")
30	expected, _ := hex.DecodeString("eb8e6175f1fe38eb1acf95fd51")
31	tag, _ := hex.DecodeString("88a8b74bb74fda553e91020a23deed45")
32	aesgcmTest(t, iv, key, plaintext, expected, tag)
33}
34
35func TestAES_GCM_NIST_gcmEncryptExtIV256_PTLen_256_Test_6(t *testing.T) {
36	iv, _ := hex.DecodeString("a291484c3de8bec6b47f525f")
37	key, _ := hex.DecodeString("37f39137416bafde6f75022a7a527cc593b6000a83ff51ec04871a0ff5360e4e")
38	plaintext, _ := hex.DecodeString("fafd94cede8b5a0730394bec68a8e77dba288d6ccaa8e1563a81d6e7ccc7fc97")
39	expected, _ := hex.DecodeString("44dc868006b21d49284016565ffb3979cc4271d967628bf7cdaf86db888e92e5")
40	tag, _ := hex.DecodeString("01a2b578aa2f41ec6379a44a31cc019c")
41	aesgcmTest(t, iv, key, plaintext, expected, tag)
42}
43
44func TestAES_GCM_NIST_gcmEncryptExtIV256_PTLen_408_Test_8(t *testing.T) {
45	iv, _ := hex.DecodeString("92f258071d79af3e63672285")
46	key, _ := hex.DecodeString("595f259c55abe00ae07535ca5d9b09d6efb9f7e9abb64605c337acbd6b14fc7e")
47	plaintext, _ := hex.DecodeString("a6fee33eb110a2d769bbc52b0f36969c287874f665681477a25fc4c48015c541fbe2394133ba490a34ee2dd67b898177849a91")
48	expected, _ := hex.DecodeString("bbca4a9e09ae9690c0f6f8d405e53dccd666aa9c5fa13c8758bc30abe1ddd1bcce0d36a1eaaaaffef20cd3c5970b9673f8a65c")
49	tag, _ := hex.DecodeString("26ccecb9976fd6ac9c2c0f372c52c821")
50	aesgcmTest(t, iv, key, plaintext, expected, tag)
51}
52
53type KAT struct {
54	IV         string `json:"iv"`
55	Key        string `json:"key"`
56	Plaintext  string `json:"pt"`
57	AAD        string `json:"aad"`
58	CipherText string `json:"ct"`
59	Tag        string `json:"tag"`
60}
61
62func TestAES_GCM_KATS(t *testing.T) {
63	fileContents, err := ioutil.ReadFile("testdata/aes_gcm.json")
64	if err != nil {
65		t.Fatalf("failed to read KAT file: %v", err)
66	}
67
68	var kats []KAT
69	err = json.Unmarshal(fileContents, &kats)
70	if err != nil {
71		t.Fatalf("failed to unmarshal KAT json file: %v", err)
72	}
73
74	for i, kat := range kats {
75		t.Run(fmt.Sprintf("Case%d", i), func(t *testing.T) {
76			if len(kat.AAD) > 0 {
77				t.Skip("Skipping... SDK implementation does not expose additional authenticated data")
78			}
79			iv, err := hex.DecodeString(kat.IV)
80			if err != nil {
81				t.Fatalf("failed to decode iv: %v", err)
82			}
83			key, err := hex.DecodeString(kat.Key)
84			if err != nil {
85				t.Fatalf("failed to decode key: %v", err)
86			}
87			plaintext, err := hex.DecodeString(kat.Plaintext)
88			if err != nil {
89				t.Fatalf("failed to decode plaintext: %v", err)
90			}
91			ciphertext, err := hex.DecodeString(kat.CipherText)
92			if err != nil {
93				t.Fatalf("failed to decode ciphertext: %v", err)
94			}
95			tag, err := hex.DecodeString(kat.Tag)
96			if err != nil {
97				t.Fatalf("failed to decode tag: %v", err)
98			}
99			aesgcmTest(t, iv, key, plaintext, ciphertext, tag)
100		})
101	}
102}
103
104func TestGCMEncryptReader_SourceError(t *testing.T) {
105	gcm := &gcmEncryptReader{
106		encrypter: &mockCipherAEAD{},
107		src:       &mockSourceReader{err: fmt.Errorf("test read error")},
108	}
109
110	b := make([]byte, 10)
111	n, err := gcm.Read(b)
112	if err == nil {
113		t.Fatalf("expected error, but got nil")
114	} else if err != nil && !strings.Contains(err.Error(), "test read error") {
115		t.Fatalf("expected source read error, but got %v", err)
116	}
117
118	if n != 0 {
119		t.Errorf("expected number of read bytes to be zero, but got %v", n)
120	}
121}
122
123func TestGCMDecryptReader_SourceError(t *testing.T) {
124	gcm := &gcmDecryptReader{
125		decrypter: &mockCipherAEAD{},
126		src:       &mockSourceReader{err: fmt.Errorf("test read error")},
127	}
128
129	b := make([]byte, 10)
130	n, err := gcm.Read(b)
131	if err == nil {
132		t.Fatalf("expected error, but got nil")
133	} else if err != nil && !strings.Contains(err.Error(), "test read error") {
134		t.Fatalf("expected source read error, but got %v", err)
135	}
136
137	if n != 0 {
138		t.Errorf("expected number of read bytes to be zero, but got %v", n)
139	}
140}
141
142func TestGCMDecryptReader_DecrypterOpenError(t *testing.T) {
143	gcm := &gcmDecryptReader{
144		decrypter: &mockCipherAEAD{openError: fmt.Errorf("test open error")},
145		src:       &mockSourceReader{err: io.EOF},
146	}
147
148	b := make([]byte, 10)
149	n, err := gcm.Read(b)
150	if err == nil {
151		t.Fatalf("expected error, but got nil")
152	} else if err != nil && !strings.Contains(err.Error(), "test open error") {
153		t.Fatalf("expected source read error, but got %v", err)
154	}
155
156	if n != 0 {
157		t.Errorf("expected number of read bytes to be zero, but got %v", n)
158	}
159}
160
161func aesgcmTest(t *testing.T, iv, key, plaintext, expected, tag []byte) {
162	t.Helper()
163	const gcmTagSize = 16
164	cd := CipherData{
165		Key: key,
166		IV:  iv,
167	}
168	gcm, err := newAESGCM(cd)
169	if err != nil {
170		t.Errorf("expected no error, but received %v", err)
171	}
172
173	cipherdata := gcm.Encrypt(bytes.NewReader(plaintext))
174
175	ciphertext, err := ioutil.ReadAll(cipherdata)
176	if err != nil {
177		t.Errorf("expected no error, but received %v", err)
178	}
179
180	// splitting tag and ciphertext
181	etag := ciphertext[len(ciphertext)-gcmTagSize:]
182	if !bytes.Equal(etag, tag) {
183		t.Errorf("expected tags to be equivalent")
184	}
185	if !bytes.Equal(ciphertext[:len(ciphertext)-gcmTagSize], expected) {
186		t.Errorf("expected ciphertext to be equivalent")
187	}
188
189	data := gcm.Decrypt(bytes.NewReader(ciphertext))
190	text, err := ioutil.ReadAll(data)
191	if err != nil {
192		t.Errorf("expected no error, but received %v", err)
193	}
194	if !bytes.Equal(plaintext, text) {
195		t.Errorf("expected ciphertext to be equivalent")
196	}
197}
198
199type mockSourceReader struct {
200	n   int
201	err error
202}
203
204func (b mockSourceReader) Read(p []byte) (n int, err error) {
205	return b.n, b.err
206}
207
208type mockCipherAEAD struct {
209	seal      []byte
210	openError error
211}
212
213func (m mockCipherAEAD) NonceSize() int {
214	panic("implement me")
215}
216
217func (m mockCipherAEAD) Overhead() int {
218	panic("implement me")
219}
220
221func (m mockCipherAEAD) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
222	return m.seal
223}
224
225func (m mockCipherAEAD) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
226	return []byte("mocked decrypt"), m.openError
227}
228