cavp_tdes_test.cc
Go to the documentation of this file.
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_tdes_test processes a NIST TMOVS test vector request file and emits the
16 // 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  enum Mode {
34  kKAT, // Known Answer Test
35  kMCT, // Monte Carlo Test
36  };
37  bool has_iv;
38  Mode mode;
39 };
40 
41 }
42 
43 static bool TestKAT(FileTest *t, void *arg) {
44  TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
45 
46  if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
47  t->PrintLine("Want either ENCRYPT or DECRYPT");
48  return false;
49  }
50  enum {
51  kEncrypt,
52  kDecrypt,
53  } operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
54 
55  if (t->HasAttribute("NumKeys")) {
56  // Another file format quirk: NumKeys is a single attribute line immediately
57  // following an instruction and should probably have been an instruction
58  // instead. If it is present, the file has separate attributes "KEY{1,2,3}".
59  // If it is not, the keys are concatenated in a single attribute "KEYs".
60  std::string num_keys;
61  t->GetAttribute(&num_keys, "NumKeys");
62  t->InjectInstruction("NumKeys", num_keys);
63 
64  std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
65  printf("%s\r\n\r\n", header.c_str());
66 
67  return true;
68  }
69 
70  enum {
71  kNotPresent,
72  kTwo,
73  kThree,
74  } num_keys = kNotPresent;
75  if (t->HasInstruction("NumKeys")) {
76  std::string num_keys_str;
77  t->GetInstruction(&num_keys_str, "NumKeys");
78  const int n = strtoul(num_keys_str.c_str(), nullptr, 0);
79  if (n == 2) {
80  num_keys = kTwo;
81  } else if (n == 3) {
82  num_keys = kThree;
83  } else {
84  t->PrintLine("invalid NumKeys value");
85  return false;
86  }
87  }
88 
90  std::vector<uint8_t> keys, key1, key2, key3, iv, in, result;
91  const std::string in_label =
92  operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
93  // clang-format off
94  if (!t->GetAttribute(&count, "COUNT") ||
95  (num_keys == 0 && !t->GetBytes(&keys, "KEYs")) ||
96  (num_keys > 0 &&
97  (!t->GetBytes(&key1, "KEY1") ||
98  !t->GetBytes(&key2, "KEY2") ||
99  !t->GetBytes(&key3, "KEY3"))) ||
100  (ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
101  !t->GetBytes(&in, in_label)) {
102  return false;
103  }
104  // clang-format on
105  std::vector<uint8_t> key;
106  if (num_keys != kNotPresent) {
107  key.insert(key.end(), key1.begin(), key1.end());
108  key.insert(key.end(), key2.begin(), key2.end());
109  if (num_keys == kThree) {
110  key.insert(key.end(), key3.begin(), key3.end());
111  }
112  } else {
113  key.insert(key.end(), keys.begin(), keys.end());
114  key.insert(key.end(), keys.begin(), keys.end());
115  key.insert(key.end(), keys.begin(), keys.end());
116  }
117 
118  if (!CipherOperation(ctx->cipher, &result, operation == kEncrypt, key, iv,
119  in)) {
120  return false;
121  }
122 
123  // TDES fax files output format differs from file to file, and the input
124  // format is inconsistent with the output, so we construct the output manually
125  // rather than printing CurrentTestToString().
126  if (t->IsAtNewInstructionBlock() && num_keys == kNotPresent) {
127  // If NumKeys is present, header is printed when parsing NumKeys.
128  std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
129  printf("%s\r\n", header.c_str());
130  }
131  const std::string result_label =
132  operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
133  printf("COUNT = %s\r\n", count.c_str());
134  if (num_keys == kNotPresent) {
135  printf("KEYs = %s\r\n", EncodeHex(keys).c_str());
136  } else {
137  printf("KEY1 = %s\r\nKEY2 = %s\r\nKEY3 = %s\r\n", EncodeHex(key1).c_str(),
138  EncodeHex(key2).c_str(), EncodeHex(key3).c_str());
139  }
140  if (ctx->has_iv) {
141  printf("IV = %s\r\n", EncodeHex(iv).c_str());
142  }
143  printf("%s = %s\r\n", in_label.c_str(), EncodeHex(in).c_str());
144  printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
145 
146  return true;
147 }
148 
149 // XORKeyWithOddParityLSB sets |*key| to |key| XOR |value| and then writes
150 // the LSB of each byte to establish odd parity for that byte. This parity-based
151 // embedded of a DES key into 64 bits is an old tradition and something that
152 // NIST's tests require.
153 static void XORKeyWithOddParityLSB(std::vector<uint8_t> *key,
154  const std::vector<uint8_t> &value) {
155  for (size_t i = 0; i < key->size(); i++) {
156  uint8_t v = (*key)[i] ^ value[i];
157 
158  // Use LSB to establish odd parity.
159  v |= 0x01;
160  for (uint8_t j = 1; j < 8; j++) {
161  v ^= ((v >> j) & 0x01);
162  }
163  (*key)[i] = v;
164  }
165 }
166 
167 static bool TestMCT(FileTest *t, void *arg) {
168  TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
169 
170  if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
171  t->PrintLine("Want either ENCRYPT or DECRYPT");
172  return false;
173  }
174  enum {
175  kEncrypt,
176  kDecrypt,
177  } operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
178 
179  if (t->HasAttribute("NumKeys")) {
180  // Another file format quirk: NumKeys is a single attribute line immediately
181  // following an instruction and should probably have been an instruction
182  // instead.
183  std::string num_keys;
184  t->GetAttribute(&num_keys, "NumKeys");
185  t->InjectInstruction("NumKeys", num_keys);
186  return true;
187  }
188 
189  enum {
190  kTwo,
191  kThree,
192  } num_keys;
193  std::string num_keys_str;
194  if (!t->GetInstruction(&num_keys_str, "NumKeys")) {
195  return false;
196  } else {
197  const int n = strtoul(num_keys_str.c_str(), nullptr, 0);
198  if (n == 2) {
199  num_keys = kTwo;
200  } else if (n == 3) {
201  num_keys = kThree;
202  } else {
203  t->PrintLine("invalid NumKeys value");
204  return false;
205  }
206  }
207 
209  std::vector<uint8_t> key1, key2, key3, iv, in, result;
210  const std::string in_label =
211  operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
212  // clang-format off
213  if (!t->GetBytes(&key1, "KEY1") ||
214  !t->GetBytes(&key2, "KEY2") ||
215  !t->GetBytes(&key3, "KEY3") ||
216  (ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
217  !t->GetBytes(&in, in_label)) {
218  return false;
219  }
220  // clang-format on
221 
222  for (int i = 0; i < 400; i++) {
223  std::vector<uint8_t> current_iv = iv, current_in = in, prev_result,
224  prev_prev_result;
225 
226  std::vector<uint8_t> key(key1);
227  key.insert(key.end(), key2.begin(), key2.end());
228  key.insert(key.end(), key3.begin(), key3.end());
229 
230  for (int j = 0; j < 10000; j++) {
231  prev_prev_result = prev_result;
232  prev_result = result;
233  const EVP_CIPHER *cipher = ctx->cipher;
234  if (!CipherOperation(cipher, &result, operation == kEncrypt, key,
235  current_iv, current_in)) {
236  t->PrintLine("CipherOperation failed");
237  return false;
238  }
239  if (ctx->has_iv) {
240  if (operation == kEncrypt) {
241  if (j == 0) {
242  current_in = current_iv;
243  } else {
244  current_in = prev_result;
245  }
246  current_iv = result;
247  } else { // operation == kDecrypt
248  current_iv = current_in;
249  current_in = result;
250  }
251  } else {
252  current_in = result;
253  }
254  }
255 
256  // Output result for COUNT = i.
257  const std::string result_label =
258  operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
259  if (i == 0) {
260  const std::string op_label =
261  operation == kEncrypt ? "ENCRYPT" : "DECRYPT";
262  printf("[%s]\n\n", op_label.c_str());
263  }
264  printf("COUNT = %d\r\nKEY1 = %s\r\nKEY2 = %s\r\nKEY3 = %s\r\n", i,
266  EncodeHex(key3).c_str());
267  if (ctx->has_iv) {
268  printf("IV = %s\r\n", EncodeHex(iv).c_str());
269  }
270  printf("%s = %s\r\n", in_label.c_str(), EncodeHex(in).c_str());
271  printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
272 
273 
275  XORKeyWithOddParityLSB(&key2, prev_result);
276  if (num_keys == kThree) {
277  XORKeyWithOddParityLSB(&key3, prev_prev_result);
278  } else {
280  }
281 
282  if (ctx->has_iv) {
283  if (operation == kEncrypt) {
284  in = prev_result;
285  iv = result;
286  } else {
287  iv = current_iv;
288  in = current_in;
289  }
290  } else {
291  in = result;
292  }
293  }
294 
295  return true;
296 }
297 
298 static int usage(char *arg) {
299  fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
300  return 1;
301 }
302 
303 int cavp_tdes_test_main(int argc, char **argv) {
304  if (argc != 4) {
305  return usage(argv[0]);
306  }
307 
308  const std::string tm(argv[1]);
309  enum TestCtx::Mode test_mode;
310  if (tm == "kat") {
311  test_mode = TestCtx::kKAT;
312  } else if (tm == "mct") {
313  test_mode = TestCtx::kMCT;
314  } else {
315  fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
316  return usage(argv[0]);
317  }
318 
319  const std::string cipher_name(argv[2]);
320  const EVP_CIPHER *cipher = GetCipher(argv[2]);
321  if (cipher == nullptr) {
322  fprintf(stderr, "invalid cipher: %s\n", argv[2]);
323  return 1;
324  }
325  bool has_iv = cipher_name != "des-ede" && cipher_name != "des-ede3";
326  TestCtx ctx = {cipher, has_iv, test_mode};
327 
328  FileTestFunc test_fn = test_mode == TestCtx::kKAT ? &TestKAT : &TestMCT;
330  opts.path = argv[3];
331  opts.callback = test_fn;
332  opts.arg = &ctx;
333  opts.silent = true;
334  opts.comment_callback = EchoComment;
335  return FileTestMain(opts);
336 }
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
cavp_tdes_test_main
int cavp_tdes_test_main(int argc, char **argv)
Definition: cavp_tdes_test.cc:303
ctx
Definition: benchmark-async.c:30
FileTestMain
int FileTestMain(FileTestFunc run_test, void *arg, const char *path)
Definition: file_test.cc:399
grpc::testing::key2
const char key2[]
Definition: client_context_test_peer_test.cc:33
keys
const void * keys
Definition: abseil-cpp/absl/random/internal/randen.cc:49
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
XORKeyWithOddParityLSB
static void XORKeyWithOddParityLSB(std::vector< uint8_t > *key, const std::vector< uint8_t > &value)
Definition: cavp_tdes_test.cc:153
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
cstest_report.opts
opts
Definition: cstest_report.py:81
mode
const char int mode
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
ctx
static struct test_ctx ctx
Definition: test-ipc-send-recv.c:65
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
evp_cipher_st
Definition: cipher.h:585
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
grpc::testing::key1
const char key1[]
Definition: client_context_test_peer_test.cc:32
TestKAT
static bool TestKAT(FileTest *t, void *arg)
Definition: cavp_tdes_test.cc:43
FileTestFunc
bool(* FileTestFunc)(FileTest *t, void *arg)
Definition: file_test.h:88
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
cavp_test_util.h
EncodeHex
std::string EncodeHex(bssl::Span< const uint8_t > in)
Definition: boringssl-with-bazel/src/crypto/test/test_util.cc:75
FileTest
Definition: file_test.h:90
header
struct absl::base_internal::@2940::AllocList::Header header
err.h
crypto.h
cipher.h
arg
Definition: cmdline.cc:40
EchoComment
void EchoComment(const std::string &comment)
Definition: cavp_test_util.cc:218
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
TestMCT
static bool TestMCT(FileTest *t, void *arg)
Definition: cavp_tdes_test.cc:167
CipherOperation
bool CipherOperation(const EVP_CIPHER *cipher, std::vector< uint8_t > *out, bool encrypt, const std::vector< uint8_t > &key, const std::vector< uint8_t > &iv, const std::vector< uint8_t > &in)
Definition: cavp_test_util.cc:68
tm
static uv_timer_t tm
Definition: test-tcp-open.c:41
value
const char * value
Definition: hpack_parser_table.cc:165
key
const char * key
Definition: hpack_parser_table.cc:164
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
arg
struct arg arg
FileTest::Options
Definition: file_test.h:104
usage
static int usage(char *arg)
Definition: cavp_tdes_test.cc:298
GetCipher
static const EVP_CIPHER * GetCipher(const std::string &name)
Definition: cipher_test.cc:78
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
test_mode
static test_mode_t test_mode
Definition: test-poll.c:78


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:52