Line data Source code
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 1 : 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 1 : struct GNUNET_CRYPTO_BlindingInputValues bi = {
46 : .cipher = GNUNET_CRYPTO_BSA_RSA
47 : };
48 1 : struct TALER_ExchangeBlindingValues alg1 = {
49 : .blinding_inputs = &bi
50 : };
51 1 : struct TALER_ExchangeBlindingValues alg2 = {
52 : .blinding_inputs = &bi
53 : };
54 :
55 1 : GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv);
56 1 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
57 : &coin_pub.eddsa_pub);
58 1 : GNUNET_CRYPTO_ecdhe_key_create (&trans_priv.ecdhe_priv);
59 1 : GNUNET_CRYPTO_ecdhe_key_get_public (&trans_priv.ecdhe_priv,
60 : &trans_pub.ecdhe_pub);
61 1 : TALER_link_derive_transfer_secret (&coin_priv,
62 : &trans_priv,
63 : &secret);
64 1 : TALER_link_reveal_transfer_secret (&trans_priv,
65 : &coin_pub,
66 : &secret2);
67 1 : GNUNET_assert (0 ==
68 : GNUNET_memcmp (&secret,
69 : &secret2));
70 1 : TALER_link_recover_transfer_secret (&trans_pub,
71 : &coin_priv,
72 : &secret2);
73 1 : GNUNET_assert (0 ==
74 : GNUNET_memcmp (&secret,
75 : &secret2));
76 1 : TALER_transfer_secret_to_planchet_secret (&secret,
77 : 0,
78 : &ps1);
79 1 : TALER_planchet_setup_coin_priv (&ps1,
80 : &alg1,
81 : &coin_priv1);
82 1 : TALER_planchet_blinding_secret_create (&ps1,
83 : &alg1,
84 : &bks1);
85 1 : TALER_transfer_secret_to_planchet_secret (&secret,
86 : 1,
87 : &ps2);
88 1 : TALER_planchet_setup_coin_priv (&ps2,
89 : &alg2,
90 : &coin_priv2);
91 1 : TALER_planchet_blinding_secret_create (&ps2,
92 : &alg2,
93 : &bks2);
94 1 : GNUNET_assert (0 !=
95 : GNUNET_memcmp (&ps1,
96 : &ps2));
97 1 : GNUNET_assert (0 !=
98 : GNUNET_memcmp (&coin_priv1,
99 : &coin_priv2));
100 1 : GNUNET_assert (0 !=
101 : GNUNET_memcmp (&bks1,
102 : &bks2));
103 1 : 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 2 : 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 2 : struct TALER_AgeCommitmentHashP *ach = NULL;
132 2 : struct TALER_AgeCommitmentHashP ah = {0};
133 :
134 2 : alg_values = TALER_denom_ewv_rsa_singleton ();
135 2 : if (0 < age)
136 : {
137 : struct TALER_AgeCommitmentProof acp;
138 : struct GNUNET_HashCode seed;
139 :
140 1 : GNUNET_CRYPTO_random_block (&seed,
141 : sizeof(seed));
142 1 : TALER_age_restriction_commit (&age_mask,
143 : age,
144 : &seed,
145 : &acp);
146 1 : TALER_age_commitment_hash (&acp.commitment,
147 : &ah);
148 1 : ach = &ah;
149 1 : TALER_age_commitment_proof_free (&acp);
150 : }
151 :
152 2 : GNUNET_CRYPTO_random_block (&ps,
153 : sizeof (ps));
154 2 : GNUNET_log_skip (1, GNUNET_YES);
155 2 : GNUNET_assert (GNUNET_SYSERR ==
156 : TALER_denom_priv_create (&dk_priv,
157 : &dk_pub,
158 : GNUNET_CRYPTO_BSA_INVALID));
159 2 : GNUNET_log_skip (1, GNUNET_YES);
160 2 : GNUNET_assert (GNUNET_SYSERR ==
161 : TALER_denom_priv_create (&dk_priv,
162 : &dk_pub,
163 : 42));
164 :
165 2 : GNUNET_assert (GNUNET_OK ==
166 : TALER_denom_priv_create (&dk_priv,
167 : &dk_pub,
168 : GNUNET_CRYPTO_BSA_RSA,
169 : 1024));
170 2 : TALER_planchet_setup_coin_priv (&ps,
171 : alg_values,
172 : &coin_priv);
173 2 : TALER_planchet_blinding_secret_create (&ps,
174 : alg_values,
175 : &bks);
176 2 : 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 2 : GNUNET_assert (GNUNET_OK ==
186 : TALER_denom_sign_blinded (&blind_sig,
187 : &dk_priv,
188 : false,
189 : &pd.blinded_planchet));
190 2 : TALER_planchet_detail_free (&pd);
191 2 : 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 2 : TALER_blinded_denom_sig_free (&blind_sig);
201 2 : TALER_denom_sig_free (&coin.sig);
202 2 : TALER_denom_priv_free (&dk_priv);
203 2 : TALER_denom_pub_free (&dk_pub);
204 2 : 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 2 : 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 2 : struct TALER_AgeCommitmentHashP *ach = NULL;
231 2 : struct TALER_AgeCommitmentHashP ah = {0};
232 2 : const uint32_t coin_offset = 0;
233 :
234 2 : if (0 < age)
235 : {
236 : struct TALER_AgeCommitmentProof acp;
237 : struct GNUNET_HashCode seed;
238 :
239 1 : GNUNET_CRYPTO_random_block (&seed,
240 : sizeof(seed));
241 1 : TALER_age_restriction_commit (&age_mask,
242 : age,
243 : &seed,
244 : &acp);
245 1 : TALER_age_commitment_hash (&acp.commitment,
246 : &ah);
247 1 : ach = &ah;
248 1 : TALER_age_commitment_proof_free (&acp);
249 : }
250 :
251 2 : TALER_withdraw_master_seed_setup_random (&seed);
252 2 : TALER_withdraw_expand_secrets (1,
253 : &seed,
254 : &ps);
255 2 : TALER_cs_withdraw_seed_to_blinding_seed (&seed,
256 : &blinding_seed);
257 2 : GNUNET_assert (GNUNET_OK ==
258 : TALER_denom_priv_create (&dk_priv,
259 : &dk_pub,
260 : GNUNET_CRYPTO_BSA_CS));
261 2 : 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 2 : = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key,
270 : &nonce,
271 : "rw");
272 2 : TALER_denom_pub_hash (&dk_pub,
273 : &pd.denom_pub_hash);
274 2 : TALER_planchet_setup_coin_priv (&ps,
275 : &alg_values,
276 : &coin_priv);
277 2 : TALER_planchet_blinding_secret_create (&ps,
278 : &alg_values,
279 : &bks);
280 2 : 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 2 : GNUNET_assert (GNUNET_OK ==
290 : TALER_denom_sign_blinded (&blind_sig,
291 : &dk_priv,
292 : false,
293 : &pd.blinded_planchet));
294 2 : 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 2 : TALER_blinded_denom_sig_free (&blind_sig);
304 2 : TALER_denom_sig_free (&coin.sig);
305 2 : TALER_denom_priv_free (&dk_priv);
306 2 : TALER_denom_pub_free (&dk_pub);
307 2 : 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 2 : test_planchets (uint8_t age)
320 : {
321 2 : if (0 != test_planchets_rsa (age))
322 0 : return -1;
323 2 : return test_planchets_cs (age);
324 : }
325 :
326 :
327 : static int
328 1 : test_exchange_sigs (void)
329 : {
330 1 : const struct TALER_FullPayto pt = {
331 : .full_payto
332 : = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
333 : };
334 1 : 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 1 : GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
344 1 : rest = json_array ();
345 1 : GNUNET_assert (NULL != rest);
346 1 : TALER_exchange_wire_signature_make (pt,
347 : NULL,
348 : "https://example.com/",
349 : NULL,
350 : rest,
351 : rest,
352 : &priv,
353 : &sig);
354 1 : GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
355 : &pub.eddsa_pub);
356 1 : if (GNUNET_OK !=
357 1 : TALER_exchange_wire_signature_check (pt,
358 : NULL,
359 : "https://example.com/",
360 : NULL,
361 : rest,
362 : rest,
363 : &pub,
364 : &sig))
365 : {
366 0 : GNUNET_break (0);
367 0 : return 1;
368 : }
369 1 : if (GNUNET_OK ==
370 1 : 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 0 : GNUNET_break (0);
381 0 : return 1;
382 : }
383 1 : if (GNUNET_OK ==
384 1 : 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 0 : GNUNET_break (0);
395 0 : return 1;
396 : }
397 1 : json_decref (rest);
398 1 : return 0;
399 : }
400 :
401 :
402 : static int
403 1 : test_merchant_sigs (void)
404 : {
405 1 : const struct TALER_FullPayto pt = {
406 : .full_payto
407 : = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
408 : };
409 1 : 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 1 : GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
419 1 : memset (&salt,
420 : 42,
421 : sizeof (salt));
422 1 : TALER_merchant_wire_signature_make (pt,
423 : &salt,
424 : &priv,
425 : &sig);
426 1 : GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
427 : &pub.eddsa_pub);
428 1 : if (GNUNET_OK !=
429 1 : TALER_merchant_wire_signature_check (pt,
430 : &salt,
431 : &pub,
432 : &sig))
433 : {
434 0 : GNUNET_break (0);
435 0 : return 1;
436 : }
437 1 : if (GNUNET_OK ==
438 1 : TALER_merchant_wire_signature_check (
439 : pto,
440 : &salt,
441 : &pub,
442 : &sig))
443 : {
444 0 : GNUNET_break (0);
445 0 : return 1;
446 : }
447 1 : memset (&salt,
448 : 43,
449 : sizeof (salt));
450 1 : if (GNUNET_OK ==
451 1 : TALER_merchant_wire_signature_check (pt,
452 : &salt,
453 : &pub,
454 : &sig))
455 : {
456 0 : GNUNET_break (0);
457 0 : return 1;
458 : }
459 1 : return 0;
460 : }
461 :
462 :
463 : static int
464 1 : 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 1 : GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv);
476 1 : GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv);
477 1 : GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv,
478 : &purse_pub.eddsa_pub);
479 1 : memset (&mpriv_in,
480 : 42,
481 : sizeof (mpriv_in));
482 1 : c = json_pack ("{s:s}", "test", "value");
483 1 : GNUNET_assert (NULL != c);
484 1 : TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
485 : &cpriv,
486 : &mpriv_in,
487 : c,
488 : &econtract,
489 : &econtract_size);
490 1 : json_decref (c);
491 1 : c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv,
492 : &purse_pub,
493 : econtract,
494 : econtract_size,
495 : &mpriv_out);
496 1 : GNUNET_free (econtract);
497 1 : if (NULL == c)
498 0 : return 1;
499 1 : json_decref (c);
500 1 : if (0 != GNUNET_memcmp (&mpriv_in,
501 : &mpriv_out))
502 0 : return 1;
503 1 : return 0;
504 : }
505 :
506 :
507 : static int
508 1 : test_attributes (void)
509 : {
510 : struct TALER_AttributeEncryptionKeyP key;
511 : void *eattr;
512 : size_t eattr_size;
513 : json_t *c;
514 :
515 1 : GNUNET_CRYPTO_random_block (&key,
516 : sizeof (key));
517 1 : c = json_pack ("{s:s}", "test", "value");
518 1 : GNUNET_assert (NULL != c);
519 1 : TALER_CRYPTO_kyc_attributes_encrypt (&key,
520 : c,
521 : &eattr,
522 : &eattr_size);
523 1 : json_decref (c);
524 1 : c = TALER_CRYPTO_kyc_attributes_decrypt (&key,
525 : eattr,
526 : eattr_size);
527 1 : GNUNET_free (eattr);
528 1 : if (NULL == c)
529 : {
530 0 : GNUNET_break (0);
531 0 : return 1;
532 : }
533 1 : GNUNET_assert (0 ==
534 : strcmp ("value",
535 : json_string_value (json_object_get (c,
536 : "test"))));
537 1 : json_decref (c);
538 1 : return 0;
539 : }
540 :
541 :
542 : int
543 1 : main (int argc,
544 : const char *const argv[])
545 : {
546 : (void) argc;
547 : (void) argv;
548 1 : GNUNET_log_setup ("test-crypto",
549 : "WARNING",
550 : NULL);
551 1 : if (0 != test_high_level ())
552 0 : return 1;
553 1 : if (0 != test_planchets (0))
554 0 : return 2;
555 1 : if (0 != test_planchets (13))
556 0 : return 3;
557 1 : if (0 != test_exchange_sigs ())
558 0 : return 4;
559 1 : if (0 != test_merchant_sigs ())
560 0 : return 5;
561 1 : if (0 != test_contracts ())
562 0 : return 6;
563 1 : if (0 != test_attributes ())
564 0 : return 7;
565 1 : return 0;
566 : }
567 :
568 :
569 : /* end of test_crypto.c */
|