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 "platform.h"
23 : #include "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 1 : 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 1 : struct GNUNET_CRYPTO_BlindingInputValues bi = {
47 : .cipher = GNUNET_CRYPTO_BSA_RSA
48 : };
49 1 : struct TALER_ExchangeBlindingValues alg1 = {
50 : .blinding_inputs = &bi
51 : };
52 1 : struct TALER_ExchangeBlindingValues alg2 = {
53 : .blinding_inputs = &bi
54 : };
55 :
56 1 : GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv);
57 1 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
58 : &coin_pub.eddsa_pub);
59 1 : GNUNET_CRYPTO_ecdhe_key_create (&trans_priv.ecdhe_priv);
60 1 : GNUNET_CRYPTO_ecdhe_key_get_public (&trans_priv.ecdhe_priv,
61 : &trans_pub.ecdhe_pub);
62 1 : TALER_link_derive_transfer_secret (&coin_priv,
63 : &trans_priv,
64 : &secret);
65 1 : TALER_link_reveal_transfer_secret (&trans_priv,
66 : &coin_pub,
67 : &secret2);
68 1 : GNUNET_assert (0 ==
69 : GNUNET_memcmp (&secret,
70 : &secret2));
71 1 : TALER_link_recover_transfer_secret (&trans_pub,
72 : &coin_priv,
73 : &secret2);
74 1 : GNUNET_assert (0 ==
75 : GNUNET_memcmp (&secret,
76 : &secret2));
77 1 : TALER_transfer_secret_to_planchet_secret (&secret,
78 : 0,
79 : &ps1);
80 1 : TALER_planchet_setup_coin_priv (&ps1,
81 : &alg1,
82 : &coin_priv1);
83 1 : TALER_planchet_blinding_secret_create (&ps1,
84 : &alg1,
85 : &bks1);
86 1 : TALER_transfer_secret_to_planchet_secret (&secret,
87 : 1,
88 : &ps2);
89 1 : TALER_planchet_setup_coin_priv (&ps2,
90 : &alg2,
91 : &coin_priv2);
92 1 : TALER_planchet_blinding_secret_create (&ps2,
93 : &alg2,
94 : &bks2);
95 1 : GNUNET_assert (0 !=
96 : GNUNET_memcmp (&ps1,
97 : &ps2));
98 1 : GNUNET_assert (0 !=
99 : GNUNET_memcmp (&coin_priv1,
100 : &coin_priv2));
101 1 : GNUNET_assert (0 !=
102 : GNUNET_memcmp (&bks1,
103 : &bks2));
104 1 : 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 2 : 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 2 : struct TALER_AgeCommitmentHash *ach = NULL;
133 2 : struct TALER_AgeCommitmentHash ah = {0};
134 :
135 2 : alg_values = TALER_denom_ewv_rsa_singleton ();
136 2 : if (0 < age)
137 : {
138 : struct TALER_AgeCommitmentProof acp;
139 : struct GNUNET_HashCode seed;
140 :
141 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
142 : &seed,
143 : sizeof(seed));
144 1 : TALER_age_restriction_commit (&age_mask,
145 : age,
146 : &seed,
147 : &acp);
148 1 : TALER_age_commitment_hash (&acp.commitment,
149 : &ah);
150 1 : ach = &ah;
151 1 : TALER_age_commitment_proof_free (&acp);
152 : }
153 :
154 2 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
155 : &ps,
156 : sizeof (ps));
157 2 : GNUNET_log_skip (1, GNUNET_YES);
158 2 : GNUNET_assert (GNUNET_SYSERR ==
159 : TALER_denom_priv_create (&dk_priv,
160 : &dk_pub,
161 : GNUNET_CRYPTO_BSA_INVALID));
162 2 : GNUNET_log_skip (1, GNUNET_YES);
163 2 : GNUNET_assert (GNUNET_SYSERR ==
164 : TALER_denom_priv_create (&dk_priv,
165 : &dk_pub,
166 : 42));
167 :
168 2 : GNUNET_assert (GNUNET_OK ==
169 : TALER_denom_priv_create (&dk_priv,
170 : &dk_pub,
171 : GNUNET_CRYPTO_BSA_RSA,
172 : 1024));
173 2 : TALER_planchet_setup_coin_priv (&ps,
174 : alg_values,
175 : &coin_priv);
176 2 : TALER_planchet_blinding_secret_create (&ps,
177 : alg_values,
178 : &bks);
179 2 : 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 2 : GNUNET_assert (GNUNET_OK ==
189 : TALER_denom_sign_blinded (&blind_sig,
190 : &dk_priv,
191 : false,
192 : &pd.blinded_planchet));
193 2 : TALER_planchet_detail_free (&pd);
194 2 : 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 2 : TALER_blinded_denom_sig_free (&blind_sig);
204 2 : TALER_denom_sig_free (&coin.sig);
205 2 : TALER_denom_priv_free (&dk_priv);
206 2 : TALER_denom_pub_free (&dk_pub);
207 2 : 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 2 : 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 2 : struct TALER_AgeCommitmentHash *ach = NULL;
232 2 : struct TALER_AgeCommitmentHash ah = {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 (GNUNET_CRYPTO_QUALITY_WEAK,
240 : &seed,
241 : sizeof(seed));
242 1 : TALER_age_restriction_commit (&age_mask,
243 : age,
244 : &seed,
245 : &acp);
246 1 : TALER_age_commitment_hash (&acp.commitment,
247 : &ah);
248 1 : ach = &ah;
249 1 : TALER_age_commitment_proof_free (&acp);
250 : }
251 :
252 2 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
253 : &ps,
254 : sizeof (ps));
255 2 : 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 2 : TALER_cs_withdraw_nonce_derive (
261 : &ps,
262 : &nonce.cs_nonce);
263 : // FIXME: define Taler abstraction for this:
264 : alg_values.blinding_inputs
265 2 : = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key,
266 : &nonce,
267 : "rw");
268 2 : TALER_denom_pub_hash (&dk_pub,
269 : &pd.denom_pub_hash);
270 2 : TALER_planchet_setup_coin_priv (&ps,
271 : &alg_values,
272 : &coin_priv);
273 2 : TALER_planchet_blinding_secret_create (&ps,
274 : &alg_values,
275 : &bks);
276 2 : 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 2 : GNUNET_assert (GNUNET_OK ==
286 : TALER_denom_sign_blinded (&blind_sig,
287 : &dk_priv,
288 : false,
289 : &pd.blinded_planchet));
290 2 : 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 2 : TALER_blinded_denom_sig_free (&blind_sig);
300 2 : TALER_denom_sig_free (&coin.sig);
301 2 : TALER_denom_priv_free (&dk_priv);
302 2 : TALER_denom_pub_free (&dk_pub);
303 2 : 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 2 : test_planchets (uint8_t age)
316 : {
317 2 : if (0 != test_planchets_rsa (age))
318 0 : return -1;
319 2 : return test_planchets_cs (age);
320 : }
321 :
322 :
323 : static int
324 1 : test_exchange_sigs (void)
325 : {
326 1 : const struct TALER_FullPayto pt = {
327 : .full_payto
328 : = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
329 : };
330 1 : 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 1 : GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
340 1 : rest = json_array ();
341 1 : GNUNET_assert (NULL != rest);
342 1 : TALER_exchange_wire_signature_make (pt,
343 : NULL,
344 : rest,
345 : rest,
346 : &priv,
347 : &sig);
348 1 : GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
349 : &pub.eddsa_pub);
350 1 : if (GNUNET_OK !=
351 1 : TALER_exchange_wire_signature_check (pt,
352 : NULL,
353 : rest,
354 : rest,
355 : &pub,
356 : &sig))
357 : {
358 0 : GNUNET_break (0);
359 0 : return 1;
360 : }
361 1 : if (GNUNET_OK ==
362 1 : TALER_exchange_wire_signature_check (
363 : pto,
364 : NULL,
365 : rest,
366 : rest,
367 : &pub,
368 : &sig))
369 : {
370 0 : GNUNET_break (0);
371 0 : return 1;
372 : }
373 1 : if (GNUNET_OK ==
374 1 : TALER_exchange_wire_signature_check (
375 : pt,
376 : "http://example.com/",
377 : rest,
378 : rest,
379 : &pub,
380 : &sig))
381 : {
382 0 : GNUNET_break (0);
383 0 : return 1;
384 : }
385 1 : json_decref (rest);
386 1 : return 0;
387 : }
388 :
389 :
390 : static int
391 1 : test_merchant_sigs (void)
392 : {
393 1 : const struct TALER_FullPayto pt = {
394 : .full_payto
395 : = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
396 : };
397 1 : 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 1 : GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
407 1 : memset (&salt,
408 : 42,
409 : sizeof (salt));
410 1 : TALER_merchant_wire_signature_make (pt,
411 : &salt,
412 : &priv,
413 : &sig);
414 1 : GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
415 : &pub.eddsa_pub);
416 1 : if (GNUNET_OK !=
417 1 : TALER_merchant_wire_signature_check (pt,
418 : &salt,
419 : &pub,
420 : &sig))
421 : {
422 0 : GNUNET_break (0);
423 0 : return 1;
424 : }
425 1 : if (GNUNET_OK ==
426 1 : TALER_merchant_wire_signature_check (
427 : pto,
428 : &salt,
429 : &pub,
430 : &sig))
431 : {
432 0 : GNUNET_break (0);
433 0 : return 1;
434 : }
435 1 : memset (&salt,
436 : 43,
437 : sizeof (salt));
438 1 : if (GNUNET_OK ==
439 1 : TALER_merchant_wire_signature_check (pt,
440 : &salt,
441 : &pub,
442 : &sig))
443 : {
444 0 : GNUNET_break (0);
445 0 : return 1;
446 : }
447 1 : return 0;
448 : }
449 :
450 :
451 : static int
452 1 : 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 1 : GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv);
464 1 : GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv);
465 1 : GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv,
466 : &purse_pub.eddsa_pub);
467 1 : memset (&mpriv_in,
468 : 42,
469 : sizeof (mpriv_in));
470 1 : c = json_pack ("{s:s}", "test", "value");
471 1 : GNUNET_assert (NULL != c);
472 1 : TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
473 : &cpriv,
474 : &mpriv_in,
475 : c,
476 : &econtract,
477 : &econtract_size);
478 1 : json_decref (c);
479 1 : c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv,
480 : &purse_pub,
481 : econtract,
482 : econtract_size,
483 : &mpriv_out);
484 1 : GNUNET_free (econtract);
485 1 : if (NULL == c)
486 0 : return 1;
487 1 : json_decref (c);
488 1 : if (0 != GNUNET_memcmp (&mpriv_in,
489 : &mpriv_out))
490 0 : return 1;
491 1 : return 0;
492 : }
493 :
494 :
495 : static int
496 1 : test_attributes (void)
497 : {
498 : struct TALER_AttributeEncryptionKeyP key;
499 : void *eattr;
500 : size_t eattr_size;
501 : json_t *c;
502 :
503 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
504 : &key,
505 : sizeof (key));
506 1 : c = json_pack ("{s:s}", "test", "value");
507 1 : GNUNET_assert (NULL != c);
508 1 : TALER_CRYPTO_kyc_attributes_encrypt (&key,
509 : c,
510 : &eattr,
511 : &eattr_size);
512 1 : json_decref (c);
513 1 : c = TALER_CRYPTO_kyc_attributes_decrypt (&key,
514 : eattr,
515 : eattr_size);
516 1 : GNUNET_free (eattr);
517 1 : if (NULL == c)
518 : {
519 0 : GNUNET_break (0);
520 0 : return 1;
521 : }
522 1 : GNUNET_assert (0 ==
523 : strcmp ("value",
524 : json_string_value (json_object_get (c,
525 : "test"))));
526 1 : json_decref (c);
527 1 : return 0;
528 : }
529 :
530 :
531 : int
532 1 : main (int argc,
533 : const char *const argv[])
534 : {
535 : (void) argc;
536 : (void) argv;
537 1 : GNUNET_log_setup ("test-crypto",
538 : "WARNING",
539 : NULL);
540 1 : if (0 != test_high_level ())
541 0 : return 1;
542 1 : if (0 != test_planchets (0))
543 0 : return 2;
544 1 : if (0 != test_planchets (13))
545 0 : return 3;
546 1 : if (0 != test_exchange_sigs ())
547 0 : return 4;
548 1 : if (0 != test_merchant_sigs ())
549 0 : return 5;
550 1 : if (0 != test_contracts ())
551 0 : return 6;
552 1 : if (0 != test_attributes ())
553 0 : return 7;
554 1 : return 0;
555 : }
556 :
557 :
558 : /* end of test_crypto.c */
|