LCOV - code coverage report
Current view: top level - util - crypto_confirmation.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 95 0
Test Date: 2026-01-04 22:17:00 Functions: 0.0 % 4 0

            Line data    Source code
       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            0 : 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            0 :   now = ts.abs_time;
      61            0 :   while (time_off < 0)
      62              :   {
      63            0 :     now = GNUNET_TIME_absolute_subtract (now,
      64              :                                          TOTP_VALIDITY_PERIOD);
      65            0 :     time_off++;
      66              :   }
      67            0 :   while (time_off > 0)
      68              :   {
      69            0 :     now = GNUNET_TIME_absolute_add (now,
      70              :                                     TOTP_VALIDITY_PERIOD);
      71            0 :     time_off--;
      72              :   }
      73            0 :   t = now.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
      74            0 :   ctr = GNUNET_htonll (t / 30LLU);
      75              : 
      76              :   {
      77              :     gcry_md_hd_t md;
      78              :     const unsigned char *mc;
      79              : 
      80            0 :     GNUNET_assert (GPG_ERR_NO_ERROR ==
      81              :                    gcry_md_open (&md,
      82              :                                  GCRY_MD_SHA1,
      83              :                                  GCRY_MD_FLAG_HMAC));
      84            0 :     GNUNET_assert (GPG_ERR_NO_ERROR ==
      85              :                    gcry_md_setkey (md,
      86              :                                    key,
      87              :                                    key_size));
      88            0 :     gcry_md_write (md,
      89              :                    &ctr,
      90              :                    sizeof (ctr));
      91            0 :     mc = gcry_md_read (md,
      92              :                        GCRY_MD_SHA1);
      93            0 :     GNUNET_assert (NULL != mc);
      94            0 :     GNUNET_memcpy (hmac,
      95              :                    mc,
      96              :                    sizeof (hmac));
      97            0 :     gcry_md_close (md);
      98              :   }
      99              : 
     100              :   {
     101            0 :     uint32_t code = 0;
     102              :     int offset;
     103              : 
     104            0 :     offset = hmac[sizeof (hmac) - 1] & 0x0f;
     105            0 :     for (int count = 0; count < 4; count++)
     106            0 :       code |= ((uint32_t) hmac[offset + 3 - count]) << (8 * count);
     107            0 :     code &= 0x7fffffff;
     108              :     /* always use 8 digits (maximum) */
     109            0 :     code = code % 100000000;
     110            0 :     return code;
     111              :   }
     112              : }
     113              : 
     114              : 
     115              : int
     116            0 : 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            0 :   unsigned char *udata = key;
     126            0 :   unsigned int wpos = 0;
     127            0 :   unsigned int rpos = 0;
     128            0 :   unsigned int bits = 0;
     129            0 :   unsigned int vbit = 0;
     130              : 
     131            0 :   while ((rpos < val_size) || (vbit >= 8))
     132              :   {
     133            0 :     if ((rpos < val_size) && (vbit < 8))
     134              :     {
     135              :       const char *p;
     136            0 :       char c = val[rpos++];
     137              : 
     138            0 :       if (c == '=')
     139              :       {
     140              :         /* padding character */
     141            0 :         if (rpos == val_size)
     142            0 :           break; /* Ok, 1x '=' padding is allowed */
     143            0 :         if ( ('=' == val[rpos]) &&
     144            0 :              (rpos + 1 == val_size) )
     145            0 :           break; /* Ok, 2x '=' padding is allowed */
     146            0 :         return -1; /* invalid padding */
     147              :       }
     148            0 :       p = strchr (decTable__, toupper (c));
     149            0 :       if (! p)
     150              :       {
     151              :         /* invalid character */
     152            0 :         return -1;
     153              :       }
     154            0 :       bits = (bits << 5) | (p - decTable__);
     155            0 :       vbit += 5;
     156              :     }
     157            0 :     if (vbit >= 8)
     158              :     {
     159            0 :       udata[wpos++] = (bits >> (vbit - 8)) & 0xFF;
     160            0 :       vbit -= 8;
     161              :     }
     162              :   }
     163            0 :   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            0 : 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            0 :   ret = NULL;
     183              : 
     184            0 :   for (int i = -TIME_INTERVAL_RANGE; i<= TIME_INTERVAL_RANGE; i++)
     185              :   {
     186            0 :     code = compute_totp (ts,
     187              :                          i,
     188              :                          h_key,
     189              :                          h_key_len);
     190            0 :     if (NULL == ret)
     191              :     {
     192            0 :       GNUNET_asprintf (&ret,
     193              :                        "%08llu",
     194              :                        (unsigned long long) code);
     195              :     }
     196              :     else
     197              :     {
     198              :       char *tmp;
     199              : 
     200            0 :       GNUNET_asprintf (&tmp,
     201              :                        "%s\n%08llu",
     202              :                        ret,
     203              :                        (unsigned long long) code);
     204            0 :       GNUNET_free (ret);
     205            0 :       ret = tmp;
     206              :     }
     207              :   }
     208            0 :   return ret;
     209              : 
     210              : }
     211              : 
     212              : 
     213              : char *
     214            0 : 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            0 :   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            0 :   if (TALER_MCA_NONE == pos_alg)
     226            0 :     return NULL;
     227            0 :   key_len = pos_key_length * 5 / 8;
     228            0 :   key = GNUNET_malloc (key_len);
     229            0 :   dret = TALER_rfc3548_base32decode (pos_key,
     230              :                                      pos_key_length,
     231              :                                      key,
     232              :                                      key_len);
     233            0 :   if (-1 == dret)
     234              :   {
     235            0 :     GNUNET_free (key);
     236            0 :     GNUNET_break_op (0);
     237            0 :     return NULL;
     238              :   }
     239            0 :   GNUNET_assert (dret <= key_len);
     240            0 :   key_len = (size_t) dret;
     241            0 :   switch (pos_alg)
     242              :   {
     243            0 :   case TALER_MCA_NONE:
     244            0 :     GNUNET_break (0);
     245            0 :     GNUNET_free (key);
     246            0 :     return NULL;
     247            0 :   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            0 :     ret = executive_totp (key,
     256              :                           key_len,
     257              :                           ts);
     258            0 :     GNUNET_free (key);
     259            0 :     return ret;
     260            0 :   case TALER_MCA_WITH_PRICE:
     261              :     {
     262              :       struct GNUNET_HashCode hkey;
     263              :       struct TALER_AmountNBO ntotal;
     264              : 
     265            0 :       if ( (NULL == total) ||
     266              :            (GNUNET_YES !=
     267            0 :             TALER_amount_is_valid (total) ) )
     268              :       {
     269            0 :         GNUNET_break_op (0);
     270            0 :         return NULL;
     271              :       }
     272            0 :       TALER_amount_hton (&ntotal,
     273              :                          total);
     274            0 :       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            0 :       GNUNET_free (key);
     284            0 :       ret = executive_totp (&hkey,
     285              :                             sizeof(hkey),
     286              :                             ts);
     287            0 :       GNUNET_free (key);
     288            0 :       return ret;
     289              :     }
     290              :   }
     291            0 :   GNUNET_free (key);
     292            0 :   GNUNET_break (0);
     293            0 :   return NULL;
     294              : }
        

Generated by: LCOV version 2.0-1