* Copyright 2005-2014 Colin Percival. All rights reserved.
* Copyright 2014 Sean Kelly. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <ByteOrder.h>
#include "pbkdf2.h"
static void
insecure_memzero_func(volatile void * buf, size_t len)
{
volatile uint8_t * _buf = (volatile uint8_t *)buf;
size_t i;
for (i = 0; i < len; i++)
_buf[i] = 0;
}
void (* volatile insecure_memzero_ptr)(volatile void *, size_t) =
insecure_memzero_func;
* HMAC_SHA256_Init(ctx, K, Klen):
* Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
* ${K}.
*/
void
HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
{
uint8_t pad[64];
uint8_t khash[32];
const uint8_t * K = (const uint8_t *)_K;
size_t i;
if (Klen > 64) {
ctx->ictx.Init();
ctx->ictx.Update(K, Klen);
memcpy(khash, ctx->ictx.Digest(), 32);
K = khash;
Klen = 32;
}
ctx->ictx.Init();
memset(pad, 0x36, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
ctx->ictx.Update(pad, 64);
ctx->octx.Init();
memset(pad, 0x5c, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
ctx->octx.Update(pad, 64);
insecure_memzero(khash, 32);
insecure_memzero(pad, 64);
}
* HMAC_SHA256_Update(ctx, in, len):
* Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
*/
void
HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len)
{
ctx->ictx.Update(in, len);
}
* HMAC_SHA256_Final(digest, ctx):
* Output the HMAC-SHA256 of the data input to the context ${ctx} into the
* buffer ${digest}.
*/
void
HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx)
{
uint8_t ihash[32];
memcpy(ihash, ctx->ictx.Digest(), 32);
ctx->octx.Update(ihash, 32);
memcpy(digest, ctx->octx.Digest(), 32);
insecure_memzero(ihash, 32);
}
* PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
* Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
* write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
*/
void
PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
{
HMAC_SHA256_CTX PShctx, hctx;
size_t i;
uint32_t ivec;
uint8_t U[32];
uint8_t T[32];
uint64_t j;
int k;
size_t clen;
assert(dkLen <= 32 * (size_t)(UINT32_MAX));
HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
HMAC_SHA256_Update(&PShctx, salt, saltlen);
for (i = 0; i * 32 < dkLen; i++) {
ivec = B_HOST_TO_BENDIAN_INT32((uint32_t)(i + 1));
memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
HMAC_SHA256_Update(&hctx, &ivec, 4);
HMAC_SHA256_Final(U, &hctx);
memcpy(T, U, 32);
for (j = 2; j <= c; j++) {
HMAC_SHA256_Init(&hctx, passwd, passwdlen);
HMAC_SHA256_Update(&hctx, U, 32);
HMAC_SHA256_Final(U, &hctx);
for (k = 0; k < 32; k++)
T[k] ^= U[k];
}
clen = dkLen - i * 32;
if (clen > 32)
clen = 32;
memcpy(&buf[i * 32], T, clen);
}
insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX));
}