sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit eec1b415d5fac8deee51eae51d245d6184a31d74
parent 50054a652ca1ef9659304fadef2772f90a16aef5
Author: stateless <stateless@archlinux.us>
Date:   Thu Jul  4 12:14:14 +0100

Add sha1sum

No support for -c at the moment.

Diffstat:
Makefile | 4+++-
sha1.h | 18++++++++++++++++++
sha1sum.1 | 8++++++++
sha1sum.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
util/sha1.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 230 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile @@ -18,7 +18,8 @@ LIB = \ util/md5.o \ util/putword.o \ util/recurse.o \ - util/rm.o + util/rm.o \ + util/sha1.o SRC = \ basename.c \ @@ -76,6 +77,7 @@ SRC = \ uniq.c \ unlink.c \ seq.c \ + sha1sum.c \ wc.c \ who.c \ yes.c diff --git a/sha1.h b/sha1.h @@ -0,0 +1,18 @@ +/* public domain sha1 implementation based on rfc3174 and libtomcrypt */ + +struct sha1 { + uint64_t len; /* processed message length */ + uint32_t h[5]; /* hash state */ + uint8_t buf[64]; /* message block buffer */ +}; + +enum { SHA1_DIGEST_LENGTH = 20 }; + +/* reset state */ +void sha1_init(struct sha1 *s); +/* process message */ +void sha1_update(struct sha1 *s, 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(struct sha1 *s, uint8_t md[SHA1_DIGEST_LENGTH]); diff --git a/sha1sum.1 b/sha1sum.1 @@ -0,0 +1,8 @@ +.TH SHA1SUM 1 sbase\-VERSION +.SH NAME +sha1sum \- compute SHA-1 message digest +.SH SYNOPSIS +.B sha1sum +.RI [ file ...] +.SH DESCRIPTION +Print SHA-1 (160-bit) checksums. With no file, read standard input. diff --git a/sha1sum.c b/sha1sum.c @@ -0,0 +1,67 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include "util.h" +#include "sha1.h" + +static void sha1sum(int fd, const char *f); + +static void +usage(void) +{ + eprintf("usage: %s [file...]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int fd; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if (argc == 0) { + sha1sum(STDIN_FILENO, "<stdin>"); + } else { + for (; argc > 0; argc--) { + if ((fd = open(*argv, O_RDONLY)) < 0) + eprintf("open %s:", *argv); + sha1sum(fd, *argv); + close(fd); + argv++; + } + } + + return 0; +} + +static void +sha1sum(int fd, const char *f) +{ + unsigned char buf[BUFSIZ]; + unsigned char digest[SHA1_DIGEST_LENGTH]; + struct sha1 s; + ssize_t n; + int i; + + sha1_init(&s); + while ((n = read(fd, buf, sizeof buf)) > 0) + sha1_update(&s, buf, n); + if (n < 0) { + eprintf("%s: read error:", f); + return; + } + + sha1_sum(&s, digest); + + for (i = 0; i < sizeof(digest); i++) + printf("%02x", digest[i]); + printf(" %s\n", f); +} diff --git a/util/sha1.c b/util/sha1.c @@ -0,0 +1,134 @@ +/* public domain sha1 implementation based on rfc3174 and libtomcrypt */ +#include <stdint.h> +#include <string.h> +#include "../sha1.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++); + } + for (; 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++); + } + for (; 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++); + } + for (; 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(struct sha1 *s) +{ + 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(struct sha1 *s, uint8_t md[20]) +{ + 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(struct sha1 *s, const void *m, unsigned long len) +{ + 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); +}