1// aes_test.go - AES tests.
2//
3// To the extent possible under law, Yawning Angel has waived all copyright
4// and related or neighboring rights to aes_test.go, using the Creative
5// Commons "CC0" public domain dedication. See LICENSE or
6// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
7
8package bsaes
9
10import (
11	"bytes"
12	"crypto/aes"
13	"crypto/cipher"
14	"crypto/rand"
15	"encoding/hex"
16	"fmt"
17	"math"
18	"testing"
19
20	"git.schwanenlied.me/yawning/bsaes.git/ct32"
21	"git.schwanenlied.me/yawning/bsaes.git/ct64"
22)
23
24type Impl struct {
25	name string
26	ctor func([]byte) cipher.Block
27}
28
29var (
30	implCt32    = &Impl{"ct32", ct32.NewCipher}
31	implCt64    = &Impl{"ct64", ct64.NewCipher}
32	implRuntime = &Impl{"runtime", func(k []byte) cipher.Block {
33		blk, err := NewCipher(k)
34		if err != nil {
35			panic("implRuntime: NewCipher failed: " + err.Error())
36		}
37		return blk
38	}}
39
40	impls      = []*Impl{implCt32, implCt64}
41	nativeImpl = implCt64
42)
43
44// The test vectors are shamelessly stolen from NIST Special Pub. 800-38A,
45// my tax dollars at work.
46//
47// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
48
49var ecbVectors = []struct {
50	key        string
51	plaintext  string
52	ciphertext string
53}{
54	// ECB-AES128
55	{
56		"2b7e151628aed2a6abf7158809cf4f3c",
57		"6bc1bee22e409f96e93d7e117393172a",
58		"3ad77bb40d7a3660a89ecaf32466ef97",
59	},
60	{
61		"2b7e151628aed2a6abf7158809cf4f3c",
62		"ae2d8a571e03ac9c9eb76fac45af8e51",
63		"f5d3d58503b9699de785895a96fdbaaf",
64	},
65	{
66		"2b7e151628aed2a6abf7158809cf4f3c",
67		"30c81c46a35ce411e5fbc1191a0a52ef",
68		"43b1cd7f598ece23881b00e3ed030688",
69	},
70	{
71		"2b7e151628aed2a6abf7158809cf4f3c",
72		"f69f2445df4f9b17ad2b417be66c3710",
73		"7b0c785e27e8ad3f8223207104725dd4",
74	},
75
76	// ECB-AES192
77	{
78		"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
79		"6bc1bee22e409f96e93d7e117393172a",
80		"bd334f1d6e45f25ff712a214571fa5cc",
81	},
82	{
83		"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
84		"ae2d8a571e03ac9c9eb76fac45af8e51",
85		"974104846d0ad3ad7734ecb3ecee4eef",
86	},
87	{
88		"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
89		"30c81c46a35ce411e5fbc1191a0a52ef",
90		"ef7afd2270e2e60adce0ba2face6444e",
91	},
92	{
93		"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
94		"f69f2445df4f9b17ad2b417be66c3710",
95		"9a4b41ba738d6c72fb16691603c18e0e",
96	},
97
98	// ECB-AES256
99	{
100		"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
101		"6bc1bee22e409f96e93d7e117393172a",
102		"f3eed1bdb5d2a03c064b5a7e3db181f8",
103	},
104	{
105		"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
106		"ae2d8a571e03ac9c9eb76fac45af8e51",
107		"591ccb10d410ed26dc5ba74a31362870",
108	},
109	{
110		"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
111		"30c81c46a35ce411e5fbc1191a0a52ef",
112		"b6ed21b99ca6f4f9f153e7b1beafed1d",
113	},
114	{
115		"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
116		"f69f2445df4f9b17ad2b417be66c3710",
117		"23304b7a39f9f3ff067d8d8f9e24ecc7",
118	},
119}
120
121func TestECB_SP800_38A(t *testing.T) {
122	for _, impl := range impls {
123		t.Logf("Testing implementation: %v\n", impl.name)
124		for i, vec := range ecbVectors {
125			key, err := hex.DecodeString(vec.key[:])
126			if err != nil {
127				t.Fatal(err)
128			}
129			pt, err := hex.DecodeString(vec.plaintext[:])
130			if err != nil {
131				t.Fatal(err)
132			}
133			ct, err := hex.DecodeString(vec.ciphertext[:])
134			if err != nil {
135				t.Fatal(err)
136			}
137
138			b := impl.ctor(key)
139
140			var dst [16]byte
141			b.Encrypt(dst[:], pt)
142			assertEqual(t, i, ct, dst[:])
143
144			b.Decrypt(dst[:], ct)
145			assertEqual(t, i, pt, dst[:])
146		}
147	}
148}
149
150var ctrVectors = []struct {
151	key        string
152	iv         string
153	plaintext  string
154	ciphertext string
155}{
156	// CTR-AES128
157	{
158		"2b7e151628aed2a6abf7158809cf4f3c",
159		"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
160		"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
161		"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
162	},
163	// CTR-AES192
164	{
165		"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
166		"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
167		"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
168		"1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
169	},
170	// CTR-AES256
171	{
172		"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
173		"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
174		"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
175		"601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
176	},
177}
178
179func TestCTR_SP800_38A(t *testing.T) {
180	for _, impl := range impls {
181		t.Logf("Testing implementation: %v\n", impl.name)
182		for i, vec := range ctrVectors {
183			key, err := hex.DecodeString(vec.key[:])
184			if err != nil {
185				t.Fatal(err)
186			}
187			iv, err := hex.DecodeString(vec.iv[:])
188			if err != nil {
189				t.Fatal(err)
190			}
191			ct, err := hex.DecodeString(vec.ciphertext[:])
192			if err != nil {
193				t.Fatal(err)
194			}
195			pt, err := hex.DecodeString(vec.plaintext[:])
196			if err != nil {
197				t.Fatal(err)
198			}
199
200			b := impl.ctor(key)
201			dst := make([]byte, len(ct))
202
203			ctr := cipher.NewCTR(b, iv)
204			ctr.XORKeyStream(dst, pt)
205			assertEqual(t, i, ct, dst)
206		}
207	}
208}
209
210func TestCTR_keystream(t *testing.T) {
211	var iv [16]byte
212
213	for _, impl := range impls {
214		strideSz := 0
215		switch impl.name {
216		case "ct32":
217			strideSz = 2 * 16
218		case "ct64":
219			strideSz = 4 * 16
220		case "runtime":
221			// The CTR tests are tailored towards the bsaes CTR
222			// so there is not much sense in testing `crypto/aes`'s,
223			// when it's using AES-NI and assembly.
224			t.Logf("Skipping CTR tests: %v\n", impl.name)
225			continue
226		default:
227			panic("unable to determine stride")
228		}
229		t.Logf("Testing implementation: %v\n", impl.name)
230
231		key := make([]byte, 16)
232		if _, err := rand.Read(key[:]); err != nil {
233			t.Error(err)
234			t.Fail()
235		}
236
237		for sz := 0; sz <= strideSz; sz++ {
238			blk := impl.ctor(key[:])
239			ctr := cipher.NewCTR(blk, iv[:])
240
241			refBlk, _ := aes.NewCipher(key[:])
242			refCtr := cipher.NewCTR(refBlk, iv[:])
243
244			n := sz + strideSz + sz
245			src := make([]byte, n)
246			dst := make([]byte, n)
247			check := make([]byte, n)
248
249			if _, err := rand.Read(src[:]); err != nil {
250				t.Error(err)
251				t.Fail()
252			}
253
254			ctr.XORKeyStream(dst, src[:sz])
255			ctr.XORKeyStream(dst[sz:], src[sz:sz+strideSz])
256			ctr.XORKeyStream(dst[sz+strideSz:], src[sz+strideSz:])
257
258			refCtr.XORKeyStream(check, src)
259			assertEqual(t, sz, check, dst)
260		}
261	}
262}
263
264var cbcDecVectors = []struct {
265	key        string
266	iv         string
267	ciphertext string
268	plaintext  string
269}{
270	// CBC-AES128
271	{
272		"2b7e151628aed2a6abf7158809cf4f3c",
273		"000102030405060708090a0b0c0d0e0f",
274		"7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7",
275		"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
276	},
277	// CBC-AES192
278	{
279		"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
280		"000102030405060708090a0b0c0d0e0f",
281		"4f021db243bc633d7178183a9fa071e8b4d9ada9ad7dedf4e5e738763f69145a571b242012fb7ae07fa9baac3df102e008b0e27988598881d920a9e64f5615cd",
282		"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
283	},
284	// CBC-AES256
285	{
286
287		"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
288		"000102030405060708090a0b0c0d0e0f",
289		"f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b",
290		"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
291	},
292}
293
294func TestCBCDecrypt_SP800_38A(t *testing.T) {
295	for _, impl := range impls {
296		t.Logf("Testing implementation: %v\n", impl.name)
297		for i, vec := range cbcDecVectors {
298			key, err := hex.DecodeString(vec.key[:])
299			if err != nil {
300				t.Fatal(err)
301			}
302			iv, err := hex.DecodeString(vec.iv[:])
303			if err != nil {
304				t.Fatal(err)
305			}
306			ct, err := hex.DecodeString(vec.ciphertext[:])
307			if err != nil {
308				t.Fatal(err)
309			}
310			pt, err := hex.DecodeString(vec.plaintext[:])
311			if err != nil {
312				t.Fatal(err)
313			}
314
315			b := impl.ctor(key)
316			dst := make([]byte, len(ct))
317
318			cbc := cipher.NewCBCDecrypter(b, iv)
319			cbc.CryptBlocks(dst, ct)
320			assertEqual(t, i, pt, dst)
321		}
322	}
323}
324
325var gcmVectors = []struct {
326	k  string
327	iv string
328	a  string
329	p  string
330	c  string
331	t  string
332}{
333	// GCM-AES128
334	{
335		"00000000000000000000000000000000",
336		"000000000000000000000000",
337		"",
338		"",
339		"",
340		"58e2fccefa7e3061367f1d57a4e7455a",
341	},
342	{
343		"00000000000000000000000000000000",
344		"000000000000000000000000",
345		"",
346		"00000000000000000000000000000000",
347		"0388dace60b6a392f328c2b971b2fe78",
348		"ab6e47d42cec13bdf53a67b21257bddf",
349	},
350	{
351		"feffe9928665731c6d6a8f9467308308",
352		"cafebabefacedbaddecaf888",
353		"",
354		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
355		"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
356		"4d5c2af327cd64a62cf35abd2ba6fab4",
357	},
358	{
359		"feffe9928665731c6d6a8f9467308308",
360		"cafebabefacedbaddecaf888",
361		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
362		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
363		"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
364		"5bc94fbc3221a5db94fae95ae7121a47",
365	},
366	{
367		"feffe9928665731c6d6a8f9467308308",
368		"cafebabefacedbad",
369		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
370		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
371		"61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
372		"3612d2e79e3b0785561be14aaca2fccb",
373	},
374	{
375		"feffe9928665731c6d6a8f9467308308",
376		"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
377		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
378		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
379		"8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
380		"619cc5aefffe0bfa462af43c1699d050",
381	},
382	// GCM-AES192
383	{
384		"000000000000000000000000000000000000000000000000",
385		"000000000000000000000000",
386		"",
387		"",
388		"",
389		"cd33b28ac773f74ba00ed1f312572435",
390	},
391	{
392		"000000000000000000000000000000000000000000000000",
393		"000000000000000000000000",
394		"",
395		"00000000000000000000000000000000",
396		"98e7247c07f0fe411c267e4384b0f600",
397		"2ff58d80033927ab8ef4d4587514f0fb",
398	},
399	{
400		"feffe9928665731c6d6a8f9467308308feffe9928665731c",
401		"cafebabefacedbaddecaf888",
402		"",
403		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
404		"3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
405		"9924a7c8587336bfb118024db8674a14",
406	},
407	{
408		"feffe9928665731c6d6a8f9467308308feffe9928665731c",
409		"cafebabefacedbaddecaf888",
410		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
411		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
412		"3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
413		"2519498e80f1478f37ba55bd6d27618c",
414	},
415	{
416		"feffe9928665731c6d6a8f9467308308feffe9928665731c",
417		"cafebabefacedbad",
418		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
419		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
420		"0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
421		"65dcc57fcf623a24094fcca40d3533f8",
422	},
423	{
424		"feffe9928665731c6d6a8f9467308308feffe9928665731c",
425		"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
426		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
427		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
428		"d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
429		"dcf566ff291c25bbb8568fc3d376a6d9",
430	},
431	// GCM-AES256
432	{
433		"0000000000000000000000000000000000000000000000000000000000000000",
434		"000000000000000000000000",
435		"",
436		"",
437		"",
438		"530f8afbc74536b9a963b4f1c4cb738b",
439	},
440	{
441		"0000000000000000000000000000000000000000000000000000000000000000",
442		"000000000000000000000000",
443		"",
444		"00000000000000000000000000000000",
445		"cea7403d4d606b6e074ec5d3baf39d18",
446		"d0d1c8a799996bf0265b98b5d48ab919",
447	},
448	{
449		"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
450		"cafebabefacedbaddecaf888",
451		"",
452		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
453		"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
454		"b094dac5d93471bdec1a502270e3cc6c",
455	},
456	{
457		"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
458		"cafebabefacedbaddecaf888",
459		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
460		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
461		"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
462		"76fc6ece0f4e1768cddf8853bb2d551b",
463	},
464	{
465		"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
466		"cafebabefacedbad",
467		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
468		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
469		"c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
470		"3a337dbf46a792c45e454913fe2ea8f2",
471	},
472	{
473		"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
474		"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
475		"feedfacedeadbeeffeedfacedeadbeefabaddad2",
476		"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
477		"5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
478		"a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
479	},
480}
481
482func TestGCM(t *testing.T) {
483	for _, impl := range impls {
484		t.Logf("Testing implementation: %v\n", impl.name)
485		for i, vec := range gcmVectors {
486			key, err := hex.DecodeString(vec.k[:])
487			if err != nil {
488				t.Fatal(err)
489			}
490			iv, err := hex.DecodeString(vec.iv[:])
491			if err != nil {
492				t.Fatal(err)
493			}
494			a, err := hex.DecodeString(vec.a[:])
495			if err != nil {
496				t.Fatal(err)
497			}
498			p, err := hex.DecodeString(vec.p[:])
499			if err != nil {
500				t.Fatal(err)
501			}
502			c, err := hex.DecodeString(vec.c[:])
503			if err != nil {
504				t.Fatal(err)
505			}
506			tag, err := hex.DecodeString(vec.t[:])
507			if err != nil {
508				t.Fatal(err)
509			}
510			sealOut := make([]byte, 0, len(c)+len(tag))
511			sealOut = append(sealOut, c...)
512			sealOut = append(sealOut, tag...)
513
514			b := impl.ctor(key[:])
515			g, err := cipher.NewGCMWithNonceSize(b, len(iv))
516			if err != nil {
517				t.Fatal(err)
518			}
519
520			ct := g.Seal(nil, iv, p, a)
521			assertEqual(t, i, sealOut, ct)
522
523			pt, err := g.Open(nil, iv, ct, a)
524			if err != nil {
525				t.Fatal(err)
526			}
527			assertEqual(t, i, p, pt)
528		}
529	}
530}
531
532func assertEqual(t *testing.T, idx int, expected, actual []byte) {
533	if !bytes.Equal(expected, actual) {
534		for i, v := range actual {
535			if expected[i] != v {
536				t.Errorf("[%d] first mismatch at offset: %d (%02x != %02x)", idx, i, expected[i], v)
537				break
538			}
539		}
540		t.Errorf("expected: %s", hex.Dump(expected))
541		t.Errorf("actual: %s", hex.Dump(actual))
542		t.FailNow()
543	}
544}
545
546var ecbBenchOutput [16]byte
547
548func doBenchECB(b *testing.B, impl *Impl, ksz int) {
549	var src, dst, check [16]byte
550
551	key := make([]byte, ksz)
552	if _, err := rand.Read(key[:]); err != nil {
553		b.Error(err)
554		b.Fail()
555	}
556
557	blk := impl.ctor(key[:])
558
559	b.SetBytes(16)
560	b.ResetTimer()
561	for i := 0; i < b.N; i++ {
562		b.StartTimer()
563		blk.Encrypt(dst[:], src[:])
564		b.StopTimer()
565
566		// Check forward/back because, why not.
567		blk.Decrypt(check[:], dst[:])
568		if !bytes.Equal(check[:], src[:]) {
569			b.Fatalf("decrypt produced invalid output")
570		}
571		copy(src[:], dst[:])
572	}
573	copy(ecbBenchOutput[:], dst[:])
574}
575
576var benchOutput []byte
577
578func doBenchCTR(b *testing.B, impl *Impl, ksz, n int) {
579	var iv [16]byte
580
581	key := make([]byte, ksz)
582	if _, err := rand.Read(key[:]); err != nil {
583		b.Error(err)
584		b.Fail()
585	}
586
587	blk := impl.ctor(key[:])
588	ctr := cipher.NewCTR(blk, iv[:])
589
590	src := make([]byte, n)
591	dst := make([]byte, n)
592
593	b.SetBytes(int64(n))
594	b.ResetTimer()
595	for i := 0; i < b.N; i++ {
596		ctr.XORKeyStream(dst, src)
597	}
598	benchOutput = dst
599}
600
601func doBenchCBC(b *testing.B, impl *Impl, ksz, n int) {
602	var iv [16]byte
603	key := make([]byte, ksz)
604
605	if _, err := rand.Read(key[:]); err != nil {
606		b.Error(err)
607		b.Fail()
608	}
609
610	blk := impl.ctor(key[:])
611	cbc := cipher.NewCBCDecrypter(blk, iv[:])
612
613	src := make([]byte, n)
614	dst := make([]byte, n)
615
616	b.SetBytes(int64(n))
617	b.ResetTimer()
618	for i := 0; i < b.N; i++ {
619		cbc.CryptBlocks(dst, src)
620	}
621	benchOutput = dst
622}
623
624func doBenchGCM(b *testing.B, impl *Impl, ksz, n int) {
625	var iv [96 / 8]byte
626	key := make([]byte, ksz)
627
628	if _, err := rand.Read(key[:]); err != nil {
629		b.Error(err)
630		b.Fail()
631	}
632
633	blk := impl.ctor(key[:])
634	gcm, err := cipher.NewGCM(blk)
635	if err != nil {
636		b.Error(err)
637		b.Fail()
638	}
639
640	src := make([]byte, n)
641	var dst []byte
642
643	b.SetBytes(int64(n))
644	b.ResetTimer()
645	for i := 0; i < b.N; i++ {
646		dst = gcm.Seal(nil, iv[:], src, nil)
647	}
648	benchOutput = dst
649}
650
651func implIsNative(impl *Impl) bool {
652	return impl == nativeImpl || impl == implRuntime
653}
654
655func doBench(b *testing.B, impl *Impl) {
656	if testing.Short() && !implIsNative(impl) {
657		b.SkipNow()
658	}
659
660	b.SetParallelism(1) // We want per-core figures.
661
662	b.Run("ECB-AES128", func(b *testing.B) { doBenchECB(b, implCt32, 16) })
663	if !testing.Short() { // No one cares about this mode.
664		b.Run("ECB-AES192", func(b *testing.B) { doBenchECB(b, implCt32, 24) })
665	}
666	b.Run("ECB-AES256", func(b *testing.B) { doBenchECB(b, implCt32, 32) })
667
668	for _, sz := range []int{16, 64, 256, 1024, 8192, 16384} {
669		n := fmt.Sprintf("CTR-AES128_%d", sz)
670		b.Run(n, func(b *testing.B) { doBenchCTR(b, impl, 16, sz) })
671	}
672	for _, sz := range []int{16, 64, 256, 1024, 8192, 16384} {
673		n := fmt.Sprintf("DecryptCBC-AES128_%d", sz)
674		b.Run(n, func(b *testing.B) { doBenchCBC(b, impl, 16, sz) })
675	}
676	for _, sz := range []int{16, 64, 256, 1024, 8192, 16384} {
677		n := fmt.Sprintf("GCM-AES128_%d", sz)
678		b.Run(n, func(b *testing.B) { doBenchGCM(b, impl, 16, sz) })
679	}
680}
681
682func Benchmark_ct32(b *testing.B) {
683	doBench(b, implCt32)
684}
685
686func Benchmark_ct64(b *testing.B) {
687	doBench(b, implCt64)
688}
689
690func Benchmark_runtime(b *testing.B) {
691	if !useCryptoAES {
692		b.SkipNow()
693	}
694	doBench(b, implRuntime)
695}
696
697func init() {
698	maxUintptr := uint64(^uintptr(0))
699	switch maxUintptr {
700	case math.MaxUint32:
701		nativeImpl = implCt32
702	case math.MaxUint64:
703		nativeImpl = implCt64
704	default:
705		panic("bsaes: unsupported architecture")
706	}
707	if useCryptoAES {
708		impls = append(impls, implRuntime)
709	}
710}
711