test_crypto.c (18602B)
1 /* 2 This file is part of TALER 3 (C) 2015, 2020-2024 Taler Systems SA 4 5 TALER 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 TALER 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 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 /** 18 * @file util/test_crypto.c 19 * @brief Tests for Taler-specific crypto logic 20 * @author Christian Grothoff <christian@grothoff.org> 21 */ 22 #include "taler/taler_util.h" 23 24 25 /** 26 * Test high-level link encryption/decryption API. 27 * 28 * @return 0 on success 29 */ 30 static int 31 test_high_level (void) 32 { 33 struct TALER_CoinSpendPrivateKeyP coin_priv; 34 struct TALER_CoinSpendPublicKeyP coin_pub; 35 struct TALER_TransferPrivateKeyP trans_priv; 36 struct TALER_TransferPublicKeyP trans_pub; 37 struct TALER_TransferSecretP secret; 38 struct TALER_TransferSecretP secret2; 39 union GNUNET_CRYPTO_BlindingSecretP bks1; 40 union GNUNET_CRYPTO_BlindingSecretP bks2; 41 struct TALER_CoinSpendPrivateKeyP coin_priv1; 42 struct TALER_CoinSpendPrivateKeyP coin_priv2; 43 struct TALER_PlanchetMasterSecretP ps1; 44 struct TALER_PlanchetMasterSecretP ps2; 45 struct GNUNET_CRYPTO_BlindingInputValues bi = { 46 .cipher = GNUNET_CRYPTO_BSA_RSA 47 }; 48 struct TALER_ExchangeBlindingValues alg1 = { 49 .blinding_inputs = &bi 50 }; 51 struct TALER_ExchangeBlindingValues alg2 = { 52 .blinding_inputs = &bi 53 }; 54 55 GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv); 56 GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv, 57 &coin_pub.eddsa_pub); 58 GNUNET_CRYPTO_ecdhe_key_create (&trans_priv.ecdhe_priv); 59 GNUNET_CRYPTO_ecdhe_key_get_public (&trans_priv.ecdhe_priv, 60 &trans_pub.ecdhe_pub); 61 TALER_link_derive_transfer_secret (&coin_priv, 62 &trans_priv, 63 &secret); 64 TALER_link_reveal_transfer_secret (&trans_priv, 65 &coin_pub, 66 &secret2); 67 GNUNET_assert (0 == 68 GNUNET_memcmp (&secret, 69 &secret2)); 70 TALER_link_recover_transfer_secret (&trans_pub, 71 &coin_priv, 72 &secret2); 73 GNUNET_assert (0 == 74 GNUNET_memcmp (&secret, 75 &secret2)); 76 TALER_transfer_secret_to_planchet_secret (&secret, 77 0, 78 &ps1); 79 TALER_planchet_setup_coin_priv (&ps1, 80 &alg1, 81 &coin_priv1); 82 TALER_planchet_blinding_secret_create (&ps1, 83 &alg1, 84 &bks1); 85 TALER_transfer_secret_to_planchet_secret (&secret, 86 1, 87 &ps2); 88 TALER_planchet_setup_coin_priv (&ps2, 89 &alg2, 90 &coin_priv2); 91 TALER_planchet_blinding_secret_create (&ps2, 92 &alg2, 93 &bks2); 94 GNUNET_assert (0 != 95 GNUNET_memcmp (&ps1, 96 &ps2)); 97 GNUNET_assert (0 != 98 GNUNET_memcmp (&coin_priv1, 99 &coin_priv2)); 100 GNUNET_assert (0 != 101 GNUNET_memcmp (&bks1, 102 &bks2)); 103 return 0; 104 } 105 106 107 static struct TALER_AgeMask age_mask = { 108 .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12 109 | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21 110 }; 111 112 /** 113 * Test the basic planchet functionality of creating a fresh planchet 114 * and extracting the respective signature. 115 * 116 * @return 0 on success 117 */ 118 static int 119 test_planchets_rsa (uint8_t age) 120 { 121 struct TALER_PlanchetMasterSecretP ps; 122 struct TALER_CoinSpendPrivateKeyP coin_priv; 123 union GNUNET_CRYPTO_BlindingSecretP bks; 124 struct TALER_DenominationPrivateKey dk_priv; 125 struct TALER_DenominationPublicKey dk_pub; 126 const struct TALER_ExchangeBlindingValues *alg_values; 127 struct TALER_PlanchetDetail pd; 128 struct TALER_BlindedDenominationSignature blind_sig; 129 struct TALER_FreshCoin coin; 130 struct TALER_CoinPubHashP c_hash; 131 struct TALER_AgeCommitmentHashP *ach = NULL; 132 struct TALER_AgeCommitmentHashP ah = {0}; 133 134 alg_values = TALER_denom_ewv_rsa_singleton (); 135 if (0 < age) 136 { 137 struct TALER_AgeCommitmentProof acp; 138 struct GNUNET_HashCode seed; 139 140 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 141 &seed, 142 sizeof(seed)); 143 TALER_age_restriction_commit (&age_mask, 144 age, 145 &seed, 146 &acp); 147 TALER_age_commitment_hash (&acp.commitment, 148 &ah); 149 ach = &ah; 150 TALER_age_commitment_proof_free (&acp); 151 } 152 153 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, 154 &ps, 155 sizeof (ps)); 156 GNUNET_log_skip (1, GNUNET_YES); 157 GNUNET_assert (GNUNET_SYSERR == 158 TALER_denom_priv_create (&dk_priv, 159 &dk_pub, 160 GNUNET_CRYPTO_BSA_INVALID)); 161 GNUNET_log_skip (1, GNUNET_YES); 162 GNUNET_assert (GNUNET_SYSERR == 163 TALER_denom_priv_create (&dk_priv, 164 &dk_pub, 165 42)); 166 167 GNUNET_assert (GNUNET_OK == 168 TALER_denom_priv_create (&dk_priv, 169 &dk_pub, 170 GNUNET_CRYPTO_BSA_RSA, 171 1024)); 172 TALER_planchet_setup_coin_priv (&ps, 173 alg_values, 174 &coin_priv); 175 TALER_planchet_blinding_secret_create (&ps, 176 alg_values, 177 &bks); 178 GNUNET_assert (GNUNET_OK == 179 TALER_planchet_prepare (&dk_pub, 180 alg_values, 181 &bks, 182 NULL, 183 &coin_priv, 184 ach, 185 &c_hash, 186 &pd)); 187 GNUNET_assert (GNUNET_OK == 188 TALER_denom_sign_blinded (&blind_sig, 189 &dk_priv, 190 false, 191 &pd.blinded_planchet)); 192 TALER_planchet_detail_free (&pd); 193 GNUNET_assert (GNUNET_OK == 194 TALER_planchet_to_coin (&dk_pub, 195 &blind_sig, 196 &bks, 197 &coin_priv, 198 ach, 199 &c_hash, 200 alg_values, 201 &coin)); 202 TALER_blinded_denom_sig_free (&blind_sig); 203 TALER_denom_sig_free (&coin.sig); 204 TALER_denom_priv_free (&dk_priv); 205 TALER_denom_pub_free (&dk_pub); 206 return 0; 207 } 208 209 210 /** 211 * Test the basic planchet functionality of creating a fresh planchet with CS denomination 212 * and extracting the respective signature. 213 * 214 * @return 0 on success 215 */ 216 static int 217 test_planchets_cs (uint8_t age) 218 { 219 struct TALER_PlanchetMasterSecretP ps; 220 struct TALER_CoinSpendPrivateKeyP coin_priv; 221 union GNUNET_CRYPTO_BlindingSecretP bks; 222 struct TALER_DenominationPrivateKey dk_priv; 223 struct TALER_DenominationPublicKey dk_pub; 224 struct TALER_PlanchetDetail pd; 225 struct TALER_CoinPubHashP c_hash; 226 union GNUNET_CRYPTO_BlindSessionNonce nonce; 227 struct TALER_BlindedDenominationSignature blind_sig; 228 struct TALER_FreshCoin coin; 229 struct TALER_ExchangeBlindingValues alg_values; 230 struct TALER_AgeCommitmentHashP *ach = NULL; 231 struct TALER_AgeCommitmentHashP ah = {0}; 232 233 if (0 < age) 234 { 235 struct TALER_AgeCommitmentProof acp; 236 struct GNUNET_HashCode seed; 237 238 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 239 &seed, 240 sizeof(seed)); 241 TALER_age_restriction_commit (&age_mask, 242 age, 243 &seed, 244 &acp); 245 TALER_age_commitment_hash (&acp.commitment, 246 &ah); 247 ach = &ah; 248 TALER_age_commitment_proof_free (&acp); 249 } 250 251 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, 252 &ps, 253 sizeof (ps)); 254 GNUNET_assert (GNUNET_OK == 255 TALER_denom_priv_create (&dk_priv, 256 &dk_pub, 257 GNUNET_CRYPTO_BSA_CS)); 258 #pragma message "phase out TALER_cs_withdraw_nonce_derive" 259 TALER_cs_withdraw_nonce_derive ( 260 &ps, 261 &nonce.cs_nonce); 262 // FIXME: define Taler abstraction for this: 263 alg_values.blinding_inputs 264 = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key, 265 &nonce, 266 "rw"); 267 TALER_denom_pub_hash (&dk_pub, 268 &pd.denom_pub_hash); 269 TALER_planchet_setup_coin_priv (&ps, 270 &alg_values, 271 &coin_priv); 272 TALER_planchet_blinding_secret_create (&ps, 273 &alg_values, 274 &bks); 275 GNUNET_assert (GNUNET_OK == 276 TALER_planchet_prepare (&dk_pub, 277 &alg_values, 278 &bks, 279 &nonce, 280 &coin_priv, 281 ach, 282 &c_hash, 283 &pd)); 284 GNUNET_assert (GNUNET_OK == 285 TALER_denom_sign_blinded (&blind_sig, 286 &dk_priv, 287 false, 288 &pd.blinded_planchet)); 289 GNUNET_assert (GNUNET_OK == 290 TALER_planchet_to_coin (&dk_pub, 291 &blind_sig, 292 &bks, 293 &coin_priv, 294 ach, 295 &c_hash, 296 &alg_values, 297 &coin)); 298 TALER_blinded_denom_sig_free (&blind_sig); 299 TALER_denom_sig_free (&coin.sig); 300 TALER_denom_priv_free (&dk_priv); 301 TALER_denom_pub_free (&dk_pub); 302 return 0; 303 } 304 305 306 /** 307 * Test the basic planchet functionality of creating a fresh planchet 308 * and extracting the respective signature. 309 * Calls test_planchets_rsa and test_planchets_cs 310 * 311 * @return 0 on success 312 */ 313 static int 314 test_planchets (uint8_t age) 315 { 316 if (0 != test_planchets_rsa (age)) 317 return -1; 318 return test_planchets_cs (age); 319 } 320 321 322 static int 323 test_exchange_sigs (void) 324 { 325 const struct TALER_FullPayto pt = { 326 .full_payto 327 = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC" 328 }; 329 const struct TALER_FullPayto pto = { 330 .full_payto 331 = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH" 332 }; 333 struct TALER_MasterPrivateKeyP priv; 334 struct TALER_MasterPublicKeyP pub; 335 struct TALER_MasterSignatureP sig; 336 json_t *rest; 337 338 GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); 339 rest = json_array (); 340 GNUNET_assert (NULL != rest); 341 TALER_exchange_wire_signature_make (pt, 342 NULL, 343 "https://example.com/", 344 NULL, 345 rest, 346 rest, 347 &priv, 348 &sig); 349 GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, 350 &pub.eddsa_pub); 351 if (GNUNET_OK != 352 TALER_exchange_wire_signature_check (pt, 353 NULL, 354 "https://example.com/", 355 NULL, 356 rest, 357 rest, 358 &pub, 359 &sig)) 360 { 361 GNUNET_break (0); 362 return 1; 363 } 364 if (GNUNET_OK == 365 TALER_exchange_wire_signature_check ( 366 pto, 367 NULL, 368 "https://example.com/", 369 NULL, 370 rest, 371 rest, 372 &pub, 373 &sig)) 374 { 375 GNUNET_break (0); 376 return 1; 377 } 378 if (GNUNET_OK == 379 TALER_exchange_wire_signature_check ( 380 pt, 381 "http://example.com/", 382 NULL, 383 NULL, 384 rest, 385 rest, 386 &pub, 387 &sig)) 388 { 389 GNUNET_break (0); 390 return 1; 391 } 392 json_decref (rest); 393 return 0; 394 } 395 396 397 static int 398 test_merchant_sigs (void) 399 { 400 const struct TALER_FullPayto pt = { 401 .full_payto 402 = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC" 403 }; 404 const struct TALER_FullPayto pto = { 405 .full_payto 406 = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH" 407 }; 408 struct TALER_WireSaltP salt; 409 struct TALER_MerchantPrivateKeyP priv; 410 struct TALER_MerchantPublicKeyP pub; 411 struct TALER_MerchantSignatureP sig; 412 413 GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); 414 memset (&salt, 415 42, 416 sizeof (salt)); 417 TALER_merchant_wire_signature_make (pt, 418 &salt, 419 &priv, 420 &sig); 421 GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, 422 &pub.eddsa_pub); 423 if (GNUNET_OK != 424 TALER_merchant_wire_signature_check (pt, 425 &salt, 426 &pub, 427 &sig)) 428 { 429 GNUNET_break (0); 430 return 1; 431 } 432 if (GNUNET_OK == 433 TALER_merchant_wire_signature_check ( 434 pto, 435 &salt, 436 &pub, 437 &sig)) 438 { 439 GNUNET_break (0); 440 return 1; 441 } 442 memset (&salt, 443 43, 444 sizeof (salt)); 445 if (GNUNET_OK == 446 TALER_merchant_wire_signature_check (pt, 447 &salt, 448 &pub, 449 &sig)) 450 { 451 GNUNET_break (0); 452 return 1; 453 } 454 return 0; 455 } 456 457 458 static int 459 test_contracts (void) 460 { 461 struct TALER_ContractDiffiePrivateP cpriv; 462 struct TALER_PurseContractPublicKeyP purse_pub; 463 struct TALER_PurseContractPrivateKeyP purse_priv; 464 void *econtract; 465 size_t econtract_size; 466 struct TALER_PurseMergePrivateKeyP mpriv_in; 467 struct TALER_PurseMergePrivateKeyP mpriv_out; 468 json_t *c; 469 470 GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv); 471 GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv); 472 GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv, 473 &purse_pub.eddsa_pub); 474 memset (&mpriv_in, 475 42, 476 sizeof (mpriv_in)); 477 c = json_pack ("{s:s}", "test", "value"); 478 GNUNET_assert (NULL != c); 479 TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub, 480 &cpriv, 481 &mpriv_in, 482 c, 483 &econtract, 484 &econtract_size); 485 json_decref (c); 486 c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv, 487 &purse_pub, 488 econtract, 489 econtract_size, 490 &mpriv_out); 491 GNUNET_free (econtract); 492 if (NULL == c) 493 return 1; 494 json_decref (c); 495 if (0 != GNUNET_memcmp (&mpriv_in, 496 &mpriv_out)) 497 return 1; 498 return 0; 499 } 500 501 502 static int 503 test_attributes (void) 504 { 505 struct TALER_AttributeEncryptionKeyP key; 506 void *eattr; 507 size_t eattr_size; 508 json_t *c; 509 510 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 511 &key, 512 sizeof (key)); 513 c = json_pack ("{s:s}", "test", "value"); 514 GNUNET_assert (NULL != c); 515 TALER_CRYPTO_kyc_attributes_encrypt (&key, 516 c, 517 &eattr, 518 &eattr_size); 519 json_decref (c); 520 c = TALER_CRYPTO_kyc_attributes_decrypt (&key, 521 eattr, 522 eattr_size); 523 GNUNET_free (eattr); 524 if (NULL == c) 525 { 526 GNUNET_break (0); 527 return 1; 528 } 529 GNUNET_assert (0 == 530 strcmp ("value", 531 json_string_value (json_object_get (c, 532 "test")))); 533 json_decref (c); 534 return 0; 535 } 536 537 538 int 539 main (int argc, 540 const char *const argv[]) 541 { 542 (void) argc; 543 (void) argv; 544 GNUNET_log_setup ("test-crypto", 545 "WARNING", 546 NULL); 547 if (0 != test_high_level ()) 548 return 1; 549 if (0 != test_planchets (0)) 550 return 2; 551 if (0 != test_planchets (13)) 552 return 3; 553 if (0 != test_exchange_sigs ()) 554 return 4; 555 if (0 != test_merchant_sigs ()) 556 return 5; 557 if (0 != test_contracts ()) 558 return 6; 559 if (0 != test_attributes ()) 560 return 7; 561 return 0; 562 } 563 564 565 /* end of test_crypto.c */