exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_crypto.c (18630B)


      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                                       "https://example.com/",
    345                                       NULL,
    346                                       rest,
    347                                       rest,
    348                                       &priv,
    349                                       &sig);
    350   GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
    351                                       &pub.eddsa_pub);
    352   if (GNUNET_OK !=
    353       TALER_exchange_wire_signature_check (pt,
    354                                            NULL,
    355                                            "https://example.com/",
    356                                            NULL,
    357                                            rest,
    358                                            rest,
    359                                            &pub,
    360                                            &sig))
    361   {
    362     GNUNET_break (0);
    363     return 1;
    364   }
    365   if (GNUNET_OK ==
    366       TALER_exchange_wire_signature_check (
    367         pto,
    368         NULL,
    369         "https://example.com/",
    370         NULL,
    371         rest,
    372         rest,
    373         &pub,
    374         &sig))
    375   {
    376     GNUNET_break (0);
    377     return 1;
    378   }
    379   if (GNUNET_OK ==
    380       TALER_exchange_wire_signature_check (
    381         pt,
    382         "http://example.com/",
    383         NULL,
    384         NULL,
    385         rest,
    386         rest,
    387         &pub,
    388         &sig))
    389   {
    390     GNUNET_break (0);
    391     return 1;
    392   }
    393   json_decref (rest);
    394   return 0;
    395 }
    396 
    397 
    398 static int
    399 test_merchant_sigs (void)
    400 {
    401   const struct TALER_FullPayto pt = {
    402     .full_payto
    403       = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
    404   };
    405   const struct TALER_FullPayto pto = {
    406     .full_payto
    407       = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH"
    408   };
    409   struct TALER_WireSaltP salt;
    410   struct TALER_MerchantPrivateKeyP priv;
    411   struct TALER_MerchantPublicKeyP pub;
    412   struct TALER_MerchantSignatureP sig;
    413 
    414   GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
    415   memset (&salt,
    416           42,
    417           sizeof (salt));
    418   TALER_merchant_wire_signature_make (pt,
    419                                       &salt,
    420                                       &priv,
    421                                       &sig);
    422   GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
    423                                       &pub.eddsa_pub);
    424   if (GNUNET_OK !=
    425       TALER_merchant_wire_signature_check (pt,
    426                                            &salt,
    427                                            &pub,
    428                                            &sig))
    429   {
    430     GNUNET_break (0);
    431     return 1;
    432   }
    433   if (GNUNET_OK ==
    434       TALER_merchant_wire_signature_check (
    435         pto,
    436         &salt,
    437         &pub,
    438         &sig))
    439   {
    440     GNUNET_break (0);
    441     return 1;
    442   }
    443   memset (&salt,
    444           43,
    445           sizeof (salt));
    446   if (GNUNET_OK ==
    447       TALER_merchant_wire_signature_check (pt,
    448                                            &salt,
    449                                            &pub,
    450                                            &sig))
    451   {
    452     GNUNET_break (0);
    453     return 1;
    454   }
    455   return 0;
    456 }
    457 
    458 
    459 static int
    460 test_contracts (void)
    461 {
    462   struct TALER_ContractDiffiePrivateP cpriv;
    463   struct TALER_PurseContractPublicKeyP purse_pub;
    464   struct TALER_PurseContractPrivateKeyP purse_priv;
    465   void *econtract;
    466   size_t econtract_size;
    467   struct TALER_PurseMergePrivateKeyP mpriv_in;
    468   struct TALER_PurseMergePrivateKeyP mpriv_out;
    469   json_t *c;
    470 
    471   GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv);
    472   GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv);
    473   GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv,
    474                                       &purse_pub.eddsa_pub);
    475   memset (&mpriv_in,
    476           42,
    477           sizeof (mpriv_in));
    478   c = json_pack ("{s:s}", "test", "value");
    479   GNUNET_assert (NULL != c);
    480   TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
    481                                            &cpriv,
    482                                            &mpriv_in,
    483                                            c,
    484                                            &econtract,
    485                                            &econtract_size);
    486   json_decref (c);
    487   c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv,
    488                                                &purse_pub,
    489                                                econtract,
    490                                                econtract_size,
    491                                                &mpriv_out);
    492   GNUNET_free (econtract);
    493   if (NULL == c)
    494     return 1;
    495   json_decref (c);
    496   if (0 != GNUNET_memcmp (&mpriv_in,
    497                           &mpriv_out))
    498     return 1;
    499   return 0;
    500 }
    501 
    502 
    503 static int
    504 test_attributes (void)
    505 {
    506   struct TALER_AttributeEncryptionKeyP key;
    507   void *eattr;
    508   size_t eattr_size;
    509   json_t *c;
    510 
    511   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
    512                               &key,
    513                               sizeof (key));
    514   c = json_pack ("{s:s}", "test", "value");
    515   GNUNET_assert (NULL != c);
    516   TALER_CRYPTO_kyc_attributes_encrypt (&key,
    517                                        c,
    518                                        &eattr,
    519                                        &eattr_size);
    520   json_decref (c);
    521   c = TALER_CRYPTO_kyc_attributes_decrypt (&key,
    522                                            eattr,
    523                                            eattr_size);
    524   GNUNET_free (eattr);
    525   if (NULL == c)
    526   {
    527     GNUNET_break (0);
    528     return 1;
    529   }
    530   GNUNET_assert (0 ==
    531                  strcmp ("value",
    532                          json_string_value (json_object_get (c,
    533                                                              "test"))));
    534   json_decref (c);
    535   return 0;
    536 }
    537 
    538 
    539 int
    540 main (int argc,
    541       const char *const argv[])
    542 {
    543   (void) argc;
    544   (void) argv;
    545   GNUNET_log_setup ("test-crypto",
    546                     "WARNING",
    547                     NULL);
    548   if (0 != test_high_level ())
    549     return 1;
    550   if (0 != test_planchets (0))
    551     return 2;
    552   if (0 != test_planchets (13))
    553     return 3;
    554   if (0 != test_exchange_sigs ())
    555     return 4;
    556   if (0 != test_merchant_sigs ())
    557     return 5;
    558   if (0 != test_contracts ())
    559     return 6;
    560   if (0 != test_attributes ())
    561     return 7;
    562   return 0;
    563 }
    564 
    565 
    566 /* end of test_crypto.c */