github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/aez/aez_test.go (about) 1 // aez_test.go - AEZ tests. 2 // 3 // To the extent possible under law, Yawning Angel has waived all copyright 4 // and related or neighboring rights to aez, using the Creative 5 // Commons "CC0" public domain dedication. See LICENSE or 6 // <http://creativecommons.org/publicdomain/zero/1.0/> for full details. 7 8 package aez 9 10 import ( 11 "bytes" 12 "crypto/cipher" 13 "crypto/rand" 14 "encoding/hex" 15 "encoding/json" 16 "fmt" 17 "os" 18 "path/filepath" 19 "testing" 20 ) 21 22 func readJsonTestdata(t *testing.T, name string, destination interface{}) { 23 var file *os.File 24 file, err := os.Open(filepath.Join("testdata", name)) 25 if err != nil { 26 t.Fatalf("Failed to read test vectors in %s", name) 27 } 28 29 decoder := json.NewDecoder(file) 30 if err := decoder.Decode(&destination); err != nil { 31 t.Fatalf("Failed to parse test vectors in %s", name) 32 } 33 } 34 35 // (a,b) ==> Extract(a) = b. 36 type ExtractVector struct { 37 A string `json:"a"` 38 B string `json:"b"` 39 } 40 41 func TestExtract(t *testing.T) { 42 var extractVectors []ExtractVector 43 44 readJsonTestdata(t, "extract.json", &extractVectors) 45 46 for i, vec := range extractVectors { 47 var extractedKey [extractedKeySize]byte 48 49 vecA, err := hex.DecodeString(vec.A) 50 if err != nil { 51 t.Fatal(err) 52 } 53 vecB, err := hex.DecodeString(vec.B) 54 if err != nil { 55 t.Fatal(err) 56 } 57 58 extract(vecA, &extractedKey) 59 assertEqual(t, i, vecB, extractedKey[:]) 60 } 61 } 62 63 // {K, tau, [N, A...], V) ==> AEZ-hash{K, {[tau]_128, N, A...)) = V 64 type HashVector struct { 65 K string `json:"k"` 66 Tau int `json:"tau"` 67 Data []string `json:"data"` 68 V string `json:"v"` 69 } 70 71 func TestHash(t *testing.T) { 72 var e eState 73 var hashVectors []HashVector 74 75 readJsonTestdata(t, "hash.json", &hashVectors) 76 77 for i, vec := range hashVectors { 78 vecK, err := hex.DecodeString(vec.K) 79 if err != nil { 80 t.Fatal(err) 81 } 82 var data [][]byte 83 for _, v := range vec.Data { 84 d, err := hex.DecodeString(v) 85 if err != nil { 86 t.Fatal(err) 87 } 88 data = append(data, d) 89 } 90 vecV, err := hex.DecodeString(vec.V) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 var nonce []byte 96 var ad [][]byte 97 if len(data) > 0 { 98 nonce = data[0] 99 if len(data) > 1 { 100 ad = data[1:] 101 } 102 } 103 104 var result [blockSize]byte 105 106 e.init(vecK) 107 e.aezHash(nonce, ad, vec.Tau, result[:]) 108 assertEqual(t, i, vecV, result[:]) 109 } 110 } 111 112 // (K, delta, tau, R) ==> AEZ-prf(K, T, tau*8) = R where delta = AEZ-hash(K,T) 113 type PrfVector struct { 114 K string `json:"k"` 115 Delta string `json:"delta"` 116 Tau int `json:"tau"` 117 R string `json:"R"` 118 } 119 120 func TestPRF(t *testing.T) { 121 var e eState 122 var prfVectors []PrfVector 123 124 readJsonTestdata(t, "prf.json", &prfVectors) 125 126 for i, vec := range prfVectors { 127 vecK, err := hex.DecodeString(vec.K) 128 if err != nil { 129 t.Fatal(err) 130 } 131 vecDelta, err := hex.DecodeString(vec.Delta) 132 if err != nil { 133 t.Fatal(err) 134 } 135 vecR, err := hex.DecodeString(vec.R) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 var vDelta [blockSize]byte 141 copy(vDelta[:], vecDelta) 142 143 result := make([]byte, len(vecR)) 144 e.init(vecK) 145 e.aezPRF(&vDelta, vec.Tau, result) 146 assertEqual(t, i, vecR, result) 147 } 148 } 149 150 // (K, N, A, taubytes, M, C) ==> Encrypt(K,N,A,taubytes,M) = C 151 type EncryptVector struct { 152 K string `json:"k"` 153 Nonce string `json:"nonce"` 154 Data []string `json:"data"` 155 Tau int `json:"tau"` 156 M string `json:"m"` 157 C string `json:"c"` 158 } 159 160 func TestEncryptDecrypt(t *testing.T) { 161 var encryptVectors []EncryptVector 162 163 readJsonTestdata(t, "encrypt.json", &encryptVectors) 164 assertEncrypt(t, encryptVectors) 165 166 // 167 // No AD test cases 168 // 169 readJsonTestdata(t, "encrypt_no_ad.json", &encryptVectors) 170 assertEncrypt(t, encryptVectors) 171 172 // 173 // 33 bytes of AD test cases 174 // 175 readJsonTestdata(t, "encrypt_33_byte_ad.json", &encryptVectors) 176 assertEncrypt(t, encryptVectors) 177 178 // 179 // 16 byte key test cases 180 // 181 readJsonTestdata(t, "encrypt_16_byte_key.json", &encryptVectors) 182 assertEncrypt(t, encryptVectors) 183 } 184 185 func assertEncrypt(t *testing.T, vectors []EncryptVector) { 186 var e eState 187 188 for i, vec := range vectors { 189 vecK, err := hex.DecodeString(vec.K) 190 if err != nil { 191 t.Fatal(err) 192 } 193 vecNonce, err := hex.DecodeString(vec.Nonce) 194 if err != nil { 195 t.Fatal(err) 196 } 197 var vecData [][]byte 198 for _, s := range vec.Data { 199 d, err := hex.DecodeString(s) 200 if err != nil { 201 t.Fatal(err) 202 } 203 vecData = append(vecData, d) 204 } 205 vecM, err := hex.DecodeString(vec.M) 206 if err != nil { 207 t.Fatal(err) 208 } 209 vecC, err := hex.DecodeString(vec.C) 210 if err != nil { 211 t.Fatal(err) 212 } 213 214 // Test the cipher.AEAD code as well, for applicable test vectors. 215 var aead cipher.AEAD 216 var ad []byte 217 if len(vecNonce) == aeadNonceSize && vec.Tau == aeadOverhead && len(vecData) <= 1 { 218 aead, err = New(vecK) 219 if err != nil { 220 t.Fatal(err) 221 } 222 if len(vecData) == 1 { 223 ad = vecData[0] 224 } 225 } 226 227 e.init(vecK) 228 c := Encrypt(vecK, vecNonce, vecData, vec.Tau, vecM, nil) 229 assertEqual(t, i, vecC, c) 230 if aead != nil { 231 ac := aead.Seal(nil, vecNonce, vecM, ad) 232 assertEqual(t, i, vecC, ac) 233 } 234 235 m, ok := Decrypt(vecK, vecNonce, vecData, vec.Tau, vecC, nil) 236 if !ok { 237 t.Fatalf("decrypt failed: [%d]", i) 238 } 239 assertEqual(t, i, vecM, m) 240 if aead != nil { 241 am, err := aead.Open(nil, vecNonce, vecC, ad) 242 if err != nil { 243 t.Fatal(err) 244 } 245 assertEqual(t, i, vecM, am) 246 } 247 } 248 } 249 250 func assertEqual(t *testing.T, idx int, expected, actual []byte) { 251 if !bytes.Equal(expected, actual) { 252 for i, v := range actual { 253 if expected[i] != v { 254 t.Errorf("[%d] first mismatch at offset: %d (%02x != %02x)", idx, i, expected[i], v) 255 break 256 } 257 } 258 t.Errorf("expected: %s", hex.Dump(expected)) 259 t.Errorf("actual: %s", hex.Dump(actual)) 260 t.FailNow() 261 } 262 } 263 264 var benchOutput []byte 265 266 func doBenchEncrypt(b *testing.B, n int) { 267 var key [extractedKeySize]byte 268 if _, err := rand.Read(key[:]); err != nil { 269 b.Error(err) 270 b.Fail() 271 } 272 273 const tau = 16 274 275 var nonce [16]byte 276 src := make([]byte, n) 277 dst := make([]byte, n+tau) 278 check := make([]byte, n+tau) 279 280 b.SetBytes(int64(n)) 281 b.ResetTimer() 282 for i := 0; i < b.N; i++ { 283 b.StartTimer() 284 dst = Encrypt(key[:], nonce[:], nil, tau, src[:n], dst[:0]) 285 b.StopTimer() 286 dec, ok := Decrypt(key[:], nonce[:], nil, tau, dst, check[:0]) 287 if !ok { 288 b.Fatalf("decrypt failed") 289 } 290 if !bytes.Equal(dec, src) { 291 b.Fatalf("decrypt produced invalid output") 292 } 293 copy(src, dst[:n]) 294 } 295 296 benchOutput = src 297 } 298 299 func BenchmarkEncrypt(b *testing.B) { 300 sizes := []int{1, 32, 512, 1024, 2048, 16384, 32768, 65536, 1024768} 301 if testing.Short() { 302 sizes = []int{1, 32, 512, 1024, 16384, 65536, 1024768} 303 } 304 305 b.SetParallelism(1) // AES-NI is a per-physical core thing. 306 307 for _, sz := range sizes { 308 n := fmt.Sprintf("%d", sz) 309 b.Run(n, func(b *testing.B) { doBenchEncrypt(b, sz) }) 310 } 311 }