Mercurial > dovecot > core-2.2
changeset 20251:89e2abf6b828
auth: Add PBKDF2 password scheme
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Wed, 27 Apr 2016 09:14:29 +0300 |
parents | 5bdcdff02638 |
children | 2cacbc8e95c5 |
files | src/auth/Makefile.am src/auth/password-scheme-pbkdf2.c src/auth/password-scheme.c src/auth/password-scheme.h |
diffstat | 4 files changed, 91 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/Makefile.am Wed Jun 01 12:24:57 2016 +0300 +++ b/src/auth/Makefile.am Wed Apr 27 09:14:29 2016 +0300 @@ -47,7 +47,8 @@ password-scheme-md5crypt.c \ password-scheme-scram.c \ password-scheme-otp.c \ - password-scheme-rpa.c + password-scheme-rpa.c \ + password-scheme-pbkdf2.c auth_libs = \ libstats_auth.la \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/password-scheme-pbkdf2.c Wed Apr 27 09:14:29 2016 +0300 @@ -0,0 +1,82 @@ +/* Copyright (c) 2015 Dovecot Oy, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "str.h" +#include "password-scheme.h" +#include "hex-binary.h" +#include "hash-method.h" +#include "pkcs5.h" + +#define PBKDF2_KEY_SIZE_SHA1 20 + +#define PBKDF2_GENERATE_SALT_LEN 16 +#define PBKDF2_ROUNDS_DEFAULT 5000 + +static void +pbkdf_run(const char *plaintext, const char *salt, + unsigned int rounds, unsigned char key_r[PBKDF2_KEY_SIZE_SHA1]) +{ + memset(key_r, 0, PBKDF2_KEY_SIZE_SHA1); + buffer_t buf; + buffer_create_from_data(&buf, key_r, PBKDF2_KEY_SIZE_SHA1); + + pkcs5_pbkdf(PKCS5_PBKDF2, hash_method_lookup("sha1"), + (const unsigned char *)plaintext, strlen(plaintext), + (const unsigned char *)salt, strlen(salt), + rounds, PBKDF2_KEY_SIZE_SHA1, &buf); +} + +void pbkdf2_generate(const char *plaintext, const char *user ATTR_UNUSED, + const unsigned char **raw_password_r, size_t *size_r) +{ + unsigned char key[PBKDF2_KEY_SIZE_SHA1]; + const char *salt; + string_t *str = t_str_new(64); + unsigned int rounds = password_scheme_encryption_rounds; + + if (rounds == 0) + rounds = PBKDF2_ROUNDS_DEFAULT; + salt = password_generate_salt(PBKDF2_GENERATE_SALT_LEN); + pbkdf_run(plaintext, salt, rounds, key); + + str_printfa(str, "$1$%s$%u$", salt, rounds); + binary_to_hex_append(str, key, sizeof(key)); + + *raw_password_r = str_data(str); + *size_r = str_len(str); +} + +int pbkdf2_verify(const char *plaintext, const char *user ATTR_UNUSED, + const unsigned char *raw_password, size_t size, + const char **error_r) +{ + const char *const *fields; + const char *salt; + unsigned int rounds; + unsigned char key1[PBKDF2_KEY_SIZE_SHA1], key2[PBKDF2_KEY_SIZE_SHA1]; + buffer_t buf; + + /* $1$salt$rounds$hash */ + if (size < 3 || memcmp(raw_password, "$1$", 3) != 0) { + *error_r = "Invalid PBKDF2 passdb entry prefix"; + return -1; + } + + fields = t_strsplit(t_strndup(raw_password + 3, size - 3), "$"); + salt = fields[0]; + if (str_array_length(fields) != 3 || + str_to_uint(fields[1], &rounds) < 0) { + *error_r = "Invalid PBKDF2 passdb entry format"; + return -1; + } + buffer_create_from_data(&buf, key1, sizeof(key1)); + if (strlen(fields[2]) != sizeof(key1)*2 || + hex_to_binary(fields[2], &buf) < 0) { + *error_r = "PBKDF2 hash not 160bit hex-encoded"; + return -1; + } + + pbkdf_run(plaintext, salt, rounds, key2); + return memcmp(key1, key2, sizeof(key1)) == 0 ? 1 : 0; +}
--- a/src/auth/password-scheme.c Wed Jun 01 12:24:57 2016 +0300 +++ b/src/auth/password-scheme.c Wed Apr 27 09:14:29 2016 +0300 @@ -825,7 +825,8 @@ { "NTLM", PW_ENCODING_HEX, NTLMSSP_HASH_SIZE, NULL, ntlm_generate }, { "OTP", PW_ENCODING_NONE, 0, otp_verify, otp_generate }, { "SKEY", PW_ENCODING_NONE, 0, otp_verify, skey_generate }, - { "RPA", PW_ENCODING_HEX, MD5_RESULTLEN, NULL, rpa_generate } + { "RPA", PW_ENCODING_HEX, MD5_RESULTLEN, NULL, rpa_generate }, + { "PBKDF2", PW_ENCODING_NONE, 0, pbkdf2_verify, pbkdf2_generate }, }; void password_scheme_register(const struct password_scheme *scheme)
--- a/src/auth/password-scheme.h Wed Jun 01 12:24:57 2016 +0300 +++ b/src/auth/password-scheme.h Wed Apr 27 09:14:29 2016 +0300 @@ -95,6 +95,11 @@ const char **error_r ATTR_UNUSED); void scram_sha1_generate(const char *plaintext, const char *user ATTR_UNUSED, const unsigned char **raw_password_r, size_t *size_r); +void pbkdf2_generate(const char *plaintext, const char *user ATTR_UNUSED, + const unsigned char **raw_password_r, size_t *size_r); +int pbkdf2_verify(const char *plaintext, const char *user ATTR_UNUSED, + const unsigned char *raw_password, size_t size, + const char **error_r); /* check wich of the algorithms Blowfisch, SHA-256 and SHA-512 are supported by the used libc's/glibc's crypt() */