|
|
|
/*
|
|
|
|
* scdtools - Tools for Scdaemon and OpenPGP smartcards
|
|
|
|
#define DEFAULT_PRIVATE_DO 1
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert a time value (in seconds) into a moving factor for the
|
|
|
|
* TOTP algorithm as per RFC 6238.
|
|
|
|
*
|
|
|
|
* @param time Elapsed seconds since Unix epoch.
|
|
|
|
* @param step Time step parameter.
|
|
|
|
* @param buffer Byte buffer to store the formatted factor. Must be
|
|
|
|
* at least 8 bytes long.
|
|
|
|
* @param len Size of the output buffer.
|
|
|
|
*
|
|
|
|
* @return The number of bytes written to the buffer (always 8).
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
time2factor(time_t time, int step, unsigned char *buffer, size_t len)
|
|
|
|
{
|
|
|
|
unsigned n_steps;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
n_steps = time / step;
|
|
|
|
|
|
|
|
for ( i = 0, j = 7; i < 8; i++, j-- )
|
|
|
|
buffer[i] = (n_steps & (uint64_t)(0xFF << (j * 8))) >> (j * 8);
|
|
|
|
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert a hexstring into a bytes array.
|
|
|
|
*
|
|
|
|
* @param hexstring The string to convert.
|
|
|
|
* @param buffer The output buffer.
|
|
|
|
* @param len Size of the output buffer.
|
|
|
|
*
|
|
|
|
* @return The number of bytes written to the output buffer, or
|
|
|
|
* -1 if the buffer is not large enough.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
hexstring2bytes(const char *hexstring, unsigned char *buffer, size_t len)
|
|
|
|
{
|
|
|
|
int high_nibble, n;
|
|
|
|
unsigned val;
|
|
|
|
|
|
|
|
high_nibble = 1;
|
|
|
|
n = 0;
|
|
|
|
|
|
|
|
while ( *hexstring && n < len ) {
|
|
|
|
switch ( *hexstring ) {
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
val = *hexstring - '0';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
case 'b':
|
|
|
|
case 'c':
|
|
|
|
case 'd':
|
|
|
|
case 'e':
|
|
|
|
case 'f':
|
|
|
|
val = *hexstring - 'a' + 10;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'A':
|
|
|
|
case 'B':
|
|
|
|
case 'C':
|
|
|
|
case 'D':
|
|
|
|
case 'E':
|
|
|
|
case 'F':
|
|
|
|
val = *hexstring - 'A' + 10;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
hexstring += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( high_nibble ) {
|
|
|
|
buffer[n] = val << 4;
|
|
|
|
high_nibble = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
buffer[n] |= (val & 0xF);
|
|
|
|
high_nibble = 1;
|
|
|
|
n += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
hexstring += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( *hexstring )
|
|
|
|
return -1; /* Buffer too small. */
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate a time-based one-time password as per RFC 6238.
|
|
|
|
*
|
|
|
|
* @param otp Pointer to an unsigned integer to store the
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct key_data_t {
|
|
|
|
unsigned char *buffer;
|
|
|
|
size_t len;
|
|
|
|
int found;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback for the below function.
|
|
|
|
*/
|
|
|
|
static gpg_error_t
|
|
|
|
get_otp_key_cb(void *arg, const char *line)
|
|
|
|
{
|
|
|
|
struct key_data_t *key = (struct key_data_t *)arg;
|
|
|
|
|
|
|
|
return gcry_error(GPG_ERR_INV_ARG);
|
|
|
|
|
|
|
|
{ "step", 1, NULL, 's' },
|
|
|
|
{ "digits", 1, NULL, 'd' },
|
|
|
|
break;
|