diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/auth/password-scheme-crypt.c | |
parent | Initial commit. (diff) | |
download | dovecot-upstream.tar.xz dovecot-upstream.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/auth/password-scheme-crypt.c')
-rw-r--r-- | src/auth/password-scheme-crypt.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/auth/password-scheme-crypt.c b/src/auth/password-scheme-crypt.c new file mode 100644 index 0000000..34febad --- /dev/null +++ b/src/auth/password-scheme-crypt.c @@ -0,0 +1,196 @@ +/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mycrypt.h" +#include "password-scheme.h" +#include "crypt-blowfish.h" +#include "randgen.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 16 /* raw salt */ +#define CRYPT_BLF_PREFIX_LEN (7+22+1) /* $2.$nn$ + salt */ +#define CRYPT_BLF_BUFFER_LEN 128 +#define CRYPT_BLF_PREFIX "$2y" +#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 void +crypt_generate_des(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED, + const unsigned char **raw_password_r, size_t *size_r) +{ +#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); +} + +static void +crypt_generate_blowfish(const char *plaintext, const struct password_generate_params *params, + const unsigned char **raw_password_r, size_t *size_r) +{ + char salt[CRYPT_BLF_SALT_LEN]; + char password[CRYPT_BLF_BUFFER_LEN]; + char magic_salt[CRYPT_BLF_PREFIX_LEN]; + unsigned int rounds = params->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; + + random_fill(salt, CRYPT_BLF_SALT_LEN); + if (crypt_gensalt_blowfish_rn(CRYPT_BLF_PREFIX, rounds, + salt, CRYPT_BLF_SALT_LEN, + magic_salt, CRYPT_BLF_PREFIX_LEN) == NULL) + i_fatal("crypt_gensalt_blowfish_rn failed: %m"); + + if (crypt_blowfish_rn(plaintext, magic_salt, password, + CRYPT_BLF_BUFFER_LEN) == NULL) + i_fatal("crypt_blowfish_rn failed: %m"); + + *raw_password_r = (const unsigned char *)t_strdup(password); + *size_r = strlen(password); +} + +static int +crypt_verify_blowfish(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED, + const unsigned char *raw_password, size_t size, + const char **error_r) +{ + const char *password; + const char *salt; + char crypted[CRYPT_BLF_BUFFER_LEN]; + + if (size == 0) { + /* the default mycrypt() handler would return match */ + return 0; + } + password = t_strndup(raw_password, size); + + if (size < CRYPT_BLF_PREFIX_LEN || + !str_begins(password, "$2") || + password[2] < 'a' || password[2] > 'z' || + password[3] != '$') { + *error_r = "Password is not blowfish password"; + return -1; + } + + salt = t_strndup(password, CRYPT_BLF_PREFIX_LEN); + if (crypt_blowfish_rn(plaintext, salt, crypted, CRYPT_BLF_BUFFER_LEN) == NULL) { + /* really shouldn't happen unless the system is broken */ + *error_r = t_strdup_printf("crypt_blowfish_rn failed: %m"); + return -1; + } + + return strcmp(crypted, password) == 0 ? 1 : 0; +} + +static void +crypt_generate_sha256(const char *plaintext, const struct password_generate_params *params, + const unsigned char **raw_password_r, size_t *size_r) +{ + const char *password, *salt, *magic_salt; + unsigned int rounds = params->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 struct password_generate_params *params, + const unsigned char **raw_password_r, size_t *size_r) +{ + const char *password, *salt, *magic_salt; + unsigned int rounds = params->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", "JB", "JBOZ0DgmtucwE" }, + { "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[] = { + { "DES-CRYPT", PW_ENCODING_NONE, 0, crypt_verify, + crypt_generate_des }, + { "SHA256-CRYPT", PW_ENCODING_NONE, 0, crypt_verify, + crypt_generate_sha256 }, + { "SHA512-CRYPT", PW_ENCODING_NONE, 0, crypt_verify, + crypt_generate_sha512 } +}; + +static const struct password_scheme blf_crypt_scheme = { + "BLF-CRYPT", PW_ENCODING_NONE, 0, crypt_verify_blowfish, + crypt_generate_blowfish +}; + +static const struct password_scheme default_crypt_scheme = { + "CRYPT", PW_ENCODING_NONE, 0, crypt_verify, + crypt_generate_blowfish +}; + +void password_scheme_register_crypt(void) +{ + unsigned int i; + const char *crypted; + + i_assert(N_ELEMENTS(crypt_schemes) == N_ELEMENTS(sample)); + + 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]); + } + password_scheme_register(&blf_crypt_scheme); + password_scheme_register(&default_crypt_scheme); +} |