deployd/server/blake2s.c
Arija A. 9c818c2aa5
Implement basic client flow
Signed-off-by: Arija A. <ari@ari.lt>
2025-07-24 17:50:47 +03:00

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;
}