From aebcb9b4474703f55764db8f41dcabcf7044b87d Mon Sep 17 00:00:00 2001
From: stateless <stateless@archlinux.us>
Date: Wed, 19 Jun 2013 09:54:52 +0100
Subject: [PATCH] Add md5sum

No support for -c at the moment.
---
 Makefile        |    3 +
 md5.h           |   16 ++++
 md5sum.1        |    8 ++
 md5sum.c        |   67 ++++++++++++++
 util/md5.c      |  148 ++++++++++++++++++++++++++++++
 util/md5block.c |  269 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 511 insertions(+)
 create mode 100644 md5.h
 create mode 100644 md5sum.1
 create mode 100644 md5sum.c
 create mode 100644 util/md5.c
 create mode 100644 util/md5block.c

diff --git a/Makefile b/Makefile
index 4c45ff6..ff37a7b 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,8 @@ LIB = \
 	util/estrtol.o   \
 	util/fnck.o      \
 	util/getlines.o  \
+	util/md5.o       \
+	util/md5block.o  \
 	util/putword.o   \
 	util/recurse.o   \
 	util/rm.o
@@ -43,6 +45,7 @@ SRC = \
 	ln.c       \
 	ls.c       \
 	mc.c       \
+	md5sum.c   \
 	mkdir.c    \
 	mkfifo.c   \
 	mv.c       \
diff --git a/md5.h b/md5.h
new file mode 100644
index 0000000..67c3296
--- /dev/null
+++ b/md5.h
@@ -0,0 +1,16 @@
+enum { MD5dlen = 16 };
+
+typedef struct DigestState DigestState;
+struct DigestState
+{
+	unsigned long len;
+	uint32_t state[5];
+	unsigned char buf[128];
+	int blen;
+	char malloced;
+	char seeded;
+};
+typedef struct DigestState MD5state;
+
+DigestState *md5(unsigned char *, unsigned long, unsigned char *,
+		 DigestState *);
diff --git a/md5sum.1 b/md5sum.1
new file mode 100644
index 0000000..070aa65
--- /dev/null
+++ b/md5sum.1
@@ -0,0 +1,8 @@
+.TH MD5SUM 1 sbase\-VERSION
+.SH NAME
+md5sum \- compute MD5 message digest
+.SH SYNOPSIS
+.B md5sum
+.RI [ file ...]
+.SH DESCRIPTION
+Print MD5 (128-bit) checksums. With no FILE, read standard input.
diff --git a/md5sum.c b/md5sum.c
new file mode 100644
index 0000000..f0e35f2
--- /dev/null
+++ b/md5sum.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 "md5.h"
+
+static void md5sum(int fd, const char *s);
+
+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) {
+		md5sum(STDIN_FILENO, "<stdin>");
+	} else {
+		for (; argc > 0; argc--) {
+			if ((fd = open(*argv, O_RDONLY)) < 0)
+				eprintf("open %s:", *argv);
+			md5sum(fd, *argv);
+			close(fd);
+			argv++;
+		}
+	}
+
+	return 0;
+}
+
+static void
+md5sum(int fd, const char *s)
+{
+	unsigned char buf[BUFSIZ];
+	unsigned char digest[MD5dlen];
+	DigestState *ds;
+	ssize_t n;
+	int i;
+
+	ds = md5(NULL, 0, NULL, NULL);
+	while ((n = read(fd, buf, sizeof buf)) > 0)
+		md5(buf, n, NULL, ds);
+	if (n < 0) {
+		eprintf("%s: read error:", s);
+		return;
+	}
+
+	md5(NULL, 0, digest, ds);
+
+	for (i = 0; i < MD5dlen; i++)
+		printf("%02x", digest[i]);
+	printf("  %s\n", s);
+}
diff --git a/util/md5.c b/util/md5.c
new file mode 100644
index 0000000..f97457f
--- /dev/null
+++ b/util/md5.c
@@ -0,0 +1,148 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "../md5.h"
+
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+
+static void encode(unsigned char *, uint32_t *, unsigned long);
+extern void _md5block(unsigned char *, unsigned long, uint32_t *);
+
+MD5state*
+md5(unsigned char *p, unsigned long len, unsigned char *digest, MD5state *s)
+{
+	uint32_t x[16];
+	unsigned char buf[128];
+	int i;
+	unsigned char *e;
+
+	if(s == NULL){
+		s = malloc(sizeof(*s));
+		if(s == NULL)
+			return NULL;
+		memset(s, 0, sizeof(*s));
+		s->malloced = 1;
+	}
+
+	if(s->seeded == 0){
+		/* seed the state, these constants would look nicer big-endian */
+		s->state[0] = 0x67452301;
+		s->state[1] = 0xefcdab89;
+		s->state[2] = 0x98badcfe;
+		s->state[3] = 0x10325476;
+		s->seeded = 1;
+	}
+
+	/* fill out the partial 64 byte block from previous calls */
+	if(s->blen){
+		i = 64 - s->blen;
+		if(len < i)
+			i = len;
+		memmove(s->buf + s->blen, p, i);
+		len -= i;
+		s->blen += i;
+		p += i;
+		if(s->blen == 64){
+			_md5block(s->buf, s->blen, s->state);
+			s->len += s->blen;
+			s->blen = 0;
+		}
+	}
+
+	/* do 64 byte blocks */
+	i = len & ~0x3f;
+	if(i){
+		_md5block(p, i, s->state);
+		s->len += i;
+		len -= i;
+		p += i;
+	}
+
+	/* save the left overs if not last call */
+	if(digest == 0){
+		if(len){
+			memmove(s->buf, p, len);
+			s->blen += len;
+		}
+		return s;
+	}
+
+	/*
+	 *  this is the last time through, pad what's left with 0x80,
+	 *  0's, and the input count to create a multiple of 64 bytes
+	 */
+	if(s->blen){
+		p = s->buf;
+		len = s->blen;
+	} else {
+		memmove(buf, p, len);
+		p = buf;
+	}
+	s->len += len;
+	e = p + len;
+	if(len < 56)
+		i = 56 - len;
+	else
+		i = 120 - len;
+	memset(e, 0, i);
+	*e = 0x80;
+	len += i;
+
+	/* append the count */
+	x[0] = s->len<<3;
+	x[1] = s->len>>29;
+	encode(p+len, x, 8);
+
+	/* digest the last part */
+	_md5block(p, len+8, s->state);
+	s->len += len;
+
+	/* return result and free state */
+	encode(digest, s->state, MD5dlen);
+	if(s->malloced == 1)
+		free(s);
+	return NULL;
+}
+
+/*
+ *	encodes input (uint32_t) into output (unsigned char). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+encode(unsigned char *output, uint32_t *input, unsigned long len)
+{
+	uint32_t x;
+	unsigned char *e;
+
+	for(e = output + len; output < e;) {
+		x = *input++;
+		*output++ = x;
+		*output++ = x >> 8;
+		*output++ = x >> 16;
+		*output++ = x >> 24;
+	}
+}
diff --git a/util/md5block.c b/util/md5block.c
new file mode 100644
index 0000000..e018993
--- /dev/null
+++ b/util/md5block.c
@@ -0,0 +1,269 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "../md5.h"
+
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+
+/*
+ *	Rotate ammounts used in the algorithm
+ */
+enum
+{
+	S11=	7,
+	S12=	12,
+	S13=	17,
+	S14=	22,
+
+	S21=	5,
+	S22=	9,
+	S23=	14,
+	S24=	20,
+
+	S31=	4,
+	S32=	11,
+	S33=	16,
+	S34=	23,
+
+	S41=	6,
+	S42=	10,
+	S43=	15,
+	S44=	21
+};
+
+static uint32_t md5tab[] =
+{
+	/* round 1 */
+/*[0]*/	0xd76aa478,
+	0xe8c7b756,
+	0x242070db,
+	0xc1bdceee,
+	0xf57c0faf,
+	0x4787c62a,
+	0xa8304613,
+	0xfd469501,
+	0x698098d8,
+	0x8b44f7af,
+	0xffff5bb1,
+	0x895cd7be,
+	0x6b901122,
+	0xfd987193,
+	0xa679438e,
+	0x49b40821,
+
+	/* round 2 */
+/*[16]*/0xf61e2562,
+	0xc040b340,
+	0x265e5a51,
+	0xe9b6c7aa,
+	0xd62f105d,
+	 0x2441453,
+	0xd8a1e681,
+	0xe7d3fbc8,
+	0x21e1cde6,
+	0xc33707d6,
+	0xf4d50d87,
+	0x455a14ed,
+	0xa9e3e905,
+	0xfcefa3f8,
+	0x676f02d9,
+	0x8d2a4c8a,
+
+	/* round 3 */
+/*[32]*/0xfffa3942,
+	0x8771f681,
+	0x6d9d6122,
+	0xfde5380c,
+	0xa4beea44,
+	0x4bdecfa9,
+	0xf6bb4b60,
+	0xbebfbc70,
+	0x289b7ec6,
+	0xeaa127fa,
+	0xd4ef3085,
+	 0x4881d05,
+	0xd9d4d039,
+	0xe6db99e5,
+	0x1fa27cf8,
+	0xc4ac5665,
+
+	/* round 4 */
+/*[48]*/0xf4292244,
+	0x432aff97,
+	0xab9423a7,
+	0xfc93a039,
+	0x655b59c3,
+	0x8f0ccc92,
+	0xffeff47d,
+	0x85845dd1,
+	0x6fa87e4f,
+	0xfe2ce6e0,
+	0xa3014314,
+	0x4e0811a1,
+	0xf7537e82,
+	0xbd3af235,
+	0x2ad7d2bb,
+	0xeb86d391,
+};
+
+static void decode(uint32_t *, unsigned char *, unsigned long);
+extern void _md5block(unsigned char *p, unsigned long len, uint32_t *s);
+
+void
+_md5block(unsigned char *p, unsigned long len, uint32_t *s)
+{
+	uint32_t a, b, c, d, sh;
+	uint32_t *t;
+	unsigned char *end;
+	uint32_t x[16];
+
+	for(end = p+len; p < end; p += 64){
+		a = s[0];
+		b = s[1];
+		c = s[2];
+		d = s[3];
+
+		decode(x, p, 64);
+
+		t = md5tab;
+		sh = 0;
+		for(; sh != 16; t += 4){
+			a += ((c ^ d) & b) ^ d;
+			a += x[sh] + t[0];
+			a = (a << S11) | (a >> (32 - S11));
+			a += b;
+
+			d += ((b ^ c) & a) ^ c;
+			d += x[sh + 1] + t[1];
+			d = (d << S12) | (d >> (32 - S12));
+			d += a;
+
+			c += ((a ^ b) & d) ^ b;
+			c += x[sh + 2] + t[2];
+			c = (c << S13) | (c >> (32 - S13));
+			c += d;
+
+			b += ((d ^ a) & c) ^ a;
+			b += x[sh + 3] + t[3];
+			b = (b << S14) | (b >> (32 - S14));
+			b += c;
+
+			sh += 4;
+		}
+		sh = 1;
+		for(; sh != 1+20*4; t += 4){
+			a += ((b ^ c) & d) ^ c;
+			a += x[sh & 0xf] + t[0];
+			a = (a << S21) | (a >> (32 - S21));
+			a += b;
+
+			d += ((a ^ b) & c) ^ b;
+			d += x[(sh + 5) & 0xf] + t[1];
+			d = (d << S22) | (d >> (32 - S22));
+			d += a;
+
+			c += ((d ^ a) & b) ^ a;
+			c += x[(sh + 10) & 0xf] + t[2];
+			c = (c << S23) | (c >> (32 - S23));
+			c += d;
+
+			b += ((c ^ d) & a) ^ d;
+			b += x[(sh + 15) & 0xf] + t[3];
+			b = (b << S24) | (b >> (32 - S24));
+			b += c;
+
+			sh += 20;
+		}
+		sh = 5;
+		for(; sh != 5+12*4; t += 4){
+			a += b ^ c ^ d;
+			a += x[sh & 0xf] + t[0];
+			a = (a << S31) | (a >> (32 - S31));
+			a += b;
+
+			d += a ^ b ^ c;
+			d += x[(sh + 3) & 0xf] + t[1];
+			d = (d << S32) | (d >> (32 - S32));
+			d += a;
+
+			c += d ^ a ^ b;
+			c += x[(sh + 6) & 0xf] + t[2];
+			c = (c << S33) | (c >> (32 - S33));
+			c += d;
+
+			b += c ^ d ^ a;
+			b += x[(sh + 9) & 0xf] + t[3];
+			b = (b << S34) | (b >> (32 - S34));
+			b += c;
+
+			sh += 12;
+		}
+		sh = 0;
+		for(; sh != 28*4; t += 4){
+			a += c ^ (b | ~d);
+			a += x[sh & 0xf] + t[0];
+			a = (a << S41) | (a >> (32 - S41));
+			a += b;
+
+			d += b ^ (a | ~c);
+			d += x[(sh + 7) & 0xf] + t[1];
+			d = (d << S42) | (d >> (32 - S42));
+			d += a;
+
+			c += a ^ (d | ~b);
+			c += x[(sh + 14) & 0xf] + t[2];
+			c = (c << S43) | (c >> (32 - S43));
+			c += d;
+
+			b += d ^ (c | ~a);
+			b += x[(sh + 21) & 0xf] + t[3];
+			b = (b << S44) | (b >> (32 - S44));
+			b += c;
+
+			sh += 28;
+		}
+
+		s[0] += a;
+		s[1] += b;
+		s[2] += c;
+		s[3] += d;
+	}
+}
+
+/*
+ *	decodes input (unsigned char) into output (uint32_t). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+decode(uint32_t *output, unsigned char *input, unsigned long len)
+{
+	unsigned char *e;
+
+	for(e = input+len; input < e; input += 4)
+		*output++ = input[0] | (input[1] << 8) |
+			(input[2] << 16) | (input[3] << 24);
+}
-- 
1.7.10.4

