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 (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 }