#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <ctype.h>
#include <stdio.h>
#include <syslog.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/des.h>
#include "token.h"
#include "tokendb.h"
typedef union {
DES_cblock cb;
char ct[9];
uint32_t ul[2];
} TOKEN_CBlock;
static TOKEN_CBlock tokennumber;
static void tokenseed(TOKEN_CBlock *);
static void lcase(char *);
static void h2d(char *);
static void h2cb(char *, TOKEN_CBlock *);
static void cb2h(TOKEN_CBlock, char *);
static void
tokenseed(TOKEN_CBlock *cb)
{
cb->ul[0] = arc4random();
cb->ul[1] = arc4random();
}
void
tokenchallenge(char *user, char *challenge, int size, char *card_type)
{
TOKENDB_Rec tr;
TOKEN_CBlock cb;
DES_key_schedule ks;
int r, c;
r = 1;
if ((tt->modes & TOKEN_RIM) &&
tokendb_getrec(user, &tr) == 0 &&
(tr.mode & TOKEN_RIM)) {
c = 0;
while ((r = tokendb_lockrec(user, &tr, TOKEN_LOCKED)) == 1) {
if (c++ >= 60)
break;
sleep(1);
}
tr.flags &= ~TOKEN_LOCKED;
if (r == 0 && tr.rim[0]) {
h2cb(tr.secret, &cb);
DES_fixup_key_parity(&cb.cb);
DES_key_sched(&cb.cb, &ks);
DES_ecb_encrypt(&tr.rim, &cb.cb, &ks, DES_ENCRYPT);
memcpy(tr.rim, cb.cb, 8);
for (r = 0; r < 8; ++r) {
if ((tr.rim[r] &= 0xf) > 9)
tr.rim[r] -= 10;
tr.rim[r] |= 0x30;
}
r = 0;
memcpy(tokennumber.ct, tr.rim, 8);
tokennumber.ct[8] = 0;
tokendb_putrec(user, &tr);
}
}
if (r != 0 || tr.rim[0] == '\0') {
memset(tokennumber.ct, 0, sizeof(tokennumber.ct));
snprintf(tokennumber.ct, sizeof(tokennumber.ct), "%8.8u",
arc4random());
if (r == 0) {
memcpy(tr.rim, tokennumber.ct, 8);
tokendb_putrec(user, &tr);
}
}
snprintf(challenge, size, "%s Challenge \"%s\"\r\n%s Response: ",
card_type, tokennumber.ct, card_type);
}
int
tokenverify(char *username, char *challenge, char *response)
{
char *state;
TOKENDB_Rec tokenrec;
TOKEN_CBlock tmp;
TOKEN_CBlock cmp_text;
TOKEN_CBlock user_seed;
TOKEN_CBlock cipher_text;
DES_key_schedule key_schedule;
memset(cmp_text.ct, 0, sizeof(cmp_text.ct));
memset(user_seed.ct, 0, sizeof(user_seed.ct));
memset(cipher_text.ct, 0, sizeof(cipher_text.ct));
memset(tokennumber.ct, 0, sizeof(tokennumber.ct));
(void)strtok(challenge, "\"");
state = strtok(NULL, "\"");
tmp.ul[0] = strtoul(state, NULL, 10);
snprintf(tokennumber.ct, sizeof(tokennumber.ct), "%8.8u",tmp.ul[0]);
if (tokendb_getrec(username, &tokenrec))
return (-1);
h2cb(tokenrec.secret, &user_seed);
explicit_bzero(&tokenrec.secret, sizeof(tokenrec.secret));
if (!(tokenrec.flags & TOKEN_ENABLED))
return (-1);
DES_fixup_key_parity(&user_seed.cb);
DES_key_sched(&user_seed.cb, &key_schedule);
explicit_bzero(user_seed.ct, sizeof(user_seed.ct));
DES_ecb_encrypt(&tokennumber.cb, &cipher_text.cb, &key_schedule,
DES_ENCRYPT);
explicit_bzero(&key_schedule, sizeof(key_schedule));
HTONL(cipher_text.ul[0]);
snprintf(cmp_text.ct, sizeof(cmp_text.ct), "%8.8x", cipher_text.ul[0]);
if (tokenrec.mode & TOKEN_PHONEMODE) {
lcase(response);
if (response[3] == '-')
cmp_text.ct[3] = '-';
}
if ((tokenrec.mode & TOKEN_HEXMODE) && !strcmp(response, cmp_text.ct))
return (0);
h2d(cmp_text.ct);
if ((tokenrec.mode & TOKEN_DECMODE) && !strcmp(response, cmp_text.ct))
return (0);
return (-1);
}
int
tokenuserinit(int flags, char *username, unsigned char *usecret, unsigned mode)
{
TOKENDB_Rec tokenrec;
TOKEN_CBlock secret;
TOKEN_CBlock nulls;
TOKEN_CBlock checksum;
TOKEN_CBlock checktxt;
DES_key_schedule key_schedule;
memset(&secret, 0, sizeof(secret));
if ( (flags & TOKEN_GENSECRET) )
tokenseed(&secret);
else
memcpy(&secret, usecret, sizeof(DES_cblock));
DES_fixup_key_parity(&secret.cb);
if (!(flags & TOKEN_FORCEINIT) &&
tokendb_getrec(username, &tokenrec) == 0)
return (1);
memset(&tokenrec, 0, sizeof(tokenrec));
strlcpy(tokenrec.uname, username, sizeof(tokenrec.uname));
cb2h(secret, tokenrec.secret);
tokenrec.mode = 0;
tokenrec.flags = TOKEN_ENABLED | TOKEN_USEMODES;
tokenrec.mode = mode;
memset(tokenrec.reserved_char1, 0, sizeof(tokenrec.reserved_char1));
memset(tokenrec.reserved_char2, 0, sizeof(tokenrec.reserved_char2));
if (tokendb_putrec(username, &tokenrec))
return (-1);
if (!(flags & TOKEN_GENSECRET)) {
explicit_bzero(&secret, sizeof(secret));
return (0);
}
printf("Shared secret for %s\'s token: "
"%03o %03o %03o %03o %03o %03o %03o %03o\n",
username, secret.cb[0], secret.cb[1], secret.cb[2], secret.cb[3],
secret.cb[4], secret.cb[5], secret.cb[6], secret.cb[7]);
DES_key_sched(&secret.cb, &key_schedule);
explicit_bzero(&secret, sizeof(secret));
memset(&nulls, 0, sizeof(nulls));
DES_ecb_encrypt(&nulls.cb, &checksum.cb, &key_schedule, DES_ENCRYPT);
explicit_bzero(&key_schedule, sizeof(key_schedule));
HTONL(checksum.ul[0]);
snprintf(checktxt.ct, sizeof(checktxt.ct), "%8.8x", checksum.ul[0]);
printf("Hex Checksum: \"%s\"", checktxt.ct);
h2d(checktxt.ct);
printf("\tDecimal Checksum: \"%s\"\n", checktxt.ct);
return (0);
}
static void
h2d(char *cp)
{
int i;
for (i=0; i<sizeof(DES_cblock); i++, cp++) {
if (*cp >= 'a' && *cp <= 'f')
*cp = tt->map[*cp - 'a'];
}
}
static void
h2cb(char *hp, TOKEN_CBlock *cb)
{
char scratch[9];
strlcpy(scratch, hp, sizeof(scratch));
cb->ul[0] = strtoul(scratch, NULL, 16);
strlcpy(scratch, hp + 8, sizeof(scratch));
cb->ul[1] = strtoul(scratch, NULL, 16);
}
static void
cb2h(TOKEN_CBlock cb, char* hp)
{
char scratch[17];
snprintf(scratch, 9, "%8.8x", cb.ul[0]);
snprintf(scratch+8, 9, "%8.8x", cb.ul[1]);
memcpy(hp, scratch, 16);
}
static void
lcase(char *cp)
{
while (*cp) {
if (isupper((unsigned char)*cp))
*cp = tolower((unsigned char)*cp);
cp++;
}
}