tls

tls.git
git clone git://git.lenczewski.org/tls.git
Log | Files | Refs

commit ba577b46f19095c5c86057119e5b9e594f3f8e9b
parent 1a5b5acc814fbd49f9b090809615063960f4db96
Author: MikoĊ‚aj Lenczewski <mikolaj@lenczewski.org>
Date:   Wed, 16 Sep 2026 01:18:29 +0100

Add sha512 implementation

Diffstat:
Msha.c | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msha.h | 7+++----
Atest-sha512.c | 40++++++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 9 deletions(-)

diff --git a/sha.c b/sha.c @@ -95,12 +95,12 @@ _sha256_block(struct sha256_ctx *ctx) for (t = 0; t < SHA256_SCHEDULE_WORDS; t++) { t1 = h + SHA256_S1(e) - + SHA256_Ch(e, f, g) + + SHA_Ch(e, f, g) + _sha256_constants[t] + ctx->schedule[t]; t2 = SHA256_S0(a) - + SHA256_Maj(a, b, c); + + SHA_Maj(a, b, c); h = g; g = f; @@ -199,6 +199,8 @@ sha256(void const *buf, size_t len, unsigned char digest[static SHA256_DIGEST_SI void sha512_init(struct sha512_ctx *ctx) { + memset(ctx, 0, sizeof *ctx); + ctx->digest[0] = 0x6a09e667f3bcc908; ctx->digest[1] = 0xbb67ae8584caa73b; ctx->digest[2] = 0x3c6ef372fe94f82b; @@ -210,25 +212,124 @@ sha512_init(struct sha512_ctx *ctx) } static inline void -_sha512_block() +_sha512_block(struct sha512_ctx *ctx) { + sha512_word_t a, b, c, d, e, f, g, h, t, t1, t2; + + // load block words + for (t = 0; t < SHA512_BLOCK_WORDS; t++) { + ctx->schedule[t] = htobe64(ctx->schedule[t]); + } + + // expand out block words into full schedule + for (; t < SHA512_SCHEDULE_WORDS; t++) { + ctx->schedule[t] = SHA512_s1(ctx->schedule[t - 2]) + + ctx->schedule[t - 7] + + SHA512_s0(ctx->schedule[t - 15]) + + ctx->schedule[t - 16]; + } + + // initialise working variables + a = ctx->digest[0]; + b = ctx->digest[1]; + c = ctx->digest[2]; + d = ctx->digest[3]; + e = ctx->digest[4]; + f = ctx->digest[5]; + g = ctx->digest[6]; + h = ctx->digest[7]; + + // perform rounds of sha512 compression (as many as words in our schedule) + for (t = 0; t < SHA512_SCHEDULE_WORDS; t++) { + t1 = h + + SHA512_S1(e) + + SHA_Ch(e, f, g) + + _sha512_constants[t] + + ctx->schedule[t]; + + t2 = SHA512_S0(a) + + SHA_Maj(a, b, c); + + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + // save intermediate hash + ctx->digest[0] += a; + ctx->digest[1] += b; + ctx->digest[2] += c; + ctx->digest[3] += d; + ctx->digest[4] += e; + ctx->digest[5] += f; + ctx->digest[6] += g; + ctx->digest[7] += h; } void sha512_push(struct sha512_ctx *ctx, void const *buf, size_t len) { + unsigned char const *ptr = buf, *end = ptr + len; + unsigned char *block = ((unsigned char *) ctx->schedule); + + while (ptr < end) { + size_t idx = ctx->ctr++ & SHA512_BLOCK_MASK; + block[idx] = *ptr++; + + if (idx == SHA512_BLOCK_MASK) { // filled a block; hash it + _sha512_block(ctx); + } + } } static inline void -_sha512_digest_bswap(struct sha512_ctx *ctx, size_t len) +_sha512_digest_bswap(struct sha512_ctx *ctx, size_t words) { - for (size_t i = 0; i < len; i++) + for (size_t i = 0; i < words; i++) ctx->digest[i] = htobe64(ctx->digest[i]); } void sha512_dgst(struct sha512_ctx *ctx) { + unsigned char *block = ((unsigned char *) ctx->schedule); + unsigned char *cur = block + (ctx->ctr & SHA512_BLOCK_MASK); + unsigned char *end = block + SHA512_BLOCK_SIZE; + unsigned char *len = end - (128 / CHAR_BIT); + + // TODO: handle 128-bit overflow here + assert(ctx->ctr < (UINT64_MAX / CHAR_BIT)); + __uint128_t bits = ctx->ctr * CHAR_BIT; + + // append the 1 bit + *cur++ = 0x80; + + // can we fit our message bit length? if not, add an extra padding block + if (len < cur) { + memset(cur, 0, end - cur); + _sha512_block(ctx); + + cur = block; + } + + // pad out final block + memset(cur, 0, len - cur); + + // write out message bit length + __uint128_t hi = (__uint128_t) htobe64(bits & UINT64_MAX); + __uint128_t lo = (__uint128_t) htobe64(bits >> 64); + ((__uint128_t *) len)[0] = (hi << 64) | (lo); + + // hash final block + _sha512_block(ctx); + + // write out internally host-endian hash as big-endian hash + _sha512_digest_bswap(ctx, SHA512_DIGEST_WORDS); } void diff --git a/sha.h b/sha.h @@ -88,15 +88,14 @@ struct sha512_ctx { // sha functions // =========================================================================== -#define SHA256_Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) -#define SHA256_Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define SHA_Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define SHA_Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + #define SHA256_S0(x) (SHA_ROTR32((x), 2) ^ SHA_ROTR32((x), 13) ^ SHA_ROTR32((x), 22)) #define SHA256_S1(x) (SHA_ROTR32((x), 6) ^ SHA_ROTR32((x), 11) ^ SHA_ROTR32((x), 25)) #define SHA256_s0(x) (SHA_ROTR32((x), 7) ^ SHA_ROTR32((x), 18) ^ SHA_SHR((x), 3)) #define SHA256_s1(x) (SHA_ROTR32((x), 17) ^ SHA_ROTR32((x), 19) ^ SHA_SHR((x), 10)) -#define SHA512_Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) -#define SHA512_Maj(x, y, z) (((x) ^ (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define SHA512_S0(x) (SHA_ROTR64((x), 28) ^ SHA_ROTR64((x), 34) ^ SHA_ROTR64((x), 39)) #define SHA512_S1(x) (SHA_ROTR64((x), 14) ^ SHA_ROTR64((x), 18) ^ SHA_ROTR64((x), 41)) #define SHA512_s0(x) (SHA_ROTR64((x), 1) ^ SHA_ROTR64((x), 8) ^ SHA_SHR((x), 7)) diff --git a/test-sha512.c b/test-sha512.c @@ -0,0 +1,40 @@ +#include "sha.h" +#include <stdio.h> + +int +main(void) +{ + char msg[] = "abc"; + + uint8_t dgst[SHA512_DIGEST_SIZE]; + sha512(msg, strlen(msg), dgst); + + uint8_t expected[SHA512_DIGEST_SIZE] = { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f, + }; + + printf("msg: \"%.*s\" (%lu bytes)\n", sizeof msg, msg, strlen(msg)); + + printf("dgst: "); + for (size_t i = 0; i < sizeof dgst; i++) { + printf("%.2x", dgst[i]); + } + printf("\n"); + + printf("exp.: "); + for (size_t i = 0; i < sizeof expected; i++) { + printf("%.2x", expected[i]); + } + printf("\n"); + + return memcmp(expected, dgst, SHA512_DIGEST_SIZE); +} + +#include "sha.c"