Mercurial > dovecot > core-2.2
changeset 11278:2ead7574bb08 HEAD
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.
author | Pascal Volk <user@localhost.localdomain.org> |
---|---|
date | Sun, 09 May 2010 20:57:27 +0000 |
parents | 1485d8bafb5e |
children | 521e36311440 |
files | src/auth/Makefile.am src/auth/password-scheme-crypt.c src/auth/password-scheme.c src/auth/password-scheme.h src/doveadm/doveadm-pw.c |
diffstat | 5 files changed, 176 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- 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
--- /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]); + } +}
--- 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)
--- 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
--- 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"