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