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