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 (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 */