blob: 6c0cf3cfd5eaaf78e2762a9da5e8989d8bbbf843 [file] [log] [blame]
Robert Sloan2424d842017-05-01 07:46:28 -07001/* 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
Robert Sloan8ff03552017-06-14 12:40:58 -070016// the corresponding response.
Robert Sloan2424d842017-05-01 07:46:28 -070017
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
Robert Sloan8ff03552017-06-14 12:40:58 -070028namespace {
29
Robert Sloan2424d842017-05-01 07:46:28 -070030struct TestCtx {
31 const EVP_CIPHER *cipher;
Robert Sloan2424d842017-05-01 07:46:28 -070032 bool has_iv;
33 enum Mode {
34 kKAT, // Known Answer Test
35 kMCT, // Monte Carlo Test
36 };
37 Mode mode;
38};
39
Robert Sloan8ff03552017-06-14 12:40:58 -070040}
41
Robert Sloan2424d842017-05-01 07:46:28 -070042static 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
Robert Sloan2424d842017-05-01 07:46:28 -070094 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
130static 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());
Robert Sloan2424d842017-05-01 07:46:28 -0700169 } 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
186static int usage(char *arg) {
Robert Sloan8ff03552017-06-14 12:40:58 -0700187 fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
Robert Sloan2424d842017-05-01 07:46:28 -0700188 return 1;
189}
190
Robert Sloan8ff03552017-06-14 12:40:58 -0700191int cavp_aes_test_main(int argc, char **argv) {
192 if (argc != 4) {
Robert Sloan2424d842017-05-01 07:46:28 -0700193 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
Robert Sloan8ff03552017-06-14 12:40:58 -0700218 TestCtx ctx = {cipher, has_iv, test_mode};
Robert Sloan2424d842017-05-01 07:46:28 -0700219
Robert Sloan8ff03552017-06-14 12:40:58 -0700220 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);
Robert Sloan2424d842017-05-01 07:46:28 -0700227}