Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

343 строки
10 KiB

  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. // cavp_tdes_test processes a NIST TMOVS test vector request file and emits the
  15. // corresponding response.
  16. #include <stdlib.h>
  17. #include <openssl/cipher.h>
  18. #include <openssl/crypto.h>
  19. #include <openssl/err.h>
  20. #include "../crypto/test/file_test.h"
  21. #include "cavp_test_util.h"
  22. namespace {
  23. struct TestCtx {
  24. const EVP_CIPHER *cipher;
  25. enum Mode {
  26. kKAT, // Known Answer Test
  27. kMCT, // Monte Carlo Test
  28. };
  29. bool has_iv;
  30. Mode mode;
  31. };
  32. }
  33. static bool TestKAT(FileTest *t, void *arg) {
  34. TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
  35. if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
  36. t->PrintLine("Want either ENCRYPT or DECRYPT");
  37. return false;
  38. }
  39. enum {
  40. kEncrypt,
  41. kDecrypt,
  42. } operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
  43. if (t->HasAttribute("NumKeys")) {
  44. // Another file format quirk: NumKeys is a single attribute line immediately
  45. // following an instruction and should probably have been an instruction
  46. // instead. If it is present, the file has separate attributes "KEY{1,2,3}".
  47. // If it is not, the keys are concatenated in a single attribute "KEYs".
  48. std::string num_keys;
  49. t->GetAttribute(&num_keys, "NumKeys");
  50. t->InjectInstruction("NumKeys", num_keys);
  51. std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
  52. printf("%s\r\n\r\n", header.c_str());
  53. return true;
  54. }
  55. enum {
  56. kNotPresent,
  57. kTwo,
  58. kThree,
  59. } num_keys = kNotPresent;
  60. if (t->HasInstruction("NumKeys")) {
  61. std::string num_keys_str;
  62. t->GetInstruction(&num_keys_str, "NumKeys");
  63. const int n = strtoul(num_keys_str.c_str(), nullptr, 0);
  64. if (n == 2) {
  65. num_keys = kTwo;
  66. } else if (n == 3) {
  67. num_keys = kThree;
  68. } else {
  69. t->PrintLine("invalid NumKeys value");
  70. return false;
  71. }
  72. }
  73. std::string count;
  74. std::vector<uint8_t> keys, key1, key2, key3, iv, in, result;
  75. const std::string in_label =
  76. operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
  77. // clang-format off
  78. if (!t->GetAttribute(&count, "COUNT") ||
  79. (num_keys == 0 && !t->GetBytes(&keys, "KEYs")) ||
  80. (num_keys > 0 &&
  81. (!t->GetBytes(&key1, "KEY1") ||
  82. !t->GetBytes(&key2, "KEY2") ||
  83. !t->GetBytes(&key3, "KEY3"))) ||
  84. (ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
  85. !t->GetBytes(&in, in_label)) {
  86. return false;
  87. }
  88. // clang-format on
  89. std::vector<uint8_t> key;
  90. if (num_keys != kNotPresent) {
  91. key.insert(key.end(), key1.begin(), key1.end());
  92. key.insert(key.end(), key2.begin(), key2.end());
  93. if (num_keys == kThree) {
  94. key.insert(key.end(), key3.begin(), key3.end());
  95. }
  96. } else {
  97. key.insert(key.end(), keys.begin(), keys.end());
  98. key.insert(key.end(), keys.begin(), keys.end());
  99. key.insert(key.end(), keys.begin(), keys.end());
  100. }
  101. if (!CipherOperation(ctx->cipher, &result, operation == kEncrypt, key, iv,
  102. in)) {
  103. return false;
  104. }
  105. // TDES fax files output format differs from file to file, and the input
  106. // format is inconsistent with the output, so we construct the output manually
  107. // rather than printing CurrentTestToString().
  108. if (t->IsAtNewInstructionBlock() && num_keys == kNotPresent) {
  109. // If NumKeys is present, header is printed when parsing NumKeys.
  110. std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
  111. printf("%s\r\n", header.c_str());
  112. }
  113. const std::string result_label =
  114. operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
  115. printf("COUNT = %s\r\n", count.c_str());
  116. if (num_keys == kNotPresent) {
  117. printf("KEYs = %s\r\n", EncodeHex(keys.data(), keys.size()).c_str());
  118. } else {
  119. printf("KEY1 = %s\r\nKEY2 = %s\r\nKEY3 = %s\r\n",
  120. EncodeHex(key1.data(), key1.size()).c_str(),
  121. EncodeHex(key2.data(), key2.size()).c_str(),
  122. EncodeHex(key3.data(), key3.size()).c_str());
  123. }
  124. if (ctx->has_iv) {
  125. printf("IV = %s\r\n", EncodeHex(iv.data(), iv.size()).c_str());
  126. }
  127. printf("%s = %s\r\n", in_label.c_str(),
  128. EncodeHex(in.data(), in.size()).c_str());
  129. printf("%s = %s\r\n\r\n", result_label.c_str(),
  130. EncodeHex(result.data(), result.size()).c_str());
  131. return true;
  132. }
  133. // XORKeyWithOddParityLSB sets |*key| to |key| XOR |value| and then writes
  134. // the LSB of each byte to establish odd parity for that byte. This parity-based
  135. // embedded of a DES key into 64 bits is an old tradition and something that
  136. // NIST's tests require.
  137. static void XORKeyWithOddParityLSB(std::vector<uint8_t> *key,
  138. const std::vector<uint8_t> &value) {
  139. for (size_t i = 0; i < key->size(); i++) {
  140. uint8_t v = (*key)[i] ^ value[i];
  141. // Use LSB to establish odd parity.
  142. v |= 0x01;
  143. for (uint8_t j = 1; j < 8; j++) {
  144. v ^= ((v >> j) & 0x01);
  145. }
  146. (*key)[i] = v;
  147. }
  148. }
  149. static bool TestMCT(FileTest *t, void *arg) {
  150. TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
  151. if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
  152. t->PrintLine("Want either ENCRYPT or DECRYPT");
  153. return false;
  154. }
  155. enum {
  156. kEncrypt,
  157. kDecrypt,
  158. } operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
  159. if (t->HasAttribute("NumKeys")) {
  160. // Another file format quirk: NumKeys is a single attribute line immediately
  161. // following an instruction and should probably have been an instruction
  162. // instead.
  163. std::string num_keys;
  164. t->GetAttribute(&num_keys, "NumKeys");
  165. t->InjectInstruction("NumKeys", num_keys);
  166. return true;
  167. }
  168. enum {
  169. kTwo,
  170. kThree,
  171. } num_keys;
  172. std::string num_keys_str;
  173. if (!t->GetInstruction(&num_keys_str, "NumKeys")) {
  174. return false;
  175. } else {
  176. const int n = strtoul(num_keys_str.c_str(), nullptr, 0);
  177. if (n == 2) {
  178. num_keys = kTwo;
  179. } else if (n == 3) {
  180. num_keys = kThree;
  181. } else {
  182. t->PrintLine("invalid NumKeys value");
  183. return false;
  184. }
  185. }
  186. std::string count;
  187. std::vector<uint8_t> key1, key2, key3, iv, in, result;
  188. const std::string in_label =
  189. operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
  190. // clang-format off
  191. if (!t->GetBytes(&key1, "KEY1") ||
  192. !t->GetBytes(&key2, "KEY2") ||
  193. !t->GetBytes(&key3, "KEY3") ||
  194. (ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
  195. !t->GetBytes(&in, in_label)) {
  196. return false;
  197. }
  198. // clang-format on
  199. for (int i = 0; i < 400; i++) {
  200. std::vector<uint8_t> current_iv = iv, current_in = in, prev_result,
  201. prev_prev_result;
  202. std::vector<uint8_t> key(key1);
  203. key.insert(key.end(), key2.begin(), key2.end());
  204. key.insert(key.end(), key3.begin(), key3.end());
  205. for (int j = 0; j < 10000; j++) {
  206. prev_prev_result = prev_result;
  207. prev_result = result;
  208. const EVP_CIPHER *cipher = ctx->cipher;
  209. if (!CipherOperation(cipher, &result, operation == kEncrypt, key,
  210. current_iv, current_in)) {
  211. t->PrintLine("CipherOperation failed");
  212. return false;
  213. }
  214. if (ctx->has_iv) {
  215. if (operation == kEncrypt) {
  216. if (j == 0) {
  217. current_in = current_iv;
  218. } else {
  219. current_in = prev_result;
  220. }
  221. current_iv = result;
  222. } else { // operation == kDecrypt
  223. current_iv = current_in;
  224. current_in = result;
  225. }
  226. } else {
  227. current_in = result;
  228. }
  229. }
  230. // Output result for COUNT = i.
  231. const std::string result_label =
  232. operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
  233. if (i == 0) {
  234. const std::string op_label =
  235. operation == kEncrypt ? "ENCRYPT" : "DECRYPT";
  236. printf("[%s]\n\n", op_label.c_str());
  237. }
  238. printf("COUNT = %d\r\nKEY1 = %s\r\nKEY2 = %s\r\nKEY3 = %s\r\n", i,
  239. EncodeHex(key1.data(), key1.size()).c_str(),
  240. EncodeHex(key2.data(), key2.size()).c_str(),
  241. EncodeHex(key3.data(), key3.size()).c_str());
  242. if (ctx->has_iv) {
  243. printf("IV = %s\r\n", EncodeHex(iv.data(), iv.size()).c_str());
  244. }
  245. printf("%s = %s\r\n", in_label.c_str(),
  246. EncodeHex(in.data(), in.size()).c_str());
  247. printf("%s = %s\r\n\r\n", result_label.c_str(),
  248. EncodeHex(result.data(), result.size()).c_str());
  249. XORKeyWithOddParityLSB(&key1, result);
  250. XORKeyWithOddParityLSB(&key2, prev_result);
  251. if (num_keys == kThree) {
  252. XORKeyWithOddParityLSB(&key3, prev_prev_result);
  253. } else {
  254. XORKeyWithOddParityLSB(&key3, result);
  255. }
  256. if (ctx->has_iv) {
  257. if (operation == kEncrypt) {
  258. in = prev_result;
  259. iv = result;
  260. } else {
  261. iv = current_iv;
  262. in = current_in;
  263. }
  264. } else {
  265. in = result;
  266. }
  267. }
  268. return true;
  269. }
  270. static int usage(char *arg) {
  271. fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
  272. return 1;
  273. }
  274. int cavp_tdes_test_main(int argc, char **argv) {
  275. if (argc != 4) {
  276. return usage(argv[0]);
  277. }
  278. const std::string tm(argv[1]);
  279. enum TestCtx::Mode test_mode;
  280. if (tm == "kat") {
  281. test_mode = TestCtx::kKAT;
  282. } else if (tm == "mct") {
  283. test_mode = TestCtx::kMCT;
  284. } else {
  285. fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
  286. return usage(argv[0]);
  287. }
  288. const std::string cipher_name(argv[2]);
  289. const EVP_CIPHER *cipher = GetCipher(argv[2]);
  290. if (cipher == nullptr) {
  291. fprintf(stderr, "invalid cipher: %s\n", argv[2]);
  292. return 1;
  293. }
  294. bool has_iv = cipher_name != "des-ede" && cipher_name != "des-ede3";
  295. TestCtx ctx = {cipher, has_iv, test_mode};
  296. FileTestFunc test_fn = test_mode == TestCtx::kKAT ? &TestKAT : &TestMCT;
  297. FileTest::Options opts;
  298. opts.path = argv[3];
  299. opts.callback = test_fn;
  300. opts.arg = &ctx;
  301. opts.silent = true;
  302. opts.comment_callback = EchoComment;
  303. return FileTestMain(opts);
  304. }