• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2017, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 // cavp_aes_test processes a NIST CAVP AES test vector request file and emits
16 // the corresponding response.
17 
18 #include <stdlib.h>
19 
20 #include <openssl/cipher.h>
21 #include <openssl/crypto.h>
22 #include <openssl/err.h>
23 
24 #include "../crypto/test/file_test.h"
25 #include "../crypto/test/test_util.h"
26 #include "cavp_test_util.h"
27 
28 
29 namespace {
30 
31 struct TestCtx {
32   const EVP_CIPHER *cipher;
33   bool has_iv;
34   enum Mode {
35     kKAT,  // Known Answer Test
36     kMCT,  // Monte Carlo Test
37   };
38   Mode mode;
39 };
40 
41 }
42 
MonteCarlo(const TestCtx * ctx,FileTest * t,const EVP_CIPHER * cipher,std::vector<uint8_t> * out,bool encrypt,std::vector<uint8_t> key,std::vector<uint8_t> iv,std::vector<uint8_t> in)43 static bool MonteCarlo(const TestCtx *ctx, FileTest *t,
44                        const EVP_CIPHER *cipher, std::vector<uint8_t> *out,
45                        bool encrypt, std::vector<uint8_t> key,
46                        std::vector<uint8_t> iv, std::vector<uint8_t> in) {
47   const std::string in_label = encrypt ? "PLAINTEXT" : "CIPHERTEXT",
48                     result_label = encrypt ? "CIPHERTEXT" : "PLAINTEXT";
49   std::vector<uint8_t> prev_result, result, prev_in;
50   for (int i = 0; i < 100; i++) {
51     printf("COUNT = %d\r\nKEY = %s\r\n", i, EncodeHex(key).c_str());
52     if (ctx->has_iv) {
53       printf("IV = %s\r\n", EncodeHex(iv).c_str());
54     }
55     printf("%s = %s\r\n", in_label.c_str(), EncodeHex(in).c_str());
56 
57     if (!ctx->has_iv) {  // ECB mode
58       for (int j = 0; j < 1000; j++) {
59         prev_result = result;
60         if (!CipherOperation(cipher, &result, encrypt, key, iv, in)) {
61           return false;
62         }
63         in = result;
64       }
65     } else {
66       for (int j = 0; j < 1000; j++) {
67         prev_result = result;
68         if (j > 0) {
69           if (encrypt) {
70             iv = result;
71           } else {
72             iv = prev_in;
73           }
74         }
75 
76         if (!CipherOperation(cipher, &result, encrypt, key, iv, in)) {
77           return false;
78         }
79 
80         prev_in = in;
81 
82         if (j == 0) {
83           in = iv;
84         } else {
85           in = prev_result;
86         }
87       }
88     }
89 
90     printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
91 
92     const size_t key_len = key.size() * 8;
93     if (key_len == 128) {
94       for (size_t k = 0; k < key.size(); k++) {
95         key[k] ^= result[k];
96       }
97     } else if (key_len == 192) {
98       for (size_t k = 0; k < key.size(); k++) {
99         // Key[i+1] = Key[i] xor (last 64-bits of CT[j-1] || CT[j])
100         if (k < 8) {
101           key[k] ^= prev_result[prev_result.size() - 8 + k];
102         } else {
103           key[k] ^= result[k - 8];
104         }
105       }
106     } else {  // key_len == 256
107       for (size_t k = 0; k < key.size(); k++) {
108         // Key[i+1] = Key[i] xor (CT[j-1] || CT[j])
109         if (k < 16) {
110           key[k] ^= prev_result[k];
111         } else {
112           key[k] ^= result[k - 16];
113         }
114       }
115     }
116 
117     if (ctx->has_iv) {
118       iv = result;
119       in = prev_result;
120     } else {
121       in = result;
122     }
123   }
124 
125   return true;
126 }
127 
TestCipher(FileTest * t,void * arg)128 static bool TestCipher(FileTest *t, void *arg) {
129   TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
130 
131   if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
132     t->PrintLine("Want either ENCRYPT or DECRYPT");
133     return false;
134   }
135   enum {
136     kEncrypt,
137     kDecrypt,
138   } operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
139 
140   std::string count;
141   std::vector<uint8_t> key, iv, in, result;
142   if (!t->GetAttribute(&count, "COUNT") ||
143       !t->GetBytes(&key, "KEY") ||
144       (ctx->has_iv && !t->GetBytes(&iv, "IV"))) {
145     return false;
146   }
147 
148   const EVP_CIPHER *cipher = ctx->cipher;
149   if (operation == kEncrypt) {
150     if (!t->GetBytes(&in, "PLAINTEXT")) {
151       return false;
152     }
153   } else {  // operation == kDecrypt
154     if (!t->GetBytes(&in, "CIPHERTEXT")) {
155       return false;
156     }
157   }
158 
159   if (ctx->mode == TestCtx::kKAT) {
160     if (!CipherOperation(cipher, &result, operation == kEncrypt, key, iv, in)) {
161       return false;
162     }
163     const std::string label =
164         operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
165     printf("%s%s = %s\r\n\r\n", t->CurrentTestToString().c_str(), label.c_str(),
166            EncodeHex(result).c_str());
167   } else {  // ctx->mode == kMCT
168     const std::string op_label =
169         operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
170     printf("%s\r\n\r\n", op_label.c_str());
171     if (!MonteCarlo(ctx, t, cipher, &result, operation == kEncrypt, key, iv,
172                     in)) {
173       return false;
174     }
175     if (operation == kEncrypt) {
176       // MCT tests contain a stray blank line after the ENCRYPT section.
177       printf("\r\n");
178     }
179   }
180 
181   return true;
182 }
183 
usage(char * arg)184 static int usage(char *arg) {
185   fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
186   return 1;
187 }
188 
cavp_aes_test_main(int argc,char ** argv)189 int cavp_aes_test_main(int argc, char **argv) {
190   if (argc != 4) {
191     return usage(argv[0]);
192   }
193 
194   const std::string tm(argv[1]);
195   enum TestCtx::Mode test_mode;
196   if (tm == "kat") {
197     test_mode = TestCtx::kKAT;
198   } else if (tm == "mct") {
199     test_mode = TestCtx::kMCT;
200   } else {
201     fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
202     return usage(argv[0]);
203   }
204 
205   const std::string cipher_name(argv[2]);
206   const EVP_CIPHER *cipher = GetCipher(argv[2]);
207   if (cipher == nullptr) {
208     fprintf(stderr, "invalid cipher: %s\n", argv[2]);
209     return 1;
210   }
211   const bool has_iv =
212       (cipher_name != "aes-128-ecb" &&
213        cipher_name != "aes-192-ecb" &&
214        cipher_name != "aes-256-ecb");
215 
216   TestCtx ctx = {cipher, has_iv, test_mode};
217 
218   FileTest::Options opts;
219   opts.path = argv[3];
220   opts.callback = TestCipher;
221   opts.arg = &ctx;
222   opts.silent = true;
223   opts.comment_callback = EchoComment;
224   return FileTestMain(opts);
225 }
226