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