diff --git a/src/securid.c b/src/securid.c index f5685e1..05c22a5 100644 --- a/src/securid.c +++ b/src/securid.c @@ -20,6 +20,7 @@ #include "config.h" +#include #include #include #include @@ -32,6 +33,8 @@ #include #include +#include + #include "securid.h" #include "sdtid.h" @@ -219,6 +222,88 @@ static void sha256_pbkdf2(const uint8_t *pass, int pass_len, } } +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif +/* + * RFC 4758 D.2.2 + */ +static void ct_kip_prf_aes(const char *k, size_t klen, const char *s, + size_t slen, char *dst, size_t dstlen) +{ + const unsigned blen = AES_BLOCK_SIZE; + + size_t n, j, i; + + /* "2. ... Derived data too long" */ + assert(dstlen / blen <= UINT32_MAX); + + n = howmany(dstlen, blen); + j = dstlen % blen; + + for (i = 0; i < n; i++) { + size_t reslen; + uint32_t INT_i; + + if (i == n - 1 && j != 0) + reslen = j; + else + reslen = blen; + + INT_i = htonl(i + 1); + stc_omac1_aes(k, klen, &dst[i * blen], reslen, + &INT_i, 4, s, slen, NULL); + } +} + +/* + * RFC 4758 D.3. + */ +static void ct_kip_prf_sha256(const void *k, size_t klen, const char *s, + size_t slen, char *dst, size_t dstlen) +{ + const unsigned blen = SHA256_HASH_SIZE; + + void *out; + char tmp_hash[SHA256_HASH_SIZE], *maccontents; + size_t n, j, i; + + /* "2. ... Derived data too long" */ + assert(dstlen / blen <= UINT32_MAX); + + /* crappy workaround for missing iterative sha256_hmac */ + maccontents = malloc(slen + 4); + assert(maccontents != NULL); + memcpy(maccontents + 4, s, slen); + + n = howmany(dstlen, blen); + j = dstlen % blen; + + for (i = 0; i < n; i++) { + size_t reslen; + uint32_t INT_i; + + if (i == n - 1 && j != 0) { + out = tmp_hash; + reslen = j; + } else { + reslen = blen; + out = &dst[i * blen]; + } + + INT_i = htonl(i + 1); + memcpy(maccontents, &INT_i, 4); + sha256_hmac(k, klen, (void *)maccontents, slen + 4, out); + + if (out == tmp_hash) { + memcpy(&dst[i * blen], out, j); + explicit_bzero(tmp_hash, sizeof(tmp_hash)); + } + } + + free(maccontents); +} + /******************************************************************** * V1/V2 token handling ********************************************************************/ diff --git a/src/stc-tomcrypt.c b/src/stc-tomcrypt.c index 424c736..9f05508 100644 --- a/src/stc-tomcrypt.c +++ b/src/stc-tomcrypt.c @@ -121,6 +121,44 @@ void stc_aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len, rijndael_done(&skey); } +void stc_omac1_aes(const void *key, size_t klen, void *result, size_t reslen, + ...) +{ + unsigned long olen; + omac_state md; + int aes_idx; + va_list ap; + int rc; + + aes_idx = find_cipher("aes"); + if (aes_idx == -1) + aes_idx = find_cipher("rijndael"); + if (aes_idx == -1) + abort(); + + rc = omac_init(&md, aes_idx, key, klen); + assert(rc == CRYPT_OK); + + va_start(ap, reslen); + while (1) { + const void *nextin = va_arg(ap, const void *); + size_t inlen; + + if (nextin == NULL) + break; + inlen = va_arg(ap, size_t); + + rc = omac_process(&md, nextin, inlen); + assert(rc == CRYPT_OK); + } + va_end(ap); + + olen = reslen; + rc = omac_done(&md, result, &olen); + assert(rc == CRYPT_OK); + assert(olen == reslen); +} + void stc_sha1_hash(uint8_t *out, ...) { va_list ap; diff --git a/src/stoken-internal.h b/src/stoken-internal.h index f7a69c0..d95ae33 100644 --- a/src/stoken-internal.h +++ b/src/stoken-internal.h @@ -21,6 +21,7 @@ #ifndef __STOKEN_INTERNAL_H__ #define __STOKEN_INTERNAL_H__ +#include #include #include "stoken.h" @@ -101,6 +102,8 @@ void stc_aes256_cbc_decrypt(const uint8_t *key, const uint8_t *in, int in_len, const uint8_t *iv, uint8_t *out); void stc_aes256_cbc_encrypt(const uint8_t *key, const uint8_t *in, int in_len, const uint8_t *iv, uint8_t *out); +void stc_omac1_aes(const void *key, size_t klen, void *result, size_t reslen, + ...); void stc_sha1_hash(uint8_t *out, ...); void stc_sha256_hash(uint8_t *out, ...); int stc_b64_encode(const uint8_t *in, unsigned long len,