Package: shadow
Severity: wishlist
Tags: patch

----- Forwarded message from Robert Connolly <[EMAIL PROTECTED]> -----

From: Robert Connolly <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Date: Sun, 17 Aug 2008 02:03:30 -0400
Subject: [Pkg-shadow-devel] Linking Shadow to OpenSSL
X-CRM114-Status: Good  ( pR: 64.2989 )

Hello. I started a feature request for this, but maybe it will get more 
feedback here. Attached is a patch to add --with-openssl. So far I got it 
working with DES and MD5. I worked by example, and I didn't find examples of 
using OpenSSL to make sha512 passwords that are compatible. Maybe someone who 
knows what they're doing could help.

There are great advantages to using OpenSSL instead of Libc. We would have a 
more robust choice in algorithms, random sources for salt, maybe hmac, and it 
could pave the way towards AES passwords. Better performance with actively 
maintained (asm) code for algorithms. Better portability.

I don't have the knowledge to finish the SHA patch, but I would like to use 
RAND_pseudo_bytes() for password salt so we can finally start using 
unpredictable (not gettimeofday+getpid) non-alphanumeric salt.

Opinions, help, comments?

robert

This patch adds --with-openssl to Shadow, and currently only supports DES and
MD5.

lib/openssl-md5crypt.c should probably use OpenSSL's EVP_DigestInit.

I made this patch by example, and I have no examples for sha512. I hope that
this patch can be taken over by someone who know what they're doing, so more
algorithms can be added.

This patch is fairly conservative and I believe it is safe to use.

robert @ lfs


This patch adds --with-openssl to Shadow, and currently only supports DES and
MD5.

lib/openssl-md5crypt.c should probably use OpenSSL's EVP_DigestInit.

I made this patch by example, and I have no examples for sha512. I hope that
this patch can be taken over by someone who know what they're doing, so more
algorithms can be added.

This patch is fairly conservative and I believe it is safe to use.

robert @ lfs

Index: configure.in
===================================================================
--- configure.in	(revision 2270)
+++ configure.in	(working copy)
@@ -235,7 +235,14 @@
 AC_ARG_WITH(sha-crypt,
 	[AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])],
 	[with_sha_crypt=$withval], [with_sha_crypt=yes])
+AC_ARG_WITH(openssl,
+	[AC_HELP_STRING([--with-openssl], [use OpenSSL libcrypto instead of libcrypt. This option disables --with-sha-crypt. Currently only MD5 and DES work. @<:@default=no@:>@])],
+	[with_openssl=$withval], [with_openssl=no])
 
+if test "x$with_openssl" = "xyes"; then
+	with_sha_crypt="no"
+fi
+
 AM_CONDITIONAL(USE_SHA_CRYPT, test "x$with_sha_crypt" = "xyes")
 if test "$with_sha_crypt" = "yes"; then
 		AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms])
@@ -272,8 +279,17 @@
 AM_CONDITIONAL(ENABLE_REGENERATE_MAN, test "x$enable_man" != "xno")
 
 AC_SUBST(LIBCRYPT)
-AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
-	[AC_MSG_ERROR([crypt() not found])])
+if test "x$with_openssl" = "xyes"; then
+	AC_CHECK_LIB(crypto, DES_crypt,
+		[LIBCRYPT=-lcrypto AC_DEFINE(USE_OPENSSL, 1, [Defined to use OpenSSL.])],
+			[AC_MSG_ERROR([DES_crypt() not found])])
+	AC_CHECK_HEADER([openssl/des.h],,[AC_MSG_ERROR([openssl/des.h not found])])
+	AC_CHECK_HEADER([openssl/md5.h],,[AC_MSG_ERROR([openssl/md5.h not found])])
+	AC_CHECK_HEADER([openssl/buffer.h],,[AC_MSG_ERROR([openssl/buffer.h not found])])
+	else
+		AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
+			[AC_MSG_ERROR([crypt() not found])])
+fi
 
 AC_SUBST(LIBAUDIT)
 if test "$with_audit" != "no"; then
@@ -457,4 +473,5 @@
 echo "	shadow group support:		$enable_shadowgrp"
 echo "	S/Key support:			$with_skey"
 echo "	SHA passwords encryption:	$with_sha_crypt"
+echo "	OpenSSL support:		$with_openssl"
 echo
Index: lib/defines.h
===================================================================
--- lib/defines.h	(revision 2270)
+++ lib/defines.h	(working copy)
@@ -350,4 +350,10 @@
 # define unused
 #endif
 
+#ifdef USE_OPENSSL
+# define CRYPT openssl_crypt
+#else
+# define CRYPT crypt
+#endif
+
 #endif				/* _DEFINES_H_ */
Index: lib/encrypt.c
===================================================================
--- lib/encrypt.c	(revision 2270)
+++ lib/encrypt.c	(working copy)
@@ -45,7 +45,7 @@
 	static char cipher[128];
 	char *cp;
 
-	cp = crypt (clear, salt);
+	cp = CRYPT (clear, salt);
 	if (!cp) {
 		/*
 		 * Single Unix Spec: crypt() may return a null pointer,
Index: lib/openssl-md5crypt.c
===================================================================
--- lib/openssl-md5crypt.c	(revision 0)
+++ lib/openssl-md5crypt.c	(revision 0)
@@ -0,0 +1,153 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <[EMAIL PROTECTED]> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * from NetBSD: md5crypt.c,v 1.9 2007/01/17 23:24:22 hubertf Exp
+ * via FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp
+ * via OpenBSD: md5crypt.c,v 1.9 1997/07/23 20:58:27 kstailey Exp
+ *
+ */
+
+#include <config.h>
+
+#ifdef USE_OPENSSL
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/md5.h>
+#include <openssl/buffer.h> /* For BUF_strlcat/strlcpy */
+
+#include "prototypes.h"
+#include "defines.h"
+
+#define MD5_MAGIC	"$1$"
+#define MD5_MAGIC_LEN	3
+
+static const unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
+	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+__crypt_to64(char *s, u_int32_t v, int n)
+{
+
+	while (--n >= 0) {
+		*s++ = itoa64[v & 0x3f];
+		v >>= 6;
+	}
+}
+
+/*
+ * MD5 password encryption.
+ */
+char *
+openssl_md5crypt(const char *pw, const char *salt)
+{
+	static char passwd[120], *p;
+	const char *sp, *ep;
+	unsigned char final[MD5_DIGEST_LENGTH];
+	unsigned int i, sl, pwl;
+	MD5_CTX	ctx, ctx1;
+	u_int32_t l;
+	int pl;
+	
+	pwl = strlen(pw);
+	
+	/* Refine the salt first */
+	sp = salt;
+
+	/* If it starts with the magic string, then skip that */
+	if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
+		sp += MD5_MAGIC_LEN;
+
+	/* It stops at the first '$', max 8 chars */
+	for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
+		continue;
+
+	/* get the length of the true salt */
+	sl = ep - sp;
+
+	MD5_Init(&ctx);
+
+	/* The password first, since that is what is most unknown */
+	MD5_Update(&ctx, (const unsigned char *)pw, pwl);
+
+	/* Then our magic string */
+	MD5_Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
+
+	/* Then the raw salt */
+	MD5_Update(&ctx, (const unsigned char *)sp, sl);
+
+	/* Then just as many characters of the MD5(pw,salt,pw) */
+	MD5_Init(&ctx1);
+	MD5_Update(&ctx1, (const unsigned char *)pw, pwl);
+	MD5_Update(&ctx1, (const unsigned char *)sp, sl);
+	MD5_Update(&ctx1, (const unsigned char *)pw, pwl);
+	MD5_Final(final, &ctx1);
+
+	for (pl = pwl; pl > 0; pl -= 16)
+		MD5_Update(&ctx, final, (unsigned int)(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 = pwl; i != 0; i >>= 1)
+		if ((i & 1) != 0)
+		    MD5_Update(&ctx, final, 1);
+		else
+		    MD5_Update(&ctx, (const unsigned char *)pw, 1);
+
+	/* Now make the output string */
+	memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
+	BUF_strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
+	BUF_strlcat(passwd, "$", sizeof(passwd));
+
+	MD5_Final(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++) {
+		MD5_Init(&ctx1);
+
+		if ((i & 1) != 0)
+			MD5_Update(&ctx1, (const unsigned char *)pw, pwl);
+		else
+			MD5_Update(&ctx1, final, 16);
+
+		if ((i % 3) != 0)
+			MD5_Update(&ctx1, (const unsigned char *)sp, sl);
+
+		if ((i % 7) != 0)
+			MD5_Update(&ctx1, (const unsigned char *)pw, pwl);
+
+		if ((i & 1) != 0)
+			MD5_Update(&ctx1, final, 16);
+		else
+			MD5_Update(&ctx1, (const unsigned char *)pw, pwl);
+
+		MD5_Final(final, &ctx1);
+	}
+
+	p = passwd + sl + MD5_MAGIC_LEN + 1;
+
+	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; __crypt_to64(p,l,4); p += 4;
+	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; __crypt_to64(p,l,4); p += 4;
+	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; __crypt_to64(p,l,4); p += 4;
+	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; __crypt_to64(p,l,4); p += 4;
+	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; __crypt_to64(p,l,4); p += 4;
+	l =		       final[11]		; __crypt_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);
+}
+#endif /* USE_OPENSSL */
Index: lib/openssl-crypt.c
===================================================================
--- lib/openssl-crypt.c	(revision 0)
+++ lib/openssl-crypt.c	(revision 0)
@@ -0,0 +1,37 @@
+/* If I wrote this it would be public domain, but I didn't. - robert */
+
+#include <config.h>
+
+#ifdef USE_OPENSSL
+
+#include <string.h>
+#include <openssl/des.h>
+
+#include "prototypes.h"
+#include "defines.h"
+
+/* From Glibc-2.7 crypt/crypt-entry.c */
+static const char md5_salt_prefix[] = "$1$";
+#if 0
+static const char sha256_salt_prefix[] = "$5$";
+static const char sha512_salt_prefix[] = "$6$";
+#endif
+
+char *
+openssl_crypt (const char *key, const char *salt)
+{
+if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
+  return (char *)openssl_md5crypt (key, salt);
+
+#if 0
+if (strncmp (sha256_salt_prefix, salt, sizeof (sha256_salt_prefix) - 1) == 0)
+  return (char *)openssl_sha256crypt (key, salt);
+
+if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
+  return (char *)openssl_sha512crypt (key, salt);
+#endif
+
+/* Else, default to DES. */
+return (char *)DES_crypt (key, salt);
+}
+#endif /* USE_OPENSSL */
Index: lib/Makefile.am
===================================================================
--- lib/Makefile.am	(revision 2270)
+++ lib/Makefile.am	(working copy)
@@ -24,6 +24,8 @@
 	lockpw.c \
 	nscd.c \
 	nscd.h \
+	openssl-crypt.c \
+	openssl-md5crypt.c \
 	pam_defs.h \
 	port.c \
 	port.h \
Index: lib/prototypes.h
===================================================================
--- lib/prototypes.h	(revision 2270)
+++ lib/prototypes.h	(working copy)
@@ -285,4 +285,5 @@
 /* yesno.c */
 extern bool yes_or_no (bool read_only);
 
+extern char * openssl_crypt (const char *key, const char *salt);
 #endif				/* _PROTOTYPES_H */

Attachment: signature.asc
Description: Digital signature

Reply via email to