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 (16981B)


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