From 8105b1409307f7b254daab8d91f7f00e96090633 Mon Sep 17 00:00:00 2001 From: Daniel Fone Date: Wed, 29 Sep 2021 10:31:26 +1300 Subject: [PATCH] Merge upstream crypt_blowfish 1.3 This adds support for 2y and 2b hash variants. --- contrib/pgcrypto/crypt-blowfish.c | 363 ++++++++++++++----- contrib/pgcrypto/crypt-gensalt.c | 46 ++- contrib/pgcrypto/expected/crypt-blowfish.out | 7 + contrib/pgcrypto/px-crypt.c | 17 +- contrib/pgcrypto/px-crypt.h | 12 +- contrib/pgcrypto/sql/crypt-blowfish.sql | 3 + doc/src/sgml/pgcrypto.sgml | 2 +- 7 files changed, 344 insertions(+), 106 deletions(-) diff --git a/contrib/pgcrypto/crypt-blowfish.c b/contrib/pgcrypto/crypt-blowfish.c index a663852c..2f89b79a 100644 --- a/contrib/pgcrypto/crypt-blowfish.c +++ b/contrib/pgcrypto/crypt-blowfish.c @@ -1,27 +1,40 @@ /* * contrib/pgcrypto/crypt-blowfish.c * + * The crypt_blowfish homepage is: + * + * http://www.openwall.com/crypt/ + * * This code comes from John the Ripper password cracker, with reentrant * and crypt(3) interfaces added, but optimizations specific to password * cracking removed. * - * Written by Solar Designer in 1998-2002 and - * placed in the public domain. + * Written by Solar Designer in 1998-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. * - * There's absolutely no warranty. + * There's ABSOLUTELY NO WARRANTY, express or implied. * * It is my intent that you should be able to use this on your system, - * as a part of a software package, or anywhere else to improve security, - * ensure compatibility, or for any other purpose. I would appreciate + * as part of a software package, or anywhere else to improve security, + * ensure compatibility, or for any other purpose. I would appreciate * it if you give credit where it is due and keep your modifications in * the public domain as well, but I don't require that in order to let * you place this code and any modifications you make under a license * of your choice. * - * This implementation is compatible with OpenBSD bcrypt.c (version 2a) - * by Niels Provos , and uses some of his - * ideas. The password hashing algorithm was designed by David Mazieres - * . + * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix + * "$2b$", originally by Niels Provos , and it uses + * some of his ideas. The password hashing algorithm was designed by David + * Mazieres . For information on the level of + * compatibility for bcrypt hash prefixes other than "$2b$", please refer to + * the comments in BF_set_key() below and to the openwall crypt(3) man page. * * There's a paper on the algorithm that explains its design decisions: * @@ -30,13 +43,25 @@ * Some of the tricks in BF_ROUND might be inspired by Eric Young's * Blowfish library (I can't be sure if I would think of something if I * hadn't seen his code). + * + * Changes from upstream crypt_blowfish 1.3 + * + * - Indent with pgindent + * - Set BF_ASM 0 instead of 1 + * - Don't set errno, report errors instead + * - Add do/while to macros + * - Remove semicolons from macros + * - Use autoconf's WORDS_BIGENDIAN + * - Add parentheses to macros when args are used in computations. + * - Validate salt length + * - Check for interrupts when generating hash + * - Move blowfish gensalt to crypt-gensalt.c */ #include "postgres.h" #include "miscadmin.h" #include "px-crypt.h" -#include "px.h" #ifdef __i386__ #define BF_ASM 0 /* 1 */ @@ -519,13 +544,9 @@ BF_swap(BF_word *x, int count) L = tmp4 ^ data.ctx.P[BF_N + 1] #if BF_ASM - -extern void _BF_body_r(BF_ctx *ctx); - #define BF_body() \ _BF_body_r(&data.ctx) #else - #define BF_body() \ do { \ L = R = 0; \ @@ -549,39 +570,128 @@ do { \ static void BF_set_key(const char *key, BF_key expanded, BF_key initial, - int sign_extension_bug) + unsigned char flags) { const char *ptr = key; - int i, + unsigned int bug, + i, j; - BF_word tmp; + BF_word safety, + sign, + diff, + tmp[2]; + +/* + * There was a sign extension bug in older revisions of this function. While + * we would have liked to simply fix the bug and move on, we have to provide + * a backwards compatibility feature (essentially the bug) for some systems and + * a safety measure for some others. The latter is needed because for certain + * multiple inputs to the buggy algorithm there exist easily found inputs to + * the correct algorithm that produce the same hash. Thus, we optionally + * deviate from the correct algorithm just enough to avoid such collisions. + * While the bug itself affected the majority of passwords containing + * characters with the 8th bit set (although only a percentage of those in a + * collision-producing way), the anti-collision safety measure affects + * only a subset of passwords containing the '\xff' character (not even all of + * those passwords, just some of them). This character is not found in valid + * UTF-8 sequences and is rarely used in popular 8-bit character encodings. + * Thus, the safety measure is unlikely to cause much annoyance, and is a + * reasonable tradeoff to use when authenticating against existing hashes that + * are not reliably known to have been computed with the correct algorithm. + * + * We use an approach that tries to minimize side-channel leaks of password + * information - that is, we mostly use fixed-cost bitwise operations instead + * of branches or table lookups. (One conditional branch based on password + * length remains. It is not part of the bug aftermath, though, and is + * difficult and possibly unreasonable to avoid given the use of C strings by + * the caller, which results in similar timing leaks anyway.) + * + * For actual implementation, we set an array index in the variable "bug" + * (0 means no bug, 1 means sign extension bug emulation) and a flag in the + * variable "safety" (bit 16 is set when the safety measure is requested). + * Valid combinations of settings are: + * + * Prefix "$2a$": bug = 0, safety = 0x10000 + * Prefix "$2b$": bug = 0, safety = 0 + * Prefix "$2x$": bug = 1, safety = 0 + * Prefix "$2y$": bug = 0, safety = 0 + */ + bug = (unsigned int) flags & 1; + safety = ((BF_word) flags & 2) << 15; + + sign = diff = 0; for (i = 0; i < BF_N + 2; i++) { - tmp = 0; + tmp[0] = tmp[1] = 0; for (j = 0; j < 4; j++) { - tmp <<= 8; - if (sign_extension_bug) - tmp |= (BF_word_signed) (signed char) *ptr; - else - tmp |= (unsigned char) *ptr; - + tmp[0] <<= 8; + tmp[0] |= (unsigned char) *ptr; /* correct */ + tmp[1] <<= 8; + tmp[1] |= (BF_word_signed) (signed char) *ptr; /* bug */ +/* + * Sign extension in the first char has no effect - nothing to overwrite yet, + * and those extra 24 bits will be fully shifted out of the 32-bit word. For + * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign + * extension in tmp[1] occurs. Once this flag is set, it remains set. + */ + if (j) + sign |= tmp[1] & 0x80; if (!*ptr) ptr = key; else ptr++; } + diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ - expanded[i] = tmp; - initial[i] = BF_init_state.P[i] ^ tmp; + expanded[i] = tmp[bug]; + initial[i] = BF_init_state.P[i] ^ tmp[bug]; } + +/* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on + * non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to + * bit 16 */ + sign &= ~diff & safety; /* action needed? */ + +/* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + initial[0] ^= sign; } -char * -_crypt_blowfish_rn(const char *key, const char *setting, - char *output, int size) +static const unsigned char flags_by_subtype[26] = +{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; + +static char * +BF_crypt(const char *key, const char *setting, + char *output, int size, + BF_word min) { +#if BF_ASM + extern void _BF_body_r(BF_ctx *ctx); +#endif struct { BF_ctx ctx; @@ -618,7 +728,8 @@ _crypt_blowfish_rn(const char *key, const char *setting, if (setting[0] != '$' || setting[1] != '2' || - (setting[2] != 'a' && setting[2] != 'x') || + setting[2] < 'a' || setting[2] > 'z' || + !flags_by_subtype[(unsigned int) (unsigned char) setting[2] - 'a'] || setting[3] != '$' || setting[4] < '0' || setting[4] > '3' || setting[5] < '0' || setting[5] > '9' || @@ -631,16 +742,16 @@ _crypt_blowfish_rn(const char *key, const char *setting, } count = (BF_word) 1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); - if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) + if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { - px_memset(data.binary.salt, 0, sizeof(data.binary.salt)); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid salt"))); } BF_swap(data.binary.salt, 4); - BF_set_key(key, data.expanded_key, data.ctx.P, setting[2] == 'x'); + BF_set_key(key, data.expanded_key, data.ctx.P, + flags_by_subtype[(unsigned int) (unsigned char) setting[2] - 'a']); memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); @@ -673,53 +784,38 @@ _crypt_blowfish_rn(const char *key, const char *setting, do { + int done; + CHECK_FOR_INTERRUPTS(); - data.ctx.P[0] ^= data.expanded_key[0]; - data.ctx.P[1] ^= data.expanded_key[1]; - data.ctx.P[2] ^= data.expanded_key[2]; - data.ctx.P[3] ^= data.expanded_key[3]; - data.ctx.P[4] ^= data.expanded_key[4]; - data.ctx.P[5] ^= data.expanded_key[5]; - data.ctx.P[6] ^= data.expanded_key[6]; - data.ctx.P[7] ^= data.expanded_key[7]; - data.ctx.P[8] ^= data.expanded_key[8]; - data.ctx.P[9] ^= data.expanded_key[9]; - data.ctx.P[10] ^= data.expanded_key[10]; - data.ctx.P[11] ^= data.expanded_key[11]; - data.ctx.P[12] ^= data.expanded_key[12]; - data.ctx.P[13] ^= data.expanded_key[13]; - data.ctx.P[14] ^= data.expanded_key[14]; - data.ctx.P[15] ^= data.expanded_key[15]; - data.ctx.P[16] ^= data.expanded_key[16]; - data.ctx.P[17] ^= data.expanded_key[17]; - - BF_body(); - - tmp1 = data.binary.salt[0]; - tmp2 = data.binary.salt[1]; - tmp3 = data.binary.salt[2]; - tmp4 = data.binary.salt[3]; - data.ctx.P[0] ^= tmp1; - data.ctx.P[1] ^= tmp2; - data.ctx.P[2] ^= tmp3; - data.ctx.P[3] ^= tmp4; - data.ctx.P[4] ^= tmp1; - data.ctx.P[5] ^= tmp2; - data.ctx.P[6] ^= tmp3; - data.ctx.P[7] ^= tmp4; - data.ctx.P[8] ^= tmp1; - data.ctx.P[9] ^= tmp2; - data.ctx.P[10] ^= tmp3; - data.ctx.P[11] ^= tmp4; - data.ctx.P[12] ^= tmp1; - data.ctx.P[13] ^= tmp2; - data.ctx.P[14] ^= tmp3; - data.ctx.P[15] ^= tmp4; - data.ctx.P[16] ^= tmp1; - data.ctx.P[17] ^= tmp2; - - BF_body(); + for (i = 0; i < BF_N + 2; i += 2) + { + data.ctx.P[i] ^= data.expanded_key[i]; + data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; + } + + done = 0; + do + { + BF_body(); + if (done) + break; + done = 1; + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + for (i = 0; i < BF_N; i += 4) + { + data.ctx.P[i] ^= tmp1; + data.ctx.P[i + 1] ^= tmp2; + data.ctx.P[i + 2] ^= tmp3; + data.ctx.P[i + 3] ^= tmp4; + } + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + } while (1); } while (--count); for (i = 0; i < 6; i += 2) @@ -747,10 +843,111 @@ _crypt_blowfish_rn(const char *key, const char *setting, BF_encode(&output[7 + 22], data.binary.output, 23); output[7 + 22 + 31] = '\0'; -/* Overwrite the most obvious sensitive data we have on the stack. Note - * that this does not guarantee there's no sensitive data left on the - * stack and/or in registers; I'm not aware of portable code that does. */ - px_memset(&data, 0, sizeof(data)); - return output; } + +int +_crypt_output_magic(const char *setting, char *output, int size) +{ + if (size < 3) + return -1; + + output[0] = '*'; + output[1] = '0'; + output[2] = '\0'; + + if (setting[0] == '*' && setting[1] == '0') + output[1] = '1'; + + return 0; +} + +/* + * Please preserve the runtime self-test. It serves two purposes at once: + * + * 1. We really can't afford the risk of producing incompatible hashes e.g. + * when there's something like gcc bug 26587 again, whereas an application or + * library integrating this code might not also integrate our external tests or + * it might not run them after every build. Even if it does, the miscompile + * might only occur on the production build, but not on a testing build (such + * as because of different optimization settings). It is painful to recover + * from incorrectly-computed hashes - merely fixing whatever broke is not + * enough. Thus, a proactive measure like this self-test is needed. + * + * 2. We don't want to leave sensitive data from our actual password hash + * computation on the stack or in registers. Previous revisions of the code + * would do explicit cleanups, but simply running the self-test after hash + * computation is more reliable. + * + * The performance cost of this quick self-test is around 0.6% at the "$2a$08" + * setting. + */ +char * +_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size) +{ + const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; + static const char *const test_hashes[2] = + {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ + "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ + const char *test_hash = test_hashes[0]; + char *retval; + const char *p; + int ok; + struct + { + char s[7 + 22 + 1]; + char o[7 + 22 + 31 + 1 + 1 + 1]; + } buf; + +/* Hash the supplied password */ + _crypt_output_magic(setting, output, size); + retval = BF_crypt(key, setting, output, size, 16); + +/* + * Do a quick self-test. It is important that we make both calls to BF_crypt() + * from the same scope such that they likely use the same stack locations, + * which makes the second call overwrite the first call's sensitive data on the + * stack and makes it more likely that any alignment related issues would be + * detected by the self-test. + */ + memcpy(buf.s, test_setting, sizeof(buf.s)); + if (retval) + { + unsigned int flags = flags_by_subtype[ + (unsigned int) (unsigned char) setting[2] - 'a']; + + test_hash = test_hashes[flags & 1]; + buf.s[2] = setting[2]; + } + memset(buf.o, 0x55, sizeof(buf.o)); + buf.o[sizeof(buf.o) - 1] = 0; + p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); + + ok = (p == buf.o && + !memcmp(p, buf.s, 7 + 22) && + !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); + + { + const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + BF_key ae, + ai, + ye, + yi; + + BF_set_key(k, ae, ai, 2); /* $2a$ */ + BF_set_key(k, ye, yi, 4); /* $2y$ */ + ai[0] ^= 0x10000; /* undo the safety (for comparison) */ + ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && + !memcmp(ae, ye, sizeof(ae)) && + !memcmp(ai, yi, sizeof(ai)); + } + + if (ok) + return retval; + +/* Should not happen */ + _crypt_output_magic(setting, output, size); + return NULL; +} diff --git a/contrib/pgcrypto/crypt-gensalt.c b/contrib/pgcrypto/crypt-gensalt.c index 740f3612..6f2149d2 100644 --- a/contrib/pgcrypto/crypt-gensalt.c +++ b/contrib/pgcrypto/crypt-gensalt.c @@ -1,15 +1,31 @@ /* - * Written by Solar Designer and placed in the public domain. - * See crypt_blowfish.c for more information. - * * contrib/pgcrypto/crypt-gensalt.c * + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + * * This file contains salt generation functions for the traditional and * other common crypt(3) algorithms, except for bcrypt which is defined * entirely in crypt_blowfish.c. * - * Put bcrypt generator also here as crypt-blowfish.c - * may not be compiled always. -- marko + * Changes from upstream crypt_blowfish 1.3 + * + * - Format with pgindent + * - Don't set errno + * - Make _crypt_itoa64 static + * - Include bcrypt generator also here as crypt-blowfish.c may not always be + * compiled */ #include "postgres.h" @@ -22,9 +38,11 @@ static unsigned char _crypt_itoa64[64 + 1] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; char * -_crypt_gensalt_traditional_rn(unsigned long count, +_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { + (void) prefix; + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { if (output_size > 0) @@ -40,11 +58,13 @@ _crypt_gensalt_traditional_rn(unsigned long count, } char * -_crypt_gensalt_extended_rn(unsigned long count, +_crypt_gensalt_extended_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { unsigned long value; + (void) prefix; + /* Even iteration counts make it easier to detect weak DES keys from a look * at the hash, so they should be avoided */ if (size < 3 || output_size < 1 + 4 + 4 + 1 || @@ -76,11 +96,13 @@ _crypt_gensalt_extended_rn(unsigned long count, } char * -_crypt_gensalt_md5_rn(unsigned long count, +_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { unsigned long value; + (void) prefix; + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { if (output_size > 0) @@ -158,11 +180,13 @@ BF_encode(char *dst, const BF_word *src, int size) } char * -_crypt_gensalt_blowfish_rn(unsigned long count, +_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size) { if (size < 16 || output_size < 7 + 22 + 1 || - (count && (count < 4 || count > 31))) + (count && (count < 4 || count > 31)) || + prefix[0] != '$' || prefix[1] != '2' || + (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { if (output_size > 0) output[0] = '\0'; @@ -174,7 +198,7 @@ _crypt_gensalt_blowfish_rn(unsigned long count, output[0] = '$'; output[1] = '2'; - output[2] = 'a'; + output[2] = prefix[2]; output[3] = '$'; output[4] = '0' + count / 10; output[5] = '0' + count % 10; diff --git a/contrib/pgcrypto/expected/crypt-blowfish.out b/contrib/pgcrypto/expected/crypt-blowfish.out index d79b0c04..3d6b215c 100644 --- a/contrib/pgcrypto/expected/crypt-blowfish.out +++ b/contrib/pgcrypto/expected/crypt-blowfish.out @@ -13,6 +13,13 @@ SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); $2a$06$RQiOJ.3ELirrXwxIZY8q0OR3CVJrAfda1z26CCHPnB6mmVZD8p0/C (1 row) +-- support $2b$ hashes +SELECT crypt('password', '$2b$06$cqhNY4qXkVeKliLWOxCFieDY6/J4SmCEojsXfHs7iF4X1r3tuNepW'); + crypt +-------------------------------------------------------------- + $2b$06$cqhNY4qXkVeKliLWOxCFieDY6/J4SmCEojsXfHs7iF4X1r3tuNepW +(1 row) + -- error, salt too short: SELECT crypt('foox', '$2a$'); ERROR: invalid salt diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c index 0913ff2c..1e7a712a 100644 --- a/contrib/pgcrypto/px-crypt.c +++ b/contrib/pgcrypto/px-crypt.c @@ -78,7 +78,9 @@ struct px_crypt_algo static const struct px_crypt_algo px_crypt_list[] = { {"$2a$", 4, run_crypt_bf}, + {"$2b$", 4, run_crypt_bf}, {"$2x$", 4, run_crypt_bf}, + {"$2y$", 4, run_crypt_bf}, {"$2$", 3, NULL}, /* N/A */ {"$1$", 3, run_crypt_md5}, {"_", 1, run_crypt_des}, @@ -112,8 +114,9 @@ px_crypt(const char *psw, const char *salt, char *buf, unsigned len) struct generator { char *name; - char *(*gen) (unsigned long count, const char *input, int size, - char *output, int output_size); + char *(*gen) (const char *prefix, unsigned long count, const char *input, + int size, char *output, int output_size); + char *prefix; int input_len; int def_rounds; int min_rounds; @@ -121,10 +124,10 @@ struct generator }; static struct generator gen_list[] = { - {"des", _crypt_gensalt_traditional_rn, 2, 0, 0, 0}, - {"md5", _crypt_gensalt_md5_rn, 6, 0, 0, 0}, - {"xdes", _crypt_gensalt_extended_rn, 3, PX_XDES_ROUNDS, 1, 0xFFFFFF}, - {"bf", _crypt_gensalt_blowfish_rn, 16, PX_BF_ROUNDS, 4, 31}, + {"des", _crypt_gensalt_traditional_rn, "", 2, 0, 0, 0}, + {"md5", _crypt_gensalt_md5_rn, "$1$", 6, 0, 0, 0}, + {"xdes", _crypt_gensalt_extended_rn, "_", 3, PX_XDES_ROUNDS, 1, 0xFFFFFF}, + {"bf", _crypt_gensalt_blowfish_rn, "$2a$", 16, PX_BF_ROUNDS, 4, 31}, {NULL, NULL, 0, 0, 0, 0} }; @@ -154,7 +157,7 @@ px_gen_salt(const char *salt_type, char *buf, int rounds) if (!pg_strong_random(rbuf, g->input_len)) return PXE_NO_RANDOM; - p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN); + p = g->gen(g->prefix, rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN); px_memset(rbuf, 0, sizeof(rbuf)); if (p == NULL) diff --git a/contrib/pgcrypto/px-crypt.h b/contrib/pgcrypto/px-crypt.h index 08001a81..1a2dce77 100644 --- a/contrib/pgcrypto/px-crypt.h +++ b/contrib/pgcrypto/px-crypt.h @@ -56,19 +56,23 @@ int px_gen_salt(const char *salt_type, char *dst, int rounds); */ /* crypt-gensalt.c */ -char *_crypt_gensalt_traditional_rn(unsigned long count, +char *_crypt_gensalt_traditional_rn(const char *prefix, + unsigned long count, const char *input, int size, char *output, int output_size); -char *_crypt_gensalt_extended_rn(unsigned long count, +char *_crypt_gensalt_extended_rn(const char *prefix, + unsigned long count, const char *input, int size, char *output, int output_size); -char *_crypt_gensalt_md5_rn(unsigned long count, +char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); -char *_crypt_gensalt_blowfish_rn(unsigned long count, +char *_crypt_gensalt_blowfish_rn(const char *prefix, + unsigned long count, const char *input, int size, char *output, int output_size); /* disable 'extended DES crypt' */ /* #define DISABLE_XDES */ /* crypt-blowfish.c */ +int _crypt_output_magic(const char *setting, char *output, int size); char *_crypt_blowfish_rn(const char *key, const char *setting, char *output, int size); diff --git a/contrib/pgcrypto/sql/crypt-blowfish.sql b/contrib/pgcrypto/sql/crypt-blowfish.sql index 3b5a681c..0e96ee0c 100644 --- a/contrib/pgcrypto/sql/crypt-blowfish.sql +++ b/contrib/pgcrypto/sql/crypt-blowfish.sql @@ -6,6 +6,9 @@ SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); +-- support $2b$ hashes +SELECT crypt('password', '$2b$06$cqhNY4qXkVeKliLWOxCFieDY6/J4SmCEojsXfHs7iF4X1r3tuNepW'); + -- error, salt too short: SELECT crypt('foox', '$2a$'); diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml index bbaa2691..55842132 100644 --- a/doc/src/sgml/pgcrypto.sgml +++ b/doc/src/sgml/pgcrypto.sgml @@ -159,7 +159,7 @@ hmac(data bytea, key bytea, type text) returns bytea yes 128 60 - Blowfish-based, variant 2a + Blowfish-based, variants 2a, 2b, 2x, 2y md5 -- 2.32.0