aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-02-25 23:02:34 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2020-02-27 17:40:57 +0200
commita9a6567bac8ab7729c243b555e7fb3c4bb2c6e51 (patch)
tree3c23c862fe8531f8c113526e879aa56fed330c04
parentcc58c3358b9495044af074484dfa17b2fb65f193 (diff)
downloadping903-a9a6567bac8ab7729c243b555e7fb3c4bb2c6e51.tar.gz
ping903-a9a6567bac8ab7729c243b555e7fb3c4bb2c6e51.tar.bz2
Implement basic auth
* Makefile.am (SUBDIRS): Add lib * configure.ac: Build lib/Makefile * lib/Makefile.am: New file. * lib/apr.c: New file. * lib/basicauth.c: New file. * lib/basicauth.h: New file. * lib/md5.c: New file. * lib/md5.h: New file. * lib/sha1.c: New file. * lib/sha1.h: New file. * src/Makefile.am: Add lib to the include path * src/config.c: New statement "auth". * src/ping903.c: Implement basic auth. * src/ping903.h (cf_auth): New proto.
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac2
-rw-r--r--lib/Makefile.am10
-rw-r--r--lib/apr.c196
-rw-r--r--lib/basicauth.c199
-rw-r--r--lib/basicauth.h8
-rw-r--r--lib/md5.c281
-rw-r--r--lib/md5.h15
-rw-r--r--lib/sha1.c418
-rw-r--r--lib/sha1.h83
-rw-r--r--src/Makefile.am4
-rw-r--r--src/config.c1
-rw-r--r--src/ping903.c253
-rw-r--r--src/ping903.h1
14 files changed, 1470 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am
index 7f08c55..f8d42f0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS=src doc
+SUBDIRS=lib src doc
EXTRA_DIST=\
rc/README\
rc/debian.rc\
diff --git a/configure.ac b/configure.ac
index 0831e7e..dd8dc8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,5 +59,5 @@ AC_TYPE_SIZE_T
# Checks for library functions.
AC_CHECK_FUNCS([gettimeofday])
-AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile])
+AC_CONFIG_FILES([Makefile lib/Makefile src/Makefile doc/Makefile])
AC_OUTPUT
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..dd9386d
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,10 @@
+noinst_LIBRARIES = libdigest.a
+libdigest_a_SOURCES = \
+ apr.c\
+ basicauth.c\
+ md5.c\
+ sha1.c
+noinst_HEADERS = \
+ basicauth.h\
+ md5.h\
+ sha1.h
diff --git a/lib/apr.c b/lib/apr.c
new file mode 100644
index 0000000..1036841
--- /dev/null
+++ b/lib/apr.c
@@ -0,0 +1,196 @@
+#include <config.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include "md5.h"
+
+/* APR-specific code */
+
+/*
+ * Define the Magic String prefix that identifies a password as being
+ * hashed using our algorithm.
+ */
+#define APR1_ID_STR "$apr1$"
+#define APR1_ID_LEN (sizeof(APR1_ID_STR)-1)
+
+/*
+ * The following MD5 password encryption code was largely borrowed from
+ * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
+ * licenced as stated at the top of this file.
+ */
+
+static void
+to64(char *s, unsigned long v, int n)
+{
+ static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+#define APR_MD5_DIGESTSIZE 16
+
+char *
+apr_md5_encode(const char *pw, const char *salt, char *result, size_t nbytes)
+{
+ /*
+ * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
+ * plus 4 for the '$' separators, plus the password hash itself.
+ * Let's leave a goodly amount of leeway.
+ */
+
+ char passwd[120], *p;
+ const char *sp, *ep;
+ unsigned char final[APR_MD5_DIGESTSIZE];
+ ssize_t sl, pl, i;
+ MD5_CTX ctx, ctx1;
+ unsigned long l;
+
+ /*
+ * Refine the salt first. It's possible we were given an already-hashed
+ * string as the salt argument, so extract the actual salt value from it
+ * if so. Otherwise just use the string up to the first '$' as the salt.
+ */
+ sp = salt;
+
+ /*
+ * If it starts with the magic string, then skip that.
+ */
+ if (!strncmp(sp, APR1_ID_STR, APR1_ID_LEN)) {
+ sp += APR1_ID_LEN;
+ }
+
+ /*
+ * It stops at the first '$' or 8 chars, whichever comes first
+ */
+ for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++)
+ ;
+
+ /*
+ * Get the length of the true salt
+ */
+ sl = ep - sp;
+
+ /*
+ * 'Time to make the doughnuts..'
+ */
+ MD5Init(&ctx);
+
+ /*
+ * The password first, since that is what is most unknown
+ */
+ MD5Update(&ctx, (unsigned char const*) pw, strlen(pw));
+
+ /*
+ * Then our magic string
+ */
+ MD5Update(&ctx, (unsigned char const*)APR1_ID_STR, APR1_ID_LEN);
+
+ /*
+ * Then the raw salt
+ */
+ MD5Update(&ctx, (unsigned char const*)sp, sl);
+
+ /*
+ * Then just as many characters of the MD5(pw, salt, pw)
+ */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1, (unsigned char const*)pw, strlen(pw));
+ MD5Update(&ctx1, (unsigned char const*)sp, sl);
+ MD5Update(&ctx1, (unsigned char const*)pw, strlen(pw));
+ MD5Final(final, &ctx1);
+ for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
+ MD5Update(&ctx, final,
+ (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
+ }
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ /*
+ * Then something really weird...
+ */
+ for (i = strlen(pw); i != 0; i >>= 1) {
+ if (i & 1)
+ MD5Update(&ctx, final, 1);
+ else
+ MD5Update(&ctx, (unsigned char const*)pw, 1);
+ }
+
+ /*
+ * Now make the output string. We know our limitations, so we
+ * can use the string routines without bounds checking.
+ */
+ strcpy(passwd, APR1_ID_STR);
+ strncat(passwd, sp, sl);
+ strcat(passwd, "$");
+
+ MD5Final(final, &ctx);
+
+ /*
+ * And now, just to make sure things don't run too fast..
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ MD5Init(&ctx1);
+ /*
+ * apr_md5_final clears out ctx1.xlate at the end of each loop,
+ * so need to to set it each time through
+ */
+ if (i & 1)
+ MD5Update(&ctx1, (unsigned char const*)pw, strlen(pw));
+ else
+ MD5Update(&ctx1, final, APR_MD5_DIGESTSIZE);
+ if (i % 3)
+ MD5Update(&ctx1, (unsigned char const*)sp, sl);
+
+ if (i % 7)
+ MD5Update(&ctx1, (unsigned char const*)pw, strlen(pw));
+
+ if (i & 1)
+ MD5Update(&ctx1, final, APR_MD5_DIGESTSIZE);
+ else
+ MD5Update(&ctx1, (unsigned char const*)pw, strlen(pw));
+ MD5Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
+ l = final[11] ; to64(p, l, 2); p += 2;
+ *p = '\0';
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ i = strlen(passwd);
+ if (i >= nbytes)
+ i = nbytes - 1;
+ memcpy(result, passwd, i);
+ result[i] = 0;
+ return result;
+}
+
+#ifdef STANDALONE
+int
+main(int argc, char **argv)
+{
+ unsigned char result[120];
+ if (argc != 3)
+ exit(1);
+ apr_md5_encode(argv[1], argv[2], result, sizeof(result));
+ printf("%s\n",result);
+}
+#endif
diff --git a/lib/basicauth.c b/lib/basicauth.c
new file mode 100644
index 0000000..4d313e6
--- /dev/null
+++ b/lib/basicauth.c
@@ -0,0 +1,199 @@
+#include <config.h>
+#include <errno.h>
+#include <pthread.h>
+#include <crypt.h>
+#include <string.h>
+#include "sha1.h"
+#include "md5.h"
+#include "basicauth.h"
+
+static int b64val[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
+};
+
+static int
+base64_decode(const unsigned char *input, size_t input_len,
+ unsigned char *output, size_t output_len)
+{
+ unsigned char *out = output;
+#define AC(c) do { if (output_len-- == 0) return -1; *out++ = (c); } while (0)
+
+ if (!out)
+ return -1;
+
+ do {
+ if (input[0] > 127 || b64val[input[0]] == -1 ||
+ input[1] > 127 || b64val[input[1]] == -1 ||
+ input[2] > 127 ||
+ ((input[2] != '=') && (b64val[input[2]] == -1)) ||
+ input[3] > 127 ||
+ ((input[3] != '=') && (b64val[input[3]] == -1))) {
+ errno = EINVAL;
+ return -1;
+ }
+ AC((b64val[input[0]] << 2) | (b64val[input[1]] >> 4));
+ if (input[2] != '=') {
+ AC(((b64val[input[1]] << 4) & 0xf0) |
+ (b64val[input[2]] >> 2));
+ if (input[3] != '=')
+ AC(((b64val[input[2]] << 6) & 0xc0) |
+ b64val[input[3]]);
+ }
+ input += 4;
+ input_len -= 4;
+ } while (input_len > 0);
+ return out - output;
+}
+
+static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int
+crypt_match(const char *pass, const char *hash)
+{
+ int res = 1;
+ char *cp;
+
+ pthread_mutex_lock(&crypt_mutex);
+ cp = crypt(pass, hash);
+ if (cp)
+ res = strcmp(cp, hash);
+ pthread_mutex_unlock(&crypt_mutex);
+ return res;
+}
+
+static int
+plain_match(const char *pass, const char *hash)
+{
+ return strcmp(pass, hash);
+}
+
+static int
+apr_match(const char *pass, const char *hash)
+{
+ char buf[120];
+ char *cp = apr_md5_encode(pass, hash, buf, sizeof(buf));
+ return cp ? strcmp(cp, hash) : 1;
+}
+
+#define SHA1_DIGEST_SIZE 20
+
+static int
+sha1_match(const char *pass, const char *hash)
+{
+ char hashbuf[SHA1_DIGEST_SIZE], resbuf[SHA1_DIGEST_SIZE];
+ int n;
+
+ hash += 5; /* Skip past {SHA} */
+ n = base64_decode((const unsigned char *)hash, strlen(hash),
+ (unsigned char *)hashbuf, sizeof(hashbuf));
+ if (n < 0) {
+ /* FIXME: error("cannot decode %s", hash); */
+ return 1;
+ }
+ if (n != SHA1_DIGEST_SIZE) {
+ /* FIXME: error("bad hash length: %s %d", hash, n); */
+ return 1;
+ }
+ sha1_buffer(pass, strlen(pass), resbuf);
+
+ return memcmp(resbuf, hashbuf, SHA1_DIGEST_SIZE);
+}
+
+/* Matcher table */
+struct matcher {
+ char *cm_pfx;
+ size_t cm_len;
+ int (*cm_match)(const char *, const char *);
+};
+
+static struct matcher match_tab[] = {
+#define S(s) #s, sizeof(#s)-1
+ { S($apr1$), apr_match },
+ { S({SHA}), sha1_match },
+ { "", 0, crypt_match },
+ { "", 0, plain_match },
+ { NULL }
+};
+
+static int
+match(const char *pass, const char *hash)
+{
+ struct matcher *p;
+ size_t plen = strlen(hash);
+
+ for (p = match_tab; p->cm_match; p++) {
+ if (p->cm_len < plen &&
+ memcmp(p->cm_pfx, hash, p->cm_len) == 0 &&
+ p->cm_match(pass, hash) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+#define BASICPREF "Basic "
+#define BASICLEN (sizeof(BASICPREF)-1)
+
+BASICAUTH_RESULT
+basicauth(char const *file, char const *input)
+{
+ char buf[1024];
+ char lbuf[1024];
+ char *pass;
+ int n;
+ FILE *fp;
+ BASICAUTH_RESULT rc;
+
+ if (!input || strncmp(input, BASICPREF, BASICLEN))
+ return BASICAUTH_BAD_INPUT;
+ input += BASICLEN;
+ n = base64_decode((const unsigned char *)input, strlen(input),
+ (unsigned char *)buf, sizeof(buf));
+ if (n < 0) {
+ return BASICAUTH_BAD_INPUT;
+ } else if (n == sizeof(buf)) {
+ return BASICAUTH_BAD_INPUT;
+ }
+ buf[n] = 0;
+
+ pass = strchr(buf, ':');
+ if (!pass)
+ return BASICAUTH_BAD_INPUT;
+ *pass++ = 0;
+
+ fp = fopen(file, "r");
+ if (!fp)
+ return BASICAUTH_CANT_OPEN;
+
+ rc = BASICAUTH_DENY;
+ while (fgets(lbuf, sizeof(lbuf), fp)) {
+ char *p, *q;
+ for (p = lbuf; *p && (*p == ' ' || *p == '\t'); p++);
+ if (*p == '#')
+ continue;
+ q = p + strlen(p);
+ if (q == p)
+ continue;
+ if (q[-1] == '\n')
+ *--q = 0;
+ if (!*p)
+ continue;
+ q = strchr(p, ':');
+ if (!q)
+ continue;
+ *q++ = 0;
+ if (strcmp(p, buf))
+ continue;
+ rc = match(pass, q) ? BASICAUTH_DENY : BASICAUTH_ALLOW;
+ break;
+ }
+ fclose(fp);
+ return rc;
+}
+
diff --git a/lib/basicauth.h b/lib/basicauth.h
new file mode 100644
index 0000000..49b504f
--- /dev/null
+++ b/lib/basicauth.h
@@ -0,0 +1,8 @@
+typedef enum {
+ BASICAUTH_ALLOW,
+ BASICAUTH_DENY,
+ BASICAUTH_BAD_INPUT,
+ BASICAUTH_CANT_OPEN
+} BASICAUTH_RESULT;
+
+BASICAUTH_RESULT basicauth(char const *file, char const *input);
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
index 0000000..ea59196
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+/*
+ * Modified (2001-01-31) to work on Sparks <gray@farlep.net>
+ */
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h> /* for memcpy() */
+#include <md5.h>
+
+void
+md5_calc(unsigned char *output, unsigned char const *input,
+ unsigned int inlen)
+{
+ MD5_CTX context;
+
+ MD5Init(&context);
+ MD5Update(&context, input, inlen);
+ MD5Final(output, &context);
+}
+
+
+static void
+bytes_encode(unsigned char *output, uint32_t *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+static void
+bytes_decode(uint32_t *output, unsigned char *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint32_t)input[j]) |
+ (((uint32_t)input[j+1]) << 8) |
+ (((uint32_t)input[j+2]) << 16) |
+ (((uint32_t)input[j+3]) << 24);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ MD5Transform(ctx->buf, (uint32_t const *) buf);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * 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[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+
+ /* Append length in bits and transform */
+ bytes_encode((unsigned char*)((uint32_t *) ctx->in + 14), ctx->bits, 8);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ bytes_encode(digest,ctx->buf,16);
+ memset((char *) ctx, 0, 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 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 );
+
+#if 0
+dump(char *label,unsigned char *p, int len)
+{
+ int i;
+ return;
+ printf("dump: %s\n", label);
+ for (i=0; i<len; i++)
+ printf("%x\n", p[i]);
+ printf("--\n");
+
+}
+#endif
+
+/*
+ * 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 buf[4], uint32_t const cin[16])
+{
+ register uint32_t a, b, c, d;
+ uint32_t in[16];
+
+ bytes_decode(in, (unsigned char *) cin, 64);
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[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);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
diff --git a/lib/md5.h b/lib/md5.h
new file mode 100644
index 0000000..ffbdfb3
--- /dev/null
+++ b/lib/md5.h
@@ -0,0 +1,15 @@
+struct MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+};
+
+typedef struct MD5Context MD5_CTX;
+
+void MD5Init(struct MD5Context *ctx);
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
+void MD5Transform(uint32_t buf[4], uint32_t const cin[16]);
+
+char *apr_md5_encode(const char *pw, const char *salt, char *result,
+ size_t nbytes);
diff --git a/lib/sha1.c b/lib/sha1.c
new file mode 100644
index 0000000..a4380cb
--- /dev/null
+++ b/lib/sha1.c
@@ -0,0 +1,418 @@
+/* sha1.c - Functions to compute SHA1 message digest of files or
+ memory blocks according to the NIST specification FIPS-180-1.
+
+ Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Scott G. Miller
+ Credits:
+ Robert Klep <robert@ilse.nl> -- Expansion function fix
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sha1.h>
+
+#include <stddef.h>
+#include <string.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) (n)
+#else
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#endif
+
+#define BLOCKSIZE 4096
+#if BLOCKSIZE % 64 != 0
+# error "invalid BLOCKSIZE"
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
+ initialize it to the start constants of the SHA1 algorithm. This
+ must be called before using hash in the call to sha1_hash. */
+void
+sha1_init_ctx (struct sha1_ctx *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+ ctx->E = 0xc3d2e1f0;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 20 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32-bit value. */
+void *
+sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf)
+{
+ ((uint32_t *) resbuf)[0] = SWAP (ctx->A);
+ ((uint32_t *) resbuf)[1] = SWAP (ctx->B);
+ ((uint32_t *) resbuf)[2] = SWAP (ctx->C);
+ ((uint32_t *) resbuf)[3] = SWAP (ctx->D);
+ ((uint32_t *) resbuf)[4] = SWAP (ctx->E);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32-bit value. */
+void *
+sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ uint32_t bytes = ctx->buflen;
+ size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
+ ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3);
+
+ memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
+
+ /* Process last bytes. */
+ sha1_process_block (ctx->buffer, size * 4, ctx);
+
+ return sha1_read_ctx (ctx, resbuf);
+}
+
+/* Compute SHA1 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+sha1_stream (FILE *stream, void *resblock)
+{
+ struct sha1_ctx ctx;
+ char buffer[BLOCKSIZE + 72];
+ size_t sum;
+
+ /* Initialize the computation context. */
+ sha1_init_ctx (&ctx);
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ while (1)
+ {
+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+
+ if (sum == BLOCKSIZE)
+ break;
+
+ if (n == 0)
+ {
+ /* Check for the error flag IFF N == 0, so that we don't
+ exit the loop after a partial read due to e.g., EAGAIN
+ or EWOULDBLOCK. */
+ if (ferror (stream))
+ return 1;
+ goto process_partial_block;
+ }
+
+ /* We've read at least one byte, so ignore errors. But always
+ check for EOF, since feof may be true even though N > 0.
+ Otherwise, we could end up calling fread after EOF. */
+ if (feof (stream))
+ goto process_partial_block;
+ }
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ sha1_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ process_partial_block:;
+
+ /* Process any remaining bytes. */
+ if (sum > 0)
+ sha1_process_bytes (buffer, sum, &ctx);
+
+ /* Construct result in desired memory. */
+ sha1_finish_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+sha1_buffer (const char *buffer, size_t len, void *resblock)
+{
+ struct sha1_ctx ctx;
+
+ /* Initialize the computation context. */
+ sha1_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ sha1_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return sha1_finish_ctx (&ctx, resblock);
+}
+
+void
+sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64)
+ {
+ sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer,
+ &((char *) ctx->buffer)[(left_over + add) & ~63],
+ ctx->buflen);
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 64)
+ {
+#if !_STRING_ARCH_unaligned
+# define alignof(type) offsetof (struct { char c; type x; }, x)
+# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0)
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+#endif
+ {
+ sha1_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ size_t left_over = ctx->buflen;
+
+ memcpy (&((char *) ctx->buffer)[left_over], buffer, len);<