mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	This changes the check for valid characters in the salt string to only allow plain ASCII letters and digits. The previous coding was locale-dependent which doesn't really seem like a great idea here; moreover it could not work correctly in multibyte encodings. This fixes a careless pointer-use-after-pfree, too. Reported-by: Tom Lane <tgl@sss.pgh.pa.us> Reported-by: Andres Freund <andres@anarazel.de> Author: Bernd Helmle <mailings@oopsware.de> Discussion: https://postgr.es/m/6fab35422df6b6b9727fdcc243c5fa1c667dd3b5.camel@oopsware.de
		
			
				
	
	
		
			643 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			643 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * contrib/pgcrypto/crypt-sha.c
 | 
						|
 *
 | 
						|
 * This implements shacrypt password hash functions and follows the
 | 
						|
 * public available reference implementation from
 | 
						|
 *
 | 
						|
 * https://www.akkadia.org/drepper/SHA-crypt.txt
 | 
						|
 *
 | 
						|
 * This code is public domain.
 | 
						|
 *
 | 
						|
 * Please see the inline comments for details about the algorithm.
 | 
						|
 *
 | 
						|
 * Basically the following code implements password hashing with sha256 and
 | 
						|
 * sha512 digest via OpenSSL. Additionally, an extended salt generation (see
 | 
						|
 * crypt-gensalt.c for details) is provided, which generates a salt suitable
 | 
						|
 * for either sha256crypt and sha512crypt password hash generation.
 | 
						|
 *
 | 
						|
 * Official identifiers for suitable password hashes used in salts are
 | 
						|
 * 5 : sha256crypt and
 | 
						|
 * 6 : sha512crypt
 | 
						|
 *
 | 
						|
 * The hashing code below supports and uses salt length up to 16 bytes. Longer
 | 
						|
 * input is possible, but any additional byte of the input is disregarded.
 | 
						|
 * gen_salt(), when called with a sha256crypt or sha512crypt identifier will
 | 
						|
 * always generate a 16 byte long salt string.
 | 
						|
 *
 | 
						|
 * Output is compatible with any sha256crypt and sha512crypt output
 | 
						|
 * generated by e.g. OpenSSL or libc crypt().
 | 
						|
 *
 | 
						|
 * The described algorithm uses default computing rounds of 5000. Currently,
 | 
						|
 * even when no specific rounds specification is used, we always explicitly
 | 
						|
 * print out the rounds option flag with the final hash password string.
 | 
						|
 *
 | 
						|
 * The length of the specific password hash (without magic bytes and salt
 | 
						|
 * string) is:
 | 
						|
 *
 | 
						|
 * sha256crypt: 43 bytes and
 | 
						|
 * sha512crypt: 86 bytes.
 | 
						|
 *
 | 
						|
 * Overall hashed password length is:
 | 
						|
 *
 | 
						|
 * sha256crypt: 80 bytes and
 | 
						|
 * sha512crypt: 123 bytes
 | 
						|
 *
 | 
						|
 */
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include "common/string.h"
 | 
						|
#include "mb/pg_wchar.h"
 | 
						|
#include "miscadmin.h"
 | 
						|
 | 
						|
#include "px-crypt.h"
 | 
						|
#include "px.h"
 | 
						|
 | 
						|
typedef enum
 | 
						|
{
 | 
						|
	PGCRYPTO_SHA256CRYPT = 0,
 | 
						|
	PGCRYPTO_SHA512CRYPT = 1,
 | 
						|
	PGCRYPTO_SHA_UNKOWN
 | 
						|
} PGCRYPTO_SHA_t;
 | 
						|
 | 
						|
static const char _crypt_itoa64[64 + 1] =
 | 
						|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 | 
						|
 | 
						|
/*
 | 
						|
 * Modern UNIX password, based on SHA crypt hashes
 | 
						|
 */
 | 
						|
char *
 | 
						|
px_crypt_shacrypt(const char *pw, const char *salt, char *passwd, unsigned dstlen)
 | 
						|
{
 | 
						|
	static const char rounds_prefix[] = "rounds=";
 | 
						|
	static const char *magic_bytes[2] = {"$5$", "$6$"};
 | 
						|
 | 
						|
	/* Used to create the password hash string */
 | 
						|
	StringInfo	out_buf = NULL;
 | 
						|
 | 
						|
	PGCRYPTO_SHA_t type = PGCRYPTO_SHA_UNKOWN;
 | 
						|
	PX_MD	   *digestA = NULL;
 | 
						|
	PX_MD	   *digestB = NULL;
 | 
						|
	int			err;
 | 
						|
 | 
						|
	const char *dec_salt_binary;	/* pointer into the real salt string */
 | 
						|
	StringInfo	decoded_salt = NULL;	/* decoded salt string */
 | 
						|
	unsigned char sha_buf[PX_SHACRYPT_DIGEST_MAX_LEN];
 | 
						|
 | 
						|
	/* temporary buffer for digests */
 | 
						|
	unsigned char sha_buf_tmp[PX_SHACRYPT_DIGEST_MAX_LEN];
 | 
						|
	char		rounds_custom = 0;
 | 
						|
	char	   *p_bytes = NULL;
 | 
						|
	char	   *s_bytes = NULL;
 | 
						|
	char	   *cp = NULL;
 | 
						|
	const char *fp = NULL;		/* intermediate pointer within salt string */
 | 
						|
	const char *ep = NULL;		/* holds pointer to the end of the salt string */
 | 
						|
	size_t		buf_size = 0;	/* buffer size for sha256crypt/sha512crypt */
 | 
						|
	unsigned int block;			/* number of bytes processed */
 | 
						|
	uint32		rounds = PX_SHACRYPT_ROUNDS_DEFAULT;
 | 
						|
	unsigned int len,
 | 
						|
				salt_len = 0;
 | 
						|
 | 
						|
	/* Sanity checks */
 | 
						|
	if (!passwd)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	if (pw == NULL)
 | 
						|
		elog(ERROR, "null value for password rejected");
 | 
						|
 | 
						|
	if (salt == NULL)
 | 
						|
		elog(ERROR, "null value for salt rejected");
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Make sure result buffers are large enough.
 | 
						|
	 */
 | 
						|
	if (dstlen < PX_SHACRYPT_BUF_LEN)
 | 
						|
		elog(ERROR, "insufficient result buffer size to encrypt password");
 | 
						|
 | 
						|
	/* Init result buffer */
 | 
						|
	out_buf = makeStringInfoExt(PX_SHACRYPT_BUF_LEN);
 | 
						|
	decoded_salt = makeStringInfoExt(PX_SHACRYPT_SALT_MAX_LEN);
 | 
						|
 | 
						|
	/* Init contents of buffers properly */
 | 
						|
	memset(&sha_buf, '\0', sizeof(sha_buf));
 | 
						|
	memset(&sha_buf_tmp, '\0', sizeof(sha_buf_tmp));
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Decode the salt string. We need to know how many rounds and which
 | 
						|
	 * digest we have to use to hash the password.
 | 
						|
	 */
 | 
						|
	len = strlen(pw);
 | 
						|
	dec_salt_binary = salt;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Analyze and prepare the salt string
 | 
						|
	 *
 | 
						|
	 * The magic string should be specified in the first three bytes of the
 | 
						|
	 * salt string.  Do some sanity checks first.
 | 
						|
	 */
 | 
						|
	if (strlen(dec_salt_binary) < 3)
 | 
						|
		ereport(ERROR,
 | 
						|
				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 | 
						|
				errmsg("invalid salt"));
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Check format of magic bytes. These should define either 5=sha256crypt
 | 
						|
	 * or 6=sha512crypt in the second byte, enclosed by ascii dollar signs.
 | 
						|
	 */
 | 
						|
	if ((dec_salt_binary[0] != '$') || (dec_salt_binary[2] != '$'))
 | 
						|
		ereport(ERROR,
 | 
						|
				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 | 
						|
				errmsg("invalid format of salt"),
 | 
						|
				errhint("magic byte format for shacrypt is either \"$5$\" or \"$6$\""));
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Check magic byte for supported shacrypt digest.
 | 
						|
	 *
 | 
						|
	 * We're just interested in the very first 3 bytes of the salt string,
 | 
						|
	 * since this defines the digest length to use.
 | 
						|
	 */
 | 
						|
	if (strncmp(dec_salt_binary, magic_bytes[0], strlen(magic_bytes[0])) == 0)
 | 
						|
	{
 | 
						|
		type = PGCRYPTO_SHA256CRYPT;
 | 
						|
		dec_salt_binary += strlen(magic_bytes[0]);
 | 
						|
	}
 | 
						|
	else if (strncmp(dec_salt_binary, magic_bytes[1], strlen(magic_bytes[1])) == 0)
 | 
						|
	{
 | 
						|
		type = PGCRYPTO_SHA512CRYPT;
 | 
						|
		dec_salt_binary += strlen(magic_bytes[1]);
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * dec_salt_binary pointer is positioned after the magic bytes now
 | 
						|
	 *
 | 
						|
	 * We extract any options in the following code branch. The only optional
 | 
						|
	 * setting we need to take care of is the "rounds" option. Note that the
 | 
						|
	 * salt generator already checked for invalid settings before, but we need
 | 
						|
	 * to do it here again to protect against injection of wrong values when
 | 
						|
	 * called without the generator.
 | 
						|
	 *
 | 
						|
	 * If there is any garbage added after the magic byte and the options/salt
 | 
						|
	 * string, we don't treat this special: This is just absorbed as part of
 | 
						|
	 * the salt with up to PX_SHACRYPT_SALT_LEN_MAX.
 | 
						|
	 *
 | 
						|
	 * Unknown magic byte is handled further below.
 | 
						|
	 */
 | 
						|
	if (strncmp(dec_salt_binary,
 | 
						|
				rounds_prefix, sizeof(rounds_prefix) - 1) == 0)
 | 
						|
	{
 | 
						|
		const char *num = dec_salt_binary + sizeof(rounds_prefix) - 1;
 | 
						|
		char	   *endp;
 | 
						|
		int			srounds = strtoint(num, &endp, 10);
 | 
						|
 | 
						|
		if (*endp != '$')
 | 
						|
			ereport(ERROR,
 | 
						|
					errcode(ERRCODE_SYNTAX_ERROR),
 | 
						|
					errmsg("could not parse salt options"));
 | 
						|
 | 
						|
		dec_salt_binary = endp + 1;
 | 
						|
 | 
						|
		/*
 | 
						|
		 * We violate supported lower or upper bound of rounds, but in this
 | 
						|
		 * case we change this value to the supported lower or upper value. We
 | 
						|
		 * don't do this silently and print a NOTICE in such a case.
 | 
						|
		 *
 | 
						|
		 * Note that a salt string generated with gen_salt() would never
 | 
						|
		 * generated such a salt string, since it would error out.
 | 
						|
		 *
 | 
						|
		 * But Drepper's upstream reference implementation supports this when
 | 
						|
		 * passing the salt string directly, so we maintain compatibility.
 | 
						|
		 */
 | 
						|
		if (srounds > PX_SHACRYPT_ROUNDS_MAX)
 | 
						|
		{
 | 
						|
			ereport(NOTICE,
 | 
						|
					errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 | 
						|
					errmsg("rounds=%d exceeds maximum supported value (%d), using %d instead",
 | 
						|
						   srounds, PX_SHACRYPT_ROUNDS_MAX,
 | 
						|
						   PX_SHACRYPT_ROUNDS_MAX));
 | 
						|
			srounds = PX_SHACRYPT_ROUNDS_MAX;
 | 
						|
		}
 | 
						|
		else if (srounds < PX_SHACRYPT_ROUNDS_MIN)
 | 
						|
		{
 | 
						|
			ereport(NOTICE,
 | 
						|
					errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 | 
						|
					errmsg("rounds=%d is below supported value (%d), using %d instead",
 | 
						|
						   srounds, PX_SHACRYPT_ROUNDS_MIN,
 | 
						|
						   PX_SHACRYPT_ROUNDS_MIN));
 | 
						|
			srounds = PX_SHACRYPT_ROUNDS_MIN;
 | 
						|
		}
 | 
						|
 | 
						|
		rounds = (uint32) srounds;
 | 
						|
		rounds_custom = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Choose the correct digest length and add the magic bytes to the result
 | 
						|
	 * buffer. Also handle possible invalid magic byte we've extracted above.
 | 
						|
	 */
 | 
						|
	switch (type)
 | 
						|
	{
 | 
						|
		case PGCRYPTO_SHA256CRYPT:
 | 
						|
			{
 | 
						|
				/* Two PX_MD objects required */
 | 
						|
				err = px_find_digest("sha256", &digestA);
 | 
						|
				if (err)
 | 
						|
					goto error;
 | 
						|
 | 
						|
				err = px_find_digest("sha256", &digestB);
 | 
						|
				if (err)
 | 
						|
					goto error;
 | 
						|
 | 
						|
				/* digest buffer length is 32 for sha256 */
 | 
						|
				buf_size = 32;
 | 
						|
 | 
						|
				appendStringInfoString(out_buf, magic_bytes[0]);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
		case PGCRYPTO_SHA512CRYPT:
 | 
						|
			{
 | 
						|
				/* Two PX_MD objects required */
 | 
						|
				err = px_find_digest("sha512", &digestA);
 | 
						|
				if (err)
 | 
						|
					goto error;
 | 
						|
 | 
						|
				err = px_find_digest("sha512", &digestB);
 | 
						|
				if (err)
 | 
						|
					goto error;
 | 
						|
 | 
						|
				buf_size = PX_SHACRYPT_DIGEST_MAX_LEN;
 | 
						|
 | 
						|
				appendStringInfoString(out_buf, magic_bytes[1]);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
		case PGCRYPTO_SHA_UNKOWN:
 | 
						|
			elog(ERROR, "unknown crypt identifier \"%c\"", salt[1]);
 | 
						|
	}
 | 
						|
 | 
						|
	if (rounds_custom > 0)
 | 
						|
		appendStringInfo(out_buf, "rounds=%u$", rounds);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * We need the real decoded salt string from salt input, this is every
 | 
						|
	 * character before the last '$' in the preamble. Append every compatible
 | 
						|
	 * character up to PX_SHACRYPT_SALT_MAX_LEN to the result buffer. Note
 | 
						|
	 * that depending on the input, there might be no '$' marker after the
 | 
						|
	 * salt, when there is no password hash attached at the end.
 | 
						|
	 *
 | 
						|
	 * We try hard to recognize mistakes, but since we might get an input
 | 
						|
	 * string which might also have the password hash after the salt string
 | 
						|
	 * section we give up as soon we reach the end of the input or if there
 | 
						|
	 * are any bytes consumed for the salt string until we reach the first '$'
 | 
						|
	 * marker thereafter.
 | 
						|
	 */
 | 
						|
	for (ep = dec_salt_binary;
 | 
						|
		 *ep && ep < (dec_salt_binary + PX_SHACRYPT_SALT_MAX_LEN);
 | 
						|
		 ep++)
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * Filter out any string which shouldn't be here.
 | 
						|
		 *
 | 
						|
		 * First check for accidentally embedded magic strings here. We don't
 | 
						|
		 * support '$' in salt strings anyways and seeing a magic byte trying
 | 
						|
		 * to identify shacrypt hashes might indicate that something went
 | 
						|
		 * wrong when generating this salt string. Note that we later check
 | 
						|
		 * for non-supported literals anyways, but any '$' here confuses us at
 | 
						|
		 * this point.
 | 
						|
		 */
 | 
						|
		fp = strstr(dec_salt_binary, magic_bytes[0]);
 | 
						|
		if (fp != NULL)
 | 
						|
			elog(ERROR, "bogus magic byte found in salt string");
 | 
						|
 | 
						|
		fp = strstr(dec_salt_binary, magic_bytes[1]);
 | 
						|
		if (fp != NULL)
 | 
						|
			elog(ERROR, "bogus magic byte found in salt string");
 | 
						|
 | 
						|
		/*
 | 
						|
		 * This looks very strict, but we assume the caller did something
 | 
						|
		 * wrong when we see a "rounds=" option here.
 | 
						|
		 */
 | 
						|
		fp = strstr(dec_salt_binary, rounds_prefix);
 | 
						|
		if (fp != NULL)
 | 
						|
			elog(ERROR, "invalid rounds option specified in salt string");
 | 
						|
 | 
						|
		if (*ep != '$')
 | 
						|
		{
 | 
						|
			if (strchr(_crypt_itoa64, *ep) != NULL)
 | 
						|
				appendStringInfoCharMacro(decoded_salt, *ep);
 | 
						|
			else
 | 
						|
				ereport(ERROR,
 | 
						|
						errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 | 
						|
						errmsg("invalid character in salt string: \"%.*s\"",
 | 
						|
							   pg_mblen(ep), ep));
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/*
 | 
						|
			 * We encountered a '$' marker. Check if we already absorbed some
 | 
						|
			 * bytes from input. If true, we are optimistic and terminate at
 | 
						|
			 * this stage. If not, we try further.
 | 
						|
			 *
 | 
						|
			 * If we already consumed enough bytes for the salt string,
 | 
						|
			 * everything that is after this marker is considered to be part
 | 
						|
			 * of an optionally specified password hash and ignored.
 | 
						|
			 */
 | 
						|
			if (decoded_salt->len > 0)
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	salt_len = decoded_salt->len;
 | 
						|
	appendStringInfoString(out_buf, decoded_salt->data);
 | 
						|
	elog(DEBUG1, "using salt \"%s\", salt len = %d, rounds = %u",
 | 
						|
		 decoded_salt->data, decoded_salt->len, rounds);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Sanity check: at this point the salt string buffer must not exceed
 | 
						|
	 * expected size.
 | 
						|
	 */
 | 
						|
	if (out_buf->len > (3 + 17 * rounds_custom + salt_len))
 | 
						|
		elog(ERROR, "unexpected length of salt string");
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 1. Start digest A
 | 
						|
	 * 2. Add the password string to digest A
 | 
						|
	 * 3. Add the salt to digest A
 | 
						|
	 */
 | 
						|
	px_md_update(digestA, (const unsigned char *) pw, len);
 | 
						|
	px_md_update(digestA, (const unsigned char *) decoded_salt->data, salt_len);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 4. Create digest B
 | 
						|
	 * 5. Add password to digest B
 | 
						|
	 * 6. Add the salt string to digest B
 | 
						|
	 * 7. Add the password again to digest B
 | 
						|
	 * 8. Finalize digest B
 | 
						|
	 */
 | 
						|
	px_md_update(digestB, (const unsigned char *) pw, len);
 | 
						|
	px_md_update(digestB, (const unsigned char *) dec_salt_binary, salt_len);
 | 
						|
	px_md_update(digestB, (const unsigned char *) pw, len);
 | 
						|
	px_md_finish(digestB, sha_buf);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * 9. For each block (excluding the NULL byte), add digest B to digest A.
 | 
						|
	 */
 | 
						|
	for (block = len; block > buf_size; block -= buf_size)
 | 
						|
		px_md_update(digestA, sha_buf, buf_size);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 10. For the remaining N bytes of the password string, add the first N
 | 
						|
	 * bytes of digest B to A.
 | 
						|
	 */
 | 
						|
	px_md_update(digestA, sha_buf, block);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 11. For each bit of the binary representation of the length of the
 | 
						|
	 * password string up to and including the highest 1-digit, starting from
 | 
						|
	 * to lowest bit position (numeric value 1)
 | 
						|
	 *
 | 
						|
	 * a) for a 1-digit add digest B (sha_buf) to digest A
 | 
						|
	 * b) for a 0-digit add the password string
 | 
						|
	 */
 | 
						|
	block = len;
 | 
						|
	while (block)
 | 
						|
	{
 | 
						|
		px_md_update(digestA,
 | 
						|
					 (block & 1) ? sha_buf : (const unsigned char *) pw,
 | 
						|
					 (block & 1) ? buf_size : len);
 | 
						|
 | 
						|
		/* right shift to next byte */
 | 
						|
		block >>= 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* 12. Finalize digest A */
 | 
						|
	px_md_finish(digestA, sha_buf);
 | 
						|
 | 
						|
	/* 13. Start digest DP */
 | 
						|
	px_md_reset(digestB);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 14 Add every byte of the password string (excluding trailing NULL)
 | 
						|
	 * to the digest DP
 | 
						|
	 */
 | 
						|
	for (block = len; block > 0; block--)
 | 
						|
		px_md_update(digestB, (const unsigned char *) pw, len);
 | 
						|
 | 
						|
	/* 15. Finalize digest DP */
 | 
						|
	px_md_finish(digestB, sha_buf_tmp);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 16. produce byte sequence P with same length as password.
 | 
						|
	 *     a) for each block of 32 or 64 bytes of length of the password
 | 
						|
	 *        string the entire digest DP is used
 | 
						|
	 *     b) for the remaining N (up to  31 or 63) bytes use the
 | 
						|
	 *        first N bytes of digest DP
 | 
						|
	 */
 | 
						|
	if ((p_bytes = palloc0(len)) == NULL)
 | 
						|
	{
 | 
						|
		goto error;
 | 
						|
	}
 | 
						|
 | 
						|
	/* N step of 16, copy over the bytes from password */
 | 
						|
	for (cp = p_bytes, block = len; block > buf_size; block -= buf_size, cp += buf_size)
 | 
						|
		memcpy(cp, sha_buf_tmp, buf_size);
 | 
						|
	memcpy(cp, sha_buf_tmp, block);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * 17. Start digest DS
 | 
						|
	 */
 | 
						|
	px_md_reset(digestB);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 18. Repeat the following 16+A[0] times, where A[0] represents the first
 | 
						|
	 *    byte in digest A interpreted as an 8-bit unsigned value
 | 
						|
	 *    add the salt to digest DS
 | 
						|
	 */
 | 
						|
	for (block = 16 + sha_buf[0]; block > 0; block--)
 | 
						|
		px_md_update(digestB, (const unsigned char *) dec_salt_binary, salt_len);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * 19. Finalize digest DS
 | 
						|
	 */
 | 
						|
	px_md_finish(digestB, sha_buf_tmp);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 20. Produce byte sequence S of the same length as the salt string where
 | 
						|
	 *
 | 
						|
	 * a) for each block of 32 or 64 bytes of length of the salt string the
 | 
						|
	 *    entire digest DS is used
 | 
						|
	 *
 | 
						|
	 * b) for the remaining N (up to  31 or 63) bytes use the first N
 | 
						|
	 *    bytes of digest DS
 | 
						|
	 */
 | 
						|
	if ((s_bytes = palloc0(salt_len)) == NULL)
 | 
						|
		goto error;
 | 
						|
 | 
						|
	for (cp = s_bytes, block = salt_len; block > buf_size; block -= buf_size, cp += buf_size)
 | 
						|
		memcpy(cp, sha_buf_tmp, buf_size);
 | 
						|
	memcpy(cp, sha_buf_tmp, block);
 | 
						|
 | 
						|
	/* Make sure we don't leave something important behind */
 | 
						|
	px_memset(&sha_buf_tmp, 0, sizeof sha_buf);
 | 
						|
 | 
						|
	/*-
 | 
						|
	 * 21. Repeat a loop according to the number specified in the rounds=<N>
 | 
						|
	 *     specification in the salt (or the default value if none is
 | 
						|
	 *     present).  Each round is numbered, starting with 0 and up to N-1.
 | 
						|
	 *
 | 
						|
	 *     The loop uses a digest as input.  In the first round it is the
 | 
						|
	 *     digest produced in step 12.  In the latter steps it is the digest
 | 
						|
	 *     produced in step 21.h of the previous round.  The following text
 | 
						|
	 *     uses the notation "digest A/B" to describe this behavior.
 | 
						|
	 */
 | 
						|
	for (block = 0; block < rounds; block++)
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * Make it possible to abort in case large values for "rounds" are
 | 
						|
		 * specified.
 | 
						|
		 */
 | 
						|
		CHECK_FOR_INTERRUPTS();
 | 
						|
 | 
						|
		/* a) start digest B */
 | 
						|
		px_md_reset(digestB);
 | 
						|
 | 
						|
		/*-
 | 
						|
		 * b) for odd round numbers add the byte sequence P to digest B
 | 
						|
		 * c) for even round numbers add digest A/B
 | 
						|
		 */
 | 
						|
		px_md_update(digestB,
 | 
						|
					 (block & 1) ? (const unsigned char *) p_bytes : sha_buf,
 | 
						|
					 (block & 1) ? len : buf_size);
 | 
						|
 | 
						|
		/* d) for all round numbers not divisible by 3 add the byte sequence S */
 | 
						|
		if ((block % 3) != 0)
 | 
						|
			px_md_update(digestB, (const unsigned char *) s_bytes, salt_len);
 | 
						|
 | 
						|
		/* e) for all round numbers not divisible by 7 add the byte sequence P */
 | 
						|
		if ((block % 7) != 0)
 | 
						|
			px_md_update(digestB, (const unsigned char *) p_bytes, len);
 | 
						|
 | 
						|
		/*-
 | 
						|
		 * f) for odd round numbers add digest A/C
 | 
						|
		 * g) for even round numbers add the byte sequence P
 | 
						|
		 */
 | 
						|
		px_md_update(digestB,
 | 
						|
					 (block & 1) ? sha_buf : (const unsigned char *) p_bytes,
 | 
						|
					 (block & 1) ? buf_size : len);
 | 
						|
 | 
						|
		/* h) finish digest C. */
 | 
						|
		px_md_finish(digestB, sha_buf);
 | 
						|
	}
 | 
						|
 | 
						|
	px_md_free(digestA);
 | 
						|
	px_md_free(digestB);
 | 
						|
 | 
						|
	digestA = NULL;
 | 
						|
	digestB = NULL;
 | 
						|
 | 
						|
	pfree(s_bytes);
 | 
						|
	pfree(p_bytes);
 | 
						|
 | 
						|
	s_bytes = NULL;
 | 
						|
	p_bytes = NULL;
 | 
						|
 | 
						|
	/* prepare final result buffer */
 | 
						|
	appendStringInfoCharMacro(out_buf, '$');
 | 
						|
 | 
						|
#define b64_from_24bit(B2, B1, B0, N)                                    \
 | 
						|
	do {                                                                 \
 | 
						|
		unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);              \
 | 
						|
		int		i = (N);                                                 \
 | 
						|
		while (i-- > 0)                                                  \
 | 
						|
		{                                                                \
 | 
						|
			appendStringInfoCharMacro(out_buf, _crypt_itoa64[w & 0x3f]); \
 | 
						|
			w >>= 6;                                                     \
 | 
						|
		}                                                                \
 | 
						|
	} while (0)
 | 
						|
 | 
						|
	switch (type)
 | 
						|
	{
 | 
						|
		case PGCRYPTO_SHA256CRYPT:
 | 
						|
			{
 | 
						|
				b64_from_24bit(sha_buf[0], sha_buf[10], sha_buf[20], 4);
 | 
						|
				b64_from_24bit(sha_buf[21], sha_buf[1], sha_buf[11], 4);
 | 
						|
				b64_from_24bit(sha_buf[12], sha_buf[22], sha_buf[2], 4);
 | 
						|
				b64_from_24bit(sha_buf[3], sha_buf[13], sha_buf[23], 4);
 | 
						|
				b64_from_24bit(sha_buf[24], sha_buf[4], sha_buf[14], 4);
 | 
						|
				b64_from_24bit(sha_buf[15], sha_buf[25], sha_buf[5], 4);
 | 
						|
				b64_from_24bit(sha_buf[6], sha_buf[16], sha_buf[26], 4);
 | 
						|
				b64_from_24bit(sha_buf[27], sha_buf[7], sha_buf[17], 4);
 | 
						|
				b64_from_24bit(sha_buf[18], sha_buf[28], sha_buf[8], 4);
 | 
						|
				b64_from_24bit(sha_buf[9], sha_buf[19], sha_buf[29], 4);
 | 
						|
				b64_from_24bit(0, sha_buf[31], sha_buf[30], 3);
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
		case PGCRYPTO_SHA512CRYPT:
 | 
						|
			{
 | 
						|
				b64_from_24bit(sha_buf[0], sha_buf[21], sha_buf[42], 4);
 | 
						|
				b64_from_24bit(sha_buf[22], sha_buf[43], sha_buf[1], 4);
 | 
						|
				b64_from_24bit(sha_buf[44], sha_buf[2], sha_buf[23], 4);
 | 
						|
				b64_from_24bit(sha_buf[3], sha_buf[24], sha_buf[45], 4);
 | 
						|
				b64_from_24bit(sha_buf[25], sha_buf[46], sha_buf[4], 4);
 | 
						|
				b64_from_24bit(sha_buf[47], sha_buf[5], sha_buf[26], 4);
 | 
						|
				b64_from_24bit(sha_buf[6], sha_buf[27], sha_buf[48], 4);
 | 
						|
				b64_from_24bit(sha_buf[28], sha_buf[49], sha_buf[7], 4);
 | 
						|
				b64_from_24bit(sha_buf[50], sha_buf[8], sha_buf[29], 4);
 | 
						|
				b64_from_24bit(sha_buf[9], sha_buf[30], sha_buf[51], 4);
 | 
						|
				b64_from_24bit(sha_buf[31], sha_buf[52], sha_buf[10], 4);
 | 
						|
				b64_from_24bit(sha_buf[53], sha_buf[11], sha_buf[32], 4);
 | 
						|
				b64_from_24bit(sha_buf[12], sha_buf[33], sha_buf[54], 4);
 | 
						|
				b64_from_24bit(sha_buf[34], sha_buf[55], sha_buf[13], 4);
 | 
						|
				b64_from_24bit(sha_buf[56], sha_buf[14], sha_buf[35], 4);
 | 
						|
				b64_from_24bit(sha_buf[15], sha_buf[36], sha_buf[57], 4);
 | 
						|
				b64_from_24bit(sha_buf[37], sha_buf[58], sha_buf[16], 4);
 | 
						|
				b64_from_24bit(sha_buf[59], sha_buf[17], sha_buf[38], 4);
 | 
						|
				b64_from_24bit(sha_buf[18], sha_buf[39], sha_buf[60], 4);
 | 
						|
				b64_from_24bit(sha_buf[40], sha_buf[61], sha_buf[19], 4);
 | 
						|
				b64_from_24bit(sha_buf[62], sha_buf[20], sha_buf[41], 4);
 | 
						|
				b64_from_24bit(0, 0, sha_buf[63], 2);
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
		case PGCRYPTO_SHA_UNKOWN:
 | 
						|
			/* we shouldn't land here ... */
 | 
						|
			elog(ERROR, "unsupported digest length");
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Copy over result to specified buffer.
 | 
						|
	 *
 | 
						|
	 * The passwd character buffer should have at least PX_SHACRYPT_BUF_LEN
 | 
						|
	 * allocated, since we checked above if dstlen is smaller than
 | 
						|
	 * PX_SHACRYPT_BUF_LEN (which also includes the NULL byte).
 | 
						|
	 *
 | 
						|
	 * In that case we would have failed above already.
 | 
						|
	 */
 | 
						|
	memcpy(passwd, out_buf->data, out_buf->len);
 | 
						|
 | 
						|
	/* make sure nothing important is left behind */
 | 
						|
	px_memset(&sha_buf, 0, sizeof sha_buf);
 | 
						|
	destroyStringInfo(out_buf);
 | 
						|
	destroyStringInfo(decoded_salt);
 | 
						|
 | 
						|
	/* ...and we're done */
 | 
						|
	return passwd;
 | 
						|
 | 
						|
error:
 | 
						|
	if (digestA != NULL)
 | 
						|
		px_md_free(digestA);
 | 
						|
 | 
						|
	if (digestB != NULL)
 | 
						|
		px_md_free(digestB);
 | 
						|
 | 
						|
	destroyStringInfo(out_buf);
 | 
						|
	destroyStringInfo(decoded_salt);
 | 
						|
 | 
						|
	ereport(ERROR,
 | 
						|
			errcode(ERRCODE_INTERNAL_ERROR),
 | 
						|
			errmsg("cannot create encrypted password"));
 | 
						|
	return NULL;				/* keep compiler quiet */
 | 
						|
}
 |