From 1c581a8364ab18a6938f3153d7bea793d06a4652 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Thu, 25 Aug 2011 14:00:38 +0200 Subject: [PATCH crypt_blowfish] support for sha256 and sha512 --- crypt.3 | 14 +++++++++++++ crypt_gensalt.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.c | 23 +++++++++++++++++++++ 3 files changed, 95 insertions(+), 0 deletions(-) diff --git a/crypt.3 b/crypt.3 index e2f25bd..40a3538 100644 --- a/crypt.3 +++ b/crypt.3 @@ -399,6 +399,20 @@ too low for the currently available hardware. .hash "$1$" "\e$1\e$[^$]{1,8}\e$[./0-9A-Za-z]{22}" unlimited 8 "" 128 "6 to 48" 1000 .PP .ti -2 +.B SHA256 based +.br +This is Ulrich Drepper's SHA256-based password hashing method originally +developed for Linux. +.hash "$5$" "\e$5\e$(rounds=[0-9]{1,9}\e$)?([./0-9A-Za-z]{1,16})?\e$[./0-9A-Za-z]{43}" unlimited 8 "" 256 "0 to 96" "1000 to 999999999 (default 5000)" +.PP +.ti -2 +.B SHA512 based +.br +This is Ulrich Drepper's SHA512-based password hashing method originally +developed for Linux. +.hash "$6$" "\e$6\e$(rounds=[0-9]{1,9}\e$)?([./0-9A-Za-z]{1,16})?\e$[./0-9A-Za-z]{86}" unlimited 8 "" 512 "0 to 96" "1000 to 999999999 (default 5000)" +.PP +.ti -2 .BR "OpenBSD-style Blowfish-based" " (" bcrypt ) .br .B bcrypt diff --git a/crypt_gensalt.c b/crypt_gensalt.c index 73c15a1..5cf9812 100644 --- a/crypt_gensalt.c +++ b/crypt_gensalt.c @@ -19,6 +19,7 @@ */ #include +#include #include #ifndef __set_errno @@ -122,3 +123,60 @@ char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, return output; } + +#define SHA2_SALT_LEN_MAX 16 +#define SHA2_ROUNDS_MIN 1000 +#define SHA2_ROUNDS_MAX 999999999 +char *_crypt_gensalt_sha2_rn (const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) + +{ + char *o = output; + const char *i = input; + unsigned needed = 3 + MIN(size/3*4, SHA2_SALT_LEN_MAX) + 1; + + if (size < 3 || output_size < needed) + goto error; + + size = MIN(size, SHA2_SALT_LEN_MAX/4*3); + + o[0] = prefix[0]; + o[1] = prefix[1]; + o[2] = prefix[2]; + o += 3; + + if (count) { + count = MAX(SHA2_ROUNDS_MIN, MIN(count, SHA2_ROUNDS_MAX)); + int n = snprintf (o, output_size-3, "rounds=%ld$", count); + if (n < 0 || n >= output_size-3) + goto error; + needed += n; + o += n; + } + + if (output_size < needed) + goto error; + + while (size >= 3) { + unsigned long value = + (unsigned long)(unsigned char)i[0] | + ((unsigned long)(unsigned char)i[1] << 8) | + ((unsigned long)(unsigned char)i[2] << 16); + o[0] = _crypt_itoa64[value & 0x3f]; + o[1] = _crypt_itoa64[(value >> 6) & 0x3f]; + o[2] = _crypt_itoa64[(value >> 12) & 0x3f]; + o[3] = _crypt_itoa64[(value >> 18) & 0x3f]; + size -= 3; + i += 3; + o += 3; + } + o[0] = '\0'; + + return output; + +error: + if (output_size > 0) + output[0] = '\0'; + errno = ENOMEM; + return NULL; +} diff --git a/wrapper.c b/wrapper.c index 344053b..070d91d 100644 --- a/wrapper.c +++ b/wrapper.c @@ -44,12 +44,18 @@ #include "crypt_blowfish.h" #include "crypt_gensalt.h" +extern char *_crypt_gensalt_sha2_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size); #if defined(__GLIBC__) && defined(_LIBC) /* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */ #include "crypt.h" extern char *__md5_crypt_r(const char *key, const char *salt, char *buffer, int buflen); +extern char *__sha256_crypt_r (const char *key, const char *salt, + char *buffer, int buflen); +extern char *__sha512_crypt_r (const char *key, const char *salt, + char *buffer, int buflen); /* crypt-entry.c needs to be patched to define __des_crypt_r rather than * __crypt_r, and not define crypt_r and crypt at all */ extern char *__des_crypt_r(const char *key, const char *salt, @@ -112,6 +118,10 @@ static char *_crypt_retval_magic(char *retval, const char *setting, char *__crypt_rn(__const char *key, __const char *setting, void *data, int size) { + if (setting[0] == '$' && setting[1] == '6') + return __sha512_crypt_r(key, setting, (char *)data, size); + if (setting[0] == '$' && setting[1] == '5') + return __sha256_crypt_r(key, setting, (char *)data, size); if (setting[0] == '$' && setting[1] == '2') return _crypt_blowfish_rn(key, setting, (char *)data, size); if (setting[0] == '$' && setting[1] == '1') @@ -129,6 +139,16 @@ char *__crypt_rn(__const char *key, __const char *setting, char *__crypt_ra(__const char *key, __const char *setting, void **data, int *size) { + if (setting[0] == '$' && setting[1] == '6') { + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return __sha512_crypt_r(key, setting, (char *)*data, *size); + } + if (setting[0] == '$' && setting[1] == '5') { + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return __sha256_crypt_r(key, setting, (char *)*data, *size); + } if (setting[0] == '$' && setting[1] == '2') { if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) return NULL; @@ -210,6 +230,9 @@ char *__crypt_gensalt_rn(const char *prefix, unsigned long count, return NULL; } + if (!strncmp(prefix, "$5$", 3) || !strncmp(prefix, "$6$", 3)) + use = _crypt_gensalt_sha2_rn; + else if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2y$", 4)) use = _crypt_gensalt_blowfish_rn; else -- 1.7.3.4