anastasis-crypto-tvg.c (18537B)
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 (d, \ 142 sizeof (*d)); 143 144 145 static int 146 expect_data_fixed (json_t *vec, 147 const char *name, 148 void *data, 149 size_t expect_len) 150 { 151 const char *s = json_string_value (json_object_get (vec, name)); 152 153 if (NULL == s) 154 return GNUNET_NO; 155 156 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, 157 strlen (s), 158 data, 159 expect_len)) 160 return GNUNET_NO; 161 return GNUNET_OK; 162 } 163 164 165 static int 166 expect_data_dynamic (json_t *vec, 167 const char *name, 168 void **data, 169 size_t *ret_len) 170 { 171 const char *s = json_string_value (json_object_get (vec, name)); 172 char *tmp; 173 size_t len; 174 175 if (NULL == s) 176 return GNUNET_NO; 177 178 len = (strlen (s) * 5) / 8; 179 if (NULL != ret_len) 180 *ret_len = len; 181 tmp = GNUNET_malloc (len); 182 183 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, strlen (s), tmp, len)) 184 { 185 GNUNET_free (tmp); 186 return GNUNET_NO; 187 } 188 *data = tmp; 189 return GNUNET_OK; 190 } 191 192 193 /** 194 * Check a single vector. 195 * 196 * @param operation operator of the vector 197 * @param vec the vector, a JSON object. 198 * 199 * @returns GNUNET_OK if the vector is okay 200 */ 201 static int 202 checkvec (const char *operation, 203 json_t *vec) 204 { 205 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 206 "checking %s\n", operation); 207 208 if (0 == strcmp (operation, "hash")) 209 { 210 void *data; 211 size_t data_len; 212 struct GNUNET_HashCode hash_out; 213 struct GNUNET_HashCode hc; 214 215 if (GNUNET_OK != expect_data_dynamic (vec, 216 "input", 217 &data, 218 &data_len)) 219 { 220 GNUNET_break (0); 221 return GNUNET_SYSERR; 222 } 223 if (GNUNET_OK != expect_data_fixed (vec, 224 "output", 225 &hash_out, 226 sizeof (hash_out))) 227 { 228 GNUNET_free (data); 229 GNUNET_break (0); 230 return GNUNET_NO; 231 } 232 233 GNUNET_CRYPTO_hash (data, data_len, &hc); 234 235 if (0 != GNUNET_memcmp (&hc, &hash_out)) 236 { 237 GNUNET_free (data); 238 GNUNET_break (0); 239 return GNUNET_NO; 240 } 241 GNUNET_free (data); 242 } 243 244 return GNUNET_OK; 245 } 246 247 248 /** 249 * Check test vectors from stdin. 250 * 251 * @returns global exit code 252 */ 253 static int 254 check_vectors () 255 { 256 json_error_t err; 257 json_t *vecfile = json_loadf (stdin, 0, &err); 258 const char *encoding; 259 json_t *vectors; 260 261 if (NULL == vecfile) 262 { 263 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n"); 264 return 1; 265 } 266 encoding = json_string_value (json_object_get (vecfile, 267 "encoding")); 268 if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) ) 269 { 270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n"); 271 json_decref (vecfile); 272 return 1; 273 } 274 vectors = json_object_get (vecfile, "vectors"); 275 if (! json_is_array (vectors)) 276 { 277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n"); 278 json_decref (vecfile); 279 return 1; 280 } 281 { 282 /* array is a JSON array */ 283 size_t index; 284 json_t *value; 285 int ret; 286 287 json_array_foreach (vectors, index, value) { 288 const char *op = json_string_value (json_object_get (value, 289 "operation")); 290 291 if (NULL == op) 292 { 293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 294 "missing operation\n"); 295 ret = GNUNET_SYSERR; 296 break; 297 } 298 ret = checkvec (op, value); 299 if (GNUNET_OK != ret) 300 { 301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 302 "bad vector %u\n", 303 (unsigned int) index); 304 break; 305 } 306 } 307 return (ret == GNUNET_OK) ? 0 : 1; 308 } 309 } 310 311 312 /** 313 * Output test vectors. 314 * 315 * @returns global exit code 316 */ 317 static int 318 output_vectors () 319 { 320 json_t *vecfile = json_object (); 321 json_t *vecs = json_array (); 322 323 GNUNET_assert (NULL != vecfile); 324 GNUNET_assert (NULL != vecs); 325 GNUNET_assert (0 == 326 json_object_set_new (vecfile, 327 "encoding", 328 json_string ("base32crockford"))); 329 GNUNET_assert (0 == 330 json_object_set_new (vecfile, 331 "producer", 332 json_string ( 333 "GNU Anastasis (C implementation) " 334 PACKAGE_VERSION))); 335 GNUNET_assert (0 == 336 json_object_set_new (vecfile, 337 "vectors", 338 vecs)); 339 340 { 341 json_t *vec = vec_for (vecs, "hash"); 342 struct GNUNET_HashCode hc; 343 const char *str = "Hello, GNUnet"; 344 345 GNUNET_CRYPTO_hash (str, strlen (str), &hc); 346 347 d2j (vec, "input", str, strlen (str)); 348 d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode)); 349 } 350 351 { 352 json_t *vec = vec_for (vecs, "user_identifier_derive"); 353 struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt; 354 struct ANASTASIS_CRYPTO_UserIdentifierP id; 355 json_t *id_data = json_pack ("{s:s, s:s}", 356 "name", 357 "Fleabag", 358 "ssn", 359 "AB123"); 360 GNUNET_assert (NULL != id_data); 361 random_auto (&provider_salt); 362 363 ANASTASIS_CRYPTO_user_identifier_derive (id_data, 364 &provider_salt, 365 &id); 366 GNUNET_assert (0 == 367 json_object_set_new (vec, 368 "input_id_data", 369 id_data)); 370 d2j_auto (vec, 371 "input_provider_salt", 372 &provider_salt); 373 d2j_auto (vec, 374 "output_id", 375 &id); 376 } 377 378 { 379 json_t *vec = vec_for (vecs, "account_keypair_derive"); 380 struct ANASTASIS_CRYPTO_UserIdentifierP id; 381 struct ANASTASIS_CRYPTO_AccountPrivateKeyP priv_key; 382 struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; 383 384 random_auto (&id); 385 ANASTASIS_CRYPTO_account_public_key_derive (&id, &pub_key); 386 ANASTASIS_CRYPTO_account_private_key_derive (&id, &priv_key); 387 388 d2j_auto (vec, "input_id", &id); 389 d2j_auto (vec, "output_priv_key", &priv_key); 390 d2j_auto (vec, "output_pub_key", &pub_key); 391 392 } 393 394 { 395 json_t *vec = vec_for (vecs, "secure_answer_hash"); 396 const char *answer = "Blah"; 397 struct ANASTASIS_CRYPTO_TruthUUIDP uuid; 398 struct ANASTASIS_CRYPTO_QuestionSaltP salt; 399 struct GNUNET_HashCode result; 400 401 random_auto (&uuid); 402 random_auto (&salt); 403 ANASTASIS_CRYPTO_secure_answer_hash (answer, 404 &uuid, 405 &salt, 406 &result); 407 GNUNET_assert (0 == 408 json_object_set_new (vec, 409 "input_answer", 410 json_string (answer))); 411 d2j_auto (vec, "input_uuid", &uuid); 412 d2j_auto (vec, "input_salt", &salt); 413 d2j_auto (vec, "output_hash", &result); 414 } 415 416 { 417 json_t *vec = vec_for (vecs, "recovery_document_encryption"); 418 struct ANASTASIS_CRYPTO_UserIdentifierP id; 419 const void *rec_doc = "my recovery doc"; 420 size_t rd_size = strlen (rec_doc) + 1; 421 void *enc_rec_doc; 422 size_t erd_size; 423 424 random_auto (&id); 425 426 ANASTASIS_CRYPTO_recovery_document_encrypt (&id, 427 rec_doc, 428 rd_size, 429 &enc_rec_doc, 430 &erd_size); 431 d2j_auto (vec, "input_user_id", &id); 432 d2j (vec, "input_recovery_document", rec_doc, rd_size); 433 d2j (vec, "output_encrypted_recovery_document", &enc_rec_doc, erd_size); 434 } 435 436 { 437 /* With extra salt */ 438 json_t *vec = vec_for (vecs, "keyshare_encryption"); 439 struct ANASTASIS_CRYPTO_KeyShareP key_share; 440 struct ANASTASIS_CRYPTO_UserIdentifierP id; 441 const char *xsalt = "myanswer"; 442 struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share; 443 444 random_auto (&key_share); 445 random_auto (&id); 446 447 ANASTASIS_CRYPTO_keyshare_encrypt (&key_share, 448 &id, 449 xsalt, 450 &enc_key_share); 451 d2j_auto (vec, "input_key_share", &key_share); 452 d2j_auto (vec, "input_user_id", &id); 453 GNUNET_assert (0 == 454 json_object_set_new (vec, 455 "input_xsalt", 456 json_string (xsalt))); 457 d2j_auto (vec, 458 "output_enc_key_share", 459 &enc_key_share); 460 } 461 462 { 463 /* Without extra salt */ 464 json_t *vec = vec_for (vecs, "keyshare_encryption"); 465 struct ANASTASIS_CRYPTO_KeyShareP key_share; 466 struct ANASTASIS_CRYPTO_UserIdentifierP id; 467 char *xsalt = NULL; 468 struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share; 469 470 random_auto (&key_share); 471 random_auto (&id); 472 473 ANASTASIS_CRYPTO_keyshare_encrypt (&key_share, 474 &id, 475 xsalt, 476 &enc_key_share); 477 d2j_auto (vec, "input_key_share", &key_share); 478 d2j_auto (vec, "input_user_id", &id); 479 GNUNET_assert (0 == 480 json_object_set_new (vec, 481 "input_xsalt", 482 json_null ())); 483 d2j_auto (vec, "output_enc_key_share", &enc_key_share); 484 } 485 486 { 487 json_t *vec = vec_for (vecs, "truth_encryption"); 488 489 struct ANASTASIS_CRYPTO_NonceP nonce; 490 struct ANASTASIS_CRYPTO_TruthKeyP truth_enc_key; 491 char truth[256]; 492 size_t truth_size = 256; 493 void *enc_truth; 494 size_t ect_size; 495 496 random_auto (&nonce); 497 random_auto (&truth); 498 random_auto (&truth_enc_key); 499 500 ANASTASIS_CRYPTO_truth_encrypt (&nonce, 501 &truth_enc_key, 502 truth, 503 truth_size, 504 &enc_truth, 505 &ect_size); 506 507 d2j_auto (vec, "input_nonce", &nonce); 508 d2j_auto (vec, "input_truth_enc_key", &truth_enc_key); 509 d2j (vec, "input_truth", &truth, truth_size); 510 d2j (vec, "output_encrypted_truth", enc_truth, ect_size); 511 } 512 513 { 514 json_t *vec = vec_for (vecs, "policy_key_derive"); 515 516 struct ANASTASIS_CRYPTO_KeyShareP key_shares[2]; 517 unsigned int keyshare_length = 2; 518 struct ANASTASIS_CRYPTO_MasterSaltP salt; 519 struct ANASTASIS_CRYPTO_PolicyKeyP policy_key; 520 json_t *key_shares_json = json_array (); 521 522 GNUNET_assert (NULL != key_shares_json); 523 random_auto (&key_shares[0]); 524 random_auto (&key_shares[1]); 525 random_auto (&salt); 526 527 ANASTASIS_CRYPTO_policy_key_derive (key_shares, 528 keyshare_length, 529 &salt, 530 &policy_key); 531 532 d2j_append_auto (key_shares_json, &key_shares[0]); 533 d2j_append_auto (key_shares_json, &key_shares[1]); 534 GNUNET_assert (0 == 535 json_object_set_new (vec, 536 "input_key_shares", 537 key_shares_json)); 538 d2j_auto (vec, "input_salt", &salt); 539 d2j_auto (vec, "output_policy_key", &policy_key); 540 } 541 542 { 543 // json_t *vec = vec_for (vecs, "core_secret_encryption"); 544 // struct ANASTASIS_CRYPTO_PolicyKeyP policy_keys[2]; 545 // unsigned int policy_keys_length = 2; 546 // char core_secret[256]; 547 // size_t core_secret_size = 256; 548 // void *enc_core_secret; 549 // struct ANASTASIS_CRYPTO_EncryptedMasterKeyP encrypted_master_keys[2]; 550 // json_t *policy_keys_json = json_array (); 551 // json_t *encrypted_master_keys_json = json_array (); 552 553 // random_auto (&policy_keys[0]); 554 // random_auto (&policy_keys[1]); 555 // random_auto (&core_secret); 556 557 // ANASTASIS_CRYPTO_core_secret_encrypt (policy_keys, policy_keys_length, 558 // core_secret, core_secret_size, 559 // &enc_core_secret, 560 // encrypted_master_keys); 561 562 // d2j_append_auto (policy_keys_json, &policy_keys_json[0]); 563 // d2j_append_auto (policy_keys_json, &policy_keys_json[1]); 564 // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[0]); 565 // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[1]); 566 567 // d2j_auto (vec, "input_core_secret", &core_secret); 568 // json_object_set_new (vec, "input_policy_keys", policy_keys_json); 569 // json_object_set_new (vec, "output_encrypted_core_secret", encrypted_master_keys_json); 570 // json_object_set_new (vec, "output_encrypted_master_keys", encrypted_master_keys_json); 571 } 572 573 574 json_dumpf (vecfile, stdout, JSON_INDENT (2)); 575 json_decref (vecfile); 576 printf ("\n"); 577 578 return 0; 579 } 580 581 582 /** 583 * Main function that will be run. 584 * 585 * @param cls closure 586 * @param args remaining command-line arguments 587 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 588 * @param cfg configuration 589 */ 590 static void 591 run (void *cls, 592 char *const *args, 593 const char *cfgfile, 594 const struct GNUNET_CONFIGURATION_Handle *cfg) 595 { 596 if (GNUNET_YES == verify_flag) 597 global_ret = check_vectors (); 598 else 599 global_ret = output_vectors (); 600 } 601 602 603 /** 604 * The main function of the test vector generation tool. 605 * 606 * @param argc number of arguments from the command line 607 * @param argv command line arguments 608 * @return 0 ok, 1 on error 609 */ 610 int 611 main (int argc, 612 char *const *argv) 613 { 614 const struct GNUNET_GETOPT_CommandLineOption options[] = { 615 GNUNET_GETOPT_option_flag ('V', 616 "verify", 617 gettext_noop ( 618 "verify a test vector from stdin"), 619 &verify_flag), 620 GNUNET_GETOPT_OPTION_END 621 }; 622 623 GNUNET_assert (GNUNET_OK == 624 GNUNET_log_setup ("anastasis-crypto-tvg", 625 "INFO", 626 NULL)); 627 if (GNUNET_OK != 628 GNUNET_PROGRAM_run (ANASTASIS_project_data (), 629 argc, argv, 630 "anastasis-crypto-tvg", 631 "Generate test vectors for cryptographic operations", 632 options, 633 &run, NULL)) 634 return 1; 635 return global_ret; 636 } 637 638 639 /* end of anastasis-crypto-tvg.c */