crypto_contract.c (16734B)
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 (&nonce, 278 sizeof (nonce)); 279 blob_encrypt (&nonce, 280 &key, 281 sizeof (key), 282 hdr, 283 sizeof (*hdr) + cbuf_size, 284 MERGE_SALT, 285 econtract, 286 econtract_size); 287 GNUNET_free (hdr); 288 } 289 290 291 json_t * 292 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 if (GNUNET_OK != 309 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 310 &purse_pub->eddsa_pub, 311 &key)) 312 { 313 GNUNET_break (0); 314 return NULL; 315 } 316 if (GNUNET_OK != 317 blob_decrypt (&key, 318 sizeof (key), 319 econtract, 320 econtract_size, 321 MERGE_SALT, 322 &xhdr, 323 &hdr_size)) 324 { 325 GNUNET_break_op (0); 326 return NULL; 327 } 328 if (hdr_size < sizeof (*hdr)) 329 { 330 GNUNET_break_op (0); 331 GNUNET_free (xhdr); 332 return NULL; 333 } 334 hdr = xhdr; 335 if (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER != ntohl (hdr->header.ctype)) 336 { 337 GNUNET_break_op (0); 338 GNUNET_free (xhdr); 339 return NULL; 340 } 341 clen = ntohl (hdr->header.clen); 342 if (clen >= GNUNET_MAX_MALLOC_CHECKED) 343 { 344 GNUNET_break_op (0); 345 GNUNET_free (xhdr); 346 return NULL; 347 } 348 cstr = GNUNET_malloc (clen + 1); 349 if (Z_OK != 350 uncompress ((Bytef *) cstr, 351 &clen, 352 (const Bytef *) &hdr[1], 353 hdr_size - sizeof (*hdr))) 354 { 355 GNUNET_break_op (0); 356 GNUNET_free (cstr); 357 GNUNET_free (xhdr); 358 return NULL; 359 } 360 *merge_priv = hdr->merge_priv; 361 GNUNET_free (xhdr); 362 ret = json_loadb ((char *) cstr, 363 clen, 364 JSON_DECODE_ANY, 365 &json_error); 366 if (NULL == ret) 367 { 368 GNUNET_break_op (0); 369 GNUNET_free (cstr); 370 return NULL; 371 } 372 GNUNET_free (cstr); 373 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 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 GNUNET_assert (GNUNET_OK == 403 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 404 &purse_pub->eddsa_pub, 405 &key)); 406 cstr = json_dumps (contract_terms, 407 JSON_COMPACT | JSON_SORT_KEYS); 408 GNUNET_assert (NULL != cstr); 409 clen = strlen (cstr); 410 cbuf_size = compressBound (clen); 411 xbuf = GNUNET_malloc (cbuf_size); 412 ret = compress (xbuf, 413 &cbuf_size, 414 (const Bytef *) cstr, 415 clen); 416 GNUNET_assert (Z_OK == ret); 417 free (cstr); 418 hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size); 419 hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST); 420 hdr->clen = htonl ((uint32_t) clen); 421 GNUNET_memcpy (&hdr[1], 422 xbuf, 423 cbuf_size); 424 GNUNET_free (xbuf); 425 GNUNET_CRYPTO_random_block (&nonce, 426 sizeof (nonce)); 427 blob_encrypt (&nonce, 428 &key, 429 sizeof (key), 430 hdr, 431 sizeof (*hdr) + cbuf_size, 432 DEPOSIT_SALT, 433 &xecontract, 434 &xecontract_size); 435 GNUNET_free (hdr); 436 /* prepend purse_pub */ 437 *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub)); 438 GNUNET_memcpy (*econtract, 439 purse_pub, 440 sizeof (*purse_pub)); 441 GNUNET_memcpy (sizeof (*purse_pub) + *econtract, 442 xecontract, 443 xecontract_size); 444 *econtract_size = xecontract_size + sizeof (*purse_pub); 445 GNUNET_free (xecontract); 446 } 447 448 449 json_t * 450 TALER_CRYPTO_contract_decrypt_for_deposit ( 451 const struct TALER_ContractDiffiePrivateP *contract_priv, 452 const void *econtract, 453 size_t econtract_size) 454 { 455 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 if (econtract_size < sizeof (*purse_pub)) 466 { 467 GNUNET_break_op (0); 468 return NULL; 469 } 470 if (GNUNET_OK != 471 GNUNET_CRYPTO_ecdh_eddsa (&contract_priv->ecdhe_priv, 472 &purse_pub->eddsa_pub, 473 &key)) 474 { 475 GNUNET_break (0); 476 return NULL; 477 } 478 econtract += sizeof (*purse_pub); 479 econtract_size -= sizeof (*purse_pub); 480 if (GNUNET_OK != 481 blob_decrypt (&key, 482 sizeof (key), 483 econtract, 484 econtract_size, 485 DEPOSIT_SALT, 486 &xhdr, 487 &hdr_size)) 488 { 489 GNUNET_break_op (0); 490 return NULL; 491 } 492 if (hdr_size < sizeof (*hdr)) 493 { 494 GNUNET_break_op (0); 495 GNUNET_free (xhdr); 496 return NULL; 497 } 498 hdr = xhdr; 499 if (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST != ntohl (hdr->ctype)) 500 { 501 GNUNET_break_op (0); 502 GNUNET_free (xhdr); 503 return NULL; 504 } 505 clen = ntohl (hdr->clen); 506 if (clen >= GNUNET_MAX_MALLOC_CHECKED) 507 { 508 GNUNET_break_op (0); 509 GNUNET_free (xhdr); 510 return NULL; 511 } 512 cstr = GNUNET_malloc (clen + 1); 513 if (Z_OK != 514 uncompress ((Bytef *) cstr, 515 &clen, 516 (const Bytef *) &hdr[1], 517 hdr_size - sizeof (*hdr))) 518 { 519 GNUNET_break_op (0); 520 GNUNET_free (cstr); 521 GNUNET_free (xhdr); 522 return NULL; 523 } 524 GNUNET_free (xhdr); 525 ret = json_loadb ((char *) cstr, 526 clen, 527 JSON_DECODE_ANY, 528 &json_error); 529 if (NULL == ret) 530 { 531 GNUNET_break_op (0); 532 GNUNET_free (cstr); 533 return NULL; 534 } 535 GNUNET_free (cstr); 536 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 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 cstr = json_dumps (attr, 562 JSON_COMPACT | JSON_SORT_KEYS); 563 GNUNET_assert (NULL != cstr); 564 clen = strlen (cstr); 565 GNUNET_assert (clen <= UINT32_MAX); 566 cbuf_size = compressBound (clen); 567 xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t)); 568 belen = htonl ((uint32_t) clen); 569 GNUNET_memcpy (xbuf, 570 &belen, 571 sizeof (belen)); 572 ret = compress (xbuf + 4, 573 &cbuf_size, 574 (const Bytef *) cstr, 575 clen); 576 GNUNET_assert (Z_OK == ret); 577 free (cstr); 578 GNUNET_CRYPTO_random_block (&nonce, 579 sizeof (nonce)); 580 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 GNUNET_free (xbuf); 589 } 590 591 592 json_t * 593 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 if (GNUNET_OK != 607 blob_decrypt (key, 608 sizeof (*key), 609 enc_attr, 610 enc_attr_size, 611 ATTRIBUTE_SALT, 612 &xhdr, 613 &hdr_size)) 614 { 615 GNUNET_break_op (0); 616 return NULL; 617 } 618 GNUNET_memcpy (&belen, 619 xhdr, 620 sizeof (belen)); 621 clen = ntohl (belen); 622 if (clen >= GNUNET_MAX_MALLOC_CHECKED) 623 { 624 GNUNET_break_op (0); 625 GNUNET_free (xhdr); 626 return NULL; 627 } 628 cstr = GNUNET_malloc (clen + 1); 629 if (Z_OK != 630 uncompress ((Bytef *) cstr, 631 &clen, 632 (const Bytef *) (xhdr + sizeof (uint32_t)), 633 hdr_size - sizeof (uint32_t))) 634 { 635 GNUNET_break_op (0); 636 GNUNET_free (cstr); 637 GNUNET_free (xhdr); 638 return NULL; 639 } 640 GNUNET_free (xhdr); 641 ret = json_loadb ((char *) cstr, 642 clen, 643 JSON_DECODE_ANY, 644 &json_error); 645 if (NULL == ret) 646 { 647 GNUNET_break_op (0); 648 GNUNET_free (cstr); 649 return NULL; 650 } 651 GNUNET_free (cstr); 652 return ret; 653 }