summaryrefslogtreecommitdiffstats
path: root/src/auth/password-scheme-crypt.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
commitf7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch)
treea3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/auth/password-scheme-crypt.c
parentInitial commit. (diff)
downloaddovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz
dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.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.c196
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);
+}