dovecot-2.0: auth: added new password scheme names {BLF,SHA256,S...

dovecot at dovecot.org dovecot at dovecot.org
Sun May 9 23:58:22 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/2ead7574bb08
changeset: 11278:2ead7574bb08
user:      Pascal Volk <user at localhost.localdomain.org>
date:      Sun May 09 20:57:27 2010 +0000
description:
auth: added new password scheme names {BLF,SHA256,SHA512}-CRYPT.
Their availability depends on the used libc.

doveadm pw: added '-r rounds' option for the password schemes mentioned above.

diffstat:

 src/auth/Makefile.am             |    1 +
 src/auth/password-scheme-crypt.c |  132 ++++++++++++++++++++++++++++++++++++++++++++
 src/auth/password-scheme.c       |   29 ++++++---
 src/auth/password-scheme.h       |   12 ++++
 src/doveadm/doveadm-pw.c         |   14 ++++-
 5 files changed, 176 insertions(+), 12 deletions(-)

diffs (285 lines):

diff -r 1485d8bafb5e -r 2ead7574bb08 src/auth/Makefile.am
--- a/src/auth/Makefile.am	Sun May 09 23:48:25 2010 +0300
+++ b/src/auth/Makefile.am	Sun May 09 20:57:27 2010 +0000
@@ -34,6 +34,7 @@
 libpassword_a_SOURCES = \
 	mycrypt.c \
 	password-scheme.c \
+	password-scheme-crypt.c \
 	password-scheme-md5crypt.c \
 	password-scheme-otp.c \
 	password-scheme-rpa.c
diff -r 1485d8bafb5e -r 2ead7574bb08 src/auth/password-scheme-crypt.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/password-scheme-crypt.c	Sun May 09 20:57:27 2010 +0000
@@ -0,0 +1,132 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "mycrypt.h"
+#include "password-scheme.h"
+
+/* Lengths and limits for some crypt() algorithms. */
+#define CRYPT_BLF_ROUNDS_DEFAULT 5
+#define CRYPT_BLF_ROUNDS_MIN 4
+#define CRYPT_BLF_ROUNDS_MAX 31
+#define CRYPT_BLF_SALT_LEN 22
+#define CRYPT_SHA2_ROUNDS_DEFAULT 5000
+#define CRYPT_SHA2_ROUNDS_MIN 1000
+#define CRYPT_SHA2_ROUNDS_MAX 999999999
+#define CRYPT_SHA2_SALT_LEN 16
+
+static unsigned int encryption_rounds = 0;
+
+void password_set_encryption_rounds(unsigned int rounds)
+{
+	/* just take the new value. crypt_generate_*() will enforce their
+	   limits. */
+	encryption_rounds = rounds;
+}
+
+static void
+crypt_generate_blowfisch(const char *plaintext, const char *user ATTR_UNUSED,
+			 const unsigned char **raw_password_r, size_t *size_r)
+{
+	const char *password, *salt, *magic_salt;
+	unsigned int rounds = encryption_rounds;
+
+	if (rounds == 0)
+		rounds = CRYPT_BLF_ROUNDS_DEFAULT;
+	else if (rounds < CRYPT_BLF_ROUNDS_MIN)
+		rounds = CRYPT_BLF_ROUNDS_MIN;
+	else if (rounds > CRYPT_BLF_ROUNDS_MAX)
+		rounds = CRYPT_BLF_ROUNDS_MAX;
+
+	salt = password_generate_salt(CRYPT_BLF_SALT_LEN);
+	magic_salt = t_strdup_printf("$2a$%02u$%s", rounds, salt);
+	password = t_strdup(mycrypt(plaintext, magic_salt));
+	*raw_password_r = (const unsigned char *)password;
+	*size_r = strlen(password);
+}
+
+static void
+crypt_generate_sha256(const char *plaintext, const char *user ATTR_UNUSED,
+		      const unsigned char **raw_password_r, size_t *size_r)
+{
+	const char *password, *salt, *magic_salt;
+	unsigned int rounds = encryption_rounds;
+
+	if (rounds == 0)
+		rounds = CRYPT_SHA2_ROUNDS_DEFAULT;
+	else if (rounds < CRYPT_SHA2_ROUNDS_MIN)
+		rounds = CRYPT_SHA2_ROUNDS_MIN;
+	else if (rounds > CRYPT_SHA2_ROUNDS_MAX)
+		rounds = CRYPT_SHA2_ROUNDS_MAX;
+
+	salt = password_generate_salt(CRYPT_SHA2_SALT_LEN);
+	if (rounds == CRYPT_SHA2_ROUNDS_DEFAULT)
+		magic_salt = t_strdup_printf("$5$%s", salt);
+	else
+		magic_salt = t_strdup_printf("$5$rounds=%u$%s", rounds, salt);
+	password = t_strdup(mycrypt(plaintext, magic_salt));
+	*raw_password_r = (const unsigned char *)password;
+	*size_r = strlen(password);
+}
+
+static void
+crypt_generate_sha512(const char *plaintext, const char *user ATTR_UNUSED,
+		      const unsigned char **raw_password_r, size_t *size_r)
+{
+	const char *password, *salt, *magic_salt;
+	unsigned int rounds = encryption_rounds;
+
+	if (rounds == 0)
+		rounds = CRYPT_SHA2_ROUNDS_DEFAULT;
+	else if (rounds < CRYPT_SHA2_ROUNDS_MIN)
+		rounds = CRYPT_SHA2_ROUNDS_MIN;
+	else if (rounds > CRYPT_SHA2_ROUNDS_MAX)
+		rounds = CRYPT_SHA2_ROUNDS_MAX;
+
+	salt = password_generate_salt(CRYPT_SHA2_SALT_LEN);
+	if (rounds == CRYPT_SHA2_ROUNDS_DEFAULT)
+		magic_salt = t_strdup_printf("$6$%s", salt);
+	else
+		magic_salt = t_strdup_printf("$6$rounds=%u$%s", rounds, salt);
+	password = t_strdup(mycrypt(plaintext, magic_salt));
+	*raw_password_r = (const unsigned char *)password;
+	*size_r = strlen(password);
+}
+
+/* keep in sync with the crypt_schemes struct below */
+static const struct {
+	const char *key;
+	const char *salt;
+	const char *expected;
+} sample[] = {
+	{ "08/15!test~4711", "$2a$04$0123456789abcdefABCDEF",
+	  "$2a$04$0123456789abcdefABCDE.N.drYX5yIAL1LkTaaZotW3yI0hQhZru" },
+	{ "08/15!test~4711", "$5$rounds=1000$0123456789abcdef",
+	  "$5$rounds=1000$0123456789abcdef$K/DksR0DT01hGc8g/kt"
+	  "9McEgrbFMKi9qrb1jehe7hn4" },
+	{ "08/15!test~4711", "$6$rounds=1000$0123456789abcdef",
+	  "$6$rounds=1000$0123456789abcdef$ZIAd5WqfyLkpvsVCVUU1GrvqaZTq"
+	  "vhJoouxdSqJO71l9Ld3tVrfOatEjarhghvEYADkq//LpDnTeO90tcbtHR1" }
+};
+
+/* keep in sync with the sample struct above */
+static const struct password_scheme crypt_schemes[] = {
+	{ "BLF-CRYPT", PW_ENCODING_NONE, 0, crypt_verify,
+	  crypt_generate_blowfisch },
+	{ "SHA256-CRYPT", PW_ENCODING_NONE, 0, crypt_verify,
+	  crypt_generate_sha256 },
+	{ "SHA512-CRYPT", PW_ENCODING_NONE, 0, crypt_verify,
+	  crypt_generate_sha512 }
+};
+
+void password_scheme_register_crypt(void)
+{
+	unsigned int i;
+	const char *crypted;
+
+	for (i = 0; i < N_ELEMENTS(crypt_schemes); i++) {
+		crypted = mycrypt(sample[i].key, sample[i].salt);
+		if (crypted != NULL &&
+		   (strcmp(crypted, sample[i].expected) == 0))
+			password_scheme_register(&crypt_schemes[i]);
+	}
+}
diff -r 1485d8bafb5e -r 2ead7574bb08 src/auth/password-scheme.c
--- a/src/auth/password-scheme.c	Sun May 09 23:48:25 2010 +0300
+++ b/src/auth/password-scheme.c	Sun May 09 20:57:27 2010 +0000
@@ -227,6 +227,19 @@
 	return TRUE;
 }
 
+const char *password_generate_salt(size_t len)
+{
+	unsigned int i;
+	char *salt;
+
+	salt = t_malloc(len + 1);
+	random_fill(salt, len);
+	for (i = 0; i < len; i++)
+		salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
+	salt[len] = '\0';
+	return salt;
+}
+
 bool password_scheme_is_alias(const char *scheme1, const char *scheme2)
 {
 	const struct password_scheme *const *schemes, *s1 = NULL, *s2 = NULL;
@@ -273,9 +286,8 @@
 	return NULL;
 }
 
-static bool
-crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
-	     const unsigned char *raw_password, size_t size)
+bool crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
+		  const unsigned char *raw_password, size_t size)
 {
 	const char *password, *crypted;
 
@@ -299,14 +311,10 @@
 crypt_generate(const char *plaintext, const char *user ATTR_UNUSED,
 	       const unsigned char **raw_password_r, size_t *size_r)
 {
-	char salt[3];
-	const char *password;
+#define	CRYPT_SALT_LEN 2
+	const char *password, *salt;
 
-	random_fill(salt, sizeof(salt)-1);
-	salt[0] = salt_chars[salt[0] % (sizeof(salt_chars)-1)];
-	salt[1] = salt_chars[salt[1] % (sizeof(salt_chars)-1)];
-	salt[2] = '\0';
-
+	salt = password_generate_salt(CRYPT_SALT_LEN);
 	password = t_strdup(mycrypt(plaintext, salt));
 	*raw_password_r = (const unsigned char *)password;
 	*size_r = strlen(password);
@@ -784,6 +792,7 @@
 	i_array_init(&password_schemes, N_ELEMENTS(builtin_schemes) + 4);
 	for (i = 0; i < N_ELEMENTS(builtin_schemes); i++)
 		password_scheme_register(&builtin_schemes[i]);
+	password_scheme_register_crypt();
 }
 
 void password_schemes_deinit(void)
diff -r 1485d8bafb5e -r 2ead7574bb08 src/auth/password-scheme.h
--- a/src/auth/password-scheme.h	Sun May 09 23:48:25 2010 +0300
+++ b/src/auth/password-scheme.h	Sun May 09 20:57:27 2010 +0000
@@ -65,10 +65,22 @@
 void password_schemes_init(void);
 void password_schemes_deinit(void);
 
+/* some password schemes/algorithms supports a variable number of
+   encryption rounds. */
+void password_set_encryption_rounds(unsigned int rounds);
+
 /* INTERNAL: */
+const char *password_generate_salt(size_t len);
 const char *password_generate_md5_crypt(const char *pw, const char *salt);
 const char *password_generate_otp(const char *pw, const char *state,
 				  unsigned int algo);
 void password_generate_rpa(const char *pw, unsigned char result[]);
 
+bool crypt_verify(const char *plaintext, const char *user,
+		  const unsigned char *raw_password, size_t size);
+
+/* check wich of the algorithms Blowfisch, SHA-256 and SHA-512 are
+   supported by the used libc's/glibc's crypt() */
+void password_scheme_register_crypt(void);
+
 #endif
diff -r 1485d8bafb5e -r 2ead7574bb08 src/doveadm/doveadm-pw.c
--- a/src/doveadm/doveadm-pw.c	Sun May 09 23:48:25 2010 +0300
+++ b/src/doveadm/doveadm-pw.c	Sun May 09 20:57:27 2010 +0000
@@ -22,11 +22,12 @@
 	const char *scheme = NULL;
 	const char *plaintext = NULL;
 	int ch, lflag = 0, Vflag = 0;
+	unsigned int rounds = 0;
 
 	random_init();
 	password_schemes_init();
 	
-	while ((ch = getopt(argc, argv, "lp:s:u:V")) != -1) {
+	while ((ch = getopt(argc, argv, "lp:r:s:u:V")) != -1) {
 		switch (ch) {
 		case 'l':
 			lflag = 1;
@@ -34,6 +35,10 @@
 		case 'p':
 			plaintext = optarg;
 			break;
+		case 'r':
+			if (str_to_uint(optarg, &rounds) < 0)
+				i_fatal("Invalid number of rounds: %s", optarg);
+			break;
 		case 's':
 			scheme = optarg;
 			break;
@@ -64,6 +69,9 @@
 		help(&doveadm_cmd_pw);
 
 	scheme = scheme == NULL ? DEFAULT_SCHEME : t_str_ucase(scheme);
+	if (rounds > 0)
+		password_set_encryption_rounds(rounds);
+
 	while (plaintext == NULL) {
 		const char *check;
 		static int lives = 3;
@@ -107,9 +115,11 @@
 }
 
 struct doveadm_cmd doveadm_cmd_pw = {
-	cmd_pw, "pw", "[-l] [-p plaintext] [-s scheme] [-u user] [-V]",
+	cmd_pw, "pw",
+	"[-l] [-p plaintext] [-r rounds] [-s scheme] [-u user] [-V]",
 "  -l            List known password schemes\n"
 "  -p plaintext  New password\n"
+"  -r rounds     Number of encryption rounds (if scheme uses it)\n"
 "  -s scheme     Password scheme\n"
 "  -u user       Username (if scheme uses it)\n"
 "  -V            Internally verify the hash\n"


More information about the dovecot-cvs mailing list