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 75 : 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 75 : 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 75 : }
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 40 : 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 40 : derive_key (key,
121 : key_len,
122 : nonce,
123 : salt,
124 : &skey);
125 40 : ciphertext_size = crypto_secretbox_NONCEBYTES
126 : + crypto_secretbox_MACBYTES
127 : + data_size;
128 40 : *res_size = ciphertext_size;
129 40 : *res = GNUNET_malloc (ciphertext_size);
130 40 : GNUNET_memcpy (*res,
131 : nonce,
132 : crypto_secretbox_NONCEBYTES);
133 40 : GNUNET_assert (0 ==
134 : crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
135 : data,
136 : data_size,
137 : (void *) nonce,
138 : (void *) &skey));
139 40 : }
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 35 : 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 35 : if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES)
168 : {
169 0 : GNUNET_break (0);
170 0 : return GNUNET_SYSERR;
171 : }
172 35 : nonce = data;
173 35 : derive_key (key,
174 : key_len,
175 : nonce,
176 : salt,
177 : &skey);
178 35 : plaintext_size = data_size - (crypto_secretbox_NONCEBYTES
179 : + crypto_secretbox_MACBYTES);
180 35 : *res = GNUNET_malloc (plaintext_size);
181 35 : *res_size = plaintext_size;
182 35 : if (0 != crypto_secretbox_open_easy (*res,
183 35 : data + crypto_secretbox_NONCEBYTES,
184 35 : 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 35 : 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 (&nonce,
278 : sizeof (nonce));
279 12 : blob_encrypt (&nonce,
280 : &key,
281 : sizeof (key),
282 : hdr,
283 : sizeof (*hdr) + cbuf_size,
284 : MERGE_SALT,
285 : econtract,
286 : econtract_size);
287 12 : GNUNET_free (hdr);
288 12 : }
289 :
290 :
291 : json_t *
292 4 : TALER_CRYPTO_contract_decrypt_for_merge (
293 : const struct TALER_ContractDiffiePrivateP *contract_priv,
294 : const struct TALER_PurseContractPublicKeyP *purse_pub,
295 : const void *econtract,
296 : size_t econtract_size,
297 : struct TALER_PurseMergePrivateKeyP *merge_priv)
298 : {
299 : struct GNUNET_HashCode key;
300 : void *xhdr;
301 : size_t hdr_size;
302 : const struct ContractHeaderMergeP *hdr;
303 : char *cstr;
304 : uLongf clen;
305 : json_error_t json_error;
306 : json_t *ret;
307 :
308 4 : if (GNUNET_OK !=
309 4 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
310 : &purse_pub->eddsa_pub,
311 : &key))
312 : {
313 0 : GNUNET_break (0);
314 0 : return NULL;
315 : }
316 4 : if (GNUNET_OK !=
317 4 : blob_decrypt (&key,
318 : sizeof (key),
319 : econtract,
320 : econtract_size,
321 : MERGE_SALT,
322 : &xhdr,
323 : &hdr_size))
324 : {
325 0 : GNUNET_break_op (0);
326 0 : return NULL;
327 : }
328 4 : if (hdr_size < sizeof (*hdr))
329 : {
330 0 : GNUNET_break_op (0);
331 0 : GNUNET_free (xhdr);
332 0 : return NULL;
333 : }
334 4 : hdr = xhdr;
335 4 : if (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER != ntohl (hdr->header.ctype))
336 : {
337 0 : GNUNET_break_op (0);
338 0 : GNUNET_free (xhdr);
339 0 : return NULL;
340 : }
341 4 : clen = ntohl (hdr->header.clen);
342 4 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
343 : {
344 0 : GNUNET_break_op (0);
345 0 : GNUNET_free (xhdr);
346 0 : return NULL;
347 : }
348 4 : cstr = GNUNET_malloc (clen + 1);
349 4 : if (Z_OK !=
350 4 : uncompress ((Bytef *) cstr,
351 : &clen,
352 4 : (const Bytef *) &hdr[1],
353 : hdr_size - sizeof (*hdr)))
354 : {
355 0 : GNUNET_break_op (0);
356 0 : GNUNET_free (cstr);
357 0 : GNUNET_free (xhdr);
358 0 : return NULL;
359 : }
360 4 : *merge_priv = hdr->merge_priv;
361 4 : GNUNET_free (xhdr);
362 4 : ret = json_loadb ((char *) cstr,
363 : clen,
364 : JSON_DECODE_ANY,
365 : &json_error);
366 4 : if (NULL == ret)
367 : {
368 0 : GNUNET_break_op (0);
369 0 : GNUNET_free (cstr);
370 0 : return NULL;
371 : }
372 4 : GNUNET_free (cstr);
373 4 : return ret;
374 : }
375 :
376 :
377 : /**
378 : * Salt we use when encrypting contracts for merge.
379 : */
380 : #define DEPOSIT_SALT "p2p-deposit-contract"
381 :
382 :
383 : void
384 14 : TALER_CRYPTO_contract_encrypt_for_deposit (
385 : const struct TALER_PurseContractPublicKeyP *purse_pub,
386 : const struct TALER_ContractDiffiePrivateP *contract_priv,
387 : const json_t *contract_terms,
388 : void **econtract,
389 : size_t *econtract_size)
390 : {
391 : struct GNUNET_HashCode key;
392 : char *cstr;
393 : size_t clen;
394 : void *xbuf;
395 : struct ContractHeaderP *hdr;
396 : struct NonceP nonce;
397 : uLongf cbuf_size;
398 : int ret;
399 : void *xecontract;
400 : size_t xecontract_size;
401 :
402 14 : GNUNET_assert (GNUNET_OK ==
403 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
404 : &purse_pub->eddsa_pub,
405 : &key));
406 14 : cstr = json_dumps (contract_terms,
407 : JSON_COMPACT | JSON_SORT_KEYS);
408 14 : GNUNET_assert (NULL != cstr);
409 14 : clen = strlen (cstr);
410 14 : cbuf_size = compressBound (clen);
411 14 : xbuf = GNUNET_malloc (cbuf_size);
412 14 : ret = compress (xbuf,
413 : &cbuf_size,
414 : (const Bytef *) cstr,
415 : clen);
416 14 : GNUNET_assert (Z_OK == ret);
417 14 : free (cstr);
418 14 : hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size);
419 14 : hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST);
420 14 : hdr->clen = htonl ((uint32_t) clen);
421 14 : GNUNET_memcpy (&hdr[1],
422 : xbuf,
423 : cbuf_size);
424 14 : GNUNET_free (xbuf);
425 14 : GNUNET_CRYPTO_random_block (&nonce,
426 : sizeof (nonce));
427 14 : blob_encrypt (&nonce,
428 : &key,
429 : sizeof (key),
430 : hdr,
431 : sizeof (*hdr) + cbuf_size,
432 : DEPOSIT_SALT,
433 : &xecontract,
434 : &xecontract_size);
435 14 : GNUNET_free (hdr);
436 : /* prepend purse_pub */
437 14 : *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub));
438 14 : GNUNET_memcpy (*econtract,
439 : purse_pub,
440 : sizeof (*purse_pub));
441 14 : GNUNET_memcpy (sizeof (*purse_pub) + *econtract,
442 : xecontract,
443 : xecontract_size);
444 14 : *econtract_size = xecontract_size + sizeof (*purse_pub);
445 14 : GNUNET_free (xecontract);
446 14 : }
447 :
448 :
449 : json_t *
450 3 : TALER_CRYPTO_contract_decrypt_for_deposit (
451 : const struct TALER_ContractDiffiePrivateP *contract_priv,
452 : const void *econtract,
453 : size_t econtract_size)
454 : {
455 3 : const struct TALER_PurseContractPublicKeyP *purse_pub = econtract;
456 : struct GNUNET_HashCode key;
457 : void *xhdr;
458 : size_t hdr_size;
459 : const struct ContractHeaderP *hdr;
460 : char *cstr;
461 : uLongf clen;
462 : json_error_t json_error;
463 : json_t *ret;
464 :
465 3 : if (econtract_size < sizeof (*purse_pub))
466 : {
467 0 : GNUNET_break_op (0);
468 0 : return NULL;
469 : }
470 3 : if (GNUNET_OK !=
471 3 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
472 : &purse_pub->eddsa_pub,
473 : &key))
474 : {
475 0 : GNUNET_break (0);
476 0 : return NULL;
477 : }
478 3 : econtract += sizeof (*purse_pub);
479 3 : econtract_size -= sizeof (*purse_pub);
480 3 : if (GNUNET_OK !=
481 3 : blob_decrypt (&key,
482 : sizeof (key),
483 : econtract,
484 : econtract_size,
485 : DEPOSIT_SALT,
486 : &xhdr,
487 : &hdr_size))
488 : {
489 0 : GNUNET_break_op (0);
490 0 : return NULL;
491 : }
492 3 : if (hdr_size < sizeof (*hdr))
493 : {
494 0 : GNUNET_break_op (0);
495 0 : GNUNET_free (xhdr);
496 0 : return NULL;
497 : }
498 3 : hdr = xhdr;
499 3 : if (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST != ntohl (hdr->ctype))
500 : {
501 0 : GNUNET_break_op (0);
502 0 : GNUNET_free (xhdr);
503 0 : return NULL;
504 : }
505 3 : clen = ntohl (hdr->clen);
506 3 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
507 : {
508 0 : GNUNET_break_op (0);
509 0 : GNUNET_free (xhdr);
510 0 : return NULL;
511 : }
512 3 : cstr = GNUNET_malloc (clen + 1);
513 3 : if (Z_OK !=
514 3 : uncompress ((Bytef *) cstr,
515 : &clen,
516 3 : (const Bytef *) &hdr[1],
517 : hdr_size - sizeof (*hdr)))
518 : {
519 0 : GNUNET_break_op (0);
520 0 : GNUNET_free (cstr);
521 0 : GNUNET_free (xhdr);
522 0 : return NULL;
523 : }
524 3 : GNUNET_free (xhdr);
525 3 : ret = json_loadb ((char *) cstr,
526 : clen,
527 : JSON_DECODE_ANY,
528 : &json_error);
529 3 : if (NULL == ret)
530 : {
531 0 : GNUNET_break_op (0);
532 0 : GNUNET_free (cstr);
533 0 : return NULL;
534 : }
535 3 : GNUNET_free (cstr);
536 3 : return ret;
537 : }
538 :
539 :
540 : /**
541 : * Salt we use when encrypting KYC attributes.
542 : */
543 : #define ATTRIBUTE_SALT "kyc-attributes"
544 :
545 :
546 : void
547 14 : TALER_CRYPTO_kyc_attributes_encrypt (
548 : const struct TALER_AttributeEncryptionKeyP *key,
549 : const json_t *attr,
550 : void **enc_attr,
551 : size_t *enc_attr_size)
552 : {
553 : uLongf cbuf_size;
554 : char *cstr;
555 : uLongf clen;
556 : void *xbuf;
557 : int ret;
558 : uint32_t belen;
559 : struct NonceP nonce;
560 :
561 14 : cstr = json_dumps (attr,
562 : JSON_COMPACT | JSON_SORT_KEYS);
563 14 : GNUNET_assert (NULL != cstr);
564 14 : clen = strlen (cstr);
565 14 : GNUNET_assert (clen <= UINT32_MAX);
566 14 : cbuf_size = compressBound (clen);
567 14 : xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t));
568 14 : belen = htonl ((uint32_t) clen);
569 14 : GNUNET_memcpy (xbuf,
570 : &belen,
571 : sizeof (belen));
572 14 : ret = compress (xbuf + 4,
573 : &cbuf_size,
574 : (const Bytef *) cstr,
575 : clen);
576 14 : GNUNET_assert (Z_OK == ret);
577 14 : free (cstr);
578 14 : GNUNET_CRYPTO_random_block (&nonce,
579 : sizeof (nonce));
580 14 : blob_encrypt (&nonce,
581 : key,
582 : sizeof (*key),
583 : xbuf,
584 : cbuf_size + sizeof (uint32_t),
585 : ATTRIBUTE_SALT,
586 : enc_attr,
587 : enc_attr_size);
588 14 : GNUNET_free (xbuf);
589 14 : }
590 :
591 :
592 : json_t *
593 28 : TALER_CRYPTO_kyc_attributes_decrypt (
594 : const struct TALER_AttributeEncryptionKeyP *key,
595 : const void *enc_attr,
596 : size_t enc_attr_size)
597 : {
598 : void *xhdr;
599 : size_t hdr_size;
600 : char *cstr;
601 : uLongf clen;
602 : json_error_t json_error;
603 : json_t *ret;
604 : uint32_t belen;
605 :
606 28 : if (GNUNET_OK !=
607 28 : blob_decrypt (key,
608 : sizeof (*key),
609 : enc_attr,
610 : enc_attr_size,
611 : ATTRIBUTE_SALT,
612 : &xhdr,
613 : &hdr_size))
614 : {
615 0 : GNUNET_break_op (0);
616 0 : return NULL;
617 : }
618 28 : if (hdr_size < sizeof (uint32_t))
619 : {
620 0 : GNUNET_break_op (0);
621 0 : GNUNET_free (xhdr);
622 0 : return NULL;
623 : }
624 28 : GNUNET_memcpy (&belen,
625 : xhdr,
626 : sizeof (belen));
627 28 : clen = ntohl (belen);
628 28 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
629 : {
630 0 : GNUNET_break_op (0);
631 0 : GNUNET_free (xhdr);
632 0 : return NULL;
633 : }
634 28 : cstr = GNUNET_malloc (clen + 1);
635 28 : if (Z_OK !=
636 28 : uncompress ((Bytef *) cstr,
637 : &clen,
638 28 : (const Bytef *) (xhdr + sizeof (uint32_t)),
639 : hdr_size - sizeof (uint32_t)))
640 : {
641 0 : GNUNET_break_op (0);
642 0 : GNUNET_free (cstr);
643 0 : GNUNET_free (xhdr);
644 0 : return NULL;
645 : }
646 28 : GNUNET_free (xhdr);
647 28 : ret = json_loadb ((char *) cstr,
648 : clen,
649 : JSON_DECODE_ANY,
650 : &json_error);
651 28 : if (NULL == ret)
652 : {
653 0 : GNUNET_break_op (0);
654 0 : GNUNET_free (cstr);
655 0 : return NULL;
656 : }
657 28 : GNUNET_free (cstr);
658 28 : return ret;
659 : }
|