anastasis-crypto-tvg.c (18618B)
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 GNUNET_assert (0 == 337 json_object_set_new (vecfile, 338 "vectors", 339 vecs)); 340 341 { 342 json_t *vec = vec_for (vecs, "hash"); 343 struct GNUNET_HashCode hc; 344 const char *str = "Hello, GNUnet"; 345 346 GNUNET_CRYPTO_hash (str, strlen (str), &hc); 347 348 d2j (vec, "input", str, strlen (str)); 349 d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode)); 350 } 351 352 { 353 json_t *vec = vec_for (vecs, "user_identifier_derive"); 354 struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt; 355 struct ANASTASIS_CRYPTO_UserIdentifierP id; 356 json_t *id_data = json_pack ("{s:s, s:s}", 357 "name", 358 "Fleabag", 359 "ssn", 360 "AB123"); 361 GNUNET_assert (NULL != id_data); 362 random_auto (&provider_salt); 363 364 ANASTASIS_CRYPTO_user_identifier_derive (id_data, 365 &provider_salt, 366 &id); 367 GNUNET_assert (0 == 368 json_object_set_new (vec, 369 "input_id_data", 370 id_data)); 371 d2j_auto (vec, 372 "input_provider_salt", 373 &provider_salt); 374 d2j_auto (vec, 375 "output_id", 376 &id); 377 } 378 379 { 380 json_t *vec = vec_for (vecs, "account_keypair_derive"); 381 struct ANASTASIS_CRYPTO_UserIdentifierP id; 382 struct ANASTASIS_CRYPTO_AccountPrivateKeyP priv_key; 383 struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; 384 385 random_auto (&id); 386 ANASTASIS_CRYPTO_account_public_key_derive (&id, &pub_key); 387 ANASTASIS_CRYPTO_account_private_key_derive (&id, &priv_key); 388 389 d2j_auto (vec, "input_id", &id); 390 d2j_auto (vec, "output_priv_key", &priv_key); 391 d2j_auto (vec, "output_pub_key", &pub_key); 392 393 } 394 395 { 396 json_t *vec = vec_for (vecs, "secure_answer_hash"); 397 const char *answer = "Blah"; 398 struct ANASTASIS_CRYPTO_TruthUUIDP uuid; 399 struct ANASTASIS_CRYPTO_QuestionSaltP salt; 400 struct GNUNET_HashCode result; 401 402 random_auto (&uuid); 403 random_auto (&salt); 404 ANASTASIS_CRYPTO_secure_answer_hash (answer, 405 &uuid, 406 &salt, 407 &result); 408 GNUNET_assert (0 == 409 json_object_set_new (vec, 410 "input_answer", 411 json_string (answer))); 412 d2j_auto (vec, "input_uuid", &uuid); 413 d2j_auto (vec, "input_salt", &salt); 414 d2j_auto (vec, "output_hash", &result); 415 } 416 417 { 418 json_t *vec = vec_for (vecs, "recovery_document_encryption"); 419 struct ANASTASIS_CRYPTO_UserIdentifierP id; 420 const void *rec_doc = "my recovery doc"; 421 size_t rd_size = strlen (rec_doc) + 1; 422 void *enc_rec_doc; 423 size_t erd_size; 424 425 random_auto (&id); 426 427 ANASTASIS_CRYPTO_recovery_document_encrypt (&id, 428 rec_doc, 429 rd_size, 430 &enc_rec_doc, 431 &erd_size); 432 d2j_auto (vec, "input_user_id", &id); 433 d2j (vec, "input_recovery_document", rec_doc, rd_size); 434 d2j (vec, "output_encrypted_recovery_document", &enc_rec_doc, erd_size); 435 } 436 437 { 438 /* With extra salt */ 439 json_t *vec = vec_for (vecs, "keyshare_encryption"); 440 struct ANASTASIS_CRYPTO_KeyShareP key_share; 441 struct ANASTASIS_CRYPTO_UserIdentifierP id; 442 const char *xsalt = "myanswer"; 443 struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share; 444 445 random_auto (&key_share); 446 random_auto (&id); 447 448 ANASTASIS_CRYPTO_keyshare_encrypt (&key_share, 449 &id, 450 xsalt, 451 &enc_key_share); 452 d2j_auto (vec, "input_key_share", &key_share); 453 d2j_auto (vec, "input_user_id", &id); 454 GNUNET_assert (0 == 455 json_object_set_new (vec, 456 "input_xsalt", 457 json_string (xsalt))); 458 d2j_auto (vec, 459 "output_enc_key_share", 460 &enc_key_share); 461 } 462 463 { 464 /* Without extra salt */ 465 json_t *vec = vec_for (vecs, "keyshare_encryption"); 466 struct ANASTASIS_CRYPTO_KeyShareP key_share; 467 struct ANASTASIS_CRYPTO_UserIdentifierP id; 468 char *xsalt = NULL; 469 struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share; 470 471 random_auto (&key_share); 472 random_auto (&id); 473 474 ANASTASIS_CRYPTO_keyshare_encrypt (&key_share, 475 &id, 476 xsalt, 477 &enc_key_share); 478 d2j_auto (vec, "input_key_share", &key_share); 479 d2j_auto (vec, "input_user_id", &id); 480 GNUNET_assert (0 == 481 json_object_set_new (vec, 482 "input_xsalt", 483 json_null ())); 484 d2j_auto (vec, "output_enc_key_share", &enc_key_share); 485 } 486 487 { 488 json_t *vec = vec_for (vecs, "truth_encryption"); 489 490 struct ANASTASIS_CRYPTO_NonceP nonce; 491 struct ANASTASIS_CRYPTO_TruthKeyP truth_enc_key; 492 char truth[256]; 493 size_t truth_size = 256; 494 void *enc_truth; 495 size_t ect_size; 496 497 random_auto (&nonce); 498 random_auto (&truth); 499 random_auto (&truth_enc_key); 500 501 ANASTASIS_CRYPTO_truth_encrypt (&nonce, 502 &truth_enc_key, 503 truth, 504 truth_size, 505 &enc_truth, 506 &ect_size); 507 508 d2j_auto (vec, "input_nonce", &nonce); 509 d2j_auto (vec, "input_truth_enc_key", &truth_enc_key); 510 d2j (vec, "input_truth", &truth, truth_size); 511 d2j (vec, "output_encrypted_truth", enc_truth, ect_size); 512 } 513 514 { 515 json_t *vec = vec_for (vecs, "policy_key_derive"); 516 517 struct ANASTASIS_CRYPTO_KeyShareP key_shares[2]; 518 unsigned int keyshare_length = 2; 519 struct ANASTASIS_CRYPTO_MasterSaltP salt; 520 struct ANASTASIS_CRYPTO_PolicyKeyP policy_key; 521 json_t *key_shares_json = json_array (); 522 523 GNUNET_assert (NULL != key_shares_json); 524 random_auto (&key_shares[0]); 525 random_auto (&key_shares[1]); 526 random_auto (&salt); 527 528 ANASTASIS_CRYPTO_policy_key_derive (key_shares, 529 keyshare_length, 530 &salt, 531 &policy_key); 532 533 d2j_append_auto (key_shares_json, &key_shares[0]); 534 d2j_append_auto (key_shares_json, &key_shares[1]); 535 GNUNET_assert (0 == 536 json_object_set_new (vec, 537 "input_key_shares", 538 key_shares_json)); 539 d2j_auto (vec, "input_salt", &salt); 540 d2j_auto (vec, "output_policy_key", &policy_key); 541 } 542 543 { 544 // json_t *vec = vec_for (vecs, "core_secret_encryption"); 545 // struct ANASTASIS_CRYPTO_PolicyKeyP policy_keys[2]; 546 // unsigned int policy_keys_length = 2; 547 // char core_secret[256]; 548 // size_t core_secret_size = 256; 549 // void *enc_core_secret; 550 // struct ANASTASIS_CRYPTO_EncryptedMasterKeyP encrypted_master_keys[2]; 551 // json_t *policy_keys_json = json_array (); 552 // json_t *encrypted_master_keys_json = json_array (); 553 554 // random_auto (&policy_keys[0]); 555 // random_auto (&policy_keys[1]); 556 // random_auto (&core_secret); 557 558 // ANASTASIS_CRYPTO_core_secret_encrypt (policy_keys, policy_keys_length, 559 // core_secret, core_secret_size, 560 // &enc_core_secret, 561 // encrypted_master_keys); 562 563 // d2j_append_auto (policy_keys_json, &policy_keys_json[0]); 564 // d2j_append_auto (policy_keys_json, &policy_keys_json[1]); 565 // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[0]); 566 // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[1]); 567 568 // d2j_auto (vec, "input_core_secret", &core_secret); 569 // json_object_set_new (vec, "input_policy_keys", policy_keys_json); 570 // json_object_set_new (vec, "output_encrypted_core_secret", encrypted_master_keys_json); 571 // json_object_set_new (vec, "output_encrypted_master_keys", encrypted_master_keys_json); 572 } 573 574 575 json_dumpf (vecfile, stdout, JSON_INDENT (2)); 576 json_decref (vecfile); 577 printf ("\n"); 578 579 return 0; 580 } 581 582 583 /** 584 * Main function that will be run. 585 * 586 * @param cls closure 587 * @param args remaining command-line arguments 588 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 589 * @param cfg configuration 590 */ 591 static void 592 run (void *cls, 593 char *const *args, 594 const char *cfgfile, 595 const struct GNUNET_CONFIGURATION_Handle *cfg) 596 { 597 if (GNUNET_YES == verify_flag) 598 global_ret = check_vectors (); 599 else 600 global_ret = output_vectors (); 601 } 602 603 604 /** 605 * The main function of the test vector generation tool. 606 * 607 * @param argc number of arguments from the command line 608 * @param argv command line arguments 609 * @return 0 ok, 1 on error 610 */ 611 int 612 main (int argc, 613 char *const *argv) 614 { 615 const struct GNUNET_GETOPT_CommandLineOption options[] = { 616 GNUNET_GETOPT_option_flag ('V', 617 "verify", 618 gettext_noop ( 619 "verify a test vector from stdin"), 620 &verify_flag), 621 GNUNET_GETOPT_OPTION_END 622 }; 623 624 GNUNET_assert (GNUNET_OK == 625 GNUNET_log_setup ("anastasis-crypto-tvg", 626 "INFO", 627 NULL)); 628 if (GNUNET_OK != 629 GNUNET_PROGRAM_run (ANASTASIS_project_data (), 630 argc, argv, 631 "anastasis-crypto-tvg", 632 "Generate test vectors for cryptographic operations", 633 options, 634 &run, NULL)) 635 return 1; 636 return global_ret; 637 } 638 639 640 /* end of anastasis-crypto-tvg.c */