]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: added new password scheme names {BLF,SHA256,SHA512}-CRYPT.
authorPascal Volk <user@localhost.localdomain.org>
Sun, 9 May 2010 20:57:27 +0000 (20:57 +0000)
committerPascal Volk <user@localhost.localdomain.org>
Sun, 9 May 2010 20:57:27 +0000 (20:57 +0000)
Their availability depends on the used libc.

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

--HG--
branch : HEAD

src/auth/Makefile.am
src/auth/password-scheme-crypt.c [new file with mode: 0644]
src/auth/password-scheme.c
src/auth/password-scheme.h
src/doveadm/doveadm-pw.c

index b32b1369867d1f892517fd3eaf6a93af2fa88044..28c7f478729bd025b2a52abbd4b6589b34b9b854 100644 (file)
@@ -34,6 +34,7 @@ auth_LDFLAGS = -export-dynamic
 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 --git a/src/auth/password-scheme-crypt.c b/src/auth/password-scheme-crypt.c
new file mode 100644 (file)
index 0000000..737b967
--- /dev/null
@@ -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]);
+       }
+}
index 2bef16446c1b4bbcb08d89a869e0afdd48812578..c342ee459d5d0b73136c5db140d097743b4257cc 100644 (file)
@@ -227,6 +227,19 @@ bool password_generate_encoded(const char *plaintext, const char *user,
        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 @@ password_scheme_detect(const char *plain_password, const char *crypted_password,
        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 @@ static void
 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;
-
-       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';
+#define        CRYPT_SALT_LEN 2
+       const char *password, *salt;
 
+       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 @@ void password_schemes_init(void)
        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)
index 8527d874c078d995ac22be4c5fd374ffbf65aa4e..5b43a027413ecefe548a0ac7e9ad96cb3af48cfb 100644 (file)
@@ -65,10 +65,22 @@ void password_scheme_unregister(const struct password_scheme *scheme);
 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
index dbe28786482be0eea310de979a79524c0f96d828..4704933cc6b6c0e12a8aded064e07aa3db769506 100644 (file)
@@ -22,11 +22,12 @@ static void cmd_pw(int argc, char *argv[])
        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 @@ static void cmd_pw(int argc, char *argv[])
                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 @@ static void cmd_pw(int argc, char *argv[])
                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 @@ static void cmd_pw(int argc, char *argv[])
 }
 
 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"