anastasis-crypto-tvg.c (18674B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020,2021 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file util/anastasis-crypto-tgv.c 18 * @brief Generate test vectors for cryptographic operations. 19 * @author Florian Dold 20 * 21 * 22 * Test vectors have the following format (TypeScript pseudo code): 23 * 24 * interface TestVectorFile { 25 * encoding: "base32crockford"; 26 * producer?: string; 27 * vectors: TestVector[]; 28 * } 29 * 30 * enum Operation { 31 * Hash("hash"), 32 * ... 33 * } 34 * 35 * interface TestVector { 36 * operation: Operation; 37 * // Inputs for the operation 38 * [ k: string]: string | number; 39 * }; 40 * 41 * 42 */ 43 #include "platform.h" 44 #include <gnunet/gnunet_util_lib.h> 45 #include <gnunet/gnunet_signatures.h> 46 #include <gnunet/gnunet_testing_lib.h> 47 #include <jansson.h> 48 #include <gcrypt.h> 49 #include "anastasis_crypto_lib.h" 50 #include "anastasis_util_lib.h" 51 52 53 /** 54 * Should we verify or output test vectors? 55 */ 56 static int verify_flag = GNUNET_NO; 57 58 59 /** 60 * Global exit code. 61 */ 62 static int global_ret = 0; 63 64 65 /** 66 * Create a fresh test vector for a given operation label. 67 * 68 * @param vecs array of vectors to append the new vector to 69 * @param vecname label for the operation of the vector 70 * @returns the fresh test vector 71 */ 72 static json_t * 73 vec_for (json_t *vecs, const char *vecname) 74 { 75 json_t *t = json_object (); 76 77 GNUNET_assert (0 == 78 json_object_set_new (t, 79 "operation", 80 json_string (vecname))); 81 GNUNET_assert (0 == 82 json_array_append_new (vecs, 83 t)); 84 return t; 85 } 86 87 88 /** 89 * Add a base32crockford encoded value 90 * to a test vector. 91 * 92 * @param vec test vector to add to 93 * @param label label for the value 94 * @param data data to add 95 * @param size size of data 96 */ 97 static void 98 d2j (json_t *vec, 99 const char *label, 100 const void *data, 101 size_t size) 102 { 103 char *buf; 104 json_t *json; 105 106 buf = GNUNET_STRINGS_data_to_string_alloc (data, 107 size); 108 json = json_string (buf); 109 GNUNET_free (buf); 110 GNUNET_break (NULL != json); 111 112 GNUNET_assert (0 == 113 json_object_set_new (vec, 114 label, 115 json)); 116 } 117 118 119 static void 120 d2j_append (json_t *arr, 121 const void *data, 122 size_t size) 123 { 124 char *buf; 125 json_t *json; 126 127 buf = GNUNET_STRINGS_data_to_string_alloc (data, 128 size); 129 json = json_string (buf); 130 GNUNET_assert (NULL != json); 131 GNUNET_free (buf); 132 133 GNUNET_assert (0 == 134 json_array_append_new (arr, 135 json)); 136 } 137 138 139 #define d2j_auto(vec, label, d) d2j (vec, label, d, sizeof (*d)) 140 #define d2j_append_auto(arr, d) d2j_append (arr, d, sizeof (*d)) 141 #define random_auto(d) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, \ 142 d, \ 143 sizeof (*d)); 144 145 146 static int 147 expect_data_fixed (json_t *vec, 148 const char *name, 149 void *data, 150 size_t expect_len) 151 { 152 const char *s = json_string_value (json_object_get (vec, name)); 153 154 if (NULL == s) 155 return GNUNET_NO; 156 157 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, 158 strlen (s), 159 data, 160 expect_len)) 161 return GNUNET_NO; 162 return GNUNET_OK; 163 } 164 165 166 static int 167 expect_data_dynamic (json_t *vec, 168 const char *name, 169 void **data, 170 size_t *ret_len) 171 { 172 const char *s = json_string_value (json_object_get (vec, name)); 173 char *tmp; 174 size_t len; 175 176 if (NULL == s) 177 return GNUNET_NO; 178 179 len = (strlen (s) * 5) / 8; 180 if (NULL != ret_len) 181 *ret_len = len; 182 tmp = GNUNET_malloc (len); 183 184 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, strlen (s), tmp, len)) 185 { 186 GNUNET_free (tmp); 187 return GNUNET_NO; 188 } 189 *data = tmp; 190 return GNUNET_OK; 191 } 192 193 194 /** 195 * Check a single vector. 196 * 197 * @param operation operator of the vector 198 * @param vec the vector, a JSON object. 199 * 200 * @returns GNUNET_OK if the vector is okay 201 */ 202 static int 203 checkvec (const char *operation, 204 json_t *vec) 205 { 206 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 207 "checking %s\n", operation); 208 209 if (0 == strcmp (operation, "hash")) 210 { 211 void *data; 212 size_t data_len; 213 struct GNUNET_HashCode hash_out; 214 struct GNUNET_HashCode hc; 215 216 if (GNUNET_OK != expect_data_dynamic (vec, 217 "input", 218 &data, 219 &data_len)) 220 { 221 GNUNET_break (0); 222 return GNUNET_SYSERR; 223 } 224 if (GNUNET_OK != expect_data_fixed (vec, 225 "output", 226 &hash_out, 227 sizeof (hash_out))) 228 { 229 GNUNET_free (data); 230 GNUNET_break (0); 231 return GNUNET_NO; 232 } 233 234 GNUNET_CRYPTO_hash (data, data_len, &hc); 235 236 if (0 != GNUNET_memcmp (&hc, &hash_out)) 237 { 238 GNUNET_free (data); 239 GNUNET_break (0); 240 return GNUNET_NO; 241 } 242 GNUNET_free (data); 243 } 244 245 return GNUNET_OK; 246 } 247 248 249 /** 250 * Check test vectors from stdin. 251 * 252 * @returns global exit code 253 */ 254 static int 255 check_vectors () 256 { 257 json_error_t err; 258 json_t *vecfile = json_loadf (stdin, 0, &err); 259 const char *encoding; 260 json_t *vectors; 261 262 if (NULL == vecfile) 263 { 264 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n"); 265 return 1; 266 } 267 encoding = json_string_value (json_object_get (vecfile, 268 "encoding")); 269 if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) ) 270 { 271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n"); 272 json_decref (vecfile); 273 return 1; 274 } 275 vectors = json_object_get (vecfile, "vectors"); 276 if (! json_is_array (vectors)) 277 { 278 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n"); 279 json_decref (vecfile); 280 return 1; 281 } 282 { 283 /* array is a JSON array */ 284 size_t index; 285 json_t *value; 286 int ret; 287 288 json_array_foreach (vectors, index, value) { 289 const char *op = json_string_value (json_object_get (value, 290 "operation")); 291 292 if (NULL == op) 293 { 294 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 295 "missing operation\n"); 296 ret = GNUNET_SYSERR; 297 break; 298 } 299 ret = checkvec (op, value); 300 if (GNUNET_OK != ret) 301 { 302 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 303 "bad vector %u\n", 304 (unsigned int) index); 305 break; 306 } 307 } 308 return (ret == GNUNET_OK) ? 0 : 1; 309 } 310 } 311 312 313 /** 314 * Output test vectors. 315 * 316 * @returns global exit code 317 */ 318 static int 319 output_vectors () 320 { 321 json_t *vecfile = json_object (); 322 json_t *vecs = json_array (); 323 324 GNUNET_assert (NULL != vecfile); 325 GNUNET_assert (NULL != vecs); 326 GNUNET_assert (0 == 327 json_object_set_new (vecfile, 328 "encoding", 329 json_string ("base32crockford"))); 330 GNUNET_assert (0 == 331 json_object_set_new (vecfile, 332 "producer", 333 json_string ( 334 "GNU Anastasis (C implementation) " 335 PACKAGE_VERSION " " 336 VCS_VERSION))); 337 GNUNET_assert (0 == 338 json_object_set_new (vecfile, 339 "vectors", 340 vecs)); 341 342 { 343 json_t *vec = vec_for (vecs, "hash"); 344 struct GNUNET_HashCode hc; 345 const char *str = "Hello, GNUnet"; 346 347 GNUNET_CRYPTO_hash (str, strlen (str), &hc); 348 349 d2j (vec, "input", str, strlen (str)); 350 d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode)); 351 } 352 353 { 354 json_t *vec = vec_for (vecs, "user_identifier_derive"); 355 struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt; 356 struct ANASTASIS_CRYPTO_UserIdentifierP id; 357 json_t *id_data = json_pack ("{s:s, s:s}", 358 "name", 359 "Fleabag", 360 "ssn", 361 "AB123"); 362 GNUNET_assert (NULL != id_data); 363 random_auto (&provider_salt); 364 365 ANASTASIS_CRYPTO_user_identifier_derive (id_data, 366 &provider_salt, 367 &id); 368 GNUNET_assert (0 == 369 json_object_set_new (vec, 370 "input_id_data", 371 id_data)); 372 d2j_auto (vec, 373 "input_provider_salt", 374 &provider_salt); 375 d2j_auto (vec, 376 "output_id", 377 &id); 378 } 379 380 { 381 json_t *vec = vec_for (vecs, "account_keypair_derive"); 382 struct ANASTASIS_CRYPTO_UserIdentifierP id; 383 struct ANASTASIS_CRYPTO_AccountPrivateKeyP priv_key; 384 struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; 385 386 random_auto (&id); 387 ANASTASIS_CRYPTO_account_public_key_derive (&id, &pub_key); 388 ANASTASIS_CRYPTO_account_private_key_derive (&id, &priv_key); 389 390 d2j_auto (vec, "input_id", &id); 391 d2j_auto (vec, "output_priv_key", &priv_key); 392 d2j_auto (vec, "output_pub_key", &pub_key); 393 394 } 395 396 { 397 json_t *vec = vec_for (vecs, "secure_answer_hash"); 398 const char *answer = "Blah"; 399 struct ANASTASIS_CRYPTO_TruthUUIDP uuid; 400 struct ANASTASIS_CRYPTO_QuestionSaltP salt; 401 struct GNUNET_HashCode result; 402 403 random_auto (&uuid); 404 random_auto (&salt); 405 ANASTASIS_CRYPTO_secure_answer_hash (answer, 406 &uuid, 407 &salt, 408 &result); 409 GNUNET_assert (0 == 410 json_object_set_new (vec, 411 "input_answer", 412 json_string (answer))); 413 d2j_auto (vec, "input_uuid", &uuid); 414 d2j_auto (vec, "input_salt", &salt); 415 d2j_auto (vec, "output_hash", &result); 416 } 417 418 { 419 json_t *vec = vec_for (vecs, "recovery_document_encryption"); 420 struct ANASTASIS_CRYPTO_UserIdentifierP id; 421 const void *rec_doc = "my recovery doc"; 422 size_t rd_size = strlen (rec_doc) + 1; 423 void *enc_rec_doc; 424 size_t erd_size; 425 426 random_auto (&id); 427 428 ANASTASIS_CRYPTO_recovery_document_encrypt (&id, 429 rec_doc, 430 rd_size, 431 &enc_rec_doc, 432 &erd_size); 433 d2j_auto (vec, "input_user_id", &id); 434 d2j (vec, "input_recovery_document", rec_doc, rd_size); 435 d2j (vec, "output_encrypted_recovery_document", &enc_rec_doc, erd_size); 436 } 437 438 { 439 /* With extra salt */ 440 json_t *vec = vec_for (vecs, "keyshare_encryption"); 441 struct ANASTASIS_CRYPTO_KeyShareP key_share; 442 struct ANASTASIS_CRYPTO_UserIdentifierP id; 443 const char *xsalt = "myanswer"; 444 struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share; 445 446 random_auto (&key_share); 447 random_auto (&id); 448 449 ANASTASIS_CRYPTO_keyshare_encrypt (&key_share, 450 &id, 451 xsalt, 452 &enc_key_share); 453 d2j_auto (vec, "input_key_share", &key_share); 454 d2j_auto (vec, "input_user_id", &id); 455 GNUNET_assert (0 == 456 json_object_set_new (vec, 457 "input_xsalt", 458 json_string (xsalt))); 459 d2j_auto (vec, 460 "output_enc_key_share", 461 &enc_key_share); 462 } 463 464 { 465 /* Without extra salt */ 466 json_t *vec = vec_for (vecs, "keyshare_encryption"); 467 struct ANASTASIS_CRYPTO_KeyShareP key_share; 468 struct ANASTASIS_CRYPTO_UserIdentifierP id; 469 char *xsalt = NULL; 470 struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share; 471 472 random_auto (&key_share); 473 random_auto (&id); 474 475 ANASTASIS_CRYPTO_keyshare_encrypt (&key_share, 476 &id, 477 xsalt, 478 &enc_key_share); 479 d2j_auto (vec, "input_key_share", &key_share); 480 d2j_auto (vec, "input_user_id", &id); 481 GNUNET_assert (0 == 482 json_object_set_new (vec, 483 "input_xsalt", 484 json_null ())); 485 d2j_auto (vec, "output_enc_key_share", &enc_key_share); 486 } 487 488 { 489 json_t *vec = vec_for (vecs, "truth_encryption"); 490 491 struct ANASTASIS_CRYPTO_NonceP nonce; 492 struct ANASTASIS_CRYPTO_TruthKeyP truth_enc_key; 493 char truth[256]; 494 size_t truth_size = 256; 495 void *enc_truth; 496 size_t ect_size; 497 498 random_auto (&nonce); 499 random_auto (&truth); 500 random_auto (&truth_enc_key); 501 502 ANASTASIS_CRYPTO_truth_encrypt (&nonce, 503 &truth_enc_key, 504 truth, 505 truth_size, 506 &enc_truth, 507 &ect_size); 508 509 d2j_auto (vec, "input_nonce", &nonce); 510 d2j_auto (vec, "input_truth_enc_key", &truth_enc_key); 511 d2j (vec, "input_truth", &truth, truth_size); 512 d2j (vec, "output_encrypted_truth", enc_truth, ect_size); 513 } 514 515 { 516 json_t *vec = vec_for (vecs, "policy_key_derive"); 517 518 struct ANASTASIS_CRYPTO_KeyShareP key_shares[2]; 519 unsigned int keyshare_length = 2; 520 struct ANASTASIS_CRYPTO_MasterSaltP salt; 521 struct ANASTASIS_CRYPTO_PolicyKeyP policy_key; 522 json_t *key_shares_json = json_array (); 523 524 GNUNET_assert (NULL != key_shares_json); 525 random_auto (&key_shares[0]); 526 random_auto (&key_shares[1]); 527 random_auto (&salt); 528 529 ANASTASIS_CRYPTO_policy_key_derive (key_shares, 530 keyshare_length, 531 &salt, 532 &policy_key); 533 534 d2j_append_auto (key_shares_json, &key_shares[0]); 535 d2j_append_auto (key_shares_json, &key_shares[1]); 536 GNUNET_assert (0 == 537 json_object_set_new (vec, 538 "input_key_shares", 539 key_shares_json)); 540 d2j_auto (vec, "input_salt", &salt); 541 d2j_auto (vec, "output_policy_key", &policy_key); 542 } 543 544 { 545 // json_t *vec = vec_for (vecs, "core_secret_encryption"); 546 // struct ANASTASIS_CRYPTO_PolicyKeyP policy_keys[2]; 547 // unsigned int policy_keys_length = 2; 548 // char core_secret[256]; 549 // size_t core_secret_size = 256; 550 // void *enc_core_secret; 551 // struct ANASTASIS_CRYPTO_EncryptedMasterKeyP encrypted_master_keys[2]; 552 // json_t *policy_keys_json = json_array (); 553 // json_t *encrypted_master_keys_json = json_array (); 554 555 // random_auto (&policy_keys[0]); 556 // random_auto (&policy_keys[1]); 557 // random_auto (&core_secret); 558 559 // ANASTASIS_CRYPTO_core_secret_encrypt (policy_keys, policy_keys_length, 560 // core_secret, core_secret_size, 561 // &enc_core_secret, 562 // encrypted_master_keys); 563 564 // d2j_append_auto (policy_keys_json, &policy_keys_json[0]); 565 // d2j_append_auto (policy_keys_json, &policy_keys_json[1]); 566 // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[0]); 567 // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[1]); 568 569 // d2j_auto (vec, "input_core_secret", &core_secret); 570 // json_object_set_new (vec, "input_policy_keys", policy_keys_json); 571 // json_object_set_new (vec, "output_encrypted_core_secret", encrypted_master_keys_json); 572 // json_object_set_new (vec, "output_encrypted_master_keys", encrypted_master_keys_json); 573 } 574 575 576 json_dumpf (vecfile, stdout, JSON_INDENT (2)); 577 json_decref (vecfile); 578 printf ("\n"); 579 580 return 0; 581 } 582 583 584 /** 585 * Main function that will be run. 586 * 587 * @param cls closure 588 * @param args remaining command-line arguments 589 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 590 * @param cfg configuration 591 */ 592 static void 593 run (void *cls, 594 char *const *args, 595 const char *cfgfile, 596 const struct GNUNET_CONFIGURATION_Handle *cfg) 597 { 598 if (GNUNET_YES == verify_flag) 599 global_ret = check_vectors (); 600 else 601 global_ret = output_vectors (); 602 } 603 604 605 /** 606 * The main function of the test vector generation tool. 607 * 608 * @param argc number of arguments from the command line 609 * @param argv command line arguments 610 * @return 0 ok, 1 on error 611 */ 612 int 613 main (int argc, 614 char *const *argv) 615 { 616 const struct GNUNET_GETOPT_CommandLineOption options[] = { 617 GNUNET_GETOPT_option_flag ('V', 618 "verify", 619 gettext_noop ( 620 "verify a test vector from stdin"), 621 &verify_flag), 622 GNUNET_GETOPT_OPTION_END 623 }; 624 625 GNUNET_assert (GNUNET_OK == 626 GNUNET_log_setup ("anastasis-crypto-tvg", 627 "INFO", 628 NULL)); 629 if (GNUNET_OK != 630 GNUNET_PROGRAM_run (ANASTASIS_project_data (), 631 argc, argv, 632 "anastasis-crypto-tvg", 633 "Generate test vectors for cryptographic operations", 634 options, 635 &run, NULL)) 636 return 1; 637 return global_ret; 638 } 639 640 641 /* end of anastasis-crypto-tvg.c */