291 lines
9.2 KiB
C
291 lines
9.2 KiB
C
#include "include/conf.h"
|
|
|
|
#include <string.h>
|
|
#include <sys/random.h>
|
|
|
|
#include "include/def.h"
|
|
#include "include/blake2s.h"
|
|
|
|
#define DP_BLAKE2S_ROTR32(arg, rot) \
|
|
((((uint32_t)(arg)) >> ((uint32_t)(rot))) ^ \
|
|
(((uint32_t)(arg)) << (uint32_t)(((uint32_t)32) - ((uint32_t)(rot)))))
|
|
|
|
static const uint32_t dp_blake2s_iv[DP_BLAKE2S_STATE_SIZE] = {
|
|
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
|
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
|
|
|
|
static const uint8_t dp_blake2s_sigma[160] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 14, 10,
|
|
4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, 11, 8, 12, 0,
|
|
5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, 7, 9, 3, 1, 13, 12,
|
|
11, 14, 2, 6, 5, 10, 4, 0, 15, 8, 9, 0, 5, 7, 2, 4, 10, 15,
|
|
14, 1, 11, 12, 6, 8, 3, 13, 2, 12, 6, 10, 0, 11, 8, 3, 4, 13,
|
|
7, 5, 15, 14, 1, 9, 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3,
|
|
9, 2, 8, 11, 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6,
|
|
2, 10, 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
|
|
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0};
|
|
|
|
static const uint8_t dp_blake2s_hex_digits[] = "0123456789abcdef";
|
|
|
|
static void dp_Blake2sCtx_mix(dp_Blake2sCtx *ctx,
|
|
uint8_t v_a,
|
|
uint8_t v_b,
|
|
uint8_t v_c,
|
|
uint8_t v_d,
|
|
uint8_t sigma_x,
|
|
uint8_t sigma_y) {
|
|
ctx->work[v_a] = ctx->work[v_a] + ctx->work[v_b] +
|
|
ctx->message[dp_blake2s_sigma[sigma_x]];
|
|
ctx->work[v_d] = DP_BLAKE2S_ROTR32(ctx->work[v_d] ^ ctx->work[v_a], 16);
|
|
ctx->work[v_c] = ctx->work[v_c] + ctx->work[v_d];
|
|
ctx->work[v_b] = DP_BLAKE2S_ROTR32(ctx->work[v_b] ^ ctx->work[v_c], 12);
|
|
ctx->work[v_a] = ctx->work[v_a] + ctx->work[v_b] +
|
|
ctx->message[dp_blake2s_sigma[sigma_y]];
|
|
ctx->work[v_d] = DP_BLAKE2S_ROTR32(ctx->work[v_d] ^ ctx->work[v_a], 8);
|
|
ctx->work[v_c] = ctx->work[v_c] + ctx->work[v_d];
|
|
ctx->work[v_b] = DP_BLAKE2S_ROTR32(ctx->work[v_b] ^ ctx->work[v_c], 7);
|
|
}
|
|
|
|
static void dp_Blake2sCtx_compress(dp_Blake2sCtx *ctx, bool is_last) {
|
|
uint8_t idx = 0;
|
|
|
|
for (idx = 0; idx < 8; ++idx) {
|
|
ctx->work[idx] = ctx->state[idx];
|
|
ctx->work[idx + 8] = dp_blake2s_iv[idx];
|
|
}
|
|
|
|
ctx->work[12] ^= (uint32_t)(ctx->inputs & (uint32_t)0xFFFFFFFF);
|
|
ctx->work[13] ^= (uint32_t)(ctx->inputs >> (uint32_t)32);
|
|
|
|
/* last block flag */
|
|
|
|
if (is_last) {
|
|
ctx->work[14] = ~ctx->work[14];
|
|
}
|
|
|
|
for (idx = 0; idx < 16; ++idx) {
|
|
const uint8_t pdx = idx * 4;
|
|
|
|
ctx->message[idx] = (uint32_t)ctx->input[pdx] ^
|
|
((uint32_t)ctx->input[pdx + 1] << (uint32_t)8) ^
|
|
((uint32_t)ctx->input[pdx + 2] << (uint32_t)16) ^
|
|
((uint32_t)ctx->input[pdx + 3] << (uint32_t)24);
|
|
}
|
|
|
|
/* 10 rounds of mixing */
|
|
|
|
for (idx = 0; idx < 10; ++idx) {
|
|
/* clang-format off */
|
|
dp_Blake2sCtx_mix(ctx, 0, 4, 8, 12, (uint8_t)((idx * 16) + 0), (uint8_t)((idx * 16) + 1));
|
|
dp_Blake2sCtx_mix(ctx, 1, 5, 9, 13, (uint8_t)((idx * 16) + 2), (uint8_t)((idx * 16) + 3));
|
|
dp_Blake2sCtx_mix(ctx, 2, 6, 10, 14, (uint8_t)((idx * 16) + 4), (uint8_t)((idx * 16) + 5));
|
|
dp_Blake2sCtx_mix(ctx, 3, 7, 11, 15, (uint8_t)((idx * 16) + 6), (uint8_t)((idx * 16) + 7));
|
|
dp_Blake2sCtx_mix(ctx, 0, 5, 10, 15, (uint8_t)((idx * 16) + 8), (uint8_t)((idx * 16) + 9));
|
|
dp_Blake2sCtx_mix(ctx, 1, 6, 11, 12, (uint8_t)((idx * 16) + 10), (uint8_t)((idx * 16) + 11));
|
|
dp_Blake2sCtx_mix(ctx, 2, 7, 8, 13, (uint8_t)((idx * 16) + 12), (uint8_t)((idx * 16) + 13));
|
|
dp_Blake2sCtx_mix(ctx, 3, 4, 9, 14, (uint8_t)((idx * 16) + 14), (uint8_t)((idx * 16) + 15));
|
|
/* clang-format on */
|
|
}
|
|
|
|
/* finalize the compression */
|
|
|
|
for (idx = 0; idx < 8; ++idx) {
|
|
ctx->state[idx] ^= ctx->work[idx] ^ ctx->work[idx + 8];
|
|
}
|
|
}
|
|
|
|
bool dp_Blake2sCtx_init(dp_Blake2sCtx *ctx,
|
|
uint8_t outlen,
|
|
const void *key,
|
|
uint8_t keylen) {
|
|
uint8_t idx = 0;
|
|
|
|
if (!ctx || (key && (keylen < 1 || keylen > 32))) {
|
|
return false;
|
|
}
|
|
|
|
for (idx = 0; idx < DP_BLAKE2S_STATE_SIZE; ++idx) {
|
|
ctx->state[idx] = dp_blake2s_iv[idx];
|
|
}
|
|
|
|
for (idx = 0; idx < DP_BLAKE2S_INPUT_SIZE; ++idx) {
|
|
ctx->input[idx] = 0;
|
|
}
|
|
|
|
for (idx = 0; idx < 16; ++idx) {
|
|
ctx->work[idx] = ctx->message[idx] = 0;
|
|
}
|
|
|
|
ctx->idx = 0;
|
|
ctx->inputs = 0;
|
|
ctx->outlen = outlen;
|
|
|
|
ctx->state[0] ^= (uint32_t)0x01010000 ^ ((uint32_t)keylen << (uint32_t)8) ^
|
|
(uint32_t)outlen;
|
|
|
|
if (key && keylen != 0) {
|
|
dp_Blake2sCtx_update(ctx, key, keylen);
|
|
ctx->idx = DP_BLAKE2S_INPUT_SIZE;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool dp_Blake2sCtx_update(dp_Blake2sCtx *ctx,
|
|
const void *data,
|
|
size_t datalen) {
|
|
if (!ctx || !data || datalen == 0) {
|
|
return false;
|
|
}
|
|
|
|
const uint8_t *input = (const uint8_t *)data;
|
|
|
|
/* Fill the current partially filled block, if any */
|
|
if (ctx->idx > 0) {
|
|
const uint8_t fill = DP_BLAKE2S_INPUT_SIZE - ctx->idx;
|
|
|
|
if (datalen < fill) {
|
|
memcpy(ctx->input + ctx->idx, input, datalen);
|
|
ctx->idx += (uint8_t)datalen;
|
|
return true;
|
|
}
|
|
|
|
memcpy(ctx->input + ctx->idx, input, fill);
|
|
ctx->inputs += DP_BLAKE2S_INPUT_SIZE;
|
|
dp_Blake2sCtx_compress(ctx, false);
|
|
ctx->idx = 0;
|
|
input += fill;
|
|
datalen -= fill;
|
|
}
|
|
|
|
/* Process as many full blocks as possible directly from input */
|
|
while (datalen >= DP_BLAKE2S_INPUT_SIZE) {
|
|
memcpy(ctx->input, input, DP_BLAKE2S_INPUT_SIZE);
|
|
ctx->inputs += DP_BLAKE2S_INPUT_SIZE;
|
|
dp_Blake2sCtx_compress(ctx, false);
|
|
input += DP_BLAKE2S_INPUT_SIZE;
|
|
datalen -= DP_BLAKE2S_INPUT_SIZE;
|
|
}
|
|
|
|
/* Copy remaining bytes to buffer for next call or finalization */
|
|
if (datalen > 0) {
|
|
memcpy(ctx->input, input, datalen);
|
|
ctx->idx = (uint8_t)datalen;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool dp_Blake2sCtx_final(dp_Blake2sCtx *ctx) {
|
|
if (!ctx) {
|
|
return false;
|
|
}
|
|
|
|
ctx->inputs += ctx->idx;
|
|
|
|
while (ctx->idx < 64) {
|
|
ctx->input[ctx->idx++] = 0;
|
|
}
|
|
|
|
dp_Blake2sCtx_compress(ctx, true);
|
|
|
|
for (uint8_t idx = 0; idx < ctx->outlen; ++idx) {
|
|
ctx->digest[idx] = (ctx->state[idx >> (uint8_t)2] >>
|
|
((uint32_t)(8 * (idx & (uint8_t)3))) &
|
|
(uint32_t)0xff);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool dp_Blake2sCtx_to_hex(dp_Blake2sCtx *ctx, void *out) {
|
|
if (!ctx || !out) {
|
|
return false;
|
|
}
|
|
|
|
size_t idx = 0;
|
|
uint8_t *data = (uint8_t *)out;
|
|
|
|
for (idx = 0; idx < ctx->outlen; ++idx) {
|
|
data[(idx * 2) + 0] =
|
|
dp_blake2s_hex_digits[ctx->digest[idx] >> (uint8_t)0x4];
|
|
data[(idx * 2) + 1] =
|
|
dp_blake2s_hex_digits[ctx->digest[idx] & (uint8_t)0xf];
|
|
}
|
|
|
|
data[idx * 2] = '\0';
|
|
|
|
return true;
|
|
}
|
|
|
|
bool dp_Blake2sCtx_to_digest(dp_Blake2sCtx *ctx, void *out) {
|
|
if (!ctx || !out) {
|
|
return false;
|
|
}
|
|
memcpy(out, ctx->digest, ctx->outlen);
|
|
return true;
|
|
}
|
|
|
|
bool dp_BLAKE2s_hash_password(const void *password,
|
|
size_t password_size,
|
|
uint8_t digest[DP_BLAKE2S_OUTPUT_SIZE_MAX],
|
|
const uint8_t salt[DP_BLAKE2S_SALT_SIZE]) {
|
|
if (!password || password_size == 0 || !digest || !salt) {
|
|
return false;
|
|
}
|
|
|
|
dp_Blake2sCtx ctx = {0};
|
|
|
|
if (!dp_Blake2sCtx_init(&ctx, DP_BLAKE2S_OUTPUT_SIZE_MAX, NULL, 0)) {
|
|
return false;
|
|
}
|
|
if (!dp_Blake2sCtx_update(&ctx, salt, DP_BLAKE2S_SALT_SIZE)) {
|
|
return false;
|
|
}
|
|
if (!dp_Blake2sCtx_update(&ctx, password, password_size)) {
|
|
return false;
|
|
}
|
|
if (!dp_Blake2sCtx_final(&ctx)) {
|
|
return false;
|
|
}
|
|
if (!dp_Blake2sCtx_to_digest(&ctx, digest)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool dp_BLAKE2s_hash_password_gen(const void *password,
|
|
size_t password_size,
|
|
uint8_t digest[DP_BLAKE2S_OUTPUT_SIZE_MAX],
|
|
uint8_t salt[DP_BLAKE2S_SALT_SIZE]) {
|
|
|
|
if (!password || password_size == 0 || !digest || !salt) {
|
|
return false;
|
|
}
|
|
|
|
if (getrandom(salt, DP_BLAKE2S_SALT_SIZE, 0) != DP_BLAKE2S_SALT_SIZE) {
|
|
return false;
|
|
}
|
|
|
|
return dp_BLAKE2s_hash_password(password, password_size, digest, salt);
|
|
}
|
|
|
|
bool dp_BLAKE2s_check_password_hash(
|
|
const void *password,
|
|
size_t password_size,
|
|
const uint8_t digest[DP_BLAKE2S_OUTPUT_SIZE_MAX],
|
|
const uint8_t salt[DP_BLAKE2S_SALT_SIZE]) {
|
|
|
|
if (!password || password_size == 0 || !digest || !salt) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t new_digest[DP_BLAKE2S_OUTPUT_SIZE_MAX] = {0};
|
|
|
|
if (!dp_BLAKE2s_hash_password(password, password_size, new_digest, salt)) {
|
|
return false;
|
|
}
|
|
|
|
return memcmp(new_digest, digest, DP_BLAKE2S_OUTPUT_SIZE_MAX) == 0;
|
|
}
|