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