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