LCOV - code coverage report
Current view: top level - util - crypto_confirmation.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 95 0.0 %
Date: 2025-06-05 21:03:14 Functions: 0 4 0.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 "platform.h"
      23             : #include "taler_util.h"
      24             : #include "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 1.16