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 2 : 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 2 : 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 2 : }
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 1 : contract_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 1 : derive_key (key,
125 : key_len,
126 : nonce,
127 : salt,
128 : &skey);
129 1 : ciphertext_size = crypto_secretbox_NONCEBYTES
130 : + crypto_secretbox_MACBYTES + data_size;
131 1 : *res_size = ciphertext_size;
132 1 : *res = GNUNET_malloc (ciphertext_size);
133 1 : memcpy (*res, nonce, crypto_secretbox_NONCEBYTES);
134 1 : GNUNET_assert (0 ==
135 : crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
136 : data,
137 : data_size,
138 : (void *) nonce,
139 : (void *) &skey));
140 1 : }
141 :
142 :
143 : /**
144 : * Decryption of data like encrypted recovery document etc.
145 : *
146 : * @param key key which is used to derive a key/iv pair from
147 : * @param key_len length of key
148 : * @param data data to decrypt
149 : * @param data_size size of the data
150 : * @param salt salt value which is used for key derivation
151 : * @param[out] res plaintext output
152 : * @param[out] res_size size of the plaintext
153 : * @return #GNUNET_OK on success
154 : */
155 : static enum GNUNET_GenericReturnValue
156 1 : contract_decrypt (const void *key,
157 : size_t key_len,
158 : const void *data,
159 : size_t data_size,
160 : const char *salt,
161 : void **res,
162 : size_t *res_size)
163 : {
164 : const struct NonceP *nonce;
165 : struct SymKeyP skey;
166 : size_t plaintext_size;
167 :
168 1 : if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES)
169 : {
170 0 : GNUNET_break (0);
171 0 : return GNUNET_SYSERR;
172 : }
173 1 : nonce = data;
174 1 : derive_key (key,
175 : key_len,
176 : nonce,
177 : salt,
178 : &skey);
179 1 : plaintext_size = data_size - (crypto_secretbox_NONCEBYTES
180 : + crypto_secretbox_MACBYTES);
181 1 : *res = GNUNET_malloc (plaintext_size);
182 1 : *res_size = plaintext_size;
183 1 : if (0 != crypto_secretbox_open_easy (*res,
184 1 : data + crypto_secretbox_NONCEBYTES,
185 1 : data_size - crypto_secretbox_NONCEBYTES,
186 : (void *) nonce,
187 : (void *) &skey))
188 : {
189 0 : GNUNET_break (0);
190 0 : GNUNET_free (*res);
191 0 : return GNUNET_SYSERR;
192 : }
193 1 : return GNUNET_OK;
194 : }
195 :
196 :
197 : /**
198 : * Header for encrypted contracts.
199 : */
200 : struct ContractHeaderP
201 : {
202 : /**
203 : * Type of the contract, in NBO.
204 : */
205 : uint32_t ctype;
206 :
207 : /**
208 : * Length of the encrypted contract, in NBO.
209 : */
210 : uint32_t clen;
211 : };
212 :
213 :
214 : /**
215 : * Header for encrypted contracts.
216 : */
217 : struct ContractHeaderMergeP
218 : {
219 : /**
220 : * Generic header.
221 : */
222 : struct ContractHeaderP header;
223 :
224 : /**
225 : * Private key with the merge capability.
226 : */
227 : struct TALER_PurseMergePrivateKeyP merge_priv;
228 : };
229 :
230 :
231 : /**
232 : * Salt we use when encrypting contracts for merge.
233 : */
234 : #define MERGE_SALT "p2p-merge-contract"
235 :
236 :
237 : void
238 1 : TALER_CRYPTO_contract_encrypt_for_merge (
239 : const struct TALER_PurseContractPublicKeyP *purse_pub,
240 : const struct TALER_ContractDiffiePrivateP *contract_priv,
241 : const struct TALER_PurseMergePrivateKeyP *merge_priv,
242 : const json_t *contract_terms,
243 : void **econtract,
244 : size_t *econtract_size)
245 : {
246 : struct GNUNET_HashCode key;
247 : char *cstr;
248 : size_t clen;
249 : void *xbuf;
250 : struct ContractHeaderMergeP *hdr;
251 : struct NonceP nonce;
252 : uLongf cbuf_size;
253 : int ret;
254 :
255 1 : GNUNET_assert (GNUNET_OK ==
256 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
257 : &purse_pub->eddsa_pub,
258 : &key));
259 1 : cstr = json_dumps (contract_terms,
260 : JSON_COMPACT | JSON_SORT_KEYS);
261 1 : clen = strlen (cstr);
262 1 : cbuf_size = compressBound (clen);
263 1 : xbuf = GNUNET_malloc (cbuf_size);
264 1 : ret = compress (xbuf,
265 : &cbuf_size,
266 : (const Bytef *) cstr,
267 : clen);
268 1 : GNUNET_assert (Z_OK == ret);
269 1 : free (cstr);
270 1 : hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size);
271 1 : hdr->header.ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER);
272 1 : hdr->header.clen = htonl ((uint32_t) clen);
273 1 : hdr->merge_priv = *merge_priv;
274 1 : memcpy (&hdr[1],
275 : xbuf,
276 : cbuf_size);
277 1 : GNUNET_free (xbuf);
278 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
279 : &nonce,
280 : sizeof (nonce));
281 1 : contract_encrypt (&nonce,
282 : &key,
283 : sizeof (key),
284 : hdr,
285 : sizeof (*hdr) + cbuf_size,
286 : MERGE_SALT,
287 : econtract,
288 : econtract_size);
289 1 : GNUNET_free (hdr);
290 1 : }
291 :
292 :
293 : json_t *
294 1 : TALER_CRYPTO_contract_decrypt_for_merge (
295 : const struct TALER_ContractDiffiePrivateP *contract_priv,
296 : const struct TALER_PurseContractPublicKeyP *purse_pub,
297 : const void *econtract,
298 : size_t econtract_size,
299 : struct TALER_PurseMergePrivateKeyP *merge_priv)
300 : {
301 : struct GNUNET_HashCode key;
302 : void *xhdr;
303 : size_t hdr_size;
304 : const struct ContractHeaderMergeP *hdr;
305 : char *cstr;
306 : uLongf clen;
307 : json_error_t json_error;
308 : json_t *ret;
309 :
310 1 : if (GNUNET_OK !=
311 1 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
312 : &purse_pub->eddsa_pub,
313 : &key))
314 : {
315 0 : GNUNET_break (0);
316 0 : return NULL;
317 : }
318 1 : if (GNUNET_OK !=
319 1 : contract_decrypt (&key,
320 : sizeof (key),
321 : econtract,
322 : econtract_size,
323 : MERGE_SALT,
324 : &xhdr,
325 : &hdr_size))
326 : {
327 0 : GNUNET_break_op (0);
328 0 : return NULL;
329 : }
330 1 : if (hdr_size < sizeof (*hdr))
331 : {
332 0 : GNUNET_break_op (0);
333 0 : GNUNET_free (xhdr);
334 0 : return NULL;
335 : }
336 1 : hdr = xhdr;
337 1 : if (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER != ntohl (hdr->header.ctype))
338 : {
339 0 : GNUNET_break_op (0);
340 0 : GNUNET_free (xhdr);
341 0 : return NULL;
342 : }
343 1 : clen = ntohl (hdr->header.clen);
344 1 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
345 : {
346 0 : GNUNET_break_op (0);
347 0 : GNUNET_free (xhdr);
348 0 : return NULL;
349 : }
350 1 : cstr = GNUNET_malloc (clen + 1);
351 1 : if (Z_OK !=
352 1 : uncompress ((Bytef *) cstr,
353 : &clen,
354 1 : (const Bytef *) &hdr[1],
355 : hdr_size - sizeof (*hdr)))
356 : {
357 0 : GNUNET_break_op (0);
358 0 : GNUNET_free (cstr);
359 0 : GNUNET_free (xhdr);
360 0 : return NULL;
361 : }
362 1 : *merge_priv = hdr->merge_priv;
363 1 : GNUNET_free (xhdr);
364 1 : ret = json_loadb ((char *) cstr,
365 : clen,
366 : JSON_DECODE_ANY,
367 : &json_error);
368 1 : if (NULL == ret)
369 : {
370 0 : GNUNET_break_op (0);
371 0 : GNUNET_free (cstr);
372 0 : return NULL;
373 : }
374 1 : GNUNET_free (cstr);
375 1 : return ret;
376 : }
377 :
378 :
379 : /**
380 : * Salt we use when encrypting contracts for merge.
381 : */
382 : #define DEPOSIT_SALT "p2p-deposit-contract"
383 :
384 :
385 : void
386 0 : TALER_CRYPTO_contract_encrypt_for_deposit (
387 : const struct TALER_PurseContractPublicKeyP *purse_pub,
388 : const struct TALER_ContractDiffiePrivateP *contract_priv,
389 : const json_t *contract_terms,
390 : void **econtract,
391 : size_t *econtract_size)
392 : {
393 : struct GNUNET_HashCode key;
394 : char *cstr;
395 : size_t clen;
396 : void *xbuf;
397 : struct ContractHeaderP *hdr;
398 : struct NonceP nonce;
399 : uLongf cbuf_size;
400 : int ret;
401 : void *xecontract;
402 : size_t xecontract_size;
403 :
404 0 : GNUNET_assert (GNUNET_OK ==
405 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
406 : &purse_pub->eddsa_pub,
407 : &key));
408 0 : cstr = json_dumps (contract_terms,
409 : JSON_COMPACT | JSON_SORT_KEYS);
410 0 : clen = strlen (cstr);
411 0 : cbuf_size = compressBound (clen);
412 0 : xbuf = GNUNET_malloc (cbuf_size);
413 0 : ret = compress (xbuf,
414 : &cbuf_size,
415 : (const Bytef *) cstr,
416 : clen);
417 0 : GNUNET_assert (Z_OK == ret);
418 0 : free (cstr);
419 0 : hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size);
420 0 : hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST);
421 0 : hdr->clen = htonl ((uint32_t) clen);
422 0 : memcpy (&hdr[1],
423 : xbuf,
424 : cbuf_size);
425 0 : GNUNET_free (xbuf);
426 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
427 : &nonce,
428 : sizeof (nonce));
429 0 : contract_encrypt (&nonce,
430 : &key,
431 : sizeof (key),
432 : hdr,
433 : sizeof (*hdr) + cbuf_size,
434 : DEPOSIT_SALT,
435 : &xecontract,
436 : &xecontract_size);
437 0 : GNUNET_free (hdr);
438 : /* prepend purse_pub */
439 0 : *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub));
440 0 : memcpy (*econtract,
441 : purse_pub,
442 : sizeof (*purse_pub));
443 0 : memcpy (sizeof (*purse_pub) + *econtract,
444 : xecontract,
445 : xecontract_size);
446 0 : *econtract_size = xecontract_size + sizeof (*purse_pub);
447 0 : GNUNET_free (xecontract);
448 0 : }
449 :
450 :
451 : json_t *
452 0 : TALER_CRYPTO_contract_decrypt_for_deposit (
453 : const struct TALER_ContractDiffiePrivateP *contract_priv,
454 : const void *econtract,
455 : size_t econtract_size)
456 : {
457 0 : const struct TALER_PurseContractPublicKeyP *purse_pub = econtract;
458 :
459 0 : if (econtract_size < sizeof (*purse_pub))
460 : {
461 0 : GNUNET_break_op (0);
462 0 : return NULL;
463 : }
464 : struct GNUNET_HashCode key;
465 : void *xhdr;
466 : size_t hdr_size;
467 : const struct ContractHeaderP *hdr;
468 : char *cstr;
469 : uLongf clen;
470 : json_error_t json_error;
471 : json_t *ret;
472 :
473 0 : if (GNUNET_OK !=
474 0 : GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv,
475 : &purse_pub->eddsa_pub,
476 : &key))
477 : {
478 0 : GNUNET_break (0);
479 0 : return NULL;
480 : }
481 0 : econtract += sizeof (*purse_pub);
482 0 : econtract_size -= sizeof (*purse_pub);
483 0 : if (GNUNET_OK !=
484 0 : contract_decrypt (&key,
485 : sizeof (key),
486 : econtract,
487 : econtract_size,
488 : DEPOSIT_SALT,
489 : &xhdr,
490 : &hdr_size))
491 : {
492 0 : GNUNET_break_op (0);
493 0 : return NULL;
494 : }
495 0 : if (hdr_size < sizeof (*hdr))
496 : {
497 0 : GNUNET_break_op (0);
498 0 : GNUNET_free (xhdr);
499 0 : return NULL;
500 : }
501 0 : hdr = xhdr;
502 0 : if (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST != ntohl (hdr->ctype))
503 : {
504 0 : GNUNET_break_op (0);
505 0 : GNUNET_free (xhdr);
506 0 : return NULL;
507 : }
508 0 : clen = ntohl (hdr->clen);
509 0 : if (clen >= GNUNET_MAX_MALLOC_CHECKED)
510 : {
511 0 : GNUNET_break_op (0);
512 0 : GNUNET_free (xhdr);
513 0 : return NULL;
514 : }
515 0 : cstr = GNUNET_malloc (clen + 1);
516 0 : if (Z_OK !=
517 0 : uncompress ((Bytef *) cstr,
518 : &clen,
519 0 : (const Bytef *) &hdr[1],
520 : hdr_size - sizeof (*hdr)))
521 : {
522 0 : GNUNET_break_op (0);
523 0 : GNUNET_free (cstr);
524 0 : GNUNET_free (xhdr);
525 0 : return NULL;
526 : }
527 0 : GNUNET_free (xhdr);
528 0 : ret = json_loadb ((char *) cstr,
529 : clen,
530 : JSON_DECODE_ANY,
531 : &json_error);
532 0 : if (NULL == ret)
533 : {
534 0 : GNUNET_break_op (0);
535 0 : GNUNET_free (cstr);
536 0 : return NULL;
537 : }
538 0 : GNUNET_free (cstr);
539 0 : return ret;
540 : }
|