blob: fce6a22f269c6459903ba80a2ccb8b2e21c9b93f [file] [log] [blame]
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "pbkdf2.h"
#include "hmac.h"
#include "bitops.h"
#include "handy.h"
#include "tassert.h"
#include <string.h>
static void F(const cf_hmac_ctx *startctx,
uint32_t counter,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out)
{
uint8_t U[CF_MAXHASH];
size_t hashsz = startctx->hash->hashsz;
uint8_t countbuf[4];
write32_be(counter, countbuf);
/* First iteration:
* U_1 = PRF(P, S || INT_32_BE(i))
*/
cf_hmac_ctx ctx = *startctx;
cf_hmac_update(&ctx, salt, nsalt);
cf_hmac_update(&ctx, countbuf, sizeof countbuf);
cf_hmac_finish(&ctx, U);
memcpy(out, U, hashsz);
/* Subsequent iterations:
* U_c = PRF(P, U_{c-1})
*/
for (uint32_t i = 1; i < iterations; i++)
{
ctx = *startctx;
cf_hmac_update(&ctx, U, hashsz);
cf_hmac_finish(&ctx, U);
xor_bb(out, out, U, hashsz);
}
}
void cf_pbkdf2_hmac(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout,
const cf_chash *hash)
{
uint32_t counter = 1;
uint8_t block[CF_MAXHASH];
assert(iterations);
assert(out && nout);
assert(hash);
/* Starting point for inner loop. */
cf_hmac_ctx ctx;
cf_hmac_init(&ctx, hash, pw, npw);
while (nout)
{
F(&ctx, counter, salt, nsalt, iterations, block);
size_t taken = MIN(nout, hash->hashsz);
memcpy(out, block, taken);
out += taken;
nout -= taken;
counter++;
}
}