From ed4942c5007aa37c775252a2bf8406fbad49719b Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 11 Apr 2025 13:51:48 +0100 Subject: [PATCH] core: add support for lots of different hash algorithms --- core/hash.c | 18 -- core/hash/hash.c | 139 ++++++++++++++ core/hash/hash.h | 14 ++ core/hash/md4.c | 270 +++++++++++++++++++++++++++ core/hash/md5.c | 238 ++++++++++++++++++++++++ core/hash/sha1.c | 268 +++++++++++++++++++++++++++ core/hash/sha2_224.c | 42 +++++ core/hash/sha2_256.c | 215 ++++++++++++++++++++++ core/hash/sha2_384.c | 42 +++++ core/hash/sha2_512.c | 236 ++++++++++++++++++++++++ core/hash/sha3.c | 333 ++++++++++++++++++++++++++++++++++ core/include/blue/core/hash.h | 104 ++++++++++- 12 files changed, 1899 insertions(+), 20 deletions(-) delete mode 100644 core/hash.c create mode 100644 core/hash/hash.c create mode 100644 core/hash/hash.h create mode 100644 core/hash/md4.c create mode 100644 core/hash/md5.c create mode 100644 core/hash/sha1.c create mode 100644 core/hash/sha2_224.c create mode 100644 core/hash/sha2_256.c create mode 100644 core/hash/sha2_384.c create mode 100644 core/hash/sha2_512.c create mode 100644 core/hash/sha3.c diff --git a/core/hash.c b/core/hash.c deleted file mode 100644 index 68737b9..0000000 --- a/core/hash.c +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include - -#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; -} diff --git a/core/hash/hash.c b/core/hash/hash.c new file mode 100644 index 0000000..b0a3da9 --- /dev/null +++ b/core/hash/hash.c @@ -0,0 +1,139 @@ +#include "hash.h" + +#include +#include +#include +#include + +#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; +} diff --git a/core/hash/hash.h b/core/hash/hash.h new file mode 100644 index 0000000..821544a --- /dev/null +++ b/core/hash/hash.h @@ -0,0 +1,14 @@ +#ifndef _HASH_H_ +#define _HASH_H_ + +#include + +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 diff --git a/core/hash/md4.c b/core/hash/md4.c new file mode 100644 index 0000000..3b77819 --- /dev/null +++ b/core/hash/md4.c @@ -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 + * + * 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 +#include +#include + +/* + * 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, +}; diff --git a/core/hash/md5.c b/core/hash/md5.c new file mode 100644 index 0000000..c8ffc38 --- /dev/null +++ b/core/hash/md5.c @@ -0,0 +1,238 @@ +/* This implementation was sourced from + * https://github.com/galenguyer/md5 + * and is in the public domain. */ +#include "hash.h" + +#include +#include +#include +#include +#include + +#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, +}; diff --git a/core/hash/sha1.c b/core/hash/sha1.c new file mode 100644 index 0000000..a80adaa --- /dev/null +++ b/core/hash/sha1.c @@ -0,0 +1,268 @@ +/* +SHA-1 in C +By Steve Reid +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 +#include +#include + +/* for uint32_t */ +#include + +#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, +}; diff --git a/core/hash/sha2_224.c b/core/hash/sha2_224.c new file mode 100644 index 0000000..a55d6a2 --- /dev/null +++ b/core/hash/sha2_224.c @@ -0,0 +1,42 @@ +// SHA-224. Adapted from LibTomCrypt. This code is Public Domain +#include "hash.h" + +#include +#include + +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, +}; diff --git a/core/hash/sha2_256.c b/core/hash/sha2_256.c new file mode 100644 index 0000000..723d966 --- /dev/null +++ b/core/hash/sha2_256.c @@ -0,0 +1,215 @@ +// SHA-256. Adapted from LibTomCrypt. This code is Public Domain +#include "hash.h" + +#include +#include + +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, +}; diff --git a/core/hash/sha2_384.c b/core/hash/sha2_384.c new file mode 100644 index 0000000..4709a2e --- /dev/null +++ b/core/hash/sha2_384.c @@ -0,0 +1,42 @@ +// SHA-384. Adapted from LibTomCrypt. This code is Public Domain +#include "hash.h" + +#include +#include + +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, +}; diff --git a/core/hash/sha2_512.c b/core/hash/sha2_512.c new file mode 100644 index 0000000..ef43f34 --- /dev/null +++ b/core/hash/sha2_512.c @@ -0,0 +1,236 @@ +// SHA-512. Adapted from LibTomCrypt. This code is Public Domain +#include "hash.h" + +#include +#include +#include + +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, +}; diff --git a/core/hash/sha3.c b/core/hash/sha3.c new file mode 100644 index 0000000..b273874 --- /dev/null +++ b/core/hash/sha3.c @@ -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 + +// 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 +#include +#include + +#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, +}; diff --git a/core/include/blue/core/hash.h b/core/include/blue/core/hash.h index 7fa1158..e43452c 100644 --- a/core/include/blue/core/hash.h +++ b/core/include/blue/core/hash.h @@ -2,8 +2,108 @@ #define BLUELIB_CORE_HASH_H_ #include +#include +#include #include -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 \ No newline at end of file +#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