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