diff options
author | Thomas Voss <mail@thomasvoss.com> | 2024-08-15 17:10:10 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2024-08-15 17:10:10 +0200 |
commit | c0e5d9280dd156631bd398463dbb6a65aff37d19 (patch) | |
tree | 6883a55241a95fa9a2314b8d6189d2aa492e888f /c/sha1/sha1-naïve.c | |
parent | a97a4077ddc33f2abd53a37540158d4448adf915 (diff) |
Implement SHA-1
Diffstat (limited to 'c/sha1/sha1-naïve.c')
-rw-r--r-- | c/sha1/sha1-naïve.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/c/sha1/sha1-naïve.c b/c/sha1/sha1-naïve.c new file mode 100644 index 0000000..6f1f257 --- /dev/null +++ b/c/sha1/sha1-naïve.c @@ -0,0 +1,140 @@ +#include <endian.h> +#include <errno.h> +#include <string.h> + +#include "sha1.h" + +#define lengthof(xs) (sizeof(xs) / sizeof(*(xs))) +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +static void sha1hashblk(sha1_t *, const uint8_t *); + +static const uint32_t K[] = { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6, +}; + +static inline uint32_t +rotl32(uint32_t x, uint8_t bits) +{ +#if (__GNUC__ || __TINYC__) && __x86_64__ + asm ("roll %1, %0" : "+r" (x) : "c" (bits) : "cc"); + return x; +#else + return (x << bits) | (x >> (32 - bits)); +#endif +} + +void +sha1init(sha1_t *s) +{ + static const uint32_t H[] = { + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0, + }; + memcpy(s->dgst, H, sizeof(H)); + s->msgsz = s->bufsz = 0; +} + +int +sha1hash(sha1_t *s, const uint8_t *msg, size_t msgsz) +{ + if (s->msgsz + (msgsz * 8) < s->msgsz) + return EOVERFLOW; + + s->msgsz += msgsz * 8; + + while (msgsz != 0) { + size_t free_space = SHA1BLKSZ - s->bufsz; + size_t ncpy = MIN(msgsz, free_space); + memcpy(s->buf + s->bufsz, msg, ncpy); + s->bufsz += ncpy; + msg += ncpy; + msgsz -= ncpy; + + if (s->bufsz == SHA1BLKSZ) { + sha1hashblk(s, s->buf); + s->bufsz = 0; + } + } + + return 0; +} + +void +sha1end(sha1_t *s, uint8_t dgst[SHA1DGSTSZ]) +{ + s->buf[s->bufsz++] = 0x80; + + if (s->bufsz > SHA1BLKSZ - sizeof(uint64_t)) { + while (s->bufsz < SHA1BLKSZ) + s->buf[s->bufsz++] = 0; + sha1hashblk(s, s->buf); + s->bufsz = 0; + } + + while (s->bufsz < 56) + s->buf[s->bufsz++] = 0; + ((uint64_t *)s->buf)[SHA1BLKSZ/8 - 1] = htobe64(s->msgsz); + + sha1hashblk(s, s->buf); + + for (int i = 0; i < lengthof(s->dgst); i++) + ((uint32_t *)dgst)[i] = htobe32(s->dgst[i]); +} + +static void +sha1hashblk(sha1_t *s, const uint8_t *blk) +{ + uint32_t w[80]; + uint32_t a, b, c, d, e, tmp; + + for (int i = 0; i < 16; i++) + w[i] = htobe32(((uint32_t *)blk)[i]); + for (int i = 16; i < 32; i++) + w[i] = rotl32(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1); + for (int i = 32; i < 80; i++) + w[i] = rotl32(w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32], 2); + + a = s->dgst[0]; + b = s->dgst[1]; + c = s->dgst[2]; + d = s->dgst[3]; + e = s->dgst[4]; + + for (int i = 0; i < 80; i++) { + uint32_t f, k; + + if (i < 20) { + f = b&c | ~b&d; + k = K[0]; + } else if (i < 40) { + f = b ^ c ^ d; + k = K[1]; + } else if (i < 60) { + f = b&c | b&d | c&d; + k = K[2]; + } else { + f = b ^ c ^ d; + k = K[3]; + } + + tmp = rotl32(a, 5) + f + e + w[i] + k; + e = d; + d = c; + c = rotl32(b, 30); + b = a; + a = tmp; + } + + s->dgst[0] += a; + s->dgst[1] += b; + s->dgst[2] += c; + s->dgst[3] += d; + s->dgst[4] += e; +} |