• 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 "cavp_test_util.h"
26 
27 
28 namespace {
29 
30 struct TestCtx {
31   const EVP_CIPHER *cipher;
32   bool has_iv;
33   enum Mode {
34     kKAT,  // Known Answer Test
35     kMCT,  // Monte Carlo Test
36   };
37   Mode mode;
38 };
39 
40 }
41 
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)42 static bool MonteCarlo(const TestCtx *ctx, FileTest *t,
43                        const EVP_CIPHER *cipher, std::vector<uint8_t> *out,
44                        bool encrypt, std::vector<uint8_t> key,
45                        std::vector<uint8_t> iv, std::vector<uint8_t> in) {
46   const std::string in_label = encrypt ? "PLAINTEXT" : "CIPHERTEXT",
47                     result_label = encrypt ? "CIPHERTEXT" : "PLAINTEXT";
48   std::vector<uint8_t> prev_result, result, prev_in;
49   for (int i = 0; i < 100; i++) {
50     printf("COUNT = %d\r\nKEY = %s\r\n", i,
51            EncodeHex(key.data(), key.size()).c_str());
52     if (ctx->has_iv) {
53       printf("IV = %s\r\n", EncodeHex(iv.data(), iv.size()).c_str());
54     }
55     printf("%s = %s\r\n", in_label.c_str(),
56            EncodeHex(in.data(), in.size()).c_str());
57 
58     if (!ctx->has_iv) {  // ECB mode
59       for (int j = 0; j < 1000; j++) {
60         prev_result = result;
61         if (!CipherOperation(cipher, &result, encrypt, key, iv, in)) {
62           return false;
63         }
64         in = result;
65       }
66     } else {
67       for (int j = 0; j < 1000; j++) {
68         prev_result = result;
69         if (j > 0) {
70           if (encrypt) {
71             iv = result;
72           } else {
73             iv = prev_in;
74           }
75         }
76 
77         if (!CipherOperation(cipher, &result, encrypt, key, iv, in)) {
78           return false;
79         }
80 
81         prev_in = in;
82 
83         if (j == 0) {
84           in = iv;
85         } else {
86           in = prev_result;
87         }
88       }
89     }
90 
91     printf("%s = %s\r\n\r\n", result_label.c_str(),
92            EncodeHex(result.data(), result.size()).c_str());
93 
94     const size_t key_len = key.size() * 8;
95     if (key_len == 128) {
96       for (size_t k = 0; k < key.size(); k++) {
97         key[k] ^= result[k];
98       }
99     } else if (key_len == 192) {
100       for (size_t k = 0; k < key.size(); k++) {
101         // Key[i+1] = Key[i] xor (last 64-bits of CT[j-1] || CT[j])
102         if (k < 8) {
103           key[k] ^= prev_result[prev_result.size() - 8 + k];
104         } else {
105           key[k] ^= result[k - 8];
106         }
107       }
108     } else {  // key_len == 256
109       for (size_t k = 0; k < key.size(); k++) {
110         // Key[i+1] = Key[i] xor (CT[j-1] || CT[j])
111         if (k < 16) {
112           key[k] ^= prev_result[k];
113         } else {
114           key[k] ^= result[k - 16];
115         }
116       }
117     }
118 
119     if (ctx->has_iv) {
120       iv = result;
121       in = prev_result;
122     } else {
123       in = result;
124     }
125   }
126 
127   return true;
128 }
129 
TestCipher(FileTest * t,void * arg)130 static bool TestCipher(FileTest *t, void *arg) {
131   TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
132 
133   if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
134     t->PrintLine("Want either ENCRYPT or DECRYPT");
135     return false;
136   }
137   enum {
138     kEncrypt,
139     kDecrypt,
140   } operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
141 
142   std::string count;
143   std::vector<uint8_t> key, iv, in, result;
144   if (!t->GetAttribute(&count, "COUNT") ||
145       !t->GetBytes(&key, "KEY") ||
146       (ctx->has_iv && !t->GetBytes(&iv, "IV"))) {
147     return false;
148   }
149 
150   const EVP_CIPHER *cipher = ctx->cipher;
151   if (operation == kEncrypt) {
152     if (!t->GetBytes(&in, "PLAINTEXT")) {
153       return false;
154     }
155   } else {  // operation == kDecrypt
156     if (!t->GetBytes(&in, "CIPHERTEXT")) {
157       return false;
158     }
159   }
160 
161   if (ctx->mode == TestCtx::kKAT) {
162     if (!CipherOperation(cipher, &result, operation == kEncrypt, key, iv, in)) {
163       return false;
164     }
165     const std::string label =
166         operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
167     printf("%s%s = %s\r\n\r\n", t->CurrentTestToString().c_str(), label.c_str(),
168            EncodeHex(result.data(), result.size()).c_str());
169   } else {  // ctx->mode == kMCT
170     const std::string op_label =
171         operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
172     printf("%s\r\n\r\n", op_label.c_str());
173     if (!MonteCarlo(ctx, t, cipher, &result, operation == kEncrypt, key, iv,
174                     in)) {
175       return false;
176     }
177     if (operation == kEncrypt) {
178       // MCT tests contain a stray blank line after the ENCRYPT section.
179       printf("\r\n");
180     }
181   }
182 
183   return true;
184 }
185 
usage(char * arg)186 static int usage(char *arg) {
187   fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
188   return 1;
189 }
190 
cavp_aes_test_main(int argc,char ** argv)191 int cavp_aes_test_main(int argc, char **argv) {
192   if (argc != 4) {
193     return usage(argv[0]);
194   }
195 
196   const std::string tm(argv[1]);
197   enum TestCtx::Mode test_mode;
198   if (tm == "kat") {
199     test_mode = TestCtx::kKAT;
200   } else if (tm == "mct") {
201     test_mode = TestCtx::kMCT;
202   } else {
203     fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
204     return usage(argv[0]);
205   }
206 
207   const std::string cipher_name(argv[2]);
208   const EVP_CIPHER *cipher = GetCipher(argv[2]);
209   if (cipher == nullptr) {
210     fprintf(stderr, "invalid cipher: %s\n", argv[2]);
211     return 1;
212   }
213   const bool has_iv =
214       (cipher_name != "aes-128-ecb" &&
215        cipher_name != "aes-192-ecb" &&
216        cipher_name != "aes-256-ecb");
217 
218   TestCtx ctx = {cipher, has_iv, test_mode};
219 
220   FileTest::Options opts;
221   opts.path = argv[3];
222   opts.callback = TestCipher;
223   opts.arg = &ctx;
224   opts.silent = true;
225   opts.comment_callback = EchoComment;
226   return FileTestMain(opts);
227 }
228