exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

crypto_contract.c (17258B)


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