exchange

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

crypto_confirmation.c (7713B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2023 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_confirmation.c
     18  * @brief confirmation computation
     19  * @author Christian Grothoff
     20  * @author Priscilla Huang
     21  */
     22 #include "taler/platform.h"
     23 #include "taler/taler_util.h"
     24 #include "taler/taler_mhd_lib.h"
     25 #include <gnunet/gnunet_db_lib.h>
     26 #include <gcrypt.h>
     27 
     28 /**
     29  * How long is a TOTP code valid?
     30  */
     31 #define TOTP_VALIDITY_PERIOD GNUNET_TIME_relative_multiply ( \
     32           GNUNET_TIME_UNIT_SECONDS, 30)
     33 
     34 /**
     35  * Range of time we allow (plus-minus).
     36  */
     37 #define TIME_INTERVAL_RANGE 2
     38 
     39 
     40 /**
     41  * Compute TOTP code at current time with offset
     42  * @a time_off for the @a key.
     43  *
     44  * @param ts current time
     45  * @param time_off offset to apply when computing the code
     46  * @param key pos_key in binary
     47  * @param key_size number of bytes in @a key
     48  */
     49 static uint64_t
     50 compute_totp (struct GNUNET_TIME_Timestamp ts,
     51               int time_off,
     52               const void *key,
     53               size_t key_size)
     54 {
     55   struct GNUNET_TIME_Absolute now;
     56   time_t t;
     57   uint64_t ctr;
     58   uint8_t hmac[20]; /* SHA1: 20 bytes */
     59 
     60   now = ts.abs_time;
     61   while (time_off < 0)
     62   {
     63     now = GNUNET_TIME_absolute_subtract (now,
     64                                          TOTP_VALIDITY_PERIOD);
     65     time_off++;
     66   }
     67   while (time_off > 0)
     68   {
     69     now = GNUNET_TIME_absolute_add (now,
     70                                     TOTP_VALIDITY_PERIOD);
     71     time_off--;
     72   }
     73   t = now.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
     74   ctr = GNUNET_htonll (t / 30LLU);
     75 
     76   {
     77     gcry_md_hd_t md;
     78     const unsigned char *mc;
     79 
     80     GNUNET_assert (GPG_ERR_NO_ERROR ==
     81                    gcry_md_open (&md,
     82                                  GCRY_MD_SHA1,
     83                                  GCRY_MD_FLAG_HMAC));
     84     GNUNET_assert (GPG_ERR_NO_ERROR ==
     85                    gcry_md_setkey (md,
     86                                    key,
     87                                    key_size));
     88     gcry_md_write (md,
     89                    &ctr,
     90                    sizeof (ctr));
     91     mc = gcry_md_read (md,
     92                        GCRY_MD_SHA1);
     93     GNUNET_assert (NULL != mc);
     94     GNUNET_memcpy (hmac,
     95                    mc,
     96                    sizeof (hmac));
     97     gcry_md_close (md);
     98   }
     99 
    100   {
    101     uint32_t code = 0;
    102     int offset;
    103 
    104     offset = hmac[sizeof (hmac) - 1] & 0x0f;
    105     for (int count = 0; count < 4; count++)
    106       code |= ((uint32_t) hmac[offset + 3 - count]) << (8 * count);
    107     code &= 0x7fffffff;
    108     /* always use 8 digits (maximum) */
    109     code = code % 100000000;
    110     return code;
    111   }
    112 }
    113 
    114 
    115 int
    116 TALER_rfc3548_base32decode (const char *val,
    117                             size_t val_size,
    118                             void *key,
    119                             size_t key_len)
    120 {
    121   /**
    122    * 32 characters for decoding, using RFC 3548.
    123    */
    124   static const char *decTable__ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    125   unsigned char *udata = key;
    126   unsigned int wpos = 0;
    127   unsigned int rpos = 0;
    128   unsigned int bits = 0;
    129   unsigned int vbit = 0;
    130 
    131   while ((rpos < val_size) || (vbit >= 8))
    132   {
    133     if ((rpos < val_size) && (vbit < 8))
    134     {
    135       const char *p;
    136       char c = val[rpos++];
    137 
    138       if (c == '=')
    139       {
    140         /* padding character */
    141         if (rpos == val_size)
    142           break; /* Ok, 1x '=' padding is allowed */
    143         if ( ('=' == val[rpos]) &&
    144              (rpos + 1 == val_size) )
    145           break; /* Ok, 2x '=' padding is allowed */
    146         return -1; /* invalid padding */
    147       }
    148       p = strchr (decTable__, toupper (c));
    149       if (! p)
    150       {
    151         /* invalid character */
    152         return -1;
    153       }
    154       bits = (bits << 5) | (p - decTable__);
    155       vbit += 5;
    156     }
    157     if (vbit >= 8)
    158     {
    159       udata[wpos++] = (bits >> (vbit - 8)) & 0xFF;
    160       vbit -= 8;
    161     }
    162   }
    163   return wpos;
    164 }
    165 
    166 
    167 /**
    168  * @brief Builds POS confirmation to verify payment.
    169  *
    170  * @param h_key opaque key for the totp operation
    171  * @param h_key_len size of h_key in bytes
    172  * @param ts current time
    173  * @return Token on success, NULL of failure
    174  */
    175 static char *
    176 executive_totp (void *h_key,
    177                 size_t h_key_len,
    178                 struct GNUNET_TIME_Timestamp ts)
    179 {
    180   uint64_t code; /* totp code */
    181   char *ret;
    182   ret = NULL;
    183 
    184   for (int i = -TIME_INTERVAL_RANGE; i<= TIME_INTERVAL_RANGE; i++)
    185   {
    186     code = compute_totp (ts,
    187                          i,
    188                          h_key,
    189                          h_key_len);
    190     if (NULL == ret)
    191     {
    192       GNUNET_asprintf (&ret,
    193                        "%08llu",
    194                        (unsigned long long) code);
    195     }
    196     else
    197     {
    198       char *tmp;
    199 
    200       GNUNET_asprintf (&tmp,
    201                        "%s\n%08llu",
    202                        ret,
    203                        (unsigned long long) code);
    204       GNUNET_free (ret);
    205       ret = tmp;
    206     }
    207   }
    208   return ret;
    209 
    210 }
    211 
    212 
    213 char *
    214 TALER_build_pos_confirmation (const char *pos_key,
    215                               enum TALER_MerchantConfirmationAlgorithm pos_alg,
    216                               const struct TALER_Amount *total,
    217                               struct GNUNET_TIME_Timestamp ts)
    218 {
    219   size_t pos_key_length = strlen (pos_key);
    220   void *key; /* pos_key in binary */
    221   size_t key_len; /* length of the key */
    222   char *ret;
    223   int dret;
    224 
    225   if (TALER_MCA_NONE == pos_alg)
    226     return NULL;
    227   key_len = pos_key_length * 5 / 8;
    228   key = GNUNET_malloc (key_len);
    229   dret = TALER_rfc3548_base32decode (pos_key,
    230                                      pos_key_length,
    231                                      key,
    232                                      key_len);
    233   if (-1 == dret)
    234   {
    235     GNUNET_free (key);
    236     GNUNET_break_op (0);
    237     return NULL;
    238   }
    239   GNUNET_assert (dret <= key_len);
    240   key_len = (size_t) dret;
    241   switch (pos_alg)
    242   {
    243   case TALER_MCA_NONE:
    244     GNUNET_break (0);
    245     GNUNET_free (key);
    246     return NULL;
    247   case TALER_MCA_WITHOUT_PRICE: /* and 30s */
    248     /* Return all T-OTP codes in range separated by new lines, e.g.
    249        "12345678
    250         24522552
    251         25262425
    252         42543525
    253         25253552"
    254     */
    255     ret = executive_totp (key,
    256                           key_len,
    257                           ts);
    258     GNUNET_free (key);
    259     return ret;
    260   case TALER_MCA_WITH_PRICE:
    261     {
    262       struct GNUNET_HashCode hkey;
    263       struct TALER_AmountNBO ntotal;
    264 
    265       if ( (NULL == total) ||
    266            (GNUNET_YES !=
    267             TALER_amount_is_valid (total) ) )
    268       {
    269         GNUNET_break_op (0);
    270         return NULL;
    271       }
    272       TALER_amount_hton (&ntotal,
    273                          total);
    274       GNUNET_assert (GNUNET_YES ==
    275                      GNUNET_CRYPTO_kdf (&hkey,
    276                                         sizeof (hkey),
    277                                         &ntotal,
    278                                         sizeof (ntotal),
    279                                         key,
    280                                         key_len,
    281                                         NULL,
    282                                         0));
    283       GNUNET_free (key);
    284       ret = executive_totp (&hkey,
    285                             sizeof(hkey),
    286                             ts);
    287       GNUNET_free (key);
    288       return ret;
    289     }
    290   }
    291   GNUNET_free (key);
    292   GNUNET_break (0);
    293   return NULL;
    294 }