Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022 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 : * @file util/crypto_contract.c
18 : * @brief functions for encrypting and decrypting contracts for P2P payments
19 : * @author Christian Grothoff <christian@grothoff.org>
20 : */
21 : #include "taler/platform.h"
22 : #include "taler/taler_util.h"
23 : #include <zlib.h>
24 : #include "taler/taler_exchange_service.h"
25 :
26 :
27 : /**
28 : * Different types of contracts supported.
29 : */
30 : enum ContractFormats
31 : {
32 : /**
33 : * The encrypted contract represents a payment offer. The receiver
34 : * can merge it into a reserve/account to accept the contract and
35 : * obtain the payment.
36 : */
37 : TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER = 0,
38 :
39 : /**
40 : * The encrypted contract represents a payment request.
41 : */
42 : TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST = 1
43 : };
44 :
45 :
46 : /**
47 : * Nonce used for encryption, 24 bytes.
48 : */
49 : struct NonceP
50 : {
51 : uint8_t nonce[crypto_secretbox_NONCEBYTES];
52 : };
53 :
54 : /**
55 : * Specifies a key used for symmetric encryption, 32 bytes.
56 : */
57 : struct SymKeyP
58 : {
59 : uint32_t key[8];
60 : };
61 :
62 :
63 : /**
64 : * Compute @a key.
65 : *
66 : * @param key_material key for calculation
67 : * @param key_m_len length of key
68 : * @param nonce nonce for calculation
69 : * @param salt salt value for calculation
70 : * @param[out] key where to write the en-/description key
71 : */
72 : static void
73 57 : derive_key (const void *key_material,
74 : size_t key_m_len,
75 : const struct NonceP *nonce,
76 : const char *salt,
77 : struct SymKeyP *key)
78 : {
79 57 : GNUNET_assert (GNUNET_YES ==
80 : GNUNET_CRYPTO_hkdf_gnunet (
81 : key,
82 : sizeof (*key),
83 : /* salt / XTS */
84 : nonce,
85 : sizeof (*nonce),
86 : /* ikm */
87 : key_material,
88 : key_m_len,
89 : /* info chunks */
90 : /* The "salt" passed here is actually not something random,
91 : but a protocol-specific identifier string. Thus
92 : we pass it as a context info to the HKDF */
93 : GNUNET_CRYPTO_kdf_arg_string (salt)));
94 57 : }
95 :
96 :
97 : /**
98 : * Encryption of data.
99 : *
100 : * @param nonce value to use for the nonce
101 : * @param key key which is used to derive a key/iv pair from
102 : * @param key_len length of key
103 : * @param data data to encrypt
104 : * @param data_size size of the data
105 : * @param salt salt value which is used for key derivation
106 : * @param[out] res ciphertext output
107 : * @param[out] res_size size of the ciphertext
108 : */
109 : static void
110 37 : blob_encrypt (const struct NonceP *nonce,
111 : const void *key,
112 : size_t key_len,
113 : const void *data,
114 : size_t data_size,
115 : const char *salt,
116 : void **res,
117 : size_t *res_size)
118 : {
119 : size_t ciphertext_size;
120 : struct SymKeyP skey;
121 :
122 37 : derive_key (key,
123 : key_len,
124 : nonce,
125 : salt,
126 : &skey);
127 37 : ciphertext_size = crypto_secretbox_NONCEBYTES
128 : + crypto_secretbox_MACBYTES
129 : + data_size;
130 37 : *res_size = ciphertext_size;
131 37 : *res = GNUNET_malloc (ciphertext_size);
132 37 : GNUNET_memcpy (*res,
133 : nonce,
134 : crypto_secretbox_NONCEBYTES);
135 37 : GNUNET_assert (0 ==
136 : crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
137 : data,
138 : data_size,
139 : (void *) nonce,
140 : (void *) &skey));
141 37 : }
142 :
143 :
144 : /**
145 : * Decryption of data like encrypted recovery document etc.
146 : *
147 : * @param key key which is used to derive a key/iv pair from
148 : * @param key_len length of key
149 : * @param data data to decrypt
150 : * @param data_size size of the data
151 : * @param salt salt value which is used for key derivation
152 : * @param[out] res plaintext output
153 : * @param[out] res_size size of the plaintext
154 : * @return #GNUNET_OK on success
155 : */
156 : static enum GNUNET_GenericReturnValue
157 20 : blob_decrypt (const void *key,
158 : size_t key_len,
159 : const void *data,
160 : size_t data_size,
161 : const char *salt,
162 : void **res,
163 : size_t *res_size)
164 : {
165 : const struct NonceP *nonce;
166 : struct SymKeyP skey;
167 : size_t plaintext_size;
168 :
169 20 : if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES)
170 : {
171 0 : GNUNET_break (0);
172 0 : return GNUNET_SYSERR;
173 : }
174 20 : nonce = data;
175 20 : derive_key (key,
176 : key_len,
177 : nonce,
178 : salt,
179 : &skey);
180 20 : plaintext_size = data_size - (crypto_secretbox_NONCEBYTES
181 : + crypto_secretbox_MACBYTES);
182 20 : *res = GNUNET_malloc (plaintext_size);
183 20 : *res_size = plaintext_size;
184 20 : if (0 != crypto_secretbox_open_easy (*res,
185 20 : data + crypto_secretbox_NONCEBYTES,
186 20 : data_size - crypto_secretbox_NONCEBYTES,
187 : (void *) nonce,
188 : (void *) &skey))
189 : {
190 0 : GNUNET_break (0);
191 0 : GNUNET_free (*res);
192 0 : return GNUNET_SYSERR;
193 : }
194 20 : return GNUNET_OK;
195 : }
196 :
197 :
198 : /**
199 : * Header for encrypted contracts.
200 : */
201 : struct ContractHeaderP
202 : {
203 : /**
204 : * Type of the contract, in NBO.
205 : */
206 : uint32_t ctype;
207 :
208 : /**
209 : * Length of the encrypted contract, in NBO.
210 : */
211 : uint32_t clen;
212 : };
213 :
214 :
215 : /**
216 : * Header for encrypted contracts.
217 : */
218 : struct ContractHeaderMergeP
219 : {
220 : /**
221 : * Generic header.
222 : */
223 : struct ContractHeaderP header;
224 :
225 : /**
226 : * Private key with the merge capability.
227 : */
228 : struct TALER_PurseMergePrivateKeyP merge_priv;
229 : };
230 :
231 :
232 : /**
233 : * Salt we use when encrypting contracts for merge.
234 : */
235 : #define MERGE_SALT "p2p-merge-contract"
236 :
237 :
238 : void
239 12 : TALER_CRYPTO_contract_encrypt_for_merge (
240 : const struct TALER_PurseContractPublicKeyP *purse_pub,
241 : const struct TALER_ContractDiffiePrivateP *contract_priv,
242 : const struct TALER_PurseMergePrivateKeyP *merge_priv,
243 : const json_t *contract_terms,
244 : void **econtract,
245 : size_t *econtract_size)
246 : {
247 : struct GNUNET_HashCode key;
248 : char *cstr;
249 : size_t clen;
250 : void *xbuf;
251 : struct ContractHeaderMergeP *hdr;
252 : struct NonceP nonce;
253 : uLongf cbuf_size;
254 : int ret;
255 :
256 12 : GNUNET_assert (GNUNET_OK ==
257 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
258 : &purse_pub->eddsa_pub,
259 : &key));
260 12 : cstr = json_dumps (contract_terms,
261 : JSON_COMPACT | JSON_SORT_KEYS);
262 12 : clen = strlen (cstr);
263 12 : cbuf_size = compressBound (clen);
264 12 : xbuf = GNUNET_malloc (cbuf_size);
265 12 : ret = compress (xbuf,
266 : &cbuf_size,
267 : (const Bytef *) cstr,
268 : clen);
269 12 : GNUNET_assert (Z_OK == ret);
270 12 : free (cstr);
271 12 : hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size);
272 12 : hdr->header.ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER);
273 12 : hdr->header.clen = htonl ((uint32_t) clen);
274 12 : hdr->merge_priv = *merge_priv;
275 12 : GNUNET_memcpy (&hdr[1],
276 : xbuf,
277 : cbuf_size);
278 12 : GNUNET_free (xbuf);
279 12 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
280 : &nonce,
281 : sizeof (nonce));
282 12 : blob_encrypt (&nonce,
283 : &key,
284 : sizeof (key),
285 : hdr,
286 : sizeof (*hdr) + cbuf_size,
287 : MERGE_SALT,
288 : econtract,
289 : econtract_size);
290 12 : GNUNET_free (hdr);
291 12 : }
292 :
293 :
294 : json_t *
295 4 : TALER_CRYPTO_contract_decrypt_for_merge (
296 : const struct TALER_ContractDiffiePrivateP *contract_priv,
297 : const struct TALER_PurseContractPublicKeyP *purse_pub,
298 : const void *econtract,
299 : size_t econtract_size,
300 : struct TALER_PurseMergePrivateKeyP *merge_priv)
301 : {
302 : struct GNUNET_HashCode key;
303 : void *xhdr;
304 : size_t hdr_size;
305 : const struct ContractHeaderMergeP *hdr;
306 : char *cstr;
307 : uLongf clen;
308 : json_error_t json_error;
309 : json_t *ret;
310 :
311 4 : if (GNUNET_OK !=
312 4 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
313 : &purse_pub->eddsa_pub,
314 : &key))
315 : {
316 0 : GNUNET_break (0);
317 0 : return NULL;
318 : }
319 4 : if (GNUNET_OK !=
320 4 : blob_decrypt (&key,
321 : sizeof (key),
322 : econtract,
323 : econtract_size,
324 : MERGE_SALT,
325 : &xhdr,
326 : &hdr_size))
327 : {
328 0 : GNUNET_break_op (0);
329 0 : return NULL;
330 : }
331 4 : if (hdr_size < sizeof (*hdr))
332 : {
333 0 : GNUNET_break_op (0);
334 0 : GNUNET_free (xhdr);
335 0 : return NULL;
336 : }
337 4 : hdr = xhdr;
338 4 : if (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER != ntohl (hdr->header.ctype))
339 : {
340 0 : GNUNET_break_op (0);
341 0 : GNUNET_free (xhdr);
342 0 : return NULL;
343 : }
344 4 : clen = ntohl (hdr->header.clen);
345 4 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
346 : {
347 0 : GNUNET_break_op (0);
348 0 : GNUNET_free (xhdr);
349 0 : return NULL;
350 : }
351 4 : cstr = GNUNET_malloc (clen + 1);
352 4 : if (Z_OK !=
353 4 : uncompress ((Bytef *) cstr,
354 : &clen,
355 4 : (const Bytef *) &hdr[1],
356 : hdr_size - sizeof (*hdr)))
357 : {
358 0 : GNUNET_break_op (0);
359 0 : GNUNET_free (cstr);
360 0 : GNUNET_free (xhdr);
361 0 : return NULL;
362 : }
363 4 : *merge_priv = hdr->merge_priv;
364 4 : GNUNET_free (xhdr);
365 4 : ret = json_loadb ((char *) cstr,
366 : clen,
367 : JSON_DECODE_ANY,
368 : &json_error);
369 4 : if (NULL == ret)
370 : {
371 0 : GNUNET_break_op (0);
372 0 : GNUNET_free (cstr);
373 0 : return NULL;
374 : }
375 4 : GNUNET_free (cstr);
376 4 : return ret;
377 : }
378 :
379 :
380 : /**
381 : * Salt we use when encrypting contracts for merge.
382 : */
383 : #define DEPOSIT_SALT "p2p-deposit-contract"
384 :
385 :
386 : void
387 14 : TALER_CRYPTO_contract_encrypt_for_deposit (
388 : const struct TALER_PurseContractPublicKeyP *purse_pub,
389 : const struct TALER_ContractDiffiePrivateP *contract_priv,
390 : const json_t *contract_terms,
391 : void **econtract,
392 : size_t *econtract_size)
393 : {
394 : struct GNUNET_HashCode key;
395 : char *cstr;
396 : size_t clen;
397 : void *xbuf;
398 : struct ContractHeaderP *hdr;
399 : struct NonceP nonce;
400 : uLongf cbuf_size;
401 : int ret;
402 : void *xecontract;
403 : size_t xecontract_size;
404 :
405 14 : GNUNET_assert (GNUNET_OK ==
406 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
407 : &purse_pub->eddsa_pub,
408 : &key));
409 14 : cstr = json_dumps (contract_terms,
410 : JSON_COMPACT | JSON_SORT_KEYS);
411 14 : GNUNET_assert (NULL != cstr);
412 14 : clen = strlen (cstr);
413 14 : cbuf_size = compressBound (clen);
414 14 : xbuf = GNUNET_malloc (cbuf_size);
415 14 : ret = compress (xbuf,
416 : &cbuf_size,
417 : (const Bytef *) cstr,
418 : clen);
419 14 : GNUNET_assert (Z_OK == ret);
420 14 : free (cstr);
421 14 : hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size);
422 14 : hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST);
423 14 : hdr->clen = htonl ((uint32_t) clen);
424 14 : GNUNET_memcpy (&hdr[1],
425 : xbuf,
426 : cbuf_size);
427 14 : GNUNET_free (xbuf);
428 14 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
429 : &nonce,
430 : sizeof (nonce));
431 14 : blob_encrypt (&nonce,
432 : &key,
433 : sizeof (key),
434 : hdr,
435 : sizeof (*hdr) + cbuf_size,
436 : DEPOSIT_SALT,
437 : &xecontract,
438 : &xecontract_size);
439 14 : GNUNET_free (hdr);
440 : /* prepend purse_pub */
441 14 : *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub));
442 14 : GNUNET_memcpy (*econtract,
443 : purse_pub,
444 : sizeof (*purse_pub));
445 14 : GNUNET_memcpy (sizeof (*purse_pub) + *econtract,
446 : xecontract,
447 : xecontract_size);
448 14 : *econtract_size = xecontract_size + sizeof (*purse_pub);
449 14 : GNUNET_free (xecontract);
450 14 : }
451 :
452 :
453 : json_t *
454 3 : TALER_CRYPTO_contract_decrypt_for_deposit (
455 : const struct TALER_ContractDiffiePrivateP *contract_priv,
456 : const void *econtract,
457 : size_t econtract_size)
458 : {
459 3 : const struct TALER_PurseContractPublicKeyP *purse_pub = econtract;
460 : struct GNUNET_HashCode key;
461 : void *xhdr;
462 : size_t hdr_size;
463 : const struct ContractHeaderP *hdr;
464 : char *cstr;
465 : uLongf clen;
466 : json_error_t json_error;
467 : json_t *ret;
468 :
469 3 : if (econtract_size < sizeof (*purse_pub))
470 : {
471 0 : GNUNET_break_op (0);
472 0 : return NULL;
473 : }
474 3 : if (GNUNET_OK !=
475 3 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
476 : &purse_pub->eddsa_pub,
477 : &key))
478 : {
479 0 : GNUNET_break (0);
480 0 : return NULL;
481 : }
482 3 : econtract += sizeof (*purse_pub);
483 3 : econtract_size -= sizeof (*purse_pub);
484 3 : if (GNUNET_OK !=
485 3 : blob_decrypt (&key,
486 : sizeof (key),
487 : econtract,
488 : econtract_size,
489 : DEPOSIT_SALT,
490 : &xhdr,
491 : &hdr_size))
492 : {
493 0 : GNUNET_break_op (0);
494 0 : return NULL;
495 : }
496 3 : if (hdr_size < sizeof (*hdr))
497 : {
498 0 : GNUNET_break_op (0);
499 0 : GNUNET_free (xhdr);
500 0 : return NULL;
501 : }
502 3 : hdr = xhdr;
503 3 : if (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST != ntohl (hdr->ctype))
504 : {
505 0 : GNUNET_break_op (0);
506 0 : GNUNET_free (xhdr);
507 0 : return NULL;
508 : }
509 3 : clen = ntohl (hdr->clen);
510 3 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
511 : {
512 0 : GNUNET_break_op (0);
513 0 : GNUNET_free (xhdr);
514 0 : return NULL;
515 : }
516 3 : cstr = GNUNET_malloc (clen + 1);
517 3 : if (Z_OK !=
518 3 : uncompress ((Bytef *) cstr,
519 : &clen,
520 3 : (const Bytef *) &hdr[1],
521 : hdr_size - sizeof (*hdr)))
522 : {
523 0 : GNUNET_break_op (0);
524 0 : GNUNET_free (cstr);
525 0 : GNUNET_free (xhdr);
526 0 : return NULL;
527 : }
528 3 : GNUNET_free (xhdr);
529 3 : ret = json_loadb ((char *) cstr,
530 : clen,
531 : JSON_DECODE_ANY,
532 : &json_error);
533 3 : if (NULL == ret)
534 : {
535 0 : GNUNET_break_op (0);
536 0 : GNUNET_free (cstr);
537 0 : return NULL;
538 : }
539 3 : GNUNET_free (cstr);
540 3 : return ret;
541 : }
542 :
543 :
544 : /**
545 : * Salt we use when encrypting KYC attributes.
546 : */
547 : #define ATTRIBUTE_SALT "kyc-attributes"
548 :
549 :
550 : void
551 11 : TALER_CRYPTO_kyc_attributes_encrypt (
552 : const struct TALER_AttributeEncryptionKeyP *key,
553 : const json_t *attr,
554 : void **enc_attr,
555 : size_t *enc_attr_size)
556 : {
557 : uLongf cbuf_size;
558 : char *cstr;
559 : uLongf clen;
560 : void *xbuf;
561 : int ret;
562 : uint32_t belen;
563 : struct NonceP nonce;
564 :
565 11 : cstr = json_dumps (attr,
566 : JSON_COMPACT | JSON_SORT_KEYS);
567 11 : GNUNET_assert (NULL != cstr);
568 11 : clen = strlen (cstr);
569 11 : GNUNET_assert (clen <= UINT32_MAX);
570 11 : cbuf_size = compressBound (clen);
571 11 : xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t));
572 11 : belen = htonl ((uint32_t) clen);
573 11 : GNUNET_memcpy (xbuf,
574 : &belen,
575 : sizeof (belen));
576 11 : ret = compress (xbuf + 4,
577 : &cbuf_size,
578 : (const Bytef *) cstr,
579 : clen);
580 11 : GNUNET_assert (Z_OK == ret);
581 11 : free (cstr);
582 11 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
583 : &nonce,
584 : sizeof (nonce));
585 11 : blob_encrypt (&nonce,
586 : key,
587 : sizeof (*key),
588 : xbuf,
589 : cbuf_size + sizeof (uint32_t),
590 : ATTRIBUTE_SALT,
591 : enc_attr,
592 : enc_attr_size);
593 11 : GNUNET_free (xbuf);
594 11 : }
595 :
596 :
597 : json_t *
598 13 : TALER_CRYPTO_kyc_attributes_decrypt (
599 : const struct TALER_AttributeEncryptionKeyP *key,
600 : const void *enc_attr,
601 : size_t enc_attr_size)
602 : {
603 : void *xhdr;
604 : size_t hdr_size;
605 : char *cstr;
606 : uLongf clen;
607 : json_error_t json_error;
608 : json_t *ret;
609 : uint32_t belen;
610 :
611 13 : if (GNUNET_OK !=
612 13 : blob_decrypt (key,
613 : sizeof (*key),
614 : enc_attr,
615 : enc_attr_size,
616 : ATTRIBUTE_SALT,
617 : &xhdr,
618 : &hdr_size))
619 : {
620 0 : GNUNET_break_op (0);
621 0 : return NULL;
622 : }
623 13 : GNUNET_memcpy (&belen,
624 : xhdr,
625 : sizeof (belen));
626 13 : clen = ntohl (belen);
627 13 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
628 : {
629 0 : GNUNET_break_op (0);
630 0 : GNUNET_free (xhdr);
631 0 : return NULL;
632 : }
633 13 : cstr = GNUNET_malloc (clen + 1);
634 13 : if (Z_OK !=
635 13 : uncompress ((Bytef *) cstr,
636 : &clen,
637 13 : (const Bytef *) (xhdr + sizeof (uint32_t)),
638 : hdr_size - sizeof (uint32_t)))
639 : {
640 0 : GNUNET_break_op (0);
641 0 : GNUNET_free (cstr);
642 0 : GNUNET_free (xhdr);
643 0 : return NULL;
644 : }
645 13 : GNUNET_free (xhdr);
646 13 : ret = json_loadb ((char *) cstr,
647 : clen,
648 : JSON_DECODE_ANY,
649 : &json_error);
650 13 : if (NULL == ret)
651 : {
652 0 : GNUNET_break_op (0);
653 0 : GNUNET_free (cstr);
654 0 : return NULL;
655 : }
656 13 : GNUNET_free (cstr);
657 13 : return ret;
658 : }
|