totp algorithm

This commit is contained in:
priscilla 2023-03-02 09:54:54 -05:00
parent 468006c60b
commit b46c03b2c9
No known key found for this signature in database
GPG Key ID: B0926AF5C6A7515D
2 changed files with 279 additions and 3 deletions

View File

@ -591,7 +591,17 @@ enum TALER_MerchantConfirmationAlgorithm
/** /**
* No purchase confirmation. * No purchase confirmation.
*/ */
TALER_MCA_NONE = 0 TALER_MCA_NONE = 0,
/**
* Purchase confirmation without payment
*/
TALER_MCA_WITHOUT_PRICE = 1,
/**
* Purchase confirmation with payment
*/
TALER_MCA_WITH_PRICE = 2
}; };
@ -939,7 +949,13 @@ GNUNET_NETWORK_STRUCT_END
/** /**
* FIXME. * It is build pos confirmation to verify paiement.
*
* @param pos_key encoded key for verification payment
* @param pos_alg algorithm to compute the payment verification
* @param total of the order paid
* @parmam ts is the time given
*
*/ */
char * char *
TALER_build_pos_confirmation (const char *pos_key, TALER_build_pos_confirmation (const char *pos_key,

View File

@ -17,23 +17,283 @@
* @file util/crypto_confirmation.c * @file util/crypto_confirmation.c
* @brief confirmation computation * @brief confirmation computation
* @author Christian Grothoff * @author Christian Grothoff
* @author Priscilla Huang
*/ */
#include "platform.h" #include "platform.h"
#include "taler_util.h" #include "taler_util.h"
#include <taler/taler_mhd_lib.h>
#include <gnunet/gnunet_db_lib.h>
#include <gcrypt.h> #include <gcrypt.h>
/**
* How long is a TOTP code valid?
*/
#define TOTP_VALIDITY_PERIOD GNUNET_TIME_relative_multiply ( \
GNUNET_TIME_UNIT_SECONDS, 30)
/**
* Range of time we allow (plus-minus).
*/
#define TIME_INTERVAL_RANGE 2
/**
* Compute TOTP code at current time with offset
* @a time_off for the @a key.
*
* @param ts current time
* @param time_off offset to apply when computing the code
* @param key pos_key in binary
* @param key_size number of bytes in @a key
*/
static uint64_t
compute_totp (struct GNUNET_TIME_Timestamp ts,
int time_off,
const void *key,
size_t key_size)
{
struct GNUNET_TIME_Absolute now;
time_t t;
uint64_t ctr;
uint8_t hmac[20]; /* SHA1: 20 bytes */
now = ts.abs_time;
while (time_off < 0)
{
now = GNUNET_TIME_absolute_subtract (now,
TOTP_VALIDITY_PERIOD);
time_off++;
}
while (time_off > 0)
{
now = GNUNET_TIME_absolute_add (now,
TOTP_VALIDITY_PERIOD);
time_off--;
}
t = now.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
ctr = GNUNET_htonll (t / 30LLU);
{
gcry_md_hd_t md;
const unsigned char *mc;
GNUNET_assert (GPG_ERR_NO_ERROR ==
gcry_md_open (&md,
GCRY_MD_SHA1,
GCRY_MD_FLAG_HMAC));
gcry_md_setkey (md,
key,
key_size);
gcry_md_write (md,
&ctr,
sizeof (ctr));
mc = gcry_md_read (md,
GCRY_MD_SHA1);
GNUNET_assert (NULL != mc);
memcpy (hmac,
mc,
sizeof (hmac));
gcry_md_close (md);
}
{
uint32_t code = 0;
int offset;
offset = hmac[sizeof (hmac) - 1] & 0x0f;
for (int count = 0; count < 4; count++)
code |= hmac[offset + 3 - count] << (8 * count);
code &= 0x7fffffff;
/* always use 8 digits (maximum) */
code = code % 100000000;
return code;
}
}
/**
* Compute RFC 3548 base32 decoding of @a val and write
* result to @a udata.
*
* @param val value to decode
* @param val_size number of bytes in @a val
* @param key is the val in bits
* @param key_len is the size of @a key
*/
static int
base32decode (const char *val,
size_t val_size,
void *key,
size_t key_len)
{
/**
* 32 characters for decoding, using RFC 3548.
*/
static const char *decTable__ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
unsigned int wpos;
unsigned int rpos;
unsigned int bits;
unsigned int vbit;
unsigned char *udata;
udata = val;
vbit = 0;
wpos = 0;
rpos = 0;
bits = 0;
while ((rpos < val_size) || (vbit >= 8))
{
if ((rpos < val_size) && (vbit < 8))
{
char c = val[rpos++];
if (c == '=') { // padding character
break;
}
const char *p = strchr(decTable__, toupper(c));
if (! p)
{ // invalid character
return -1;
}
bits = (bits << 5) | (p - decTable__);
vbit += 5;
}
if (vbit >= 8)
{
udata[wpos++] = (bits >> (vbit - 8)) & 0xFF;
vbit -= 8;
}
}
return wpos;
}
/**
* It is build pos confirmation to verify payment.
*
* @param pos_key base32 (RFC 3548, not Crockford!) encoded key for verification payment
* @param pos_alg algorithm to compute the payment verification
* @param total of the order paid
* @param ts is the current time given
*/
char * char *
TALER_build_pos_confirmation (const char *pos_key, TALER_build_pos_confirmation (const char *pos_key,
enum TALER_MerchantConfirmationAlgorithm pos_alg, enum TALER_MerchantConfirmationAlgorithm pos_alg,
const struct TALER_Amount *total, const struct TALER_Amount *total,
struct GNUNET_TIME_Timestamp ts) struct GNUNET_TIME_Timestamp ts)
{ {
size_t pos_key_length = strlen (pos_key);
void *key; /* pos_key in binary */
size_t key_len; /* lengh of the key */
uint64_t code; /* totp code */
char *ret;
int dret;
if (TALER_MCA_NONE == pos_alg)
return NULL;
key_len = pos_key_length * 5 / 8;
key = GNUNET_malloc (key_len);
dret = base32decode (pos_key,
pos_key_length,
key,
key_len);
if (-1 == dret)
{
GNUNET_free (key);
GNUNET_break_op (0);
return NULL;
}
GNUNET_assert (dret <= key_len);
key_len = (size_t) dret;
switch (pos_alg) switch (pos_alg)
{ {
case TALER_MCA_NONE: case TALER_MCA_NONE:
return NULL; GNUNET_break (0);
} GNUNET_free (key);
GNUNET_break (0); // FIXME: not implemented return NULL;
case TALER_MCA_WITHOUT_PRICE: /* and 30s */
ret = NULL;
/* Return all T-OTP codes in range separated by new lines, e.g.
"12345678
24522552
25262425
42543525
25253552"
*/
for (int i = -TIME_INTERVAL_RANGE; i<= TIME_INTERVAL_RANGE; i++)
{
code = compute_totp (ts,
i,
key,
key_len);
if (NULL == ret)
{
GNUNET_asprintf (&ret,
"%llu",
(unsigned long long) code);
}
else
{
char *tmp;
GNUNET_asprintf (&tmp,
"%s\n%llu",
ret,
(unsigned long long) code);
GNUNET_free (ret);
ret = tmp;
}
}
GNUNET_free (key);
return ret;
case TALER_MCA_WITH_PRICE:
{
struct GNUNET_HashCode hkey;
struct TALER_AmountNBO ntotal;
ret = NULL;
TALER_amount_hton (&ntotal,
total);
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (&hkey,
sizeof (hkey),
&ntotal,
sizeof (ntotal),
key,
key_len,
NULL,
0));
GNUNET_free (key);
for (int i = -TIME_INTERVAL_RANGE; i<= TIME_INTERVAL_RANGE; i++)
{
code = compute_totp (ts,
i,
&hkey,
sizeof (hkey));
if (NULL == ret)
{
GNUNET_asprintf (&ret,
"%llu",
(unsigned long long) code);
}
else
{
char *tmp;
GNUNET_asprintf (&tmp,
"%s\n%llu",
ret,
(unsigned long long) code);
GNUNET_free (ret);
ret = tmp;
}
}
GNUNET_free (key);
return ret;
}
}
GNUNET_free (key);
GNUNET_break (0);
return NULL; return NULL;
} }