From 9db33d96f449348a865282b87055fab9d95eba5c 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   |    2 +
 md5.h      |   30 ++++++++
 md5sum.1   |    8 ++
 md5sum.c   |   65 ++++++++++++++++
 util/md5.c |  247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 352 insertions(+)
 create mode 100644 md5.h
 create mode 100644 md5sum.1
 create mode 100644 md5sum.c
 create mode 100644 util/md5.c

diff --git a/Makefile b/Makefile
index 4c45ff6..55c485d 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@ LIB = \
 	util/estrtol.o   \
 	util/fnck.o      \
 	util/getlines.o  \
+	util/md5.o       \
 	util/putword.o   \
 	util/recurse.o   \
 	util/rm.o
@@ -43,6 +44,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..d964061
--- /dev/null
+++ b/md5.h
@@ -0,0 +1,30 @@
+/*	$OpenBSD: md5.h,v 1.2 2012/12/05 23:20:15 deraadt Exp $	*/
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+
+#define MD5_BLOCK_LENGTH 64
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct MD5Context {
+	/* state */
+	uint32_t state[4];
+	/* number of bits, mod 2^64 */
+	uint64_t count;
+	/* input buffer */
+	uint8_t buffer[MD5_BLOCK_LENGTH];
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, const uint8_t *, size_t);
+void MD5Final(uint8_t [MD5_DIGEST_LENGTH], MD5_CTX *);
+void MD5Transform(uint32_t [4], const uint8_t [MD5_BLOCK_LENGTH]);
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..ff27183
--- /dev/null
+++ b/md5sum.c
@@ -0,0 +1,65 @@
+/* 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 "md5.h"
+#include "util.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 digest[MD5_DIGEST_LENGTH];
+	unsigned char buf[BUFSIZ];
+	MD5_CTX md5_ctx;
+	ssize_t n;
+	int i;
+
+	MD5Init(&md5_ctx);
+	while ((n = read(fd, buf, sizeof buf)) > 0)
+		MD5Update(&md5_ctx, buf, n);
+	if (n < 0) {
+		eprintf("%s: read error:", s);
+		return;
+	}
+	MD5Final(digest, &md5_ctx);
+	for (i = 0; i < MD5_DIGEST_LENGTH; 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..568174b
--- /dev/null
+++ b/util/md5.c
@@ -0,0 +1,247 @@
+/*	$OpenBSD: md5.c,v 1.2 2011/01/11 15:42:05 deraadt Exp $	*/
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdint.h>
+
+#include "../md5.h"
+
+#define PUT_64BIT_LE(cp, value) do {		\
+		(cp)[7] = (value) >> 56;	\
+		(cp)[6] = (value) >> 48;	\
+		(cp)[5] = (value) >> 40;	\
+		(cp)[4] = (value) >> 32;	\
+		(cp)[3] = (value) >> 24;	\
+		(cp)[2] = (value) >> 16;	\
+		(cp)[1] = (value) >> 8;		\
+		(cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do {		\
+		(cp)[3] = (value) >> 24;	\
+		(cp)[2] = (value) >> 16;	\
+		(cp)[1] = (value) >> 8;		\
+		(cp)[0] = (value); } while (0)
+
+static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(MD5_CTX *ctx)
+{
+	ctx->count = 0;
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
+{
+	size_t have, need;
+
+	/* Check how many bytes we already have and how many more we need. */
+	have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+	need = MD5_BLOCK_LENGTH - have;
+
+	/* Update bitcount */
+	ctx->count += (uint64_t)len << 3;
+
+	if (len >= need) {
+		if (have != 0) {
+			bcopy(input, ctx->buffer + have, need);
+			MD5Transform(ctx->state, ctx->buffer);
+			input += need;
+			len -= need;
+			have = 0;
+		}
+
+		/* Process data in MD5_BLOCK_LENGTH-byte chunks. */
+		while (len >= MD5_BLOCK_LENGTH) {
+			MD5Transform(ctx->state, input);
+			input += MD5_BLOCK_LENGTH;
+			len -= MD5_BLOCK_LENGTH;
+		}
+	}
+
+	/* Handle any remaining bytes of data. */
+	if (len != 0)
+		bcopy(input, ctx->buffer + have, len);
+}
+
+/* explicit_bzero - don't let the compiler optimize away bzero */
+static void
+explicit_bzero(void *p, size_t n)
+{
+	bzero(p, n);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
+{
+	uint8_t count[8];
+	size_t padlen;
+	int i;
+
+	/* Convert count to 8 bytes in little endian order. */
+	PUT_64BIT_LE(count, ctx->count);
+
+	/* Pad out to 56 mod 64. */
+	padlen = MD5_BLOCK_LENGTH -
+		((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+	if (padlen < 1 + 8)
+		padlen += MD5_BLOCK_LENGTH;
+	MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
+	MD5Update(ctx, count, 8);
+
+	if (digest != NULL) {
+		for (i = 0; i < 4; i++)
+			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+	}
+	explicit_bzero(ctx, sizeof(*ctx)); /* in case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
+{
+	uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+	bcopy(block, in, sizeof(in));
+#else
+	for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
+		in[a] = (uint32_t)(
+			(uint32_t)(block[a * 4 + 0]) |
+			(uint32_t)(block[a * 4 + 1]) <<  8 |
+			(uint32_t)(block[a * 4 + 2]) << 16 |
+			(uint32_t)(block[a * 4 + 3]) << 24);
+	}
+#endif
+
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+
+	MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
+	MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
+	MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
+	MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
+	MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
+	MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
+	MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
+	MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
+	MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
+	MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
+	MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
+	MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
+	MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
-- 
1.7.10.4

