test_crypto.c (18620B)
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 (&seed, 141 sizeof(seed)); 142 TALER_age_restriction_commit (&age_mask, 143 age, 144 &seed, 145 &acp); 146 TALER_age_commitment_hash (&acp.commitment, 147 &ah); 148 ach = &ah; 149 TALER_age_commitment_proof_free (&acp); 150 } 151 152 GNUNET_CRYPTO_random_block (&ps, 153 sizeof (ps)); 154 GNUNET_log_skip (1, GNUNET_YES); 155 GNUNET_assert (GNUNET_SYSERR == 156 TALER_denom_priv_create (&dk_priv, 157 &dk_pub, 158 GNUNET_CRYPTO_BSA_INVALID)); 159 GNUNET_log_skip (1, GNUNET_YES); 160 GNUNET_assert (GNUNET_SYSERR == 161 TALER_denom_priv_create (&dk_priv, 162 &dk_pub, 163 42)); 164 165 GNUNET_assert (GNUNET_OK == 166 TALER_denom_priv_create (&dk_priv, 167 &dk_pub, 168 GNUNET_CRYPTO_BSA_RSA, 169 1024)); 170 TALER_planchet_setup_coin_priv (&ps, 171 alg_values, 172 &coin_priv); 173 TALER_planchet_blinding_secret_create (&ps, 174 alg_values, 175 &bks); 176 GNUNET_assert (GNUNET_OK == 177 TALER_planchet_prepare (&dk_pub, 178 alg_values, 179 &bks, 180 NULL, 181 &coin_priv, 182 ach, 183 &c_hash, 184 &pd)); 185 GNUNET_assert (GNUNET_OK == 186 TALER_denom_sign_blinded (&blind_sig, 187 &dk_priv, 188 false, 189 &pd.blinded_planchet)); 190 TALER_planchet_detail_free (&pd); 191 GNUNET_assert (GNUNET_OK == 192 TALER_planchet_to_coin (&dk_pub, 193 &blind_sig, 194 &bks, 195 &coin_priv, 196 ach, 197 &c_hash, 198 alg_values, 199 &coin)); 200 TALER_blinded_denom_sig_free (&blind_sig); 201 TALER_denom_sig_free (&coin.sig); 202 TALER_denom_priv_free (&dk_priv); 203 TALER_denom_pub_free (&dk_pub); 204 return 0; 205 } 206 207 208 /** 209 * Test the basic planchet functionality of creating a fresh planchet with CS denomination 210 * and extracting the respective signature. 211 * 212 * @return 0 on success 213 */ 214 static int 215 test_planchets_cs (uint8_t age) 216 { 217 struct TALER_WithdrawMasterSeedP seed; 218 struct TALER_BlindingMasterSeedP blinding_seed; 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 const uint32_t coin_offset = 0; 233 234 if (0 < age) 235 { 236 struct TALER_AgeCommitmentProof acp; 237 struct GNUNET_HashCode seed; 238 239 GNUNET_CRYPTO_random_block (&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 TALER_withdraw_master_seed_setup_random (&seed); 252 TALER_withdraw_expand_secrets (1, 253 &seed, 254 &ps); 255 TALER_cs_withdraw_seed_to_blinding_seed (&seed, 256 &blinding_seed); 257 GNUNET_assert (GNUNET_OK == 258 TALER_denom_priv_create (&dk_priv, 259 &dk_pub, 260 GNUNET_CRYPTO_BSA_CS)); 261 TALER_cs_derive_only_cs_blind_nonces_from_seed ( 262 &blinding_seed, 263 false, 264 1, 265 &coin_offset, 266 &nonce); 267 // FIXME: define Taler abstraction for this: 268 alg_values.blinding_inputs 269 = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key, 270 &nonce, 271 "rw"); 272 TALER_denom_pub_hash (&dk_pub, 273 &pd.denom_pub_hash); 274 TALER_planchet_setup_coin_priv (&ps, 275 &alg_values, 276 &coin_priv); 277 TALER_planchet_blinding_secret_create (&ps, 278 &alg_values, 279 &bks); 280 GNUNET_assert (GNUNET_OK == 281 TALER_planchet_prepare (&dk_pub, 282 &alg_values, 283 &bks, 284 &nonce, 285 &coin_priv, 286 ach, 287 &c_hash, 288 &pd)); 289 GNUNET_assert (GNUNET_OK == 290 TALER_denom_sign_blinded (&blind_sig, 291 &dk_priv, 292 false, 293 &pd.blinded_planchet)); 294 GNUNET_assert (GNUNET_OK == 295 TALER_planchet_to_coin (&dk_pub, 296 &blind_sig, 297 &bks, 298 &coin_priv, 299 ach, 300 &c_hash, 301 &alg_values, 302 &coin)); 303 TALER_blinded_denom_sig_free (&blind_sig); 304 TALER_denom_sig_free (&coin.sig); 305 TALER_denom_priv_free (&dk_priv); 306 TALER_denom_pub_free (&dk_pub); 307 return 0; 308 } 309 310 311 /** 312 * Test the basic planchet functionality of creating a fresh planchet 313 * and extracting the respective signature. 314 * Calls test_planchets_rsa and test_planchets_cs 315 * 316 * @return 0 on success 317 */ 318 static int 319 test_planchets (uint8_t age) 320 { 321 if (0 != test_planchets_rsa (age)) 322 return -1; 323 return test_planchets_cs (age); 324 } 325 326 327 static int 328 test_exchange_sigs (void) 329 { 330 const struct TALER_FullPayto pt = { 331 .full_payto 332 = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC" 333 }; 334 const struct TALER_FullPayto pto = { 335 .full_payto 336 = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH" 337 }; 338 struct TALER_MasterPrivateKeyP priv; 339 struct TALER_MasterPublicKeyP pub; 340 struct TALER_MasterSignatureP sig; 341 json_t *rest; 342 343 GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); 344 rest = json_array (); 345 GNUNET_assert (NULL != rest); 346 TALER_exchange_wire_signature_make (pt, 347 NULL, 348 "https://example.com/", 349 NULL, 350 rest, 351 rest, 352 &priv, 353 &sig); 354 GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, 355 &pub.eddsa_pub); 356 if (GNUNET_OK != 357 TALER_exchange_wire_signature_check (pt, 358 NULL, 359 "https://example.com/", 360 NULL, 361 rest, 362 rest, 363 &pub, 364 &sig)) 365 { 366 GNUNET_break (0); 367 return 1; 368 } 369 if (GNUNET_OK == 370 TALER_exchange_wire_signature_check ( 371 pto, 372 NULL, 373 "https://example.com/", 374 NULL, 375 rest, 376 rest, 377 &pub, 378 &sig)) 379 { 380 GNUNET_break (0); 381 return 1; 382 } 383 if (GNUNET_OK == 384 TALER_exchange_wire_signature_check ( 385 pt, 386 "http://example.com/", 387 NULL, 388 NULL, 389 rest, 390 rest, 391 &pub, 392 &sig)) 393 { 394 GNUNET_break (0); 395 return 1; 396 } 397 json_decref (rest); 398 return 0; 399 } 400 401 402 static int 403 test_merchant_sigs (void) 404 { 405 const struct TALER_FullPayto pt = { 406 .full_payto 407 = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC" 408 }; 409 const struct TALER_FullPayto pto = { 410 .full_payto 411 = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH" 412 }; 413 struct TALER_WireSaltP salt; 414 struct TALER_MerchantPrivateKeyP priv; 415 struct TALER_MerchantPublicKeyP pub; 416 struct TALER_MerchantSignatureP sig; 417 418 GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); 419 memset (&salt, 420 42, 421 sizeof (salt)); 422 TALER_merchant_wire_signature_make (pt, 423 &salt, 424 &priv, 425 &sig); 426 GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, 427 &pub.eddsa_pub); 428 if (GNUNET_OK != 429 TALER_merchant_wire_signature_check (pt, 430 &salt, 431 &pub, 432 &sig)) 433 { 434 GNUNET_break (0); 435 return 1; 436 } 437 if (GNUNET_OK == 438 TALER_merchant_wire_signature_check ( 439 pto, 440 &salt, 441 &pub, 442 &sig)) 443 { 444 GNUNET_break (0); 445 return 1; 446 } 447 memset (&salt, 448 43, 449 sizeof (salt)); 450 if (GNUNET_OK == 451 TALER_merchant_wire_signature_check (pt, 452 &salt, 453 &pub, 454 &sig)) 455 { 456 GNUNET_break (0); 457 return 1; 458 } 459 return 0; 460 } 461 462 463 static int 464 test_contracts (void) 465 { 466 struct TALER_ContractDiffiePrivateP cpriv; 467 struct TALER_PurseContractPublicKeyP purse_pub; 468 struct TALER_PurseContractPrivateKeyP purse_priv; 469 void *econtract; 470 size_t econtract_size; 471 struct TALER_PurseMergePrivateKeyP mpriv_in; 472 struct TALER_PurseMergePrivateKeyP mpriv_out; 473 json_t *c; 474 475 GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv); 476 GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv); 477 GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv, 478 &purse_pub.eddsa_pub); 479 memset (&mpriv_in, 480 42, 481 sizeof (mpriv_in)); 482 c = json_pack ("{s:s}", "test", "value"); 483 GNUNET_assert (NULL != c); 484 TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub, 485 &cpriv, 486 &mpriv_in, 487 c, 488 &econtract, 489 &econtract_size); 490 json_decref (c); 491 c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv, 492 &purse_pub, 493 econtract, 494 econtract_size, 495 &mpriv_out); 496 GNUNET_free (econtract); 497 if (NULL == c) 498 return 1; 499 json_decref (c); 500 if (0 != GNUNET_memcmp (&mpriv_in, 501 &mpriv_out)) 502 return 1; 503 return 0; 504 } 505 506 507 static int 508 test_attributes (void) 509 { 510 struct TALER_AttributeEncryptionKeyP key; 511 void *eattr; 512 size_t eattr_size; 513 json_t *c; 514 515 GNUNET_CRYPTO_random_block (&key, 516 sizeof (key)); 517 c = json_pack ("{s:s}", "test", "value"); 518 GNUNET_assert (NULL != c); 519 TALER_CRYPTO_kyc_attributes_encrypt (&key, 520 c, 521 &eattr, 522 &eattr_size); 523 json_decref (c); 524 c = TALER_CRYPTO_kyc_attributes_decrypt (&key, 525 eattr, 526 eattr_size); 527 GNUNET_free (eattr); 528 if (NULL == c) 529 { 530 GNUNET_break (0); 531 return 1; 532 } 533 GNUNET_assert (0 == 534 strcmp ("value", 535 json_string_value (json_object_get (c, 536 "test")))); 537 json_decref (c); 538 return 0; 539 } 540 541 542 int 543 main (int argc, 544 const char *const argv[]) 545 { 546 (void) argc; 547 (void) argv; 548 GNUNET_log_setup ("test-crypto", 549 "WARNING", 550 NULL); 551 if (0 != test_high_level ()) 552 return 1; 553 if (0 != test_planchets (0)) 554 return 2; 555 if (0 != test_planchets (13)) 556 return 3; 557 if (0 != test_exchange_sigs ()) 558 return 4; 559 if (0 != test_merchant_sigs ()) 560 return 5; 561 if (0 != test_contracts ()) 562 return 6; 563 if (0 != test_attributes ()) 564 return 7; 565 return 0; 566 } 567 568 569 /* end of test_crypto.c */