logo

utils-std

Collection of commonly available Unix tools
commit: c187c3995d1fd03facc41e2bcc7a9da25f267641
parent 40eaa1f5c8c1ca6de9773435869dbf844823cd6c
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Thu, 15 Aug 2024 14:29:04 +0200

lib/sha1: New, imported from suckless sbase

Diffstat:

MMakefile6+++++-
Alib/sha1.c165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/sha1.h21+++++++++++++++++++++
Mtest-lib/Kyuafile1+
Atest-lib/sha1.c66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 258 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile @@ -27,7 +27,7 @@ selfcheck: all # Manpages with examples that cram/prysk can grok MAN_EXAMPLES = cmd/readlink.1 -TEST_LIBS = test-lib/mode test-lib/strtodur test-lib/symbolize_mode test-lib/truncation +TEST_LIBS = test-lib/mode test-lib/strtodur test-lib/symbolize_mode test-lib/truncation test-lib/sha1 .PHONY: check check: all $(TEST_LIBS) check-man MALLOC_CHECK_=3 POSIX_ME_HARDER=1 POSIXLY_CORRECT=1 LC_ALL=C.UTF-8 LDSTATIC=$(LDSTATIC) kyua test || (kyua report --verbose --results-filter=broken,failed; false) @@ -110,6 +110,10 @@ test-lib/symbolize_mode: test-lib/symbolize_mode.c lib/symbolize_mode.c Makefile test-lib/truncation: test-lib/truncation.c lib/truncation.c Makefile $(CC) -std=c99 $(CFLAGS) -o $@ test-lib/truncation.c lib/truncation.c $(LDFLAGS) $(LDSTATIC) +test-lib/sha1: test-lib/sha1.c lib/sha1.c lib/sha1.h lib/bytes2hex.c lib/strconv.h Makefile + $(CC) -std=c99 $(CFLAGS) -o $@ test-lib/sha1.c lib/sha1.c lib/bytes2hex.c $(LDFLAGS) $(LDSTATIC) + + cmd/df: cmd/df.c lib/humanize.c Makefile $(RM) -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} $(CC) -std=c99 $(CFLAGS) -o $@ cmd/df.c lib/humanize.c $(LDFLAGS) $(LDSTATIC) diff --git a/lib/sha1.c b/lib/sha1.c @@ -0,0 +1,165 @@ +// SPDX-FileCopyrightText: public domain sha1 implementation based on rfc3174 and libtomcrypt +// SPDX-License-Identifier: 0BSD +#include "sha1.h" + +#include <string.h> + +static uint32_t +rol(uint32_t n, int k) +{ + return (n << k) | (n >> (32 - k)); +} +#define F0(b, c, d) (d ^ (b & (c ^ d))) +#define F1(b, c, d) (b ^ c ^ d) +#define F2(b, c, d) ((b & c) | (d & (b | c))) +#define F3(b, c, d) (b ^ c ^ d) +#define G0(a, b, c, d, e, i) \ + e += rol(a, 5) + F0(b, c, d) + W[i] + 0x5A827999; \ + b = rol(b, 30) +#define G1(a, b, c, d, e, i) \ + e += rol(a, 5) + F1(b, c, d) + W[i] + 0x6ED9EBA1; \ + b = rol(b, 30) +#define G2(a, b, c, d, e, i) \ + e += rol(a, 5) + F2(b, c, d) + W[i] + 0x8F1BBCDC; \ + b = rol(b, 30) +#define G3(a, b, c, d, e, i) \ + e += rol(a, 5) + F3(b, c, d) + W[i] + 0xCA62C1D6; \ + b = rol(b, 30) + +static void +processblock(struct sha1 *s, const uint8_t *buf) +{ + uint32_t W[80], a, b, c, d, e; + int i; + + for(i = 0; i < 16; i++) + { + W[i] = (uint32_t)buf[4 * i] << 24; + W[i] |= (uint32_t)buf[4 * i + 1] << 16; + W[i] |= (uint32_t)buf[4 * i + 2] << 8; + W[i] |= buf[4 * i + 3]; + } + for(; i < 80; i++) + W[i] = rol(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + a = s->h[0]; + b = s->h[1]; + c = s->h[2]; + d = s->h[3]; + e = s->h[4]; + for(i = 0; i < 20;) + { + G0(a, b, c, d, e, i++); + G0(e, a, b, c, d, i++); + G0(d, e, a, b, c, i++); + G0(c, d, e, a, b, i++); + G0(b, c, d, e, a, i++); + } + while(i < 40) + { + G1(a, b, c, d, e, i++); + G1(e, a, b, c, d, i++); + G1(d, e, a, b, c, i++); + G1(c, d, e, a, b, i++); + G1(b, c, d, e, a, i++); + } + while(i < 60) + { + G2(a, b, c, d, e, i++); + G2(e, a, b, c, d, i++); + G2(d, e, a, b, c, i++); + G2(c, d, e, a, b, i++); + G2(b, c, d, e, a, i++); + } + while(i < 80) + { + G3(a, b, c, d, e, i++); + G3(e, a, b, c, d, i++); + G3(d, e, a, b, c, i++); + G3(c, d, e, a, b, i++); + G3(b, c, d, e, a, i++); + } + s->h[0] += a; + s->h[1] += b; + s->h[2] += c; + s->h[3] += d; + s->h[4] += e; +} + +static void +pad(struct sha1 *s) +{ + unsigned r = s->len % 64; + + s->buf[r++] = 0x80; + if(r > 56) + { + memset(s->buf + r, 0, 64 - r); + r = 0; + processblock(s, s->buf); + } + memset(s->buf + r, 0, 56 - r); + s->len *= 8; + s->buf[56] = s->len >> 56; + s->buf[57] = s->len >> 48; + s->buf[58] = s->len >> 40; + s->buf[59] = s->len >> 32; + s->buf[60] = s->len >> 24; + s->buf[61] = s->len >> 16; + s->buf[62] = s->len >> 8; + s->buf[63] = s->len; + processblock(s, s->buf); +} + +void +sha1_init(void *ctx) +{ + struct sha1 *s = ctx; + + s->len = 0; + s->h[0] = 0x67452301; + s->h[1] = 0xEFCDAB89; + s->h[2] = 0x98BADCFE; + s->h[3] = 0x10325476; + s->h[4] = 0xC3D2E1F0; +} + +void +sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH]) +{ + struct sha1 *s = ctx; + int i; + + pad(s); + for(i = 0; i < 5; i++) + { + md[4 * i] = s->h[i] >> 24; + md[4 * i + 1] = s->h[i] >> 16; + md[4 * i + 2] = s->h[i] >> 8; + md[4 * i + 3] = s->h[i]; + } +} + +void +sha1_update(void *ctx, const void *m, unsigned long len) +{ + struct sha1 *s = ctx; + const uint8_t *p = m; + unsigned r = s->len % 64; + + s->len += len; + if(r) + { + if(len < 64 - r) + { + memcpy(s->buf + r, p, len); + return; + } + memcpy(s->buf + r, p, 64 - r); + len -= 64 - r; + p += 64 - r; + processblock(s, s->buf); + } + for(; len >= 64; len -= 64, p += 64) + processblock(s, p); + memcpy(s->buf, p, len); +} diff --git a/lib/sha1.h b/lib/sha1.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: public domain sha1 implementation based on rfc3174 and libtomcrypt +// SPDX-License-Identifier: 0BSD +#include <stdint.h> + +struct sha1 +{ + uint64_t len; /* processed message length */ + uint32_t h[5]; /* hash state */ + uint8_t buf[64]; /* message block buffer */ +}; + +#define SHA1_DIGEST_LENGTH 20 + +/* reset state */ +void sha1_init(void *ctx); +/* process message */ +void sha1_update(void *ctx, const void *m, unsigned long len); +/* get message digest */ +/* state is ruined after sum, keep a copy if multiple sum is needed */ +/* part of the message might be left in s, zero it if secrecy is needed */ +void sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH]); diff --git a/test-lib/Kyuafile b/test-lib/Kyuafile @@ -6,6 +6,7 @@ test_suite("utils-std libs") -- 7,$|LC_ALL=C.UTF-8 sort tap_test_program{name="mode"} +tap_test_program{name="sha1"} tap_test_program{name="strtodur"} tap_test_program{name="symbolize_mode"} tap_test_program{name="truncation"} diff --git a/test-lib/sha1.c b/test-lib/sha1.c @@ -0,0 +1,66 @@ +// utils-std: Collection of commonly available Unix tools +// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: 0BSD + +#define _POSIX_C_SOURCE 200809L +#include "../lib/sha1.h" + +#include "../lib/strconv.h" + +#include <assert.h> +#include <stdio.h> // printf +#include <string.h> // memcmp, memset + +int counter = 0; +int err = 0; + +static void +t_sha1(char *name, const void *data, size_t datalen, char expected[SHA1_DIGEST_LENGTH * 2]) +{ + int id = ++counter; + + struct sha1 ctx; + sha1_init(&ctx); + sha1_update(&ctx, data, datalen); + + uint8_t res[SHA1_DIGEST_LENGTH] = ""; + sha1_sum(&ctx, res); + + char got[SHA1_DIGEST_LENGTH * 2] = ""; + bytes2hex(res, sizeof(res), got, sizeof(got)); + + if(memcmp(expected, got, SHA1_DIGEST_LENGTH * 2) == 0) + { + printf("ok %d - %s\n", id, name); + return; + } + + err = 1; + + fputs("# Expected: ", stdout); + fwrite(expected, SHA1_DIGEST_LENGTH * 2, 1, stdout); + fputs("\n", stdout); + + fputs("# Got: ", stdout); + fwrite(got, SHA1_DIGEST_LENGTH * 2, 1, stdout); + fputs("\n", stdout); + + printf("not ok %d - %s\n", id, name); +} + +int +main() +{ + int plan = 3; + printf("1..%d\n", plan); + + uint8_t million_a[1000000]; + memset(million_a, 'a', 1000000); + + t_sha1("empty", "", 0, "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + t_sha1("abc", "abc", 3, "a9993e364706816aba3e25717850c26c9cd0d89d"); + t_sha1("million_a", million_a, 1000000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + + assert(counter == plan); + return err; +}