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