LCOV - code coverage report
Current view: top level - util - crypto_contract.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 61 154 39.6 %
Date: 2022-08-25 06:15:09 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14