View Issue Details

IDProjectCategoryView StatusLast Update
0003090SOGoBackend Generalpublic2016-05-12 15:32
ReporterBigio Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
PlatformOpenBSDOSOpenBSDOS Version5.6
Product Version2.2.15 
Summary0003090: Unable to authenticate on OpenBSD with UserPasswordAlgotithm = md5-crypt
Description

Starting from OpenBSD 5.6 md5-crypt has been remove from crypt(3).
Because of this I am unable to authenticate on OpenBSD with UserPasswordAlgotithm = md5-crypt, this is useful to be able to be able to interact with other operating systems that do not supports bcrypt(3).
This patch reintroduce support for md5-crypt algorithm.

TagsNo tags attached.

Activities

Bigio

Bigio

2015-02-03 15:58

reporter  

sogo-md5crypt.diff (6,825 bytes)   
--- /dev/null	Tue Feb  3 16:54:26 2015
+++ SoObjects/SOGo/md5crypt.h	Tue Feb  3 16:52:38 2015
@@ -0,0 +1,36 @@
+/*	$OpenBSD: md5crypt.c,v 1.17 2014/04/03 15:55:29 beck Exp $	*/
+
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * If we meet some day, and you think this stuff is worth it, you
+ * can buy me a beer in return. Poul-Henning Kamp
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <md5.h>
+#include <string.h>
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *md5crypt(const char *pw, const char *salt);
--- /dev/null	Tue Feb  3 16:54:31 2015
+++ SoObjects/SOGo/md5crypt.m	Tue Feb  3 16:52:38 2015
@@ -0,0 +1,153 @@
+/*	$OpenBSD: md5crypt.c,v 1.17 2014/04/03 15:55:29 beck Exp $	*/
+
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * If we meet some day, and you think this stuff is worth it, you
+ * can buy me a beer in return. Poul-Henning Kamp
+ */
+
+#include "md5crypt.h"
+
+static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void to64(char *, u_int32_t, int);
+
+static void
+to64(char *s, u_int32_t v, int n)
+{
+	while (--n >= 0) {
+		*s++ = itoa64[v&0x3f];
+		v >>= 6;
+	}
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *
+md5crypt(const char *pw, const char *salt)
+{
+	/*
+	 * This string is the magic for this algorithm.
+	 * Having it this way, we can get better later on.
+	 */
+	static unsigned char	*magic = (unsigned char *)"$1$";
+
+	static char     passwd[120], *p;
+	static const unsigned char *sp,*ep;
+	unsigned char	final[16];
+	int sl,pl,i;
+	MD5_CTX	ctx,ctx1;
+	u_int32_t l;
+
+	/* Refine the salt first */
+	sp = (const unsigned char *)salt;
+
+	/* If it starts with the magic string, then skip that */
+	if(!strncmp((const char *)sp,(const char *)magic,strlen((const char *)magic)))
+		sp += strlen((const char *)magic);
+
+	/* It stops at the first '$', max 8 chars */
+	for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+		continue;
+
+	/* get the length of the true salt */
+	sl = ep - sp;
+
+	MD5Init(&ctx);
+
+	/* The password first, since that is what is most unknown */
+	MD5Update(&ctx,(const unsigned char *)pw,strlen(pw));
+
+	/* Then our magic string */
+	MD5Update(&ctx,magic,strlen((const char *)magic));
+
+	/* Then the raw salt */
+	MD5Update(&ctx,sp,sl);
+
+	/* Then just as many characters of the MD5(pw,salt,pw) */
+	MD5Init(&ctx1);
+	MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+	MD5Update(&ctx1,sp,sl);
+	MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+	MD5Final(final,&ctx1);
+	for(pl = strlen(pw); pl > 0; pl -= 16)
+		MD5Update(&ctx,final,pl>16 ? 16 : 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 ; i >>= 1)
+		if(i&1)
+		    MD5Update(&ctx, final, 1);
+		else
+		    MD5Update(&ctx, (const unsigned char *)pw, 1);
+
+	/* Now make the output string */
+	snprintf(passwd, sizeof(passwd), "%s%.*s$", (char *)magic,
+	    sl, (const char *)sp);
+
+	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...
+	 * On a modern machine, with possible GPU optimization,
+	 * this will run a lot faster than that.
+	 */
+	for(i=0;i<1000;i++) {
+		MD5Init(&ctx1);
+		if(i & 1)
+			MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+		else
+			MD5Update(&ctx1,final,16);
+
+		if(i % 3)
+			MD5Update(&ctx1,sp,sl);
+
+		if(i % 7)
+			MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+
+		if(i & 1)
+			MD5Update(&ctx1,final,16);
+		else
+			MD5Update(&ctx1,(const unsigned char *)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);
+
+	return passwd;
+}
--- SoObjects/SOGo/NSData+Crypto.m.orig	Tue Dec 30 14:08:51 2014
+++ SoObjects/SOGo/NSData+Crypto.m	Tue Feb  3 16:52:24 2015
@@ -559,7 +559,11 @@
 
   saltString = [[NSString alloc] initWithData: saltData  encoding: NSUTF8StringEncoding];
 
+#ifdef __OpenBSD__ 
+  buf = md5crypt([cryptString UTF8String], [saltString UTF8String]);
+#else
   buf = crypt([cryptString UTF8String], [saltString UTF8String]);
+#endif
   [cryptString release];
   [saltString release];
   if (!buf)
@@ -589,6 +593,11 @@
   // The salt is weak here, but who cares anyway, crypt should not
   // be used anymore
   buf = crypt([cryptString UTF8String], [saltString UTF8String]);
+#ifdef __OpenBSD__
+  if (!buf) {
+       buf = md5crypt([cryptString UTF8String], [saltString UTF8String]);
+  }
+#endif
   [saltString release];
   [cryptString release];
   if (!buf)
sogo-md5crypt.diff (6,825 bytes)   
buzzdee

buzzdee

2015-02-05 12:48

reporter   ~0008139

I think you are missing the part of the patch to the GNUmakefile ;)

I'm also not 100% sure, if the

#include md5crypt.h

is missing, NSData+Crypto.m, don't you get a warning when compiling, for the line where md5crypt is used?

Bigio

Bigio

2015-02-05 13:55

reporter  

sogo.diff (6,221 bytes)   
--- SoObjects/SOGo/GNUmakefile.orig	Tue Dec 30 14:08:51 2014
+++ SoObjects/SOGo/GNUmakefile	Thu Feb  5 14:51:29 2015
@@ -86,6 +86,7 @@
 	@touch SOGoBuild.m
 
 SOGo_OBJC_FILES = \
+	md5crypt.m \
 	SOGoBuild.m \
 	SOGoProductLoader.m		\
 	\
--- /dev/null	Thu Feb  5 14:53:27 2015
+++ SoObjects/SOGo/md5crypt.h	Thu Feb  5 14:52:49 2015
@@ -0,0 +1,36 @@
+/*	$OpenBSD: md5crypt.c,v 1.17 2014/04/03 15:55:29 beck Exp $	*/
+
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * If we meet some day, and you think this stuff is worth it, you
+ * can buy me a beer in return. Poul-Henning Kamp
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <md5.h>
+#include <string.h>
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *md5crypt(const char *pw, const char *salt);
--- /dev/null	Thu Feb  5 14:53:30 2015
+++ SoObjects/SOGo/md5crypt.m	Thu Feb  5 14:52:49 2015
@@ -0,0 +1,153 @@
+/*	$OpenBSD: md5crypt.c,v 1.17 2014/04/03 15:55:29 beck Exp $	*/
+
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * If we meet some day, and you think this stuff is worth it, you
+ * can buy me a beer in return. Poul-Henning Kamp
+ */
+
+#include "md5crypt.h"
+
+static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void to64(char *, u_int32_t, int);
+
+static void
+to64(char *s, u_int32_t v, int n)
+{
+	while (--n >= 0) {
+		*s++ = itoa64[v&0x3f];
+		v >>= 6;
+	}
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *
+md5crypt(const char *pw, const char *salt)
+{
+	/*
+	 * This string is the magic for this algorithm.
+	 * Having it this way, we can get better later on.
+	 */
+	static unsigned char	*magic = (unsigned char *)"$1$";
+
+	static char     passwd[120], *p;
+	static const unsigned char *sp,*ep;
+	unsigned char	final[16];
+	int sl,pl,i;
+	MD5_CTX	ctx,ctx1;
+	u_int32_t l;
+
+	/* Refine the salt first */
+	sp = (const unsigned char *)salt;
+
+	/* If it starts with the magic string, then skip that */
+	if(!strncmp((const char *)sp,(const char *)magic,strlen((const char *)magic)))
+		sp += strlen((const char *)magic);
+
+	/* It stops at the first '$', max 8 chars */
+	for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+		continue;
+
+	/* get the length of the true salt */
+	sl = ep - sp;
+
+	MD5Init(&ctx);
+
+	/* The password first, since that is what is most unknown */
+	MD5Update(&ctx,(const unsigned char *)pw,strlen(pw));
+
+	/* Then our magic string */
+	MD5Update(&ctx,magic,strlen((const char *)magic));
+
+	/* Then the raw salt */
+	MD5Update(&ctx,sp,sl);
+
+	/* Then just as many characters of the MD5(pw,salt,pw) */
+	MD5Init(&ctx1);
+	MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+	MD5Update(&ctx1,sp,sl);
+	MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+	MD5Final(final,&ctx1);
+	for(pl = strlen(pw); pl > 0; pl -= 16)
+		MD5Update(&ctx,final,pl>16 ? 16 : 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 ; i >>= 1)
+		if(i&1)
+		    MD5Update(&ctx, final, 1);
+		else
+		    MD5Update(&ctx, (const unsigned char *)pw, 1);
+
+	/* Now make the output string */
+	snprintf(passwd, sizeof(passwd), "%s%.*s$", (char *)magic,
+	    sl, (const char *)sp);
+
+	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...
+	 * On a modern machine, with possible GPU optimization,
+	 * this will run a lot faster than that.
+	 */
+	for(i=0;i<1000;i++) {
+		MD5Init(&ctx1);
+		if(i & 1)
+			MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+		else
+			MD5Update(&ctx1,final,16);
+
+		if(i % 3)
+			MD5Update(&ctx1,sp,sl);
+
+		if(i % 7)
+			MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
+
+		if(i & 1)
+			MD5Update(&ctx1,final,16);
+		else
+			MD5Update(&ctx1,(const unsigned char *)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);
+
+	return passwd;
+}
sogo.diff (6,221 bytes)   
Bigio

Bigio

2015-02-05 13:55

reporter   ~0008141

Full patch attached, sorry.

ludovic

ludovic

2016-05-12 15:32

administrator   ~0010125

Please adjust the patch so that:

1- the GNUmakefile only includes this if it is OpenBSD

2- make sur that it is tested on Linux too, with no compiler warning

Issue History

Date Modified Username Field Change
2015-02-03 15:58 Bigio New Issue
2015-02-03 15:58 Bigio File Added: sogo-md5crypt.diff
2015-02-05 12:48 buzzdee Note Added: 0008139
2015-02-05 13:55 Bigio File Added: sogo.diff
2015-02-05 13:55 Bigio Note Added: 0008141
2016-05-12 15:32 ludovic Note Added: 0010125