1
16
17 package josecipher
18
19 import (
20 "bytes"
21 "crypto/aes"
22 "crypto/cipher"
23 "crypto/rand"
24 "io"
25 "strings"
26 "testing"
27 )
28
29 func TestInvalidInputs(t *testing.T) {
30 key := []byte{
31 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
32 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
33 }
34
35 nonce := []byte{
36 92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
37
38 aead, _ := NewCBCHMAC(key, aes.NewCipher)
39 ciphertext := aead.Seal(nil, nonce, []byte("plaintext"), []byte("aad"))
40
41
42 _, err := aead.Open(nil, nonce, ciphertext, []byte("INVALID"))
43 if err == nil {
44 t.Error("must detect invalid aad")
45 }
46
47
48 _, err = aead.Open(nil, nonce, []byte{}, []byte("aad"))
49 if err == nil {
50 t.Error("must detect invalid/empty ciphertext")
51 }
52
53
54 corrupt := make([]byte, len(ciphertext))
55 copy(corrupt, ciphertext)
56 corrupt[0] ^= 0xFF
57
58 _, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
59 if err == nil {
60 t.Error("must detect corrupt ciphertext")
61 }
62
63
64 copy(corrupt, ciphertext)
65 corrupt[len(ciphertext)-1] ^= 0xFF
66
67 _, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
68 if err == nil {
69 t.Error("must detect corrupt authtag")
70 }
71
72
73 _, err = aead.Open(nil, nonce, ciphertext[:10], []byte("aad"))
74 if err == nil {
75 t.Error("must detect corrupt authtag")
76 }
77 }
78
79 func TestVectorsAESCBC128(t *testing.T) {
80
81 plaintext := []byte{
82 76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
83 112, 114, 111, 115, 112, 101, 114, 46}
84
85 aad := []byte{
86 101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
87 120, 88, 122, 85, 105, 76, 67, 74, 108, 98, 109, 77, 105, 79, 105,
88 74, 66, 77, 84, 73, 52, 81, 48, 74, 68, 76, 85, 104, 84, 77, 106, 85,
89 50, 73, 110, 48}
90
91 expectedCiphertext := []byte{
92 40, 57, 83, 181, 119, 33, 133, 148, 198, 185, 243, 24, 152, 230, 6,
93 75, 129, 223, 127, 19, 210, 82, 183, 230, 168, 33, 215, 104, 143,
94 112, 56, 102}
95
96 expectedAuthtag := []byte{
97 246, 17, 244, 190, 4, 95, 98, 3, 231, 0, 115, 157, 242, 203, 100,
98 191}
99
100 key := []byte{
101 4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106, 206,
102 107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, 44, 207}
103
104 nonce := []byte{
105 3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101}
106
107 enc, err := NewCBCHMAC(key, aes.NewCipher)
108 out := enc.Seal(nil, nonce, plaintext, aad)
109 if err != nil {
110 t.Error("Unable to encrypt:", err)
111 return
112 }
113
114 if bytes.Compare(out[:len(out)-16], expectedCiphertext) != 0 {
115 t.Error("Ciphertext did not match")
116 }
117 if bytes.Compare(out[len(out)-16:], expectedAuthtag) != 0 {
118 t.Error("Auth tag did not match")
119 }
120 }
121
122 func TestVectorsAESCBC256(t *testing.T) {
123
124 plaintext := []byte{
125 0x41, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
126 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75,
127 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65,
128 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
129 0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x20, 0x69,
130 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x66,
131 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x65, 0x6d, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f,
132 0x75, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65}
133
134 aad := []byte{
135 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63,
136 0x69, 0x70, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x65, 0x20,
137 0x4b, 0x65, 0x72, 0x63, 0x6b, 0x68, 0x6f, 0x66, 0x66, 0x73}
138
139 expectedCiphertext := []byte{
140 0x4a, 0xff, 0xaa, 0xad, 0xb7, 0x8c, 0x31, 0xc5, 0xda, 0x4b, 0x1b, 0x59, 0x0d, 0x10, 0xff, 0xbd,
141 0x3d, 0xd8, 0xd5, 0xd3, 0x02, 0x42, 0x35, 0x26, 0x91, 0x2d, 0xa0, 0x37, 0xec, 0xbc, 0xc7, 0xbd,
142 0x82, 0x2c, 0x30, 0x1d, 0xd6, 0x7c, 0x37, 0x3b, 0xcc, 0xb5, 0x84, 0xad, 0x3e, 0x92, 0x79, 0xc2,
143 0xe6, 0xd1, 0x2a, 0x13, 0x74, 0xb7, 0x7f, 0x07, 0x75, 0x53, 0xdf, 0x82, 0x94, 0x10, 0x44, 0x6b,
144 0x36, 0xeb, 0xd9, 0x70, 0x66, 0x29, 0x6a, 0xe6, 0x42, 0x7e, 0xa7, 0x5c, 0x2e, 0x08, 0x46, 0xa1,
145 0x1a, 0x09, 0xcc, 0xf5, 0x37, 0x0d, 0xc8, 0x0b, 0xfe, 0xcb, 0xad, 0x28, 0xc7, 0x3f, 0x09, 0xb3,
146 0xa3, 0xb7, 0x5e, 0x66, 0x2a, 0x25, 0x94, 0x41, 0x0a, 0xe4, 0x96, 0xb2, 0xe2, 0xe6, 0x60, 0x9e,
147 0x31, 0xe6, 0xe0, 0x2c, 0xc8, 0x37, 0xf0, 0x53, 0xd2, 0x1f, 0x37, 0xff, 0x4f, 0x51, 0x95, 0x0b,
148 0xbe, 0x26, 0x38, 0xd0, 0x9d, 0xd7, 0xa4, 0x93, 0x09, 0x30, 0x80, 0x6d, 0x07, 0x03, 0xb1, 0xf6}
149
150 expectedAuthtag := []byte{
151 0x4d, 0xd3, 0xb4, 0xc0, 0x88, 0xa7, 0xf4, 0x5c, 0x21, 0x68, 0x39, 0x64, 0x5b, 0x20, 0x12, 0xbf,
152 0x2e, 0x62, 0x69, 0xa8, 0xc5, 0x6a, 0x81, 0x6d, 0xbc, 0x1b, 0x26, 0x77, 0x61, 0x95, 0x5b, 0xc5}
153
154 key := []byte{
155 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
156 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
157 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
158 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}
159
160 nonce := []byte{
161 0x1a, 0xf3, 0x8c, 0x2d, 0xc2, 0xb9, 0x6f, 0xfd, 0xd8, 0x66, 0x94, 0x09, 0x23, 0x41, 0xbc, 0x04}
162
163 enc, err := NewCBCHMAC(key, aes.NewCipher)
164 out := enc.Seal(nil, nonce, plaintext, aad)
165 if err != nil {
166 t.Error("Unable to encrypt:", err)
167 return
168 }
169
170 if bytes.Compare(out[:len(out)-32], expectedCiphertext) != 0 {
171 t.Error("Ciphertext did not match, got", out[:len(out)-32], "wanted", expectedCiphertext)
172 }
173 if bytes.Compare(out[len(out)-32:], expectedAuthtag) != 0 {
174 t.Error("Auth tag did not match, got", out[len(out)-32:], "wanted", expectedAuthtag)
175 }
176 }
177
178 func TestAESCBCRoundtrip(t *testing.T) {
179 key128 := []byte{
180 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
181 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
182
183 key192 := []byte{
184 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
185 0, 1, 2, 3, 4, 5, 6, 7,
186 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
187 0, 1, 2, 3, 4, 5, 6, 7}
188
189 key256 := []byte{
190 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
191 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
192 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
193 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
194
195 nonce := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
196
197 RunRoundtrip(t, key128, nonce)
198 RunRoundtrip(t, key192, nonce)
199 RunRoundtrip(t, key256, nonce)
200 }
201
202 func RunRoundtrip(t *testing.T, key, nonce []byte) {
203 aead, err := NewCBCHMAC(key, aes.NewCipher)
204 if err != nil {
205 panic(err)
206 }
207
208 if aead.NonceSize() != len(nonce) {
209 panic("invalid nonce")
210 }
211
212
213 dst := []byte{15, 15, 15, 15}
214 plaintext := []byte{0, 0, 0, 0}
215 aad := []byte{4, 3, 2, 1}
216
217 result := aead.Seal(dst, nonce, plaintext, aad)
218 if bytes.Compare(dst, result[:4]) != 0 {
219 t.Error("Existing data in dst not preserved")
220 }
221
222
223 dst = make([]byte, 256)[:0]
224 result, err = aead.Open(dst, nonce, result[4:], aad)
225 if err != nil {
226 panic(err)
227 }
228
229 if bytes.Compare(result, plaintext) != 0 {
230 t.Error("Plaintext does not match output")
231 }
232 }
233
234 func TestAESCBCOverhead(t *testing.T) {
235 aead, err := NewCBCHMAC(make([]byte, 32), aes.NewCipher)
236 if err != nil {
237 panic(err)
238 }
239
240 if aead.Overhead() != 32 {
241 t.Error("CBC-HMAC reports incorrect overhead value")
242 }
243 }
244
245 func TestPadding(t *testing.T) {
246 for i := 0; i < 256; i++ {
247 slice := make([]byte, i)
248 padded := padBuffer(slice, 16)
249 if len(padded)%16 != 0 {
250 t.Error("failed to pad slice properly", i)
251 return
252 }
253 unpadded, err := unpadBuffer(padded, 16)
254 if err != nil || len(unpadded) != i {
255 t.Error("failed to unpad slice properly", i)
256 return
257 }
258 }
259 }
260
261 func TestInvalidKey(t *testing.T) {
262 key := make([]byte, 30)
263 _, err := NewCBCHMAC(key, aes.NewCipher)
264 if err == nil {
265 t.Error("should not be able to instantiate CBC-HMAC with invalid key")
266 }
267 }
268
269 func TestTruncatedCiphertext(t *testing.T) {
270 key := make([]byte, 32)
271 nonce := make([]byte, 16)
272 data := make([]byte, 32)
273
274 io.ReadFull(rand.Reader, key)
275 io.ReadFull(rand.Reader, nonce)
276
277 aead, err := NewCBCHMAC(key, aes.NewCipher)
278 if err != nil {
279 panic(err)
280 }
281
282 ctx := aead.(*cbcAEAD)
283 ct := aead.Seal(nil, nonce, data, nil)
284
285
286 truncated, tail := resize(ct[:len(ct)-ctx.authtagBytes-2], uint64(len(ct))-2)
287 copy(tail, ctx.computeAuthTag(nil, nonce, truncated[:len(truncated)-ctx.authtagBytes]))
288
289
290 _, err = aead.Open(nil, nonce, truncated, nil)
291 if err == nil {
292 t.Error("open on truncated ciphertext should fail")
293 }
294 }
295
296 func TestInvalidPaddingOpen(t *testing.T) {
297 key := make([]byte, 32)
298 nonce := make([]byte, 16)
299
300
301 plaintext := padBuffer(make([]byte, 28), aes.BlockSize)
302 plaintext[len(plaintext)-1] = 0xFF
303
304 io.ReadFull(rand.Reader, key)
305 io.ReadFull(rand.Reader, nonce)
306
307 block, _ := aes.NewCipher(key)
308 cbc := cipher.NewCBCEncrypter(block, nonce)
309 buffer := append([]byte{}, plaintext...)
310 cbc.CryptBlocks(buffer, buffer)
311
312 aead, _ := NewCBCHMAC(key, aes.NewCipher)
313 ctx := aead.(*cbcAEAD)
314
315
316 size := uint64(len(buffer))
317 ciphertext, tail := resize(buffer, size+(uint64(len(key))/2))
318 copy(tail, ctx.computeAuthTag(nil, nonce, ciphertext[:size]))
319
320
321 _, err := aead.Open(nil, nonce, ciphertext, nil)
322 if err == nil || !strings.Contains(err.Error(), "invalid padding") {
323 t.Error("no or unexpected error on open with invalid padding:", err)
324 }
325 }
326
327 func TestInvalidPadding(t *testing.T) {
328 for i := 0; i < 256; i++ {
329 slice := make([]byte, i)
330 padded := padBuffer(slice, 16)
331 if len(padded)%16 != 0 {
332 t.Error("failed to pad slice properly", i)
333 return
334 }
335
336 paddingBytes := 16 - (i % 16)
337
338
339 for j := 1; j <= paddingBytes; j++ {
340 mutated := make([]byte, len(padded))
341 copy(mutated, padded)
342 mutated[len(mutated)-j] ^= 0xFF
343
344 _, err := unpadBuffer(mutated, 16)
345 if err == nil {
346 t.Error("unpad on invalid padding should fail", i)
347 return
348 }
349 }
350
351
352 _, err := unpadBuffer(padded[:len(padded)-1], 16)
353 if err == nil {
354 t.Error("unpad on truncated padding should fail", i)
355 return
356 }
357 }
358 }
359
360 func TestZeroLengthPadding(t *testing.T) {
361 data := make([]byte, 16)
362 data, err := unpadBuffer(data, 16)
363 if err == nil {
364 t.Error("padding with 0x00 should never be valid")
365 }
366 }
367
368 func benchEncryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
369 key := make([]byte, keySize*2)
370 nonce := make([]byte, 16)
371
372 io.ReadFull(rand.Reader, key)
373 io.ReadFull(rand.Reader, nonce)
374
375 chunk := make([]byte, chunkSize)
376
377 aead, err := NewCBCHMAC(key, aes.NewCipher)
378 if err != nil {
379 panic(err)
380 }
381
382 b.SetBytes(int64(chunkSize))
383 b.ResetTimer()
384 for i := 0; i < b.N; i++ {
385 aead.Seal(nil, nonce, chunk, nil)
386 }
387 }
388
389 func benchDecryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
390 key := make([]byte, keySize*2)
391 nonce := make([]byte, 16)
392
393 io.ReadFull(rand.Reader, key)
394 io.ReadFull(rand.Reader, nonce)
395
396 chunk := make([]byte, chunkSize)
397
398 aead, err := NewCBCHMAC(key, aes.NewCipher)
399 if err != nil {
400 panic(err)
401 }
402
403 out := aead.Seal(nil, nonce, chunk, nil)
404
405 b.SetBytes(int64(chunkSize))
406 b.ResetTimer()
407 for i := 0; i < b.N; i++ {
408 aead.Open(nil, nonce, out, nil)
409 }
410 }
411
412 func BenchmarkEncryptAES128_CBCHMAC_1k(b *testing.B) {
413 benchEncryptCBCHMAC(b, 16, 1024)
414 }
415
416 func BenchmarkEncryptAES128_CBCHMAC_64k(b *testing.B) {
417 benchEncryptCBCHMAC(b, 16, 65536)
418 }
419
420 func BenchmarkEncryptAES128_CBCHMAC_1MB(b *testing.B) {
421 benchEncryptCBCHMAC(b, 16, 1048576)
422 }
423
424 func BenchmarkEncryptAES128_CBCHMAC_64MB(b *testing.B) {
425 benchEncryptCBCHMAC(b, 16, 67108864)
426 }
427
428 func BenchmarkDecryptAES128_CBCHMAC_1k(b *testing.B) {
429 benchDecryptCBCHMAC(b, 16, 1024)
430 }
431
432 func BenchmarkDecryptAES128_CBCHMAC_64k(b *testing.B) {
433 benchDecryptCBCHMAC(b, 16, 65536)
434 }
435
436 func BenchmarkDecryptAES128_CBCHMAC_1MB(b *testing.B) {
437 benchDecryptCBCHMAC(b, 16, 1048576)
438 }
439
440 func BenchmarkDecryptAES128_CBCHMAC_64MB(b *testing.B) {
441 benchDecryptCBCHMAC(b, 16, 67108864)
442 }
443
444 func BenchmarkEncryptAES192_CBCHMAC_64k(b *testing.B) {
445 benchEncryptCBCHMAC(b, 24, 65536)
446 }
447
448 func BenchmarkEncryptAES192_CBCHMAC_1MB(b *testing.B) {
449 benchEncryptCBCHMAC(b, 24, 1048576)
450 }
451
452 func BenchmarkEncryptAES192_CBCHMAC_64MB(b *testing.B) {
453 benchEncryptCBCHMAC(b, 24, 67108864)
454 }
455
456 func BenchmarkDecryptAES192_CBCHMAC_1k(b *testing.B) {
457 benchDecryptCBCHMAC(b, 24, 1024)
458 }
459
460 func BenchmarkDecryptAES192_CBCHMAC_64k(b *testing.B) {
461 benchDecryptCBCHMAC(b, 24, 65536)
462 }
463
464 func BenchmarkDecryptAES192_CBCHMAC_1MB(b *testing.B) {
465 benchDecryptCBCHMAC(b, 24, 1048576)
466 }
467
468 func BenchmarkDecryptAES192_CBCHMAC_64MB(b *testing.B) {
469 benchDecryptCBCHMAC(b, 24, 67108864)
470 }
471
472 func BenchmarkEncryptAES256_CBCHMAC_64k(b *testing.B) {
473 benchEncryptCBCHMAC(b, 32, 65536)
474 }
475
476 func BenchmarkEncryptAES256_CBCHMAC_1MB(b *testing.B) {
477 benchEncryptCBCHMAC(b, 32, 1048576)
478 }
479
480 func BenchmarkEncryptAES256_CBCHMAC_64MB(b *testing.B) {
481 benchEncryptCBCHMAC(b, 32, 67108864)
482 }
483
484 func BenchmarkDecryptAES256_CBCHMAC_1k(b *testing.B) {
485 benchDecryptCBCHMAC(b, 32, 1032)
486 }
487
488 func BenchmarkDecryptAES256_CBCHMAC_64k(b *testing.B) {
489 benchDecryptCBCHMAC(b, 32, 65536)
490 }
491
492 func BenchmarkDecryptAES256_CBCHMAC_1MB(b *testing.B) {
493 benchDecryptCBCHMAC(b, 32, 1048576)
494 }
495
496 func BenchmarkDecryptAES256_CBCHMAC_64MB(b *testing.B) {
497 benchDecryptCBCHMAC(b, 32, 67108864)
498 }
499
View as plain text