core: add support for lots of different hash algorithms

This commit is contained in:
2025-04-11 13:51:48 +01:00
parent c630321bf6
commit ed4942c500
12 changed files with 1899 additions and 20 deletions

View File

@@ -1,18 +0,0 @@
#include <blue/core/hash.h>
#include <stddef.h>
#include <stdint.h>
#define FNV1_OFFSET_BASIS 0xcbf29ce484222325
#define FNV1_PRIME 0x100000001b3
uint64_t b_hash_string(const char *s)
{
uint64_t hash = FNV1_OFFSET_BASIS;
for (size_t i = 0; s[i]; i++) {
hash ^= s[i];
hash *= FNV1_PRIME;
}
return hash;
}

139
core/hash/hash.c Normal file
View File

@@ -0,0 +1,139 @@
#include "hash.h"
#include <blue/core/hash.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define FNV1_OFFSET_BASIS 0xcbf29ce484222325
#define FNV1_PRIME 0x100000001b3
extern struct b_hash_function_ops z__b_md4_ops;
extern struct b_hash_function_ops z__b_md5_ops;
extern struct b_hash_function_ops z__b_sha1_ops;
extern struct b_hash_function_ops z__b_sha2_224_ops;
extern struct b_hash_function_ops z__b_sha2_256_ops;
extern struct b_hash_function_ops z__b_sha2_384_ops;
extern struct b_hash_function_ops z__b_sha2_512_ops;
extern struct b_hash_function_ops z__b_sha3_224_ops;
extern struct b_hash_function_ops z__b_sha3_256_ops;
extern struct b_hash_function_ops z__b_sha3_384_ops;
extern struct b_hash_function_ops z__b_sha3_512_ops;
extern struct b_hash_function_ops z__b_shake128_ops;
extern struct b_hash_function_ops z__b_shake256_ops;
static const struct b_hash_function_ops *hash_functions[] = {
[B_HASH_NONE] = NULL,
[B_HASH_MD4] = &z__b_md4_ops,
[B_HASH_MD5] = &z__b_md5_ops,
[B_HASH_SHA1] = &z__b_sha1_ops,
[B_HASH_SHA2_224] = &z__b_sha2_224_ops,
[B_HASH_SHA2_256] = &z__b_sha2_256_ops,
[B_HASH_SHA2_384] = &z__b_sha2_384_ops,
[B_HASH_SHA2_512] = &z__b_sha2_512_ops,
[B_HASH_SHA3_224] = &z__b_sha3_224_ops,
[B_HASH_SHA3_256] = &z__b_sha3_256_ops,
[B_HASH_SHA3_384] = &z__b_sha3_384_ops,
[B_HASH_SHA3_512] = &z__b_sha3_512_ops,
[B_HASH_SHAKE128] = &z__b_shake128_ops,
[B_HASH_SHAKE256] = &z__b_shake256_ops,
};
static const size_t nr_hash_functions
= sizeof hash_functions / sizeof hash_functions[0];
uint64_t b_hash_string(const char *s)
{
size_t x = 0;
return b_hash_string_ex(s, &x);
}
uint64_t b_hash_string_ex(const char *s, size_t *len)
{
uint64_t hash = FNV1_OFFSET_BASIS;
size_t i = 0;
for (i = 0; s[i]; i++) {
hash ^= s[i];
hash *= FNV1_PRIME;
}
if (len) {
*len = i;
}
return hash;
}
enum b_status b_hash_ctx_init(struct b_hash_ctx *ctx, enum b_hash_function func)
{
if (func < 0 || func >= nr_hash_functions) {
return B_ERR_NOT_SUPPORTED;
}
const struct b_hash_function_ops *hash_function = hash_functions[func];
if (!hash_function) {
return B_ERR_NOT_SUPPORTED;
}
memset(ctx, 0x0, sizeof *ctx);
ctx->ctx_func = func;
ctx->ctx_ops = hash_function;
if (hash_function->hash_init) {
hash_function->hash_init(ctx);
}
return B_SUCCESS;
}
enum b_status b_hash_ctx_reset(struct b_hash_ctx *ctx)
{
if (ctx->ctx_func == B_HASH_NONE || !ctx->ctx_ops) {
return B_ERR_BAD_STATE;
}
memset(&ctx->ctx_state, 0x0, sizeof ctx->ctx_state);
if (ctx->ctx_ops->hash_init) {
ctx->ctx_ops->hash_init(ctx);
}
return B_SUCCESS;
}
enum b_status b_hash_ctx_update(struct b_hash_ctx *ctx, const void *p, size_t len)
{
if (!ctx->ctx_ops) {
return B_ERR_BAD_STATE;
}
if (!ctx->ctx_ops->hash_update) {
return B_ERR_NOT_SUPPORTED;
}
ctx->ctx_ops->hash_update(ctx, p, len);
return B_SUCCESS;
}
enum b_status b_hash_ctx_finish(
struct b_hash_ctx *ctx, void *out_digest, size_t out_max)
{
if (!ctx->ctx_ops) {
return B_ERR_BAD_STATE;
}
if (!ctx->ctx_ops->hash_finish) {
return B_ERR_NOT_SUPPORTED;
}
ctx->ctx_ops->hash_finish(ctx, out_digest, out_max);
memset(&ctx->ctx_state, 0x0, sizeof ctx->ctx_state);
if (ctx->ctx_ops->hash_init) {
ctx->ctx_ops->hash_init(ctx);
}
return B_SUCCESS;
}

14
core/hash/hash.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _HASH_H_
#define _HASH_H_
#include <stddef.h>
struct b_hash_ctx;
struct b_hash_function_ops {
void (*hash_init)(struct b_hash_ctx *);
void (*hash_update)(struct b_hash_ctx *, const void *, size_t);
void (*hash_finish)(struct b_hash_ctx *, void *, size_t);
};
#endif

270
core/hash/md4.c Normal file
View File

@@ -0,0 +1,270 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD4 Message-Digest Algorithm (RFC 1320).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#include "hash.h"
#include <blue/core/hash.h>
#include <stdint.h>
#include <string.h>
/*
* The basic MD4 functions.
*
* F and G are optimized compared to their RFC 1320 definitions, with the
* optimization for F borrowed from Colin Plumb's MD5 implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/*
* The MD4 transformation for all three rounds.
*/
#define STEP(f, a, b, c, d, x, s) \
(a) += f((b), (c), (d)) + (x); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));
/*
* SET reads 4 input bytes in little-endian byte order and stores them in a
* properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned memory
* accesses is just an optimization. Nothing will break if it fails to detect
* a suitable architecture.
*
* Unfortunately, this optimization may be a C strict aliasing rules violation
* if the caller's data buffer has effective type that cannot be aliased by
* uint32_t. In practice, this problem may occur if these MD4 routines are
* inlined into a calling function, or with future and dangerously advanced
* link-time optimizations. For the time being, keeping these MD4 routines in
* their own translation unit avoids the problem.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) (*(uint32_t *)&ptr[(n) * 4])
#define GET(n) SET(n)
#else
#define SET(n) \
(ctx->ctx_state.md4.block[(n)] = (uint32_t)ptr[(n) * 4] \
| ((uint32_t)ptr[(n) * 4 + 1] << 8) \
| ((uint32_t)ptr[(n) * 4 + 2] << 16) \
| ((uint32_t)ptr[(n) * 4 + 3] << 24))
#define GET(n) (ctx->ctx_state.md4.block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update the bit
* counters. There are no alignment requirements.
*/
static const void *body(struct b_hash_ctx *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
uint32_t a, b, c, d;
uint32_t saved_a, saved_b, saved_c, saved_d;
const uint32_t ac1 = 0x5a827999, ac2 = 0x6ed9eba1;
ptr = (const unsigned char *)data;
a = ctx->ctx_state.md4.a;
b = ctx->ctx_state.md4.b;
c = ctx->ctx_state.md4.c;
d = ctx->ctx_state.md4.d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 3)
STEP(F, d, a, b, c, SET(1), 7)
STEP(F, c, d, a, b, SET(2), 11)
STEP(F, b, c, d, a, SET(3), 19)
STEP(F, a, b, c, d, SET(4), 3)
STEP(F, d, a, b, c, SET(5), 7)
STEP(F, c, d, a, b, SET(6), 11)
STEP(F, b, c, d, a, SET(7), 19)
STEP(F, a, b, c, d, SET(8), 3)
STEP(F, d, a, b, c, SET(9), 7)
STEP(F, c, d, a, b, SET(10), 11)
STEP(F, b, c, d, a, SET(11), 19)
STEP(F, a, b, c, d, SET(12), 3)
STEP(F, d, a, b, c, SET(13), 7)
STEP(F, c, d, a, b, SET(14), 11)
STEP(F, b, c, d, a, SET(15), 19)
/* Round 2 */
STEP(G, a, b, c, d, GET(0) + ac1, 3)
STEP(G, d, a, b, c, GET(4) + ac1, 5)
STEP(G, c, d, a, b, GET(8) + ac1, 9)
STEP(G, b, c, d, a, GET(12) + ac1, 13)
STEP(G, a, b, c, d, GET(1) + ac1, 3)
STEP(G, d, a, b, c, GET(5) + ac1, 5)
STEP(G, c, d, a, b, GET(9) + ac1, 9)
STEP(G, b, c, d, a, GET(13) + ac1, 13)
STEP(G, a, b, c, d, GET(2) + ac1, 3)
STEP(G, d, a, b, c, GET(6) + ac1, 5)
STEP(G, c, d, a, b, GET(10) + ac1, 9)
STEP(G, b, c, d, a, GET(14) + ac1, 13)
STEP(G, a, b, c, d, GET(3) + ac1, 3)
STEP(G, d, a, b, c, GET(7) + ac1, 5)
STEP(G, c, d, a, b, GET(11) + ac1, 9)
STEP(G, b, c, d, a, GET(15) + ac1, 13)
/* Round 3 */
STEP(H, a, b, c, d, GET(0) + ac2, 3)
STEP(H, d, a, b, c, GET(8) + ac2, 9)
STEP(H, c, d, a, b, GET(4) + ac2, 11)
STEP(H, b, c, d, a, GET(12) + ac2, 15)
STEP(H, a, b, c, d, GET(2) + ac2, 3)
STEP(H, d, a, b, c, GET(10) + ac2, 9)
STEP(H, c, d, a, b, GET(6) + ac2, 11)
STEP(H, b, c, d, a, GET(14) + ac2, 15)
STEP(H, a, b, c, d, GET(1) + ac2, 3)
STEP(H, d, a, b, c, GET(9) + ac2, 9)
STEP(H, c, d, a, b, GET(5) + ac2, 11)
STEP(H, b, c, d, a, GET(13) + ac2, 15)
STEP(H, a, b, c, d, GET(3) + ac2, 3)
STEP(H, d, a, b, c, GET(11) + ac2, 9)
STEP(H, c, d, a, b, GET(7) + ac2, 11)
STEP(H, b, c, d, a, GET(15) + ac2, 15)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->ctx_state.md4.a = a;
ctx->ctx_state.md4.b = b;
ctx->ctx_state.md4.c = c;
ctx->ctx_state.md4.d = d;
return ptr;
}
void md4_init(struct b_hash_ctx *ctx)
{
ctx->ctx_state.md4.a = 0x67452301;
ctx->ctx_state.md4.b = 0xefcdab89;
ctx->ctx_state.md4.c = 0x98badcfe;
ctx->ctx_state.md4.d = 0x10325476;
ctx->ctx_state.md4.lo = 0;
ctx->ctx_state.md4.hi = 0;
}
void md4_update(struct b_hash_ctx *ctx, const void *data, unsigned long size)
{
uint32_t saved_lo;
unsigned long used, available;
saved_lo = ctx->ctx_state.md4.lo;
if ((ctx->ctx_state.md4.lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->ctx_state.md4.hi++;
ctx->ctx_state.md4.hi += size >> 29;
used = saved_lo & 0x3f;
if (used) {
available = 64 - used;
if (size < available) {
memcpy(&ctx->ctx_state.md4.buffer[used], data, size);
return;
}
memcpy(&ctx->ctx_state.md4.buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
body(ctx, ctx->ctx_state.md4.buffer, 64);
}
if (size >= 64) {
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
memcpy(ctx->ctx_state.md4.buffer, data, size);
}
#define OUT(dst, src) \
(dst)[0] = (unsigned char)(src); \
(dst)[1] = (unsigned char)((src) >> 8); \
(dst)[2] = (unsigned char)((src) >> 16); \
(dst)[3] = (unsigned char)((src) >> 24);
void md4_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char *result = out;
unsigned long used, available;
used = ctx->ctx_state.md4.lo & 0x3f;
ctx->ctx_state.md4.buffer[used++] = 0x80;
available = 64 - used;
if (available < 8) {
memset(&ctx->ctx_state.md4.buffer[used], 0, available);
body(ctx, ctx->ctx_state.md4.buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->ctx_state.md4.buffer[used], 0, available - 8);
ctx->ctx_state.md4.lo <<= 3;
OUT(&ctx->ctx_state.md4.buffer[56], ctx->ctx_state.md4.lo)
OUT(&ctx->ctx_state.md4.buffer[60], ctx->ctx_state.md4.hi)
body(ctx, ctx->ctx_state.md4.buffer, 64);
OUT(&result[0], ctx->ctx_state.md4.a)
OUT(&result[4], ctx->ctx_state.md4.b)
OUT(&result[8], ctx->ctx_state.md4.c)
OUT(&result[12], ctx->ctx_state.md4.d)
memset(ctx, 0, sizeof(*ctx));
}
struct b_hash_function_ops z__b_md4_ops = {
.hash_init = md4_init,
.hash_update = md4_update,
.hash_finish = md4_finish,
};

238
core/hash/md5.c Normal file
View File

@@ -0,0 +1,238 @@
/* This implementation was sourced from
* https://github.com/galenguyer/md5
* and is in the public domain. */
#include "hash.h"
#include <blue/core/hash.h>
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define F(x, y, z) (z ^ (x & (y ^ z)))
#define G(x, y, z) (y ^ (z & (x ^ y)))
#define H(x, y, z) (x ^ y ^ z)
#define I(x, y, z) (y ^ (x | ~z))
#define ROTATE_LEFT(x, s) (x << s | x >> (32 - s))
#define STEP(f, a, b, c, d, x, t, s) \
(a += f(b, c, d) + x + t, a = ROTATE_LEFT(a, s), a += b)
void md5_init(struct b_hash_ctx *ctx)
{
ctx->ctx_state.md5.a = 0x67452301;
ctx->ctx_state.md5.b = 0xefcdab89;
ctx->ctx_state.md5.c = 0x98badcfe;
ctx->ctx_state.md5.d = 0x10325476;
ctx->ctx_state.md5.count[0] = 0;
ctx->ctx_state.md5.count[1] = 0;
}
uint8_t *md5_transform(struct b_hash_ctx *ctx, const void *data, uintmax_t size)
{
uint8_t *ptr = (uint8_t *)data;
uint32_t a, b, c, d, aa, bb, cc, dd;
#define GET(n) (ctx->ctx_state.md5.block[(n)])
#define SET(n) \
(ctx->ctx_state.md5.block[(n)] = ((uint32_t)ptr[(n) * 4 + 0] << 0) \
| ((uint32_t)ptr[(n) * 4 + 1] << 8) \
| ((uint32_t)ptr[(n) * 4 + 2] << 16) \
| ((uint32_t)ptr[(n) * 4 + 3] << 24))
a = ctx->ctx_state.md5.a;
b = ctx->ctx_state.md5.b;
c = ctx->ctx_state.md5.c;
d = ctx->ctx_state.md5.d;
do {
aa = a;
bb = b;
cc = c;
dd = d;
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7);
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12);
STEP(F, c, d, a, b, SET(2), 0x242070db, 17);
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22);
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7);
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12);
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17);
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22);
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7);
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12);
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17);
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22);
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7);
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12);
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17);
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22);
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5);
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9);
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14);
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20);
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5);
STEP(G, d, a, b, c, GET(10), 0x02441453, 9);
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14);
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20);
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5);
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9);
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14);
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20);
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5);
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9);
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14);
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20);
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4);
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11);
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16);
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23);
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4);
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11);
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16);
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23);
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4);
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11);
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16);
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23);
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4);
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11);
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16);
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23);
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6);
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10);
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15);
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21);
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6);
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10);
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15);
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21);
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6);
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10);
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15);
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21);
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6);
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10);
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15);
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21);
a += aa;
b += bb;
c += cc;
d += dd;
ptr += 64;
} while (size -= 64);
ctx->ctx_state.md5.a = a;
ctx->ctx_state.md5.b = b;
ctx->ctx_state.md5.c = c;
ctx->ctx_state.md5.d = d;
#undef GET
#undef SET
return ptr;
}
void md5_update(struct b_hash_ctx *ctx, const void *buffer, size_t buffer_size)
{
uint32_t saved_low = ctx->ctx_state.md5.count[0];
uint32_t used;
uint32_t free;
if ((ctx->ctx_state.md5.count[0] = ((saved_low + buffer_size) & 0x1fffffff))
< saved_low) {
ctx->ctx_state.md5.count[1]++;
}
ctx->ctx_state.md5.count[1] += (uint32_t)(buffer_size >> 29);
used = saved_low & 0x3f;
if (used) {
free = 64 - used;
if (buffer_size < free) {
memcpy(&ctx->ctx_state.md5.input[used], buffer,
buffer_size);
return;
}
memcpy(&ctx->ctx_state.md5.input[used], buffer, free);
buffer = (uint8_t *)buffer + free;
buffer_size -= free;
md5_transform(ctx, ctx->ctx_state.md5.input, 64);
}
if (buffer_size >= 64) {
buffer = md5_transform(
ctx, buffer, buffer_size & ~(unsigned long)0x3f);
buffer_size = buffer_size % 64;
}
memcpy(ctx->ctx_state.md5.input, buffer, buffer_size);
}
void md5_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
uint32_t used = ctx->ctx_state.md5.count[0] & 0x3f;
ctx->ctx_state.md5.input[used++] = 0x80;
uint32_t free = 64 - used;
if (free < 8) {
memset(&ctx->ctx_state.md5.input[used], 0, free);
md5_transform(ctx, ctx->ctx_state.md5.input, 64);
used = 0;
free = 64;
}
memset(&ctx->ctx_state.md5.input[used], 0, free - 8);
unsigned char digest[B_DIGEST_LENGTH_MD5];
ctx->ctx_state.md5.count[0] <<= 3;
ctx->ctx_state.md5.input[56] = (uint8_t)(ctx->ctx_state.md5.count[0]);
ctx->ctx_state.md5.input[57] = (uint8_t)(ctx->ctx_state.md5.count[0] >> 8);
ctx->ctx_state.md5.input[58]
= (uint8_t)(ctx->ctx_state.md5.count[0] >> 16);
ctx->ctx_state.md5.input[59]
= (uint8_t)(ctx->ctx_state.md5.count[0] >> 24);
ctx->ctx_state.md5.input[60] = (uint8_t)(ctx->ctx_state.md5.count[1]);
ctx->ctx_state.md5.input[61] = (uint8_t)(ctx->ctx_state.md5.count[1] >> 8);
ctx->ctx_state.md5.input[62]
= (uint8_t)(ctx->ctx_state.md5.count[1] >> 16);
ctx->ctx_state.md5.input[63]
= (uint8_t)(ctx->ctx_state.md5.count[1] >> 24);
md5_transform(ctx, ctx->ctx_state.md5.input, 64);
digest[0] = (uint8_t)(ctx->ctx_state.md5.a);
digest[1] = (uint8_t)(ctx->ctx_state.md5.a >> 8);
digest[2] = (uint8_t)(ctx->ctx_state.md5.a >> 16);
digest[3] = (uint8_t)(ctx->ctx_state.md5.a >> 24);
digest[4] = (uint8_t)(ctx->ctx_state.md5.b);
digest[5] = (uint8_t)(ctx->ctx_state.md5.b >> 8);
digest[6] = (uint8_t)(ctx->ctx_state.md5.b >> 16);
digest[7] = (uint8_t)(ctx->ctx_state.md5.b >> 24);
digest[8] = (uint8_t)(ctx->ctx_state.md5.c);
digest[9] = (uint8_t)(ctx->ctx_state.md5.c >> 8);
digest[10] = (uint8_t)(ctx->ctx_state.md5.c >> 16);
digest[11] = (uint8_t)(ctx->ctx_state.md5.c >> 24);
digest[12] = (uint8_t)(ctx->ctx_state.md5.d);
digest[13] = (uint8_t)(ctx->ctx_state.md5.d >> 8);
digest[14] = (uint8_t)(ctx->ctx_state.md5.d >> 16);
digest[15] = (uint8_t)(ctx->ctx_state.md5.d >> 24);
memcpy(out, digest, b_min(size_t, sizeof digest, max));
}
struct b_hash_function_ops z__b_md5_ops = {
.hash_init = md5_init,
.hash_update = md5_update,
.hash_finish = md5_finish,
};

268
core/hash/sha1.c Normal file
View File

@@ -0,0 +1,268 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
#include "hash.h"
#include <blue/core/hash.h>
#include <stdio.h>
#include <string.h>
/* for uint32_t */
#include <stdint.h>
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if defined(LITTLE_ENDIAN)
#define blk0(i) \
(block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \
| (rol(block->l[i], 8) & 0x00FF00FF))
#elif defined(BIG_ENDIAN)
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) \
(block->l[i & 15] \
= rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R1(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R2(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
w = rol(w, 30);
#define R3(v, w, x, y, z, i) \
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);
#define R4(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
w = rol(w, 30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
{
uint32_t a, b, c, d, e;
typedef union {
unsigned char c[64];
uint32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
* And the result is written through. I threw a "const" in, hoping
* this will cause a diagnostic.
*/
CHAR64LONG16 *block = (const CHAR64LONG16 *)buffer;
#endif
/* Copy context->ctx_state.sha1.state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a, b, c, d, e, 0);
R0(e, a, b, c, d, 1);
R0(d, e, a, b, c, 2);
R0(c, d, e, a, b, 3);
R0(b, c, d, e, a, 4);
R0(a, b, c, d, e, 5);
R0(e, a, b, c, d, 6);
R0(d, e, a, b, c, 7);
R0(c, d, e, a, b, 8);
R0(b, c, d, e, a, 9);
R0(a, b, c, d, e, 10);
R0(e, a, b, c, d, 11);
R0(d, e, a, b, c, 12);
R0(c, d, e, a, b, 13);
R0(b, c, d, e, a, 14);
R0(a, b, c, d, e, 15);
R1(e, a, b, c, d, 16);
R1(d, e, a, b, c, 17);
R1(c, d, e, a, b, 18);
R1(b, c, d, e, a, 19);
R2(a, b, c, d, e, 20);
R2(e, a, b, c, d, 21);
R2(d, e, a, b, c, 22);
R2(c, d, e, a, b, 23);
R2(b, c, d, e, a, 24);
R2(a, b, c, d, e, 25);
R2(e, a, b, c, d, 26);
R2(d, e, a, b, c, 27);
R2(c, d, e, a, b, 28);
R2(b, c, d, e, a, 29);
R2(a, b, c, d, e, 30);
R2(e, a, b, c, d, 31);
R2(d, e, a, b, c, 32);
R2(c, d, e, a, b, 33);
R2(b, c, d, e, a, 34);
R2(a, b, c, d, e, 35);
R2(e, a, b, c, d, 36);
R2(d, e, a, b, c, 37);
R2(c, d, e, a, b, 38);
R2(b, c, d, e, a, 39);
R3(a, b, c, d, e, 40);
R3(e, a, b, c, d, 41);
R3(d, e, a, b, c, 42);
R3(c, d, e, a, b, 43);
R3(b, c, d, e, a, 44);
R3(a, b, c, d, e, 45);
R3(e, a, b, c, d, 46);
R3(d, e, a, b, c, 47);
R3(c, d, e, a, b, 48);
R3(b, c, d, e, a, 49);
R3(a, b, c, d, e, 50);
R3(e, a, b, c, d, 51);
R3(d, e, a, b, c, 52);
R3(c, d, e, a, b, 53);
R3(b, c, d, e, a, 54);
R3(a, b, c, d, e, 55);
R3(e, a, b, c, d, 56);
R3(d, e, a, b, c, 57);
R3(c, d, e, a, b, 58);
R3(b, c, d, e, a, 59);
R4(a, b, c, d, e, 60);
R4(e, a, b, c, d, 61);
R4(d, e, a, b, c, 62);
R4(c, d, e, a, b, 63);
R4(b, c, d, e, a, 64);
R4(a, b, c, d, e, 65);
R4(e, a, b, c, d, 66);
R4(d, e, a, b, c, 67);
R4(c, d, e, a, b, 68);
R4(b, c, d, e, a, 69);
R4(a, b, c, d, e, 70);
R4(e, a, b, c, d, 71);
R4(d, e, a, b, c, 72);
R4(c, d, e, a, b, 73);
R4(b, c, d, e, a, 74);
R4(a, b, c, d, e, 75);
R4(e, a, b, c, d, 76);
R4(d, e, a, b, c, 77);
R4(c, d, e, a, b, 78);
R4(b, c, d, e, a, 79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
memset(block, '\0', sizeof(block));
#endif
}
/* sha_init - Initialize new context */
static void sha_init(struct b_hash_ctx *context)
{
/* SHA1 initialization constants */
context->ctx_state.sha1.state[0] = 0x67452301;
context->ctx_state.sha1.state[1] = 0xEFCDAB89;
context->ctx_state.sha1.state[2] = 0x98BADCFE;
context->ctx_state.sha1.state[3] = 0x10325476;
context->ctx_state.sha1.state[4] = 0xC3D2E1F0;
context->ctx_state.sha1.count[0] = context->ctx_state.sha1.count[1] = 0;
}
/* Run your data through this. */
static void sha_update(struct b_hash_ctx *context, const void *p, size_t len)
{
const unsigned char *data = p;
uint32_t i, j;
j = context->ctx_state.sha1.count[0];
if ((context->ctx_state.sha1.count[0] += len << 3) < j)
context->ctx_state.sha1.count[1]++;
context->ctx_state.sha1.count[1] += (len >> 29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->ctx_state.sha1.buffer[j], data, (i = 64 - j));
SHA1Transform(
context->ctx_state.sha1.state,
context->ctx_state.sha1.buffer);
for (; i + 63 < len; i += 64) {
SHA1Transform(context->ctx_state.sha1.state, &data[i]);
}
j = 0;
} else
i = 0;
memcpy(&context->ctx_state.sha1.buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
static void sha_finish(struct b_hash_ctx *context, void *out, size_t max)
{
unsigned i;
unsigned char finalcount[8] = {0};
unsigned char c;
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->ctx_state.sha1
.count[(i >= 4 ? 0 : 1)]
>> ((3 - (i & 3)) * 8))
& 255); /* Endian independent */
}
char digest[B_DIGEST_LENGTH_SHA1];
c = 0200;
sha_update(context, &c, 1);
while ((context->ctx_state.sha1.count[0] & 504) != 448) {
c = 0000;
sha_update(context, &c, 1);
}
sha_update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)((context->ctx_state.sha1.state[i >> 2]
>> ((3 - (i & 3)) * 8))
& 255);
}
memcpy(out, digest, b_min(size_t, sizeof digest, max));
/* Wipe variables */
memset(context, '\0', sizeof(*context));
memset(&finalcount, '\0', sizeof(finalcount));
}
struct b_hash_function_ops z__b_sha1_ops = {
.hash_init = sha_init,
.hash_update = sha_update,
.hash_finish = sha_finish,
};

42
core/hash/sha2_224.c Normal file
View File

@@ -0,0 +1,42 @@
// SHA-224. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <blue/core/hash.h>
#include <string.h>
extern void z__b_sha2_256_update(
struct b_hash_ctx *md, const void *src, size_t inlen);
extern void z__b_sha2_256_finish(struct b_hash_ctx *md, void *out, size_t max);
static void sha_init(struct b_hash_ctx *md)
{
md->ctx_state.sha2_256.curlen = 0;
md->ctx_state.sha2_256.length = 0;
md->ctx_state.sha2_256.state[0] = 0xc1059ed8UL;
md->ctx_state.sha2_256.state[1] = 0x367cd507UL;
md->ctx_state.sha2_256.state[2] = 0x3070dd17UL;
md->ctx_state.sha2_256.state[3] = 0xf70e5939UL;
md->ctx_state.sha2_256.state[4] = 0xffc00b31UL;
md->ctx_state.sha2_256.state[5] = 0x68581511UL;
md->ctx_state.sha2_256.state[6] = 0x64f98fa7UL;
md->ctx_state.sha2_256.state[7] = 0xbefa4fa4UL;
}
static void sha_update(struct b_hash_ctx *md, const void *in, size_t inlen)
{
z__b_sha2_256_update(md, in, inlen);
}
static void sha_finish(struct b_hash_ctx *md, void *out, size_t max)
{
unsigned char res[B_DIGEST_LENGTH_SHA2_256];
z__b_sha2_256_finish(md, res, max);
/* truncate the digest to 224 bits */
memcpy(out, res, b_min(size_t, max, B_DIGEST_LENGTH_224));
}
struct b_hash_function_ops z__b_sha2_224_ops = {
.hash_init = sha_init,
.hash_update = sha_update,
.hash_finish = sha_finish,
};

215
core/hash/sha2_256.c Normal file
View File

@@ -0,0 +1,215 @@
// SHA-256. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <blue/core/hash.h>
#include <string.h>
static const uint32_t K[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
};
static uint32_t min(uint32_t x, uint32_t y)
{
return x < y ? x : y;
}
static uint32_t load32(const unsigned char *y)
{
return ((uint32_t)(y[0]) << 24) | ((uint32_t)(y[1]) << 16)
| ((uint32_t)(y[2]) << 8) | ((uint32_t)(y[3]) << 0);
}
static void store64(uint64_t x, unsigned char *y)
{
for (int i = 0; i != 8; ++i)
y[i] = (x >> ((7 - i) * 8)) & 255;
}
static void store32(uint32_t x, unsigned char *y)
{
for (int i = 0; i != 4; ++i)
y[i] = (x >> ((3 - i) * 8)) & 255;
}
static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
{
return z ^ (x & (y ^ z));
}
static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
{
return ((x | y) & z) | (x & y);
}
static uint32_t Rot(uint32_t x, uint32_t n)
{
return (x >> (n & 31)) | (x << (32 - (n & 31)));
}
static uint32_t Sh(uint32_t x, uint32_t n)
{
return x >> n;
}
static uint32_t Sigma0(uint32_t x)
{
return Rot(x, 2) ^ Rot(x, 13) ^ Rot(x, 22);
}
static uint32_t Sigma1(uint32_t x)
{
return Rot(x, 6) ^ Rot(x, 11) ^ Rot(x, 25);
}
static uint32_t Gamma0(uint32_t x)
{
return Rot(x, 7) ^ Rot(x, 18) ^ Sh(x, 3);
}
static uint32_t Gamma1(uint32_t x)
{
return Rot(x, 17) ^ Rot(x, 19) ^ Sh(x, 10);
}
static void RND(
uint32_t *t0, uint32_t *t1, uint32_t W[], uint32_t a, uint32_t b,
uint32_t c, uint32_t *d, uint32_t e, uint32_t f, uint32_t g,
uint32_t *h, uint32_t i)
{
(*t0) = *h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
(*t1) = Sigma0(a) + Maj(a, b, c);
(*d) += *t0;
(*h) = *t0 + *t1;
}
static void sha_compress(struct b_hash_ctx *md, const unsigned char *buf)
{
uint32_t S[8], W[64], t0, t1, t;
// Copy state into S
for (int i = 0; i < 8; i++)
S[i] = md->ctx_state.sha2_256.state[i];
// Copy the state into 512-bits into W[0..15]
for (int i = 0; i < 16; i++)
W[i] = load32(buf + (4 * i));
// Fill W[16..63]
for (int i = 16; i < 64; i++)
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
// Compress
for (int i = 0; i < 64; ++i) {
RND(&t0, &t1, W, S[0], S[1], S[2], &S[3], S[4], S[5], S[6],
&S[7], i);
t = S[7];
S[7] = S[6];
S[6] = S[5];
S[5] = S[4];
S[4] = S[3];
S[3] = S[2];
S[2] = S[1];
S[1] = S[0];
S[0] = t;
}
// Feedback
for (int i = 0; i < 8; i++)
md->ctx_state.sha2_256.state[i]
= md->ctx_state.sha2_256.state[i] + S[i];
}
// Public interface
static void sha_init(struct b_hash_ctx *md)
{
md->ctx_state.sha2_256.curlen = 0;
md->ctx_state.sha2_256.length = 0;
md->ctx_state.sha2_256.state[0] = 0x6A09E667UL;
md->ctx_state.sha2_256.state[1] = 0xBB67AE85UL;
md->ctx_state.sha2_256.state[2] = 0x3C6EF372UL;
md->ctx_state.sha2_256.state[3] = 0xA54FF53AUL;
md->ctx_state.sha2_256.state[4] = 0x510E527FUL;
md->ctx_state.sha2_256.state[5] = 0x9B05688CUL;
md->ctx_state.sha2_256.state[6] = 0x1F83D9ABUL;
md->ctx_state.sha2_256.state[7] = 0x5BE0CD19UL;
}
void z__b_sha2_256_update(struct b_hash_ctx *md, const void *src, size_t inlen)
{
const uint32_t block_size = sizeof md->ctx_state.sha2_256.buf;
const unsigned char *in = (const unsigned char *)(src);
while (inlen > 0) {
if (md->ctx_state.sha2_256.curlen == 0 && inlen >= block_size) {
sha_compress(md, in);
md->ctx_state.sha2_256.length += block_size * 8;
in += block_size;
inlen -= block_size;
} else {
uint32_t n = min(
inlen,
(block_size - md->ctx_state.sha2_256.curlen));
memcpy(md->ctx_state.sha2_256.buf
+ md->ctx_state.sha2_256.curlen,
in, n);
md->ctx_state.sha2_256.curlen += n;
in += n;
inlen -= n;
if (md->ctx_state.sha2_256.curlen == block_size) {
sha_compress(md, md->ctx_state.sha2_256.buf);
md->ctx_state.sha2_256.length += 8 * block_size;
md->ctx_state.sha2_256.curlen = 0;
}
}
}
}
void z__b_sha2_256_finish(struct b_hash_ctx *md, void *out, size_t max)
{
// Increase the length of the message
md->ctx_state.sha2_256.length += md->ctx_state.sha2_256.curlen * 8;
// Append the '1' bit
md->ctx_state.sha2_256.buf[md->ctx_state.sha2_256.curlen++]
= (unsigned char)(0x80);
// If the length is currently above 56 bytes we append zeros then compress.
// Then we can fall back to padding zeros and length encoding like normal.
if (md->ctx_state.sha2_256.curlen > 56) {
while (md->ctx_state.sha2_256.curlen < 64)
md->ctx_state.sha2_256.buf[md->ctx_state.sha2_256.curlen++]
= 0;
sha_compress(md, md->ctx_state.sha2_256.buf);
md->ctx_state.sha2_256.curlen = 0;
}
// Pad upto 56 bytes of zeroes
while (md->ctx_state.sha2_256.curlen < 56)
md->ctx_state.sha2_256.buf[md->ctx_state.sha2_256.curlen++] = 0;
// Store length
store64(md->ctx_state.sha2_256.length, md->ctx_state.sha2_256.buf + 56);
sha_compress(md, md->ctx_state.sha2_256.buf);
unsigned char digest[B_DIGEST_LENGTH_SHA2_256];
// Copy output
for (int i = 0; i < 8; i++)
store32(md->ctx_state.sha2_256.state[i],
(unsigned char *)&digest[(4 * i)]);
memcpy(out, digest, b_min(size_t, sizeof digest, max));
}
struct b_hash_function_ops z__b_sha2_256_ops = {
.hash_init = sha_init,
.hash_update = z__b_sha2_256_update,
.hash_finish = z__b_sha2_256_finish,
};

42
core/hash/sha2_384.c Normal file
View File

@@ -0,0 +1,42 @@
// SHA-384. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <blue/core/hash.h>
#include <string.h>
extern void z__b_sha2_512_update(
struct b_hash_ctx *md, const void *src, size_t inlen);
extern void z__b_sha2_512_finish(struct b_hash_ctx *md, void *out, size_t max);
void sha_init(struct b_hash_ctx *md)
{
md->ctx_state.sha2_512.curlen = 0;
md->ctx_state.sha2_512.length = 0;
md->ctx_state.sha2_512.state[0] = 0xcbbb9d5dc1059ed8ULL;
md->ctx_state.sha2_512.state[1] = 0x629a292a367cd507ULL;
md->ctx_state.sha2_512.state[2] = 0x9159015a3070dd17ULL;
md->ctx_state.sha2_512.state[3] = 0x152fecd8f70e5939ULL;
md->ctx_state.sha2_512.state[4] = 0x67332667ffc00b31ULL;
md->ctx_state.sha2_512.state[5] = 0x8eb44a8768581511ULL;
md->ctx_state.sha2_512.state[6] = 0xdb0c2e0d64f98fa7ULL;
md->ctx_state.sha2_512.state[7] = 0x47b5481dbefa4fa4ULL;
}
static void sha_update(struct b_hash_ctx *md, const void *in, size_t inlen)
{
z__b_sha2_512_update(md, in, inlen);
}
static void sha_finish(struct b_hash_ctx *md, void *out, size_t max)
{
unsigned char res[B_DIGEST_LENGTH_SHA2_512];
z__b_sha2_512_finish(md, res, max);
/* truncate the digest to 384 bits */
memcpy(out, res, b_min(size_t, max, B_DIGEST_LENGTH_384));
}
struct b_hash_function_ops z__b_sha2_384_ops = {
.hash_init = sha_init,
.hash_update = sha_update,
.hash_finish = sha_finish,
};

236
core/hash/sha2_512.c Normal file
View File

@@ -0,0 +1,236 @@
// SHA-512. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <blue/core/hash.h>
#include <stdint.h>
#include <string.h>
static const uint64_t K[80]
= {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
static uint32_t min(uint32_t x, uint32_t y)
{
return x < y ? x : y;
}
static void store64(uint64_t x, unsigned char *y)
{
for (int i = 0; i != 8; ++i)
y[i] = (x >> ((7 - i) * 8)) & 255;
}
static uint64_t load64(const unsigned char *y)
{
uint64_t res = 0;
for (int i = 0; i != 8; ++i)
res |= (uint64_t)(y[i]) << ((7 - i) * 8);
return res;
}
static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
{
return z ^ (x & (y ^ z));
}
static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
{
return ((x | y) & z) | (x & y);
}
static uint64_t Rot(uint64_t x, uint64_t n)
{
return (x >> (n & 63)) | (x << (64 - (n & 63)));
}
static uint64_t Sh(uint64_t x, uint64_t n)
{
return x >> n;
}
static uint64_t Sigma0(uint64_t x)
{
return Rot(x, 28) ^ Rot(x, 34) ^ Rot(x, 39);
}
static uint64_t Sigma1(uint64_t x)
{
return Rot(x, 14) ^ Rot(x, 18) ^ Rot(x, 41);
}
static uint64_t Gamma0(uint64_t x)
{
return Rot(x, 1) ^ Rot(x, 8) ^ Sh(x, 7);
}
static uint64_t Gamma1(uint64_t x)
{
return Rot(x, 19) ^ Rot(x, 61) ^ Sh(x, 6);
}
static void RND(
uint64_t W[], uint64_t *t0, uint64_t *t1, uint64_t a, uint64_t b,
uint64_t c, uint64_t *d, uint64_t e, uint64_t f, uint64_t g,
uint64_t *h, uint64_t i)
{
*t0 = *h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
*t1 = Sigma0(a) + Maj(a, b, c);
*d += *t0;
*h = *t0 + *t1;
}
static void sha_compress(struct b_hash_ctx *md, const unsigned char *buf)
{
uint64_t S[8], W[80], t0, t1;
// Copy state into S
for (int i = 0; i < 8; i++) {
S[i] = md->ctx_state.sha2_512.state[i];
}
// Copy the state into 1024-bits into W[0..15]
for (int i = 0; i < 16; i++) {
W[i] = load64(buf + (8 * i));
}
// Fill W[16..79]
for (int i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
// Compress
for (int i = 0; i < 80; i += 8) {
RND(W, &t0, &t1, S[0], S[1], S[2], &S[3], S[4], S[5], S[6],
&S[7], i + 0);
RND(W, &t0, &t1, S[7], S[0], S[1], &S[2], S[3], S[4], S[5],
&S[6], i + 1);
RND(W, &t0, &t1, S[6], S[7], S[0], &S[1], S[2], S[3], S[4],
&S[5], i + 2);
RND(W, &t0, &t1, S[5], S[6], S[7], &S[0], S[1], S[2], S[3],
&S[4], i + 3);
RND(W, &t0, &t1, S[4], S[5], S[6], &S[7], S[0], S[1], S[2],
&S[3], i + 4);
RND(W, &t0, &t1, S[3], S[4], S[5], &S[6], S[7], S[0], S[1],
&S[2], i + 5);
RND(W, &t0, &t1, S[2], S[3], S[4], &S[5], S[6], S[7], S[0],
&S[1], i + 6);
RND(W, &t0, &t1, S[1], S[2], S[3], &S[4], S[5], S[6], S[7],
&S[0], i + 7);
}
// Feedback
for (int i = 0; i < 8; i++)
md->ctx_state.sha2_512.state[i]
= md->ctx_state.sha2_512.state[i] + S[i];
}
// Public interface
static void sha_init(struct b_hash_ctx *md)
{
md->ctx_state.sha2_512.curlen = 0;
md->ctx_state.sha2_512.length = 0;
md->ctx_state.sha2_512.state[0] = 0x6a09e667f3bcc908ULL;
md->ctx_state.sha2_512.state[1] = 0xbb67ae8584caa73bULL;
md->ctx_state.sha2_512.state[2] = 0x3c6ef372fe94f82bULL;
md->ctx_state.sha2_512.state[3] = 0xa54ff53a5f1d36f1ULL;
md->ctx_state.sha2_512.state[4] = 0x510e527fade682d1ULL;
md->ctx_state.sha2_512.state[5] = 0x9b05688c2b3e6c1fULL;
md->ctx_state.sha2_512.state[6] = 0x1f83d9abfb41bd6bULL;
md->ctx_state.sha2_512.state[7] = 0x5be0cd19137e2179ULL;
}
void z__b_sha2_512_update(struct b_hash_ctx *md, const void *src, size_t inlen)
{
const uint32_t block_size = sizeof md->ctx_state.sha2_512.block;
const unsigned char *in = (const unsigned char *)src;
while (inlen > 0) {
if (md->ctx_state.sha2_512.curlen == 0 && inlen >= block_size) {
sha_compress(md, in);
md->ctx_state.sha2_512.length += block_size * 8;
in += block_size;
inlen -= block_size;
} else {
uint32_t n = min(
inlen,
(block_size - md->ctx_state.sha2_512.curlen));
memcpy(md->ctx_state.sha2_512.block
+ md->ctx_state.sha2_512.curlen,
in, n);
md->ctx_state.sha2_512.curlen += n;
in += n;
inlen -= n;
if (md->ctx_state.sha2_512.curlen == block_size) {
sha_compress(md, md->ctx_state.sha2_512.block);
md->ctx_state.sha2_512.length += 8 * block_size;
md->ctx_state.sha2_512.curlen = 0;
}
}
}
}
void z__b_sha2_512_finish(struct b_hash_ctx *md, void *out, size_t max)
{
// Increase the length of the message
md->ctx_state.sha2_512.length += md->ctx_state.sha2_512.curlen * 8ULL;
// Append the '1' bit
md->ctx_state.sha2_512.block[md->ctx_state.sha2_512.curlen++] = 0x80;
// If the length is currently above 112 bytes we append zeros then compress.
// Then we can fall back to padding zeros and length encoding like normal.
if (md->ctx_state.sha2_512.curlen > 112) {
while (md->ctx_state.sha2_512.curlen < 128)
md->ctx_state.sha2_512.block[md->ctx_state.sha2_512.curlen++]
= 0;
sha_compress(md, md->ctx_state.sha2_512.block);
md->ctx_state.sha2_512.curlen = 0;
}
// Pad upto 120 bytes of zeroes
// note: that from 112 to 120 is the 64 MSB of the length. We assume
// that you won't hash 2^64 bits of data... :-)
while (md->ctx_state.sha2_512.curlen < 120) {
md->ctx_state.sha2_512.block[md->ctx_state.sha2_512.curlen++] = 0;
}
// Store length
store64(md->ctx_state.sha2_512.length, md->ctx_state.sha2_512.block + 120);
sha_compress(md, md->ctx_state.sha2_512.block);
unsigned char digest[B_DIGEST_LENGTH_SHA2_512];
// Copy output
for (int i = 0; i < 8; i++) {
store64(md->ctx_state.sha2_512.state[i],
(unsigned char *)&digest[(8 * i)]);
}
memcpy(out, digest, b_min(size_t, sizeof digest, max));
}
struct b_hash_function_ops z__b_sha2_512_ops = {
.hash_init = sha_init,
.hash_update = z__b_sha2_512_update,
.hash_finish = z__b_sha2_512_finish,
};

333
core/hash/sha3.c Normal file
View File

@@ -0,0 +1,333 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Markku-Juhani O. Saarinen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// sha3.c
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3"
// Revised 03-Sep-15 for portability + OpenSSL - style API
#include "hash.h"
#include <blue/core/hash.h>
#include <blue/core/misc.h>
#include <string.h>
#ifndef KECCAKF_ROUNDS
#define KECCAKF_ROUNDS 24
#endif
#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
// update the state with given number of rounds
void sha3_keccakf(uint64_t st[25])
{
// constants
const uint64_t keccakf_rndc[24]
= {0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008};
const int keccakf_rotc[24]
= {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44};
const int keccakf_piln[24]
= {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1};
// variables
int i, j, r;
uint64_t t, bc[5];
#if !defined(LITTLE_ENDIAN)
uint8_t *v;
// endianess conversion. this is redundant on little-endian targets
for (i = 0; i < 25; i++) {
v = (uint8_t *)&st[i];
st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8)
| (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24)
| (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40)
| (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56);
}
#endif
// actual iteration
for (r = 0; r < KECCAKF_ROUNDS; r++) {
// Theta
for (i = 0; i < 5; i++)
bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15]
^ st[i + 20];
for (i = 0; i < 5; i++) {
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
for (j = 0; j < 25; j += 5)
st[j + i] ^= t;
}
// Rho Pi
t = st[1];
for (i = 0; i < 24; i++) {
j = keccakf_piln[i];
bc[0] = st[j];
st[j] = ROTL64(t, keccakf_rotc[i]);
t = bc[0];
}
// Chi
for (j = 0; j < 25; j += 5) {
for (i = 0; i < 5; i++)
bc[i] = st[j + i];
for (i = 0; i < 5; i++)
st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
}
// Iota
st[0] ^= keccakf_rndc[r];
}
#if !defined(LITTLE_ENDIAN)
// endianess conversion. this is redundant on little-endian targets
for (i = 0; i < 25; i++) {
v = (uint8_t *)&st[i];
t = st[i];
v[0] = t & 0xFF;
v[1] = (t >> 8) & 0xFF;
v[2] = (t >> 16) & 0xFF;
v[3] = (t >> 24) & 0xFF;
v[4] = (t >> 32) & 0xFF;
v[5] = (t >> 40) & 0xFF;
v[6] = (t >> 48) & 0xFF;
v[7] = (t >> 56) & 0xFF;
}
#endif
}
// Initialize the context for SHA3
int sha3_init(struct b_hash_ctx *c, int mdlen)
{
int i;
for (i = 0; i < 25; i++)
c->ctx_state.sha3.st.q[i] = 0;
c->ctx_state.sha3.mdlen = mdlen;
c->ctx_state.sha3.rsiz = 200 - 2 * mdlen;
c->ctx_state.sha3.pt = 0;
return 1;
}
// update state with more data
void sha3_update(struct b_hash_ctx *c, const void *data, size_t len)
{
size_t i;
int j;
j = c->ctx_state.sha3.pt;
for (i = 0; i < len; i++) {
c->ctx_state.sha3.st.b[j++] ^= ((const uint8_t *)data)[i];
if (j >= c->ctx_state.sha3.rsiz) {
sha3_keccakf(c->ctx_state.sha3.st.q);
j = 0;
}
}
c->ctx_state.sha3.pt = j;
}
// finalize and output a hash
int sha3_final(void *md, struct b_hash_ctx *c)
{
int i;
c->ctx_state.sha3.st.b[c->ctx_state.sha3.pt] ^= 0x06;
c->ctx_state.sha3.st.b[c->ctx_state.sha3.rsiz - 1] ^= 0x80;
sha3_keccakf(c->ctx_state.sha3.st.q);
for (i = 0; i < c->ctx_state.sha3.mdlen; i++) {
((uint8_t *)md)[i] = c->ctx_state.sha3.st.b[i];
}
return 1;
}
// compute a SHA-3 hash (md) of given byte length from "in"
void *sha3(const void *in, size_t inlen, void *md, int mdlen)
{
struct b_hash_ctx sha3;
sha3_init(&sha3, mdlen);
sha3_update(&sha3, in, inlen);
sha3_final(md, &sha3);
return md;
}
// SHAKE128 and SHAKE256 extensible-output functionality
void shake_xof(struct b_hash_ctx *c)
{
c->ctx_state.sha3.st.b[c->ctx_state.sha3.pt] ^= 0x1F;
c->ctx_state.sha3.st.b[c->ctx_state.sha3.rsiz - 1] ^= 0x80;
sha3_keccakf(c->ctx_state.sha3.st.q);
c->ctx_state.sha3.pt = 0;
}
void shake_out(struct b_hash_ctx *c, void *out, size_t len)
{
size_t i;
int j;
j = c->ctx_state.sha3.pt;
for (i = 0; i < len; i++) {
if (j >= c->ctx_state.sha3.rsiz) {
sha3_keccakf(c->ctx_state.sha3.st.q);
j = 0;
}
((uint8_t *)out)[i] = c->ctx_state.sha3.st.b[j++];
}
c->ctx_state.sha3.pt = j;
}
static void sha3_224_init(struct b_hash_ctx *ctx)
{
sha3_init(ctx, B_DIGEST_LENGTH_SHA3_224);
}
static void sha3_224_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[B_DIGEST_LENGTH_SHA3_224];
sha3_final(md, ctx);
memcpy(out, md, b_min(size_t, sizeof md, max));
}
static void sha3_256_init(struct b_hash_ctx *ctx)
{
sha3_init(ctx, B_DIGEST_LENGTH_SHA3_256);
}
static void sha3_256_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[B_DIGEST_LENGTH_SHA3_256];
sha3_final(md, ctx);
memcpy(out, md, b_min(size_t, sizeof md, max));
}
static void sha3_384_init(struct b_hash_ctx *ctx)
{
sha3_init(ctx, B_DIGEST_LENGTH_SHA3_384);
}
static void sha3_384_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[B_DIGEST_LENGTH_SHA3_384];
sha3_final(md, ctx);
memcpy(out, md, b_min(size_t, sizeof md, max));
}
static void sha3_512_init(struct b_hash_ctx *ctx)
{
sha3_init(ctx, B_DIGEST_LENGTH_SHA3_512);
}
static void sha3_512_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[B_DIGEST_LENGTH_SHA3_512];
sha3_final(md, ctx);
memcpy(out, md, b_min(size_t, sizeof md, max));
}
static void shake128_init(struct b_hash_ctx *ctx)
{
sha3_init(ctx, B_DIGEST_LENGTH_SHAKE128);
}
static void shake128_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[B_DIGEST_LENGTH_SHAKE128];
shake_xof(ctx);
shake_out(ctx, md, sizeof md);
memcpy(out, md, b_min(size_t, sizeof md, max));
}
static void shake256_init(struct b_hash_ctx *ctx)
{
sha3_init(ctx, B_DIGEST_LENGTH_SHAKE256);
}
static void shake256_finish(struct b_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[B_DIGEST_LENGTH_SHAKE256];
shake_xof(ctx);
shake_out(ctx, md, sizeof md);
memcpy(out, md, b_min(size_t, sizeof md, max));
}
struct b_hash_function_ops z__b_sha3_224_ops = {
.hash_init = sha3_224_init,
.hash_update = sha3_update,
.hash_finish = sha3_224_finish,
};
struct b_hash_function_ops z__b_sha3_256_ops = {
.hash_init = sha3_256_init,
.hash_update = sha3_update,
.hash_finish = sha3_256_finish,
};
struct b_hash_function_ops z__b_sha3_384_ops = {
.hash_init = sha3_384_init,
.hash_update = sha3_update,
.hash_finish = sha3_384_finish,
};
struct b_hash_function_ops z__b_sha3_512_ops = {
.hash_init = sha3_512_init,
.hash_update = sha3_update,
.hash_finish = sha3_512_finish,
};
struct b_hash_function_ops z__b_shake128_ops = {
.hash_init = shake128_init,
.hash_update = sha3_update,
.hash_finish = shake128_finish,
};
struct b_hash_function_ops z__b_shake256_ops = {
.hash_init = shake256_init,
.hash_update = sha3_update,
.hash_finish = shake256_finish,
};

View File

@@ -2,8 +2,108 @@
#define BLUELIB_CORE_HASH_H_ #define BLUELIB_CORE_HASH_H_
#include <blue/core/misc.h> #include <blue/core/misc.h>
#include <blue/core/status.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
BLUE_API uint64_t b_hash_string(const char *s); #define B_DIGEST_LENGTH_128 16
#define B_DIGEST_LENGTH_160 20
#define B_DIGEST_LENGTH_192 24
#define B_DIGEST_LENGTH_224 28
#define B_DIGEST_LENGTH_256 32
#define B_DIGEST_LENGTH_384 48
#define B_DIGEST_LENGTH_512 64
#endif #define B_DIGEST_LENGTH_MD4 B_DIGEST_LENGTH_128
#define B_DIGEST_LENGTH_MD5 B_DIGEST_LENGTH_128
#define B_DIGEST_LENGTH_SHA1 B_DIGEST_LENGTH_160
#define B_DIGEST_LENGTH_SHA2_224 B_DIGEST_LENGTH_224
#define B_DIGEST_LENGTH_SHA2_256 B_DIGEST_LENGTH_256
#define B_DIGEST_LENGTH_SHA2_384 B_DIGEST_LENGTH_384
#define B_DIGEST_LENGTH_SHA2_512 B_DIGEST_LENGTH_512
#define B_DIGEST_LENGTH_SHA3_224 B_DIGEST_LENGTH_224
#define B_DIGEST_LENGTH_SHA3_256 B_DIGEST_LENGTH_256
#define B_DIGEST_LENGTH_SHA3_384 B_DIGEST_LENGTH_384
#define B_DIGEST_LENGTH_SHA3_512 B_DIGEST_LENGTH_512
#define B_DIGEST_LENGTH_SHAKE128 B_DIGEST_LENGTH_128
#define B_DIGEST_LENGTH_SHAKE256 B_DIGEST_LENGTH_256
struct b_hash_function_ops;
typedef enum b_hash_function {
B_HASH_NONE = 0,
B_HASH_MD4,
B_HASH_MD5,
B_HASH_SHA1,
B_HASH_SHA2_224,
B_HASH_SHA2_256,
B_HASH_SHA2_384,
B_HASH_SHA2_512,
B_HASH_SHA3_224,
B_HASH_SHA3_256,
B_HASH_SHA3_384,
B_HASH_SHA3_512,
B_HASH_SHAKE128,
B_HASH_SHAKE256,
} b_hash_function;
typedef struct b_hash_ctx {
b_hash_function ctx_func;
const struct b_hash_function_ops *ctx_ops;
union {
struct {
uint32_t lo, hi;
uint32_t a, b, c, d;
uint32_t block[16];
unsigned char buffer[64];
} md4;
struct {
unsigned int count[2];
unsigned int a, b, c, d;
unsigned int block[16];
unsigned char input[64];
} md5;
struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} sha1;
struct {
uint64_t curlen;
uint64_t length;
unsigned char buf[128];
uint32_t state[8];
} sha2_256;
struct {
uint64_t curlen;
uint64_t length;
unsigned char block[256];
uint64_t state[8];
} sha2_512;
struct {
union {
uint8_t b[200];
uint64_t q[25];
} st;
int pt, rsiz, mdlen;
} sha3;
} ctx_state;
} b_hash_ctx;
BLUE_API uint64_t b_hash_string(const char *s);
BLUE_API uint64_t b_hash_string_ex(const char *s, size_t *len);
BLUE_API b_status b_hash_ctx_init(b_hash_ctx *ctx, b_hash_function func);
BLUE_API b_status b_hash_ctx_reset(b_hash_ctx *ctx);
BLUE_API b_status b_hash_ctx_update(b_hash_ctx *ctx, const void *p, size_t len);
BLUE_API b_status b_hash_ctx_finish(
b_hash_ctx *ctx, void *out_digest, size_t out_max);
#endif