crypto_contract.c (16911B)
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 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 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 } 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 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 derive_key (key, 121 key_len, 122 nonce, 123 salt, 124 &skey); 125 ciphertext_size = crypto_secretbox_NONCEBYTES 126 + crypto_secretbox_MACBYTES 127 + data_size; 128 *res_size = ciphertext_size; 129 *res = GNUNET_malloc (ciphertext_size); 130 GNUNET_memcpy (*res, 131 nonce, 132 crypto_secretbox_NONCEBYTES); 133 GNUNET_assert (0 == 134 crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES, 135 data, 136 data_size, 137 (void *) nonce, 138 (void *) &skey)); 139 } 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 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 if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) 168 { 169 GNUNET_break (0); 170 return GNUNET_SYSERR; 171 } 172 nonce = data; 173 derive_key (key, 174 key_len, 175 nonce, 176 salt, 177 &skey); 178 plaintext_size = data_size - (crypto_secretbox_NONCEBYTES 179 + crypto_secretbox_MACBYTES); 180 *res = GNUNET_malloc (plaintext_size); 181 *res_size = plaintext_size; 182 if (0 != crypto_secretbox_open_easy (*res, 183 data + crypto_secretbox_NONCEBYTES, 184 data_size - crypto_secretbox_NONCEBYTES, 185 (void *) nonce, 186 (void *) &skey)) 187 { 188 GNUNET_break (0); 189 GNUNET_free (*res); 190 return GNUNET_SYSERR; 191 } 192 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 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 GNUNET_assert (GNUNET_OK == 255 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 256 &purse_pub->eddsa_pub, 257 &key)); 258 cstr = json_dumps (contract_terms, 259 JSON_COMPACT | JSON_SORT_KEYS); 260 clen = strlen (cstr); 261 cbuf_size = compressBound (clen); 262 xbuf = GNUNET_malloc (cbuf_size); 263 ret = compress (xbuf, 264 &cbuf_size, 265 (const Bytef *) cstr, 266 clen); 267 GNUNET_assert (Z_OK == ret); 268 free (cstr); 269 hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size); 270 hdr->header.ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER); 271 hdr->header.clen = htonl ((uint32_t) clen); 272 hdr->merge_priv = *merge_priv; 273 GNUNET_memcpy (&hdr[1], 274 xbuf, 275 cbuf_size); 276 GNUNET_free (xbuf); 277 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 278 &nonce, 279 sizeof (nonce)); 280 blob_encrypt (&nonce, 281 &key, 282 sizeof (key), 283 hdr, 284 sizeof (*hdr) + cbuf_size, 285 MERGE_SALT, 286 econtract, 287 econtract_size); 288 GNUNET_free (hdr); 289 } 290 291 292 json_t * 293 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 if (GNUNET_OK != 310 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 311 &purse_pub->eddsa_pub, 312 &key)) 313 { 314 GNUNET_break (0); 315 return NULL; 316 } 317 if (GNUNET_OK != 318 blob_decrypt (&key, 319 sizeof (key), 320 econtract, 321 econtract_size, 322 MERGE_SALT, 323 &xhdr, 324 &hdr_size)) 325 { 326 GNUNET_break_op (0); 327 return NULL; 328 } 329 if (hdr_size < sizeof (*hdr)) 330 { 331 GNUNET_break_op (0); 332 GNUNET_free (xhdr); 333 return NULL; 334 } 335 hdr = xhdr; 336 if (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER != ntohl (hdr->header.ctype)) 337 { 338 GNUNET_break_op (0); 339 GNUNET_free (xhdr); 340 return NULL; 341 } 342 clen = ntohl (hdr->header.clen); 343 if (clen >= GNUNET_MAX_MALLOC_CHECKED) 344 { 345 GNUNET_break_op (0); 346 GNUNET_free (xhdr); 347 return NULL; 348 } 349 cstr = GNUNET_malloc (clen + 1); 350 if (Z_OK != 351 uncompress ((Bytef *) cstr, 352 &clen, 353 (const Bytef *) &hdr[1], 354 hdr_size - sizeof (*hdr))) 355 { 356 GNUNET_break_op (0); 357 GNUNET_free (cstr); 358 GNUNET_free (xhdr); 359 return NULL; 360 } 361 *merge_priv = hdr->merge_priv; 362 GNUNET_free (xhdr); 363 ret = json_loadb ((char *) cstr, 364 clen, 365 JSON_DECODE_ANY, 366 &json_error); 367 if (NULL == ret) 368 { 369 GNUNET_break_op (0); 370 GNUNET_free (cstr); 371 return NULL; 372 } 373 GNUNET_free (cstr); 374 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 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 GNUNET_assert (GNUNET_OK == 404 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 405 &purse_pub->eddsa_pub, 406 &key)); 407 cstr = json_dumps (contract_terms, 408 JSON_COMPACT | JSON_SORT_KEYS); 409 GNUNET_assert (NULL != cstr); 410 clen = strlen (cstr); 411 cbuf_size = compressBound (clen); 412 xbuf = GNUNET_malloc (cbuf_size); 413 ret = compress (xbuf, 414 &cbuf_size, 415 (const Bytef *) cstr, 416 clen); 417 GNUNET_assert (Z_OK == ret); 418 free (cstr); 419 hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size); 420 hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST); 421 hdr->clen = htonl ((uint32_t) clen); 422 GNUNET_memcpy (&hdr[1], 423 xbuf, 424 cbuf_size); 425 GNUNET_free (xbuf); 426 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 427 &nonce, 428 sizeof (nonce)); 429 blob_encrypt (&nonce, 430 &key, 431 sizeof (key), 432 hdr, 433 sizeof (*hdr) + cbuf_size, 434 DEPOSIT_SALT, 435 &xecontract, 436 &xecontract_size); 437 GNUNET_free (hdr); 438 /* prepend purse_pub */ 439 *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub)); 440 GNUNET_memcpy (*econtract, 441 purse_pub, 442 sizeof (*purse_pub)); 443 GNUNET_memcpy (sizeof (*purse_pub) + *econtract, 444 xecontract, 445 xecontract_size); 446 *econtract_size = xecontract_size + sizeof (*purse_pub); 447 GNUNET_free (xecontract); 448 } 449 450 451 json_t * 452 TALER_CRYPTO_contract_decrypt_for_deposit ( 453 const struct TALER_ContractDiffiePrivateP *contract_priv, 454 const void *econtract, 455 size_t econtract_size) 456 { 457 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 if (econtract_size < sizeof (*purse_pub)) 468 { 469 GNUNET_break_op (0); 470 return NULL; 471 } 472 if (GNUNET_OK != 473 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 474 &purse_pub->eddsa_pub, 475 &key)) 476 { 477 GNUNET_break (0); 478 return NULL; 479 } 480 econtract += sizeof (*purse_pub); 481 econtract_size -= sizeof (*purse_pub); 482 if (GNUNET_OK != 483 blob_decrypt (&key, 484 sizeof (key), 485 econtract, 486 econtract_size, 487 DEPOSIT_SALT, 488 &xhdr, 489 &hdr_size)) 490 { 491 GNUNET_break_op (0); 492 return NULL; 493 } 494 if (hdr_size < sizeof (*hdr)) 495 { 496 GNUNET_break_op (0); 497 GNUNET_free (xhdr); 498 return NULL; 499 } 500 hdr = xhdr; 501 if (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST != ntohl (hdr->ctype)) 502 { 503 GNUNET_break_op (0); 504 GNUNET_free (xhdr); 505 return NULL; 506 } 507 clen = ntohl (hdr->clen); 508 if (clen >= GNUNET_MAX_MALLOC_CHECKED) 509 { 510 GNUNET_break_op (0); 511 GNUNET_free (xhdr); 512 return NULL; 513 } 514 cstr = GNUNET_malloc (clen + 1); 515 if (Z_OK != 516 uncompress ((Bytef *) cstr, 517 &clen, 518 (const Bytef *) &hdr[1], 519 hdr_size - sizeof (*hdr))) 520 { 521 GNUNET_break_op (0); 522 GNUNET_free (cstr); 523 GNUNET_free (xhdr); 524 return NULL; 525 } 526 GNUNET_free (xhdr); 527 ret = json_loadb ((char *) cstr, 528 clen, 529 JSON_DECODE_ANY, 530 &json_error); 531 if (NULL == ret) 532 { 533 GNUNET_break_op (0); 534 GNUNET_free (cstr); 535 return NULL; 536 } 537 GNUNET_free (cstr); 538 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 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 cstr = json_dumps (attr, 564 JSON_COMPACT | JSON_SORT_KEYS); 565 GNUNET_assert (NULL != cstr); 566 clen = strlen (cstr); 567 GNUNET_assert (clen <= UINT32_MAX); 568 cbuf_size = compressBound (clen); 569 xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t)); 570 belen = htonl ((uint32_t) clen); 571 GNUNET_memcpy (xbuf, 572 &belen, 573 sizeof (belen)); 574 ret = compress (xbuf + 4, 575 &cbuf_size, 576 (const Bytef *) cstr, 577 clen); 578 GNUNET_assert (Z_OK == ret); 579 free (cstr); 580 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 581 &nonce, 582 sizeof (nonce)); 583 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 GNUNET_free (xbuf); 592 } 593 594 595 json_t * 596 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 if (GNUNET_OK != 610 blob_decrypt (key, 611 sizeof (*key), 612 enc_attr, 613 enc_attr_size, 614 ATTRIBUTE_SALT, 615 &xhdr, 616 &hdr_size)) 617 { 618 GNUNET_break_op (0); 619 return NULL; 620 } 621 GNUNET_memcpy (&belen, 622 xhdr, 623 sizeof (belen)); 624 clen = ntohl (belen); 625 if (clen >= GNUNET_MAX_MALLOC_CHECKED) 626 { 627 GNUNET_break_op (0); 628 GNUNET_free (xhdr); 629 return NULL; 630 } 631 cstr = GNUNET_malloc (clen + 1); 632 if (Z_OK != 633 uncompress ((Bytef *) cstr, 634 &clen, 635 (const Bytef *) (xhdr + sizeof (uint32_t)), 636 hdr_size - sizeof (uint32_t))) 637 { 638 GNUNET_break_op (0); 639 GNUNET_free (cstr); 640 GNUNET_free (xhdr); 641 return NULL; 642 } 643 GNUNET_free (xhdr); 644 ret = json_loadb ((char *) cstr, 645 clen, 646 JSON_DECODE_ANY, 647 &json_error); 648 if (NULL == ret) 649 { 650 GNUNET_break_op (0); 651 GNUNET_free (cstr); 652 return NULL; 653 } 654 GNUNET_free (cstr); 655 return ret; 656 }