pgcrypto update
Big thanks to Solar Designer who pointed out a bug in bcrypt
salt generation code. He also urged using better random source
and making possible to choose using bcrypt and xdes rounds more
easily. So, here's patch:
* For all salt generation, use Solar Designer's own code. This
is mostly due fact that his code is more fit for get_random_bytes()
style interface.
* New function: gen_salt(type, rounds). This lets specify iteration
count for algorithm.
* random.c: px_get_random_bytes() function.
Supported randomness soure: /dev/urandom, OpenSSL PRNG, libc random()
Default: /dev/urandom.
* Draft description of C API for pgcrypto functions.
New files: API, crypt-gensalt.c, random.c
--
marko
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/API contrib/pgcrypto/API
--- contrib/pgcrypto.orig/API Thu Jan 1 03:00:00 1970
+++ contrib/pgcrypto/API Sat Sep 22 01:57:41 2001
@@ -0,0 +1,163 @@
+
+C API for pgcrypto
+==================
+
+
+UN*X crypt()
+============
+
+#include <px-crypt.h>
+
+char *
+px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen);
+
+ returns buf or NULL for error.
+
+unsigned px_gen_salt(const char *salt_type, char *dst, int rounds);
+
+ returns salt size. dst should be PX_MAX_SALT_LEN bytes.
+ 'rounds' is algorithm specific. 0 means default for
+ that algorithm.
+
+Random
+======
+
+int px_rand_get_bytes(uint8 *dst, int num)
+
+
+Crypto "objects"
+================
+
+PX_MD - Message digest
+PX_HMAC - HMAC (Hash MAC)
+PX_Cipher - cipher+mode: provided by libs
+PX_Combo - higher-level encryption -> padding, [MD]
+
+Objects are activated with following functions:
+
+int px_find_digest(const char *name, PX_MD **res);
+int px_find_hmac(const char *name, PX_HMAC **res);
+int px_find_cipher(const char *name, PX_Cipher **res);
+int px_find_combo(const char *name, PX_Combo **res);
+
+ returns 0 on success, < 0 on error. If successful,
+ *res contains pointer to new object.
+
+Message Digest
+==============
+
+uint px_md_result_size(PX_MD *md)
+
+ returns final result size in bytes
+
+void px_md_reset(PX_MD *md)
+
+ resets md to clean state
+
+uint px_md_block_size(PX_MD *md)
+
+ return algorithm block size in bytes
+
+void px_md_update(PX_MD *md, const uint8 *data, uint dlen)
+
+ updates hash state with new data
+
+void px_md_finish(PX_MD *md, uint8 *buf)
+
+ puts final hash state into buf. buf should have room
+ for px_md_result_size() bytes.
+
+void px_md_free(PX_MD *md)
+
+ frees resources.
+
+HMAC (Hash Message Authentication Code)
+=======================================
+
+int px_hmac_init(PX_HMAC *hmac, const uint8 *key, uint klen)
+
+ initalized hmac state with key.
+
+uint px_hmac_result_size(PX_HMAC *md)
+
+ returns final result size in bytes
+
+void px_hmac_reset(PX_HMAC *md)
+
+ resets md to state after _init()
+
+uint px_hmac_block_size(PX_HMAC *md)
+
+ return algorithm block size in bytes
+
+void px_hmac_update(PX_HMAC *md, const uint8 *data, uint dlen)
+
+ updates hash state with new data
+
+void px_hmac_finish(PX_HMAC *md, uint8 *buf)
+
+ puts final hash state into buf. buf should have room
+ for px_hmac_result_size() bytes.
+
+void px_hmac_free(PX_HMAC *md)
+
+ frees resources.
+
+
+Cipher
+======
+
+uint px_cipher_key_size(PX_Cipher *c)
+
+ returns max key size in bytes
+
+uint px_cipher_block_size(PX_Cipher *c)
+
+ returns cipher+mode block size in bytes. So blowfish
+ in CFB mode should return 1.
+
+uint px_cipher_iv_size(PX_Cipher *c)
+
+ returns IV size in bytes.
+
+int px_cipher_init(PX_Cipher *c, uint8 *key, uint klen, uint8 *iv)
+
+ initializes cipher with supplied key and iv.
+
+int px_cipher_encrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res)
+
+ encrypts data. res must have room for dlen bytes.
+ data must be multiple of px_cipher_block_size().
+
+int px_cipher_decrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res)
+
+ decrypts data. res must have room for dlen bytes.
+
+void px_cipher_free(PX_Cipher *c)
+
+ frees resources assiocated.
+
+PX_Combo
+========
+
+uint px_combo_encrypt_len(PX_Combo *c, uint dlen)
+
+ calculates max result length for dlen of data.
+
+uint px_combo_decrypt_len(PX_Combo *c, uint dlen)
+
+ calculates result length for dlen of data.
+
+int px_combo_init(PX_Combo *c, uint8 *key, uint klen, uint8 *iv, uint ivlen)
+
+ initializes c with key and iv. If cipher uses fixed length keys,
+ key will be padded with zeroes to needed length.
+
+int px_combo_encrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen)
+
+int px_combo_decrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen)
+
+void px_combo_free(PX_Combo *c)
+
+ frees resources assiocated.
+
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/Makefile contrib/pgcrypto/Makefile
--- contrib/pgcrypto.orig/Makefile Sun Sep 16 18:11:09 2001
+++ contrib/pgcrypto/Makefile Sat Sep 22 02:30:09 2001
@@ -12,6 +12,18 @@
# either 'builtin', 'system'
cryptsrc = builtin
+# Random source, preferred order:
+# 'dev' - read from random device
+#
+# 'openssl' - use openssl PRNG.
+# Note that currently pgcrypto does not do any
+# entropy feeding to it
+# This works ofcouse only with cryptolib = openssl
+#
+# 'silly' - use libc random() - very weak
+random = dev
+random_dev = \"/dev/urandom\"
+
##########################
ifeq ($(cryptolib), builtin)
@@ -38,8 +50,19 @@
CRYPTO_CFLAGS += -DPX_SYSTEM_CRYPT
endif
+ifeq ($(random), dev)
+CRYPTO_CFLAGS += -DRAND_DEV=$(random_dev)
+endif
+ifeq ($(random), openssl)
+CRYPTO_CFLAGS += -DRAND_OPENSSL
+endif
+ifeq ($(random), silly)
+CRYPTO_CFLAGS += -DRAND_SILLY
+endif
+
NAME := pgcrypto
-SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c
+SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \
+ crypt-gensalt.c random.c
OBJS := $(SRCS:.c=.o)
SHLIB_LINK := $(CRYPTO_LDFLAGS)
SO_MAJOR_VERSION = 0
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/README.pgcrypto contrib/pgcrypto/README.pgcrypto
--- contrib/pgcrypto.orig/README.pgcrypto Tue Aug 21 02:42:41 2001
+++ contrib/pgcrypto/README.pgcrypto Sat Sep 22 02:39:52 2001
@@ -9,6 +9,13 @@
Edit makefile, if you want to use any external library.
+NB! Default randomness source is /dev/urandom device. If you
+do not have it, you also need to edit Makefile to let pgcrypto
+use either OpenSSL PRNG or libc random() PRNG. Using libc random()
+is discouraged.
+
+After editing Makefile:
+
make
make install
@@ -72,6 +79,27 @@
When you use --enable-system-crypt then note that system
libcrypt may not support them all.
+
+gen_salt(type::text, rounds::int4)::text
+
+ same as above, but lets user specify iteration count
+ for algorithm. Number is algotithm specific:
+
+ type default min max
+ ---------------------------------
+ xdes 725 1 16777215
+ bf 6 4 31
+
+ In case of xdes there is a additional limitation that the
+ count must be a odd number.
+
+ The higher the count, the more time it takes to calculate
+ crypt and therefore the more time to break it. But beware!
+ With too high count it takes a _very_long_ time to
+ calculate it.
+
+ For maximum security, you should choose the 'bf' crypt
+ and use maximum number of rounds you can still tolerate.
encrypt(data::bytea, key::bytea, type::text)::bytea
decrypt(data::bytea, key::bytea, type::text)::bytea
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/crypt-blowfish.c contrib/pgcrypto/crypt-blowfish.c
--- contrib/pgcrypto.orig/crypt-blowfish.c Tue Aug 21 03:32:01 2001
+++ contrib/pgcrypto/crypt-blowfish.c Thu Sep 20 11:18:37 2001
@@ -705,28 +705,3 @@
return output;
}
-char *_crypt_gensalt_blowfish_rn(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))) {
- if (output_size > 0) output[0] = '\0';
- __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
- return NULL;
- }
-
- if (!count) count = 5;
-
- output[0] = '$';
- output[1] = '2';
- output[2] = 'a';
- output[3] = '$';
- output[4] = '0' + count / 10;
- output[5] = '0' + count % 10;
- output[6] = '$';
-
- BF_encode(&output[7], (BF_word *)input, 16);
- output[7 + 22] = '\0';
-
- return output;
-}
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/crypt-gensalt.c contrib/pgcrypto/crypt-gensalt.c
--- contrib/pgcrypto.orig/crypt-gensalt.c Thu Jan 1 03:00:00 1970
+++ contrib/pgcrypto/crypt-gensalt.c Wed Sep 19 12:01:51 2001
@@ -0,0 +1,181 @@
+/*
+ * Written by Solar Designer and placed in the public domain.
+ * 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
+ */
+
+#include <postgres.h>
+#include "px-crypt.h"
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+#undef __CONST
+#ifdef __GNUC__
+#define __CONST __const
+#else
+#define __CONST
+#endif
+
+typedef unsigned int BF_word;
+
+unsigned char _crypt_itoa64[64 + 1] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+char *_crypt_gensalt_traditional_rn(unsigned long count,
+ __CONST char *input, int size, char *output, int output_size)
+{
+ if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
+ if (output_size > 0) output[0] = '\0';
+ __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
+ return NULL;
+ }
+
+ output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
+ output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
+ output[2] = '\0';
+
+ return output;
+}
+
+char *_crypt_gensalt_extended_rn(unsigned long count,
+ __CONST char *input, int size, char *output, int output_size)
+{
+ unsigned long value;
+
+/* 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 ||
+ (count && (count > 0xffffff || !(count & 1)))) {
+ if (output_size > 0) output[0] = '\0';
+ __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
+ return NULL;
+ }
+
+ if (!count) count = 725;
+
+ output[0] = '_';
+ output[1] = _crypt_itoa64[count & 0x3f];
+ output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
+ output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
+ output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
+ value = (unsigned long)input[0] |
+ ((unsigned long)input[1] << 8) |
+ ((unsigned long)input[2] << 16);
+ output[5] = _crypt_itoa64[value & 0x3f];
+ output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
+ output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
+ output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
+ output[9] = '\0';
+
+ return output;
+}
+
+char *_crypt_gensalt_md5_rn(unsigned long count,
+ __CONST char *input, int size, char *output, int output_size)
+{
+ unsigned long value;
+
+ if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
+ if (output_size > 0) output[0] = '\0';
+ __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
+ return NULL;
+ }
+
+ output[0] = '$';
+ output[1] = '1';
+ output[2] = '$';
+ value = (unsigned long)input[0] |
+ ((unsigned long)input[1] << 8) |
+ ((unsigned long)input[2] << 16);
+ output[3] = _crypt_itoa64[value & 0x3f];
+ output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
+ output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
+ output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
+ output[7] = '\0';
+
+ if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
+ value = (unsigned long)input[3] |
+ ((unsigned long)input[4] << 8) |
+ ((unsigned long)input[5] << 16);
+ output[7] = _crypt_itoa64[value & 0x3f];
+ output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
+ output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
+ output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
+ output[11] = '\0';
+ }
+
+ return output;
+}
+
+
+
+static unsigned char BF_itoa64[64 + 1] =
+ "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+static void BF_encode(char *dst, __CONST BF_word *src, int size)
+{
+ unsigned char *sptr = (unsigned char *)src;
+ unsigned char *end = sptr + size;
+ unsigned char *dptr = (unsigned char *)dst;
+ unsigned int c1, c2;
+
+ do {
+ c1 = *sptr++;
+ *dptr++ = BF_itoa64[c1 >> 2];
+ c1 = (c1 & 0x03) << 4;
+ if (sptr >= end) {
+ *dptr++ = BF_itoa64[c1];
+ break;
+ }
+
+ c2 = *sptr++;
+ c1 |= c2 >> 4;
+ *dptr++ = BF_itoa64[c1];
+ c1 = (c2 & 0x0f) << 2;
+ if (sptr >= end) {
+ *dptr++ = BF_itoa64[c1];
+ break;
+ }
+
+ c2 = *sptr++;
+ c1 |= c2 >> 6;
+ *dptr++ = BF_itoa64[c1];
+ *dptr++ = BF_itoa64[c2 & 0x3f];
+ } while (sptr < end);
+}
+
+char *_crypt_gensalt_blowfish_rn(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))) {
+ if (output_size > 0) output[0] = '\0';
+ __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
+ return NULL;
+ }
+
+ if (!count) count = 5;
+
+ output[0] = '$';
+ output[1] = '2';
+ output[2] = 'a';
+ output[3] = '$';
+ output[4] = '0' + count / 10;
+ output[5] = '0' + count % 10;
+ output[6] = '$';
+
+ BF_encode(&output[7], (BF_word *)input, 16);
+ output[7 + 22] = '\0';
+
+ return output;
+}
+
Binary files contrib/pgcrypto.orig/libpgcrypto.so.0 and contrib/pgcrypto/libpgcrypto.so.0 differ
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/openssl.c contrib/pgcrypto/openssl.c
--- contrib/pgcrypto.orig/openssl.c Tue Aug 21 02:42:41 2001
+++ contrib/pgcrypto/openssl.c Thu Sep 20 11:40:12 2001
@@ -35,7 +35,6 @@
#include <openssl/evp.h>
#include <openssl/blowfish.h>
-/*#include <openssl/crypto.h>*/
static uint
digest_result_size(PX_MD * h)
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.c contrib/pgcrypto/pgcrypto.c
--- contrib/pgcrypto.orig/pgcrypto.c Tue Aug 21 02:42:41 2001
+++ contrib/pgcrypto/pgcrypto.c Wed Sep 19 10:22:27 2001
@@ -200,9 +200,44 @@
len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
memcpy(buf, VARDATA(arg0), len);
buf[len] = 0;
- len = px_gen_salt(buf, buf);
+ len = px_gen_salt(buf, buf, 0);
if (len == 0)
elog(ERROR, "No such crypt algorithm");
+
+ res = (text *) palloc(len + VARHDRSZ);
+ VARATT_SIZEP(res) = len + VARHDRSZ;
+ memcpy(VARDATA(res), buf, len);
+
+ PG_FREE_IF_COPY(arg0, 0);
+
+ PG_RETURN_TEXT_P(res);
+}
+
+/* SQL function: pg_gen_salt(text, int4) returns text */
+PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
+
+Datum
+pg_gen_salt_rounds(PG_FUNCTION_ARGS)
+{
+ text *arg0;
+ int rounds;
+ uint len;
+ text *res;
+ char buf[PX_MAX_SALT_LEN + 1];
+
+ if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+ PG_RETURN_NULL();
+
+ arg0 = PG_GETARG_TEXT_P(0);
+ rounds = PG_GETARG_INT32(1);
+
+ len = VARSIZE(arg0) - VARHDRSZ;
+ len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
+ memcpy(buf, VARDATA(arg0), len);
+ buf[len] = 0;
+ len = px_gen_salt(buf, buf, rounds);
+ if (len == 0)
+ elog(ERROR, "No such crypt algorithm or bad number of rounds");
res = (text *) palloc(len + VARHDRSZ);
VARATT_SIZEP(res) = len + VARHDRSZ;
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.h contrib/pgcrypto/pgcrypto.h
--- contrib/pgcrypto.orig/pgcrypto.h Tue Aug 21 02:42:41 2001
+++ contrib/pgcrypto/pgcrypto.h Mon Sep 17 20:21:39 2001
@@ -38,6 +38,7 @@
Datum pg_hmac(PG_FUNCTION_ARGS);
Datum pg_hmac_exists(PG_FUNCTION_ARGS);
Datum pg_gen_salt(PG_FUNCTION_ARGS);
+Datum pg_gen_salt_rounds(PG_FUNCTION_ARGS);
Datum pg_crypt(PG_FUNCTION_ARGS);
Datum pg_encrypt(PG_FUNCTION_ARGS);
Datum pg_decrypt(PG_FUNCTION_ARGS);
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql contrib/pgcrypto/pgcrypto.sql
--- contrib/pgcrypto.orig/pgcrypto.sql Thu Jan 1 03:00:00 1970
+++ contrib/pgcrypto/pgcrypto.sql Sat Sep 22 02:36:53 2001
@@ -0,0 +1,65 @@
+
+-- drop function digest(bytea, text);
+-- drop function digest_exists(text);
+-- drop function hmac(bytea, bytea, text);
+-- drop function hmac_exists(text);
+-- drop function crypt(text, text);
+-- drop function gen_salt(text);
+-- drop function gen_salt(text, int4);
+-- drop function encrypt(bytea, bytea, text);
+-- drop function decrypt(bytea, bytea, text);
+-- drop function encrypt_iv(bytea, bytea, bytea, text);
+-- drop function decrypt_iv(bytea, bytea, bytea, text);
+-- drop function cipher_exists(text);
+
+
+
+CREATE FUNCTION digest(bytea, text) RETURNS bytea
+ AS '$libdir/pgcrypto',
+ 'pg_digest' LANGUAGE 'C';
+
+CREATE FUNCTION digest_exists(text) RETURNS bool
+ AS '$libdir/pgcrypto',
+ 'pg_digest_exists' LANGUAGE 'C';
+
+CREATE FUNCTION hmac(bytea, bytea, text) RETURNS bytea
+ AS '$libdir/pgcrypto',
+ 'pg_hmac' LANGUAGE 'C';
+
+CREATE FUNCTION hmac_exists(text) RETURNS bool
+ AS '$libdir/pgcrypto',
+ 'pg_hmac_exists' LANGUAGE 'C';
+
+CREATE FUNCTION crypt(text, text) RETURNS text
+ AS '$libdir/pgcrypto',
+ 'pg_crypt' LANGUAGE 'C';
+
+CREATE FUNCTION gen_salt(text) RETURNS text
+ AS '$libdir/pgcrypto',
+ 'pg_gen_salt' LANGUAGE 'C';
+
+CREATE FUNCTION gen_salt(text, int4) RETURNS text
+ AS '$libdir/pgcrypto',
+ 'pg_gen_salt_rounds' LANGUAGE 'C';
+
+CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea
+ AS '$libdir/pgcrypto',
+ 'pg_encrypt' LANGUAGE 'C';
+
+CREATE FUNCTION decrypt(bytea, bytea, text) RETURNS bytea
+ AS '$libdir/pgcrypto',
+ 'pg_decrypt' LANGUAGE 'C';
+
+CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text) RETURNS bytea
+ AS '$libdir/pgcrypto',
+ 'pg_encrypt_iv' LANGUAGE 'C';
+
+CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text) RETURNS bytea
+ AS '$libdir/pgcrypto',
+ 'pg_decrypt_iv' LANGUAGE 'C';
+
+CREATE FUNCTION cipher_exists(text) RETURNS bool
+ AS '$libdir/pgcrypto',
+ 'pg_cipher_exists' LANGUAGE 'C';
+
+
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql.in contrib/pgcrypto/pgcrypto.sql.in
--- contrib/pgcrypto.orig/pgcrypto.sql.in Tue Aug 21 02:42:41 2001
+++ contrib/pgcrypto/pgcrypto.sql.in Mon Sep 17 20:23:56 2001
@@ -5,10 +5,12 @@
-- drop function hmac_exists(text);
-- drop function crypt(text, text);
-- drop function gen_salt(text);
+-- drop function gen_salt(text, int4);
-- drop function encrypt(bytea, bytea, text);
-- drop function decrypt(bytea, bytea, text);
-- drop function encrypt_iv(bytea, bytea, bytea, text);
-- drop function decrypt_iv(bytea, bytea, bytea, text);
+-- drop function cipher_exists(text);
@@ -35,6 +37,10 @@
CREATE FUNCTION gen_salt(text) RETURNS text
AS '@MODULE_FILENAME@',
'pg_gen_salt' LANGUAGE 'C';
+
+CREATE FUNCTION gen_salt(text, int4) RETURNS text
+ AS '@MODULE_FILENAME@',
+ 'pg_gen_salt_rounds' LANGUAGE 'C';
CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea
AS '@MODULE_FILENAME@',
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px-crypt.c contrib/pgcrypto/px-crypt.c
--- contrib/pgcrypto.orig/px-crypt.c Tue Aug 21 03:32:01 2001
+++ contrib/pgcrypto/px-crypt.c Wed Sep 19 11:34:43 2001
@@ -30,6 +30,7 @@
*/
#include <postgres.h>
+#include "px.h"
#include "px-crypt.h"
@@ -62,12 +63,8 @@
char *buf, unsigned len)
{
char *res;
-
res = _crypt_blowfish_rn(psw, salt, buf, len);
- if (!res)
- return NULL;
- strcpy(buf, res);
- return buf;
+ return res;
}
static struct
@@ -128,106 +125,53 @@
* salt generators
*/
-static int my_rand64()
-{
- return random() % 64;
-}
-
-static uint
-gen_des_salt(char *buf)
-{
- buf[0] = px_crypt_a64[my_rand64()];
- buf[1] = px_crypt_a64[my_rand64()];
- buf[2] = 0;
-
- return 2;
-}
-
-static uint
-gen_xdes_salt(char *buf)
-{
- strcpy(buf, "_12345678");
-
- px_crypt_to64(buf+1, (long)PX_XDES_ROUNDS, 4);
- px_crypt_to64(buf+5, random(), 4);
-
- return 9;
-}
-
-static uint
-gen_md5_salt(char *buf)
-{
- int i;
- strcpy(buf, "$1$12345678$");
-
- for (i = 0; i < 8; i++)
- buf[3 + i] = px_crypt_a64[my_rand64()];
-
- return 12;
-}
-
-static uint
-gen_bf_salt(char *buf)
-{
- int i, count;
- char *s;
- char saltbuf[16+3];
- unsigned slen = 16;
- uint32 *v;
-
- for (i = 0; i < slen; i++)
- saltbuf[i] = random() & 255;
- saltbuf[16] = 0;
- saltbuf[17] = 0;
- saltbuf[18] = 0;
-
- strcpy(buf, "$2a$00$0123456789012345678901");
-
- count = PX_BF_ROUNDS;
- buf[4] = '0' + count / 10;
- buf[5] = '0' + count % 10;
-
- s = buf + 7;
- for (i = 0; i < slen; )
- {
- v = (uint32 *)&saltbuf[i];
- if (i + 3 <= slen)
- px_crypt_to64(s, *v, 4);
- else
- /* slen-i could be 1,2 make it 2,3 */
- px_crypt_to64(s, *v, slen-i+1);
- s += 4;
- i += 3;
- }
-
- s = buf;
- /*s = _crypt_gensalt_blowfish_rn(count, saltbuf, 16, buf, PX_MAX_CRYPT);*/
-
- return s ? strlen(s) : 0;
-}
-
struct generator {
char *name;
- uint (*gen)(char *buf);
+ char *(*gen)(unsigned long count, const char *input, int size,
+ char *output, int output_size);
+ int input_len;
+ int def_rounds;
+ int min_rounds;
+ int max_rounds;
};
static struct generator gen_list [] = {
- { "des", gen_des_salt },
- { "md5", gen_md5_salt },
- { "xdes", gen_xdes_salt },
- { "bf", gen_bf_salt },
- { NULL, NULL }
+ { "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 },
+ { NULL, NULL, 0, 0, 0 }
};
uint
-px_gen_salt(const char *salt_type, char *buf)
+px_gen_salt(const char *salt_type, char *buf, int rounds)
{
- int i;
+ int i, res;
struct generator *g;
+ char *p;
+ char rbuf[16];
+
for (i = 0; gen_list[i].name; i++) {
g = &gen_list[i];
- if (!strcasecmp(g->name, salt_type))
- return g->gen(buf);
+ if (strcasecmp(g->name, salt_type) != 0)
+ continue;
+
+ if (g->def_rounds) {
+ if (rounds == 0)
+ rounds = g->def_rounds;
+
+ if (rounds < g->min_rounds || rounds > g->max_rounds)
+ return 0;
+ }
+
+ res = px_get_random_bytes(rbuf, g->input_len);
+ if (res != g->input_len)
+ return 0;
+
+ p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN);
+ memset(rbuf, 0, sizeof(rbuf));
+
+ return p != NULL ? strlen(p) : 0;
}
return 0;
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px-crypt.h contrib/pgcrypto/px-crypt.h
--- contrib/pgcrypto.orig/px-crypt.h Tue Aug 21 03:32:01 2001
+++ contrib/pgcrypto/px-crypt.h Wed Sep 19 10:03:03 2001
@@ -38,19 +38,22 @@
/* max salt returned by gen_salt() */
#define PX_MAX_SALT_LEN 128
-/* rounds for xdes salt */
+/* default rounds for xdes salt */
/* NetBSD bin/passwd/local_passwd.c has (29 * 25)*/
#define PX_XDES_ROUNDS (29 * 25)
-/* rounds for blowfish salt */
+/* default for blowfish salt */
#define PX_BF_ROUNDS 6
/*
* main interface
*/
char *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen);
-unsigned px_gen_salt(const char *salt_type, char *dst);
+unsigned px_gen_salt(const char *salt_type, char *dst, int rounds);
+/*
+ * internal functions
+ */
/* misc.c */
extern void px_crypt_to64(char *s, unsigned long v, int n);
@@ -59,6 +62,15 @@
#define _crypt_to64 px_crypt_to64
#define _crypt_a64 px_crypt_a64
+/* crypt-gensalt.c */
+char *_crypt_gensalt_traditional_rn(unsigned long count,
+ const char *input, int size, char *output, int output_size);
+char *_crypt_gensalt_extended_rn(unsigned long count,
+ const char *input, int size, char *output, int output_size);
+char *_crypt_gensalt_md5_rn(unsigned long count,
+ const char *input, int size, char *output, int output_size);
+char *_crypt_gensalt_blowfish_rn(unsigned long count,
+ const char *input, int size, char *output, int output_size);
#ifndef PX_SYSTEM_CRYPT
@@ -66,9 +78,6 @@
/* #define DISABLE_XDES */
/* crypt-blowfish.c */
-char *_crypt_gensalt_blowfish_rn(unsigned long count,
- const char *input, int size,
- char *output, int output_size);
char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size);
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px.h contrib/pgcrypto/px.h
--- contrib/pgcrypto.orig/px.h Tue Aug 21 03:32:01 2001
+++ contrib/pgcrypto/px.h Wed Sep 19 13:38:42 2001
@@ -133,6 +133,8 @@
int px_find_cipher(const char *name, PX_Cipher **res);
int px_find_combo(const char *name, PX_Combo **res);
+int px_get_random_bytes(uint8 *dst, unsigned count);
+
const char *px_resolve_alias(const PX_Alias *aliases, const char *name);
#define px_md_result_size(md) (md)->result_size(md)
diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/random.c contrib/pgcrypto/random.c
--- contrib/pgcrypto.orig/random.c Thu Jan 1 03:00:00 1970
+++ contrib/pgcrypto/random.c Thu Sep 20 11:39:49 2001
@@ -0,0 +1,127 @@
+/*
+ * random.c
+ * Random functions.
+ *
+ * Copyright (c) 2001 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+
+#include <postgres.h>
+
+#include "px.h"
+
+
+#ifdef RAND_DEV
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static int
+safe_read(int fd, void *buf, size_t count)
+{
+ int done = 0;
+ char *p = buf;
+ int res;
+
+ while (count) {
+ res = read(fd, p, count);
+ if (res <= 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ p += res;
+ done += res;
+ count -= res;
+ }
+ return done;
+}
+
+int
+px_get_random_bytes(uint8 *dst, unsigned count)
+{
+ int fd;
+ int res;
+
+ fd = open(RAND_DEV, O_RDONLY);
+ if (fd == -1)
+ return -1;
+ res = safe_read(fd, dst, count);
+ close(fd);
+ return res;
+}
+
+#endif /* RAND_DEV */
+
+#ifdef RAND_SILLY
+
+int px_get_random_bytes(char *dst, unsigned count)
+{
+ int i;
+ for (i = 0; i < count; i++) {
+ *dst++ = random();
+ }
+ return i;
+}
+
+#endif /* RAND_SILLY */
+
+#ifdef RAND_OPENSSL
+
+#include <openssl/evp.h>
+#include <openssl/blowfish.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+
+static int openssl_random_init = 0;
+
+int px_get_random_bytes(uint8 *dst, unsigned count)
+{
+ int res;
+
+ if (!openssl_random_init) {
+ if (RAND_get_rand_method() == NULL) {
+ RAND_set_rand_method(RAND_SSLeay());
+ }
+ openssl_random_init = 1;
+ }
+
+ /*
+ * OpenSSL random should re-feeded occasionally.
+ * From /dev/urandom preferrably.
+ */
+
+ res = RAND_bytes(dst, count);
+ if (res > 0)
+ return count;
+
+ return -1;
+}
+
+#endif /* RAND_OPENSSL */
+
Your patch has been added to the PostgreSQL unapplied patches list at:
http://candle.pha.pa.us/cgi-bin/pgpatches
I will try to apply it within the next 48 hours.
Big thanks to Solar Designer who pointed out a bug in bcrypt
salt generation code. He also urged using better random source
and making possible to choose using bcrypt and xdes rounds more
easily. So, here's patch:* For all salt generation, use Solar Designer's own code. This
is mostly due fact that his code is more fit for get_random_bytes()
style interface.
* New function: gen_salt(type, rounds). This lets specify iteration
count for algorithm.
* random.c: px_get_random_bytes() function.
Supported randomness soure: /dev/urandom, OpenSSL PRNG, libc random()
Default: /dev/urandom.
* Draft description of C API for pgcrypto functions.New files: API, crypt-gensalt.c, random.c
--
markodiff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/API contrib/pgcrypto/API --- contrib/pgcrypto.orig/API Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/API Sat Sep 22 01:57:41 2001 @@ -0,0 +1,163 @@ + +C API for pgcrypto +================== + + +UN*X crypt() +============ + +#include <px-crypt.h> + +char * +px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen); + + returns buf or NULL for error. + +unsigned px_gen_salt(const char *salt_type, char *dst, int rounds); + + returns salt size. dst should be PX_MAX_SALT_LEN bytes. + 'rounds' is algorithm specific. 0 means default for + that algorithm. + +Random +====== + +int px_rand_get_bytes(uint8 *dst, int num) + + +Crypto "objects" +================ + +PX_MD - Message digest +PX_HMAC - HMAC (Hash MAC) +PX_Cipher - cipher+mode: provided by libs +PX_Combo - higher-level encryption -> padding, [MD] + +Objects are activated with following functions: + +int px_find_digest(const char *name, PX_MD **res); +int px_find_hmac(const char *name, PX_HMAC **res); +int px_find_cipher(const char *name, PX_Cipher **res); +int px_find_combo(const char *name, PX_Combo **res); + + returns 0 on success, < 0 on error. If successful, + *res contains pointer to new object. + +Message Digest +============== + +uint px_md_result_size(PX_MD *md) + + returns final result size in bytes + +void px_md_reset(PX_MD *md) + + resets md to clean state + +uint px_md_block_size(PX_MD *md) + + return algorithm block size in bytes + +void px_md_update(PX_MD *md, const uint8 *data, uint dlen) + + updates hash state with new data + +void px_md_finish(PX_MD *md, uint8 *buf) + + puts final hash state into buf. buf should have room + for px_md_result_size() bytes. + +void px_md_free(PX_MD *md) + + frees resources. + +HMAC (Hash Message Authentication Code) +======================================= + +int px_hmac_init(PX_HMAC *hmac, const uint8 *key, uint klen) + + initalized hmac state with key. + +uint px_hmac_result_size(PX_HMAC *md) + + returns final result size in bytes + +void px_hmac_reset(PX_HMAC *md) + + resets md to state after _init() + +uint px_hmac_block_size(PX_HMAC *md) + + return algorithm block size in bytes + +void px_hmac_update(PX_HMAC *md, const uint8 *data, uint dlen) + + updates hash state with new data + +void px_hmac_finish(PX_HMAC *md, uint8 *buf) + + puts final hash state into buf. buf should have room + for px_hmac_result_size() bytes. + +void px_hmac_free(PX_HMAC *md) + + frees resources. + + +Cipher +====== + +uint px_cipher_key_size(PX_Cipher *c) + + returns max key size in bytes + +uint px_cipher_block_size(PX_Cipher *c) + + returns cipher+mode block size in bytes. So blowfish + in CFB mode should return 1. + +uint px_cipher_iv_size(PX_Cipher *c) + + returns IV size in bytes. + +int px_cipher_init(PX_Cipher *c, uint8 *key, uint klen, uint8 *iv) + + initializes cipher with supplied key and iv. + +int px_cipher_encrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res) + + encrypts data. res must have room for dlen bytes. + data must be multiple of px_cipher_block_size(). + +int px_cipher_decrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res) + + decrypts data. res must have room for dlen bytes. + +void px_cipher_free(PX_Cipher *c) + + frees resources assiocated. + +PX_Combo +======== + +uint px_combo_encrypt_len(PX_Combo *c, uint dlen) + + calculates max result length for dlen of data. + +uint px_combo_decrypt_len(PX_Combo *c, uint dlen) + + calculates result length for dlen of data. + +int px_combo_init(PX_Combo *c, uint8 *key, uint klen, uint8 *iv, uint ivlen) + + initializes c with key and iv. If cipher uses fixed length keys, + key will be padded with zeroes to needed length. + +int px_combo_encrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen) + +int px_combo_decrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen) + +void px_combo_free(PX_Combo *c) + + frees resources assiocated. + diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/Makefile contrib/pgcrypto/Makefile --- contrib/pgcrypto.orig/Makefile Sun Sep 16 18:11:09 2001 +++ contrib/pgcrypto/Makefile Sat Sep 22 02:30:09 2001 @@ -12,6 +12,18 @@ # either 'builtin', 'system' cryptsrc = builtin+# Random source, preferred order: +# 'dev' - read from random device +# +# 'openssl' - use openssl PRNG. +# Note that currently pgcrypto does not do any +# entropy feeding to it +# This works ofcouse only with cryptolib = openssl +# +# 'silly' - use libc random() - very weak +random = dev +random_dev = \"/dev/urandom\" + ##########################ifeq ($(cryptolib), builtin)
@@ -38,8 +50,19 @@
CRYPTO_CFLAGS += -DPX_SYSTEM_CRYPT
endif+ifeq ($(random), dev) +CRYPTO_CFLAGS += -DRAND_DEV=$(random_dev) +endif +ifeq ($(random), openssl) +CRYPTO_CFLAGS += -DRAND_OPENSSL +endif +ifeq ($(random), silly) +CRYPTO_CFLAGS += -DRAND_SILLY +endif + NAME := pgcrypto -SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c +SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \ + crypt-gensalt.c random.c OBJS := $(SRCS:.c=.o) SHLIB_LINK := $(CRYPTO_LDFLAGS) SO_MAJOR_VERSION = 0 diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/README.pgcrypto contrib/pgcrypto/README.pgcrypto --- contrib/pgcrypto.orig/README.pgcrypto Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/README.pgcrypto Sat Sep 22 02:39:52 2001 @@ -9,6 +9,13 @@Edit makefile, if you want to use any external library.
+NB! Default randomness source is /dev/urandom device. If you +do not have it, you also need to edit Makefile to let pgcrypto +use either OpenSSL PRNG or libc random() PRNG. Using libc random() +is discouraged. + +After editing Makefile: + make make install@@ -72,6 +79,27 @@
When you use --enable-system-crypt then note that system libcrypt may not support them all. + +gen_salt(type::text, rounds::int4)::text + + same as above, but lets user specify iteration count + for algorithm. Number is algotithm specific: + + type default min max + --------------------------------- + xdes 725 1 16777215 + bf 6 4 31 + + In case of xdes there is a additional limitation that the + count must be a odd number. + + The higher the count, the more time it takes to calculate + crypt and therefore the more time to break it. But beware! + With too high count it takes a _very_long_ time to + calculate it. + + For maximum security, you should choose the 'bf' crypt + and use maximum number of rounds you can still tolerate.encrypt(data::bytea, key::bytea, type::text)::bytea decrypt(data::bytea, key::bytea, type::text)::bytea diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/crypt-blowfish.c contrib/pgcrypto/crypt-blowfish.c --- contrib/pgcrypto.orig/crypt-blowfish.c Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/crypt-blowfish.c Thu Sep 20 11:18:37 2001 @@ -705,28 +705,3 @@ return output; }-char *_crypt_gensalt_blowfish_rn(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))) { - if (output_size > 0) output[0] = '\0'; - __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); - return NULL; - } - - if (!count) count = 5; - - output[0] = '$'; - output[1] = '2'; - output[2] = 'a'; - output[3] = '$'; - output[4] = '0' + count / 10; - output[5] = '0' + count % 10; - output[6] = '$'; - - BF_encode(&output[7], (BF_word *)input, 16); - output[7 + 22] = '\0'; - - return output; -} diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/crypt-gensalt.c contrib/pgcrypto/crypt-gensalt.c --- contrib/pgcrypto.orig/crypt-gensalt.c Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/crypt-gensalt.c Wed Sep 19 12:01:51 2001 @@ -0,0 +1,181 @@ +/* + * Written by Solar Designer and placed in the public domain. + * 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 + */ + +#include <postgres.h> +#include "px-crypt.h" + +#include <errno.h> +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +#undef __CONST +#ifdef __GNUC__ +#define __CONST __const +#else +#define __CONST +#endif + +typedef unsigned int BF_word; + +unsigned char _crypt_itoa64[64 + 1] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +char *_crypt_gensalt_traditional_rn(unsigned long count, + __CONST char *input, int size, char *output, int output_size) +{ + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f]; + output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f]; + output[2] = '\0'; + + return output; +} + +char *_crypt_gensalt_extended_rn(unsigned long count, + __CONST char *input, int size, char *output, int output_size) +{ + unsigned long value; + +/* 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 || + (count && (count > 0xffffff || !(count & 1)))) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 725; + + output[0] = '_'; + output[1] = _crypt_itoa64[count & 0x3f]; + output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; + output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; + output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; + value = (unsigned long)input[0] | + ((unsigned long)input[1] << 8) | + ((unsigned long)input[2] << 16); + output[5] = _crypt_itoa64[value & 0x3f]; + output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[9] = '\0'; + + return output; +} + +char *_crypt_gensalt_md5_rn(unsigned long count, + __CONST char *input, int size, char *output, int output_size) +{ + unsigned long value; + + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = '$'; + output[1] = '1'; + output[2] = '$'; + value = (unsigned long)input[0] | + ((unsigned long)input[1] << 8) | + ((unsigned long)input[2] << 16); + output[3] = _crypt_itoa64[value & 0x3f]; + output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[7] = '\0'; + + if (size >= 6 && output_size >= 3 + 4 + 4 + 1) { + value = (unsigned long)input[3] | + ((unsigned long)input[4] << 8) | + ((unsigned long)input[5] << 16); + output[7] = _crypt_itoa64[value & 0x3f]; + output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[11] = '\0'; + } + + return output; +} + + + +static unsigned char BF_itoa64[64 + 1] = + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static void BF_encode(char *dst, __CONST BF_word *src, int size) +{ + unsigned char *sptr = (unsigned char *)src; + unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *)dst; + unsigned int c1, c2; + + do { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +char *_crypt_gensalt_blowfish_rn(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))) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = 'a'; + output[3] = '$'; + output[4] = '0' + count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (BF_word *)input, 16); + output[7 + 22] = '\0'; + + return output; +} + Binary files contrib/pgcrypto.orig/libpgcrypto.so.0 and contrib/pgcrypto/libpgcrypto.so.0 differ diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/openssl.c contrib/pgcrypto/openssl.c --- contrib/pgcrypto.orig/openssl.c Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/openssl.c Thu Sep 20 11:40:12 2001 @@ -35,7 +35,6 @@#include <openssl/evp.h>
#include <openssl/blowfish.h>
-/*#include <openssl/crypto.h>*/static uint digest_result_size(PX_MD * h) diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.c contrib/pgcrypto/pgcrypto.c --- contrib/pgcrypto.orig/pgcrypto.c Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/pgcrypto.c Wed Sep 19 10:22:27 2001 @@ -200,9 +200,44 @@ len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len; memcpy(buf, VARDATA(arg0), len); buf[len] = 0; - len = px_gen_salt(buf, buf); + len = px_gen_salt(buf, buf, 0); if (len == 0) elog(ERROR, "No such crypt algorithm"); + + res = (text *) palloc(len + VARHDRSZ); + VARATT_SIZEP(res) = len + VARHDRSZ; + memcpy(VARDATA(res), buf, len); + + PG_FREE_IF_COPY(arg0, 0); + + PG_RETURN_TEXT_P(res); +} + +/* SQL function: pg_gen_salt(text, int4) returns text */ +PG_FUNCTION_INFO_V1(pg_gen_salt_rounds); + +Datum +pg_gen_salt_rounds(PG_FUNCTION_ARGS) +{ + text *arg0; + int rounds; + uint len; + text *res; + char buf[PX_MAX_SALT_LEN + 1]; + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + + arg0 = PG_GETARG_TEXT_P(0); + rounds = PG_GETARG_INT32(1); + + len = VARSIZE(arg0) - VARHDRSZ; + len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len; + memcpy(buf, VARDATA(arg0), len); + buf[len] = 0; + len = px_gen_salt(buf, buf, rounds); + if (len == 0) + elog(ERROR, "No such crypt algorithm or bad number of rounds");res = (text *) palloc(len + VARHDRSZ); VARATT_SIZEP(res) = len + VARHDRSZ; diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.h contrib/pgcrypto/pgcrypto.h --- contrib/pgcrypto.orig/pgcrypto.h Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/pgcrypto.h Mon Sep 17 20:21:39 2001 @@ -38,6 +38,7 @@ Datum pg_hmac(PG_FUNCTION_ARGS); Datum pg_hmac_exists(PG_FUNCTION_ARGS); Datum pg_gen_salt(PG_FUNCTION_ARGS); +Datum pg_gen_salt_rounds(PG_FUNCTION_ARGS); Datum pg_crypt(PG_FUNCTION_ARGS); Datum pg_encrypt(PG_FUNCTION_ARGS); Datum pg_decrypt(PG_FUNCTION_ARGS); diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql contrib/pgcrypto/pgcrypto.sql --- contrib/pgcrypto.orig/pgcrypto.sql Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/pgcrypto.sql Sat Sep 22 02:36:53 2001 @@ -0,0 +1,65 @@ + +-- drop function digest(bytea, text); +-- drop function digest_exists(text); +-- drop function hmac(bytea, bytea, text); +-- drop function hmac_exists(text); +-- drop function crypt(text, text); +-- drop function gen_salt(text); +-- drop function gen_salt(text, int4); +-- drop function encrypt(bytea, bytea, text); +-- drop function decrypt(bytea, bytea, text); +-- drop function encrypt_iv(bytea, bytea, bytea, text); +-- drop function decrypt_iv(bytea, bytea, bytea, text); +-- drop function cipher_exists(text); + + + +CREATE FUNCTION digest(bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_digest' LANGUAGE 'C'; + +CREATE FUNCTION digest_exists(text) RETURNS bool + AS '$libdir/pgcrypto', + 'pg_digest_exists' LANGUAGE 'C'; + +CREATE FUNCTION hmac(bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_hmac' LANGUAGE 'C'; + +CREATE FUNCTION hmac_exists(text) RETURNS bool + AS '$libdir/pgcrypto', + 'pg_hmac_exists' LANGUAGE 'C'; + +CREATE FUNCTION crypt(text, text) RETURNS text + AS '$libdir/pgcrypto', + 'pg_crypt' LANGUAGE 'C'; + +CREATE FUNCTION gen_salt(text) RETURNS text + AS '$libdir/pgcrypto', + 'pg_gen_salt' LANGUAGE 'C'; + +CREATE FUNCTION gen_salt(text, int4) RETURNS text + AS '$libdir/pgcrypto', + 'pg_gen_salt_rounds' LANGUAGE 'C'; + +CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_encrypt' LANGUAGE 'C'; + +CREATE FUNCTION decrypt(bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_decrypt' LANGUAGE 'C'; + +CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_encrypt_iv' LANGUAGE 'C'; + +CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_decrypt_iv' LANGUAGE 'C'; + +CREATE FUNCTION cipher_exists(text) RETURNS bool + AS '$libdir/pgcrypto', + 'pg_cipher_exists' LANGUAGE 'C'; + + diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql.in contrib/pgcrypto/pgcrypto.sql.in --- contrib/pgcrypto.orig/pgcrypto.sql.in Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/pgcrypto.sql.in Mon Sep 17 20:23:56 2001 @@ -5,10 +5,12 @@ -- drop function hmac_exists(text); -- drop function crypt(text, text); -- drop function gen_salt(text); +-- drop function gen_salt(text, int4); -- drop function encrypt(bytea, bytea, text); -- drop function decrypt(bytea, bytea, text); -- drop function encrypt_iv(bytea, bytea, bytea, text); -- drop function decrypt_iv(bytea, bytea, bytea, text); +-- drop function cipher_exists(text);@@ -35,6 +37,10 @@ CREATE FUNCTION gen_salt(text) RETURNS text AS '@MODULE_FILENAME@', 'pg_gen_salt' LANGUAGE 'C'; + +CREATE FUNCTION gen_salt(text, int4) RETURNS text + AS '@MODULE_FILENAME@', + 'pg_gen_salt_rounds' LANGUAGE 'C';CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea AS '@MODULE_FILENAME@', diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px-crypt.c contrib/pgcrypto/px-crypt.c --- contrib/pgcrypto.orig/px-crypt.c Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/px-crypt.c Wed Sep 19 11:34:43 2001 @@ -30,6 +30,7 @@ */#include <postgres.h>
+#include "px.h"
#include "px-crypt.h"@@ -62,12 +63,8 @@ char *buf, unsigned len) { char *res; - res = _crypt_blowfish_rn(psw, salt, buf, len); - if (!res) - return NULL; - strcpy(buf, res); - return buf; + return res; }static struct
@@ -128,106 +125,53 @@
* salt generators
*/-static int my_rand64() -{ - return random() % 64; -} - -static uint -gen_des_salt(char *buf) -{ - buf[0] = px_crypt_a64[my_rand64()]; - buf[1] = px_crypt_a64[my_rand64()]; - buf[2] = 0; - - return 2; -} - -static uint -gen_xdes_salt(char *buf) -{ - strcpy(buf, "_12345678"); - - px_crypt_to64(buf+1, (long)PX_XDES_ROUNDS, 4); - px_crypt_to64(buf+5, random(), 4); - - return 9; -} - -static uint -gen_md5_salt(char *buf) -{ - int i; - strcpy(buf, "$1$12345678$"); - - for (i = 0; i < 8; i++) - buf[3 + i] = px_crypt_a64[my_rand64()]; - - return 12; -} - -static uint -gen_bf_salt(char *buf) -{ - int i, count; - char *s; - char saltbuf[16+3]; - unsigned slen = 16; - uint32 *v; - - for (i = 0; i < slen; i++) - saltbuf[i] = random() & 255; - saltbuf[16] = 0; - saltbuf[17] = 0; - saltbuf[18] = 0; - - strcpy(buf, "$2a$00$0123456789012345678901"); - - count = PX_BF_ROUNDS; - buf[4] = '0' + count / 10; - buf[5] = '0' + count % 10; - - s = buf + 7; - for (i = 0; i < slen; ) - { - v = (uint32 *)&saltbuf[i]; - if (i + 3 <= slen) - px_crypt_to64(s, *v, 4); - else - /* slen-i could be 1,2 make it 2,3 */ - px_crypt_to64(s, *v, slen-i+1); - s += 4; - i += 3; - } - - s = buf; - /*s = _crypt_gensalt_blowfish_rn(count, saltbuf, 16, buf, PX_MAX_CRYPT);*/ - - return s ? strlen(s) : 0; -} - struct generator { char *name; - uint (*gen)(char *buf); + char *(*gen)(unsigned long count, const char *input, int size, + char *output, int output_size); + int input_len; + int def_rounds; + int min_rounds; + int max_rounds; };static struct generator gen_list [] = { - { "des", gen_des_salt }, - { "md5", gen_md5_salt }, - { "xdes", gen_xdes_salt }, - { "bf", gen_bf_salt }, - { NULL, NULL } + { "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 }, + { NULL, NULL, 0, 0, 0 } };uint -px_gen_salt(const char *salt_type, char *buf) +px_gen_salt(const char *salt_type, char *buf, int rounds) { - int i; + int i, res; struct generator *g; + char *p; + char rbuf[16]; + for (i = 0; gen_list[i].name; i++) { g = &gen_list[i]; - if (!strcasecmp(g->name, salt_type)) - return g->gen(buf); + if (strcasecmp(g->name, salt_type) != 0) + continue; + + if (g->def_rounds) { + if (rounds == 0) + rounds = g->def_rounds; + + if (rounds < g->min_rounds || rounds > g->max_rounds) + return 0; + } + + res = px_get_random_bytes(rbuf, g->input_len); + if (res != g->input_len) + return 0; + + p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN); + memset(rbuf, 0, sizeof(rbuf)); + + return p != NULL ? strlen(p) : 0; }return 0; diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px-crypt.h contrib/pgcrypto/px-crypt.h --- contrib/pgcrypto.orig/px-crypt.h Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/px-crypt.h Wed Sep 19 10:03:03 2001 @@ -38,19 +38,22 @@ /* max salt returned by gen_salt() */ #define PX_MAX_SALT_LEN 128-/* rounds for xdes salt */ +/* default rounds for xdes salt */ /* NetBSD bin/passwd/local_passwd.c has (29 * 25)*/ #define PX_XDES_ROUNDS (29 * 25)-/* rounds for blowfish salt */ +/* default for blowfish salt */ #define PX_BF_ROUNDS 6/* * main interface */ char *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen); -unsigned px_gen_salt(const char *salt_type, char *dst); +unsigned px_gen_salt(const char *salt_type, char *dst, int rounds);+/* + * internal functions + *//* misc.c */
extern void px_crypt_to64(char *s, unsigned long v, int n);
@@ -59,6 +62,15 @@
#define _crypt_to64 px_crypt_to64
#define _crypt_a64 px_crypt_a64+/* crypt-gensalt.c */ +char *_crypt_gensalt_traditional_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_extended_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_md5_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_blowfish_rn(unsigned long count, + const char *input, int size, char *output, int output_size);#ifndef PX_SYSTEM_CRYPT
@@ -66,9 +78,6 @@
/* #define DISABLE_XDES *//* crypt-blowfish.c */
-char *_crypt_gensalt_blowfish_rn(unsigned long count,
- const char *input, int size,
- char *output, int output_size);
char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size);diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px.h contrib/pgcrypto/px.h --- contrib/pgcrypto.orig/px.h Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/px.h Wed Sep 19 13:38:42 2001 @@ -133,6 +133,8 @@ int px_find_cipher(const char *name, PX_Cipher **res); int px_find_combo(const char *name, PX_Combo **res);+int px_get_random_bytes(uint8 *dst, unsigned count); + const char *px_resolve_alias(const PX_Alias *aliases, const char *name);#define px_md_result_size(md) (md)->result_size(md) diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/random.c contrib/pgcrypto/random.c --- contrib/pgcrypto.orig/random.c Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/random.c Thu Sep 20 11:39:49 2001 @@ -0,0 +1,127 @@ +/* + * random.c + * Random functions. + * + * Copyright (c) 2001 Marko Kreen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + + +#include <postgres.h> + +#include "px.h" + + +#ifdef RAND_DEV + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +static int +safe_read(int fd, void *buf, size_t count) +{ + int done = 0; + char *p = buf; + int res; + + while (count) { + res = read(fd, p, count); + if (res <= 0) { + if (errno == EINTR) + continue; + return -1; + } + p += res; + done += res; + count -= res; + } + return done; +} + +int +px_get_random_bytes(uint8 *dst, unsigned count) +{ + int fd; + int res; + + fd = open(RAND_DEV, O_RDONLY); + if (fd == -1) + return -1; + res = safe_read(fd, dst, count); + close(fd); + return res; +} + +#endif /* RAND_DEV */ + +#ifdef RAND_SILLY + +int px_get_random_bytes(char *dst, unsigned count) +{ + int i; + for (i = 0; i < count; i++) { + *dst++ = random(); + } + return i; +} + +#endif /* RAND_SILLY */ + +#ifdef RAND_OPENSSL + +#include <openssl/evp.h> +#include <openssl/blowfish.h> +#include <openssl/rand.h> +#include <openssl/err.h> + +static int openssl_random_init = 0; + +int px_get_random_bytes(uint8 *dst, unsigned count) +{ + int res; + + if (!openssl_random_init) { + if (RAND_get_rand_method() == NULL) { + RAND_set_rand_method(RAND_SSLeay()); + } + openssl_random_init = 1; + } + + /* + * OpenSSL random should re-feeded occasionally. + * From /dev/urandom preferrably. + */ + + res = RAND_bytes(dst, count); + if (res > 0) + return count; + + return -1; +} + +#endif /* RAND_OPENSSL */ +---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Patch applied. Thanks. Your name has been added to the bottom of the
TODO list.
Big thanks to Solar Designer who pointed out a bug in bcrypt
salt generation code. He also urged using better random source
and making possible to choose using bcrypt and xdes rounds more
easily. So, here's patch:* For all salt generation, use Solar Designer's own code. This
is mostly due fact that his code is more fit for get_random_bytes()
style interface.
* New function: gen_salt(type, rounds). This lets specify iteration
count for algorithm.
* random.c: px_get_random_bytes() function.
Supported randomness soure: /dev/urandom, OpenSSL PRNG, libc random()
Default: /dev/urandom.
* Draft description of C API for pgcrypto functions.New files: API, crypt-gensalt.c, random.c
--
markodiff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/API contrib/pgcrypto/API --- contrib/pgcrypto.orig/API Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/API Sat Sep 22 01:57:41 2001 @@ -0,0 +1,163 @@ + +C API for pgcrypto +================== + + +UN*X crypt() +============ + +#include <px-crypt.h> + +char * +px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen); + + returns buf or NULL for error. + +unsigned px_gen_salt(const char *salt_type, char *dst, int rounds); + + returns salt size. dst should be PX_MAX_SALT_LEN bytes. + 'rounds' is algorithm specific. 0 means default for + that algorithm. + +Random +====== + +int px_rand_get_bytes(uint8 *dst, int num) + + +Crypto "objects" +================ + +PX_MD - Message digest +PX_HMAC - HMAC (Hash MAC) +PX_Cipher - cipher+mode: provided by libs +PX_Combo - higher-level encryption -> padding, [MD] + +Objects are activated with following functions: + +int px_find_digest(const char *name, PX_MD **res); +int px_find_hmac(const char *name, PX_HMAC **res); +int px_find_cipher(const char *name, PX_Cipher **res); +int px_find_combo(const char *name, PX_Combo **res); + + returns 0 on success, < 0 on error. If successful, + *res contains pointer to new object. + +Message Digest +============== + +uint px_md_result_size(PX_MD *md) + + returns final result size in bytes + +void px_md_reset(PX_MD *md) + + resets md to clean state + +uint px_md_block_size(PX_MD *md) + + return algorithm block size in bytes + +void px_md_update(PX_MD *md, const uint8 *data, uint dlen) + + updates hash state with new data + +void px_md_finish(PX_MD *md, uint8 *buf) + + puts final hash state into buf. buf should have room + for px_md_result_size() bytes. + +void px_md_free(PX_MD *md) + + frees resources. + +HMAC (Hash Message Authentication Code) +======================================= + +int px_hmac_init(PX_HMAC *hmac, const uint8 *key, uint klen) + + initalized hmac state with key. + +uint px_hmac_result_size(PX_HMAC *md) + + returns final result size in bytes + +void px_hmac_reset(PX_HMAC *md) + + resets md to state after _init() + +uint px_hmac_block_size(PX_HMAC *md) + + return algorithm block size in bytes + +void px_hmac_update(PX_HMAC *md, const uint8 *data, uint dlen) + + updates hash state with new data + +void px_hmac_finish(PX_HMAC *md, uint8 *buf) + + puts final hash state into buf. buf should have room + for px_hmac_result_size() bytes. + +void px_hmac_free(PX_HMAC *md) + + frees resources. + + +Cipher +====== + +uint px_cipher_key_size(PX_Cipher *c) + + returns max key size in bytes + +uint px_cipher_block_size(PX_Cipher *c) + + returns cipher+mode block size in bytes. So blowfish + in CFB mode should return 1. + +uint px_cipher_iv_size(PX_Cipher *c) + + returns IV size in bytes. + +int px_cipher_init(PX_Cipher *c, uint8 *key, uint klen, uint8 *iv) + + initializes cipher with supplied key and iv. + +int px_cipher_encrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res) + + encrypts data. res must have room for dlen bytes. + data must be multiple of px_cipher_block_size(). + +int px_cipher_decrypt(PX_Cipher *c, uint8 *data, uint dlen, uint8 *res) + + decrypts data. res must have room for dlen bytes. + +void px_cipher_free(PX_Cipher *c) + + frees resources assiocated. + +PX_Combo +======== + +uint px_combo_encrypt_len(PX_Combo *c, uint dlen) + + calculates max result length for dlen of data. + +uint px_combo_decrypt_len(PX_Combo *c, uint dlen) + + calculates result length for dlen of data. + +int px_combo_init(PX_Combo *c, uint8 *key, uint klen, uint8 *iv, uint ivlen) + + initializes c with key and iv. If cipher uses fixed length keys, + key will be padded with zeroes to needed length. + +int px_combo_encrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen) + +int px_combo_decrypt(PX_Combo *c, uint8 *data, uint dlen, uint8 *res, uint rlen) + +void px_combo_free(PX_Combo *c) + + frees resources assiocated. + diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/Makefile contrib/pgcrypto/Makefile --- contrib/pgcrypto.orig/Makefile Sun Sep 16 18:11:09 2001 +++ contrib/pgcrypto/Makefile Sat Sep 22 02:30:09 2001 @@ -12,6 +12,18 @@ # either 'builtin', 'system' cryptsrc = builtin+# Random source, preferred order: +# 'dev' - read from random device +# +# 'openssl' - use openssl PRNG. +# Note that currently pgcrypto does not do any +# entropy feeding to it +# This works ofcouse only with cryptolib = openssl +# +# 'silly' - use libc random() - very weak +random = dev +random_dev = \"/dev/urandom\" + ##########################ifeq ($(cryptolib), builtin)
@@ -38,8 +50,19 @@
CRYPTO_CFLAGS += -DPX_SYSTEM_CRYPT
endif+ifeq ($(random), dev) +CRYPTO_CFLAGS += -DRAND_DEV=$(random_dev) +endif +ifeq ($(random), openssl) +CRYPTO_CFLAGS += -DRAND_OPENSSL +endif +ifeq ($(random), silly) +CRYPTO_CFLAGS += -DRAND_SILLY +endif + NAME := pgcrypto -SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c +SRCS += pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \ + crypt-gensalt.c random.c OBJS := $(SRCS:.c=.o) SHLIB_LINK := $(CRYPTO_LDFLAGS) SO_MAJOR_VERSION = 0 diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/README.pgcrypto contrib/pgcrypto/README.pgcrypto --- contrib/pgcrypto.orig/README.pgcrypto Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/README.pgcrypto Sat Sep 22 02:39:52 2001 @@ -9,6 +9,13 @@Edit makefile, if you want to use any external library.
+NB! Default randomness source is /dev/urandom device. If you +do not have it, you also need to edit Makefile to let pgcrypto +use either OpenSSL PRNG or libc random() PRNG. Using libc random() +is discouraged. + +After editing Makefile: + make make install@@ -72,6 +79,27 @@
When you use --enable-system-crypt then note that system libcrypt may not support them all. + +gen_salt(type::text, rounds::int4)::text + + same as above, but lets user specify iteration count + for algorithm. Number is algotithm specific: + + type default min max + --------------------------------- + xdes 725 1 16777215 + bf 6 4 31 + + In case of xdes there is a additional limitation that the + count must be a odd number. + + The higher the count, the more time it takes to calculate + crypt and therefore the more time to break it. But beware! + With too high count it takes a _very_long_ time to + calculate it. + + For maximum security, you should choose the 'bf' crypt + and use maximum number of rounds you can still tolerate.encrypt(data::bytea, key::bytea, type::text)::bytea decrypt(data::bytea, key::bytea, type::text)::bytea diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/crypt-blowfish.c contrib/pgcrypto/crypt-blowfish.c --- contrib/pgcrypto.orig/crypt-blowfish.c Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/crypt-blowfish.c Thu Sep 20 11:18:37 2001 @@ -705,28 +705,3 @@ return output; }-char *_crypt_gensalt_blowfish_rn(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))) { - if (output_size > 0) output[0] = '\0'; - __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); - return NULL; - } - - if (!count) count = 5; - - output[0] = '$'; - output[1] = '2'; - output[2] = 'a'; - output[3] = '$'; - output[4] = '0' + count / 10; - output[5] = '0' + count % 10; - output[6] = '$'; - - BF_encode(&output[7], (BF_word *)input, 16); - output[7 + 22] = '\0'; - - return output; -} diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/crypt-gensalt.c contrib/pgcrypto/crypt-gensalt.c --- contrib/pgcrypto.orig/crypt-gensalt.c Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/crypt-gensalt.c Wed Sep 19 12:01:51 2001 @@ -0,0 +1,181 @@ +/* + * Written by Solar Designer and placed in the public domain. + * 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 + */ + +#include <postgres.h> +#include "px-crypt.h" + +#include <errno.h> +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +#undef __CONST +#ifdef __GNUC__ +#define __CONST __const +#else +#define __CONST +#endif + +typedef unsigned int BF_word; + +unsigned char _crypt_itoa64[64 + 1] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +char *_crypt_gensalt_traditional_rn(unsigned long count, + __CONST char *input, int size, char *output, int output_size) +{ + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f]; + output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f]; + output[2] = '\0'; + + return output; +} + +char *_crypt_gensalt_extended_rn(unsigned long count, + __CONST char *input, int size, char *output, int output_size) +{ + unsigned long value; + +/* 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 || + (count && (count > 0xffffff || !(count & 1)))) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 725; + + output[0] = '_'; + output[1] = _crypt_itoa64[count & 0x3f]; + output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; + output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; + output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; + value = (unsigned long)input[0] | + ((unsigned long)input[1] << 8) | + ((unsigned long)input[2] << 16); + output[5] = _crypt_itoa64[value & 0x3f]; + output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[9] = '\0'; + + return output; +} + +char *_crypt_gensalt_md5_rn(unsigned long count, + __CONST char *input, int size, char *output, int output_size) +{ + unsigned long value; + + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = '$'; + output[1] = '1'; + output[2] = '$'; + value = (unsigned long)input[0] | + ((unsigned long)input[1] << 8) | + ((unsigned long)input[2] << 16); + output[3] = _crypt_itoa64[value & 0x3f]; + output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[7] = '\0'; + + if (size >= 6 && output_size >= 3 + 4 + 4 + 1) { + value = (unsigned long)input[3] | + ((unsigned long)input[4] << 8) | + ((unsigned long)input[5] << 16); + output[7] = _crypt_itoa64[value & 0x3f]; + output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[11] = '\0'; + } + + return output; +} + + + +static unsigned char BF_itoa64[64 + 1] = + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static void BF_encode(char *dst, __CONST BF_word *src, int size) +{ + unsigned char *sptr = (unsigned char *)src; + unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *)dst; + unsigned int c1, c2; + + do { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +char *_crypt_gensalt_blowfish_rn(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))) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = 'a'; + output[3] = '$'; + output[4] = '0' + count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (BF_word *)input, 16); + output[7 + 22] = '\0'; + + return output; +} + Binary files contrib/pgcrypto.orig/libpgcrypto.so.0 and contrib/pgcrypto/libpgcrypto.so.0 differ diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/openssl.c contrib/pgcrypto/openssl.c --- contrib/pgcrypto.orig/openssl.c Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/openssl.c Thu Sep 20 11:40:12 2001 @@ -35,7 +35,6 @@#include <openssl/evp.h>
#include <openssl/blowfish.h>
-/*#include <openssl/crypto.h>*/static uint digest_result_size(PX_MD * h) diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.c contrib/pgcrypto/pgcrypto.c --- contrib/pgcrypto.orig/pgcrypto.c Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/pgcrypto.c Wed Sep 19 10:22:27 2001 @@ -200,9 +200,44 @@ len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len; memcpy(buf, VARDATA(arg0), len); buf[len] = 0; - len = px_gen_salt(buf, buf); + len = px_gen_salt(buf, buf, 0); if (len == 0) elog(ERROR, "No such crypt algorithm"); + + res = (text *) palloc(len + VARHDRSZ); + VARATT_SIZEP(res) = len + VARHDRSZ; + memcpy(VARDATA(res), buf, len); + + PG_FREE_IF_COPY(arg0, 0); + + PG_RETURN_TEXT_P(res); +} + +/* SQL function: pg_gen_salt(text, int4) returns text */ +PG_FUNCTION_INFO_V1(pg_gen_salt_rounds); + +Datum +pg_gen_salt_rounds(PG_FUNCTION_ARGS) +{ + text *arg0; + int rounds; + uint len; + text *res; + char buf[PX_MAX_SALT_LEN + 1]; + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + + arg0 = PG_GETARG_TEXT_P(0); + rounds = PG_GETARG_INT32(1); + + len = VARSIZE(arg0) - VARHDRSZ; + len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len; + memcpy(buf, VARDATA(arg0), len); + buf[len] = 0; + len = px_gen_salt(buf, buf, rounds); + if (len == 0) + elog(ERROR, "No such crypt algorithm or bad number of rounds");res = (text *) palloc(len + VARHDRSZ); VARATT_SIZEP(res) = len + VARHDRSZ; diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.h contrib/pgcrypto/pgcrypto.h --- contrib/pgcrypto.orig/pgcrypto.h Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/pgcrypto.h Mon Sep 17 20:21:39 2001 @@ -38,6 +38,7 @@ Datum pg_hmac(PG_FUNCTION_ARGS); Datum pg_hmac_exists(PG_FUNCTION_ARGS); Datum pg_gen_salt(PG_FUNCTION_ARGS); +Datum pg_gen_salt_rounds(PG_FUNCTION_ARGS); Datum pg_crypt(PG_FUNCTION_ARGS); Datum pg_encrypt(PG_FUNCTION_ARGS); Datum pg_decrypt(PG_FUNCTION_ARGS); diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql contrib/pgcrypto/pgcrypto.sql --- contrib/pgcrypto.orig/pgcrypto.sql Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/pgcrypto.sql Sat Sep 22 02:36:53 2001 @@ -0,0 +1,65 @@ + +-- drop function digest(bytea, text); +-- drop function digest_exists(text); +-- drop function hmac(bytea, bytea, text); +-- drop function hmac_exists(text); +-- drop function crypt(text, text); +-- drop function gen_salt(text); +-- drop function gen_salt(text, int4); +-- drop function encrypt(bytea, bytea, text); +-- drop function decrypt(bytea, bytea, text); +-- drop function encrypt_iv(bytea, bytea, bytea, text); +-- drop function decrypt_iv(bytea, bytea, bytea, text); +-- drop function cipher_exists(text); + + + +CREATE FUNCTION digest(bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_digest' LANGUAGE 'C'; + +CREATE FUNCTION digest_exists(text) RETURNS bool + AS '$libdir/pgcrypto', + 'pg_digest_exists' LANGUAGE 'C'; + +CREATE FUNCTION hmac(bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_hmac' LANGUAGE 'C'; + +CREATE FUNCTION hmac_exists(text) RETURNS bool + AS '$libdir/pgcrypto', + 'pg_hmac_exists' LANGUAGE 'C'; + +CREATE FUNCTION crypt(text, text) RETURNS text + AS '$libdir/pgcrypto', + 'pg_crypt' LANGUAGE 'C'; + +CREATE FUNCTION gen_salt(text) RETURNS text + AS '$libdir/pgcrypto', + 'pg_gen_salt' LANGUAGE 'C'; + +CREATE FUNCTION gen_salt(text, int4) RETURNS text + AS '$libdir/pgcrypto', + 'pg_gen_salt_rounds' LANGUAGE 'C'; + +CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_encrypt' LANGUAGE 'C'; + +CREATE FUNCTION decrypt(bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_decrypt' LANGUAGE 'C'; + +CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_encrypt_iv' LANGUAGE 'C'; + +CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text) RETURNS bytea + AS '$libdir/pgcrypto', + 'pg_decrypt_iv' LANGUAGE 'C'; + +CREATE FUNCTION cipher_exists(text) RETURNS bool + AS '$libdir/pgcrypto', + 'pg_cipher_exists' LANGUAGE 'C'; + + diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/pgcrypto.sql.in contrib/pgcrypto/pgcrypto.sql.in --- contrib/pgcrypto.orig/pgcrypto.sql.in Tue Aug 21 02:42:41 2001 +++ contrib/pgcrypto/pgcrypto.sql.in Mon Sep 17 20:23:56 2001 @@ -5,10 +5,12 @@ -- drop function hmac_exists(text); -- drop function crypt(text, text); -- drop function gen_salt(text); +-- drop function gen_salt(text, int4); -- drop function encrypt(bytea, bytea, text); -- drop function decrypt(bytea, bytea, text); -- drop function encrypt_iv(bytea, bytea, bytea, text); -- drop function decrypt_iv(bytea, bytea, bytea, text); +-- drop function cipher_exists(text);@@ -35,6 +37,10 @@ CREATE FUNCTION gen_salt(text) RETURNS text AS '@MODULE_FILENAME@', 'pg_gen_salt' LANGUAGE 'C'; + +CREATE FUNCTION gen_salt(text, int4) RETURNS text + AS '@MODULE_FILENAME@', + 'pg_gen_salt_rounds' LANGUAGE 'C';CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea AS '@MODULE_FILENAME@', diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px-crypt.c contrib/pgcrypto/px-crypt.c --- contrib/pgcrypto.orig/px-crypt.c Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/px-crypt.c Wed Sep 19 11:34:43 2001 @@ -30,6 +30,7 @@ */#include <postgres.h>
+#include "px.h"
#include "px-crypt.h"@@ -62,12 +63,8 @@ char *buf, unsigned len) { char *res; - res = _crypt_blowfish_rn(psw, salt, buf, len); - if (!res) - return NULL; - strcpy(buf, res); - return buf; + return res; }static struct
@@ -128,106 +125,53 @@
* salt generators
*/-static int my_rand64() -{ - return random() % 64; -} - -static uint -gen_des_salt(char *buf) -{ - buf[0] = px_crypt_a64[my_rand64()]; - buf[1] = px_crypt_a64[my_rand64()]; - buf[2] = 0; - - return 2; -} - -static uint -gen_xdes_salt(char *buf) -{ - strcpy(buf, "_12345678"); - - px_crypt_to64(buf+1, (long)PX_XDES_ROUNDS, 4); - px_crypt_to64(buf+5, random(), 4); - - return 9; -} - -static uint -gen_md5_salt(char *buf) -{ - int i; - strcpy(buf, "$1$12345678$"); - - for (i = 0; i < 8; i++) - buf[3 + i] = px_crypt_a64[my_rand64()]; - - return 12; -} - -static uint -gen_bf_salt(char *buf) -{ - int i, count; - char *s; - char saltbuf[16+3]; - unsigned slen = 16; - uint32 *v; - - for (i = 0; i < slen; i++) - saltbuf[i] = random() & 255; - saltbuf[16] = 0; - saltbuf[17] = 0; - saltbuf[18] = 0; - - strcpy(buf, "$2a$00$0123456789012345678901"); - - count = PX_BF_ROUNDS; - buf[4] = '0' + count / 10; - buf[5] = '0' + count % 10; - - s = buf + 7; - for (i = 0; i < slen; ) - { - v = (uint32 *)&saltbuf[i]; - if (i + 3 <= slen) - px_crypt_to64(s, *v, 4); - else - /* slen-i could be 1,2 make it 2,3 */ - px_crypt_to64(s, *v, slen-i+1); - s += 4; - i += 3; - } - - s = buf; - /*s = _crypt_gensalt_blowfish_rn(count, saltbuf, 16, buf, PX_MAX_CRYPT);*/ - - return s ? strlen(s) : 0; -} - struct generator { char *name; - uint (*gen)(char *buf); + char *(*gen)(unsigned long count, const char *input, int size, + char *output, int output_size); + int input_len; + int def_rounds; + int min_rounds; + int max_rounds; };static struct generator gen_list [] = { - { "des", gen_des_salt }, - { "md5", gen_md5_salt }, - { "xdes", gen_xdes_salt }, - { "bf", gen_bf_salt }, - { NULL, NULL } + { "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 }, + { NULL, NULL, 0, 0, 0 } };uint -px_gen_salt(const char *salt_type, char *buf) +px_gen_salt(const char *salt_type, char *buf, int rounds) { - int i; + int i, res; struct generator *g; + char *p; + char rbuf[16]; + for (i = 0; gen_list[i].name; i++) { g = &gen_list[i]; - if (!strcasecmp(g->name, salt_type)) - return g->gen(buf); + if (strcasecmp(g->name, salt_type) != 0) + continue; + + if (g->def_rounds) { + if (rounds == 0) + rounds = g->def_rounds; + + if (rounds < g->min_rounds || rounds > g->max_rounds) + return 0; + } + + res = px_get_random_bytes(rbuf, g->input_len); + if (res != g->input_len) + return 0; + + p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN); + memset(rbuf, 0, sizeof(rbuf)); + + return p != NULL ? strlen(p) : 0; }return 0; diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px-crypt.h contrib/pgcrypto/px-crypt.h --- contrib/pgcrypto.orig/px-crypt.h Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/px-crypt.h Wed Sep 19 10:03:03 2001 @@ -38,19 +38,22 @@ /* max salt returned by gen_salt() */ #define PX_MAX_SALT_LEN 128-/* rounds for xdes salt */ +/* default rounds for xdes salt */ /* NetBSD bin/passwd/local_passwd.c has (29 * 25)*/ #define PX_XDES_ROUNDS (29 * 25)-/* rounds for blowfish salt */ +/* default for blowfish salt */ #define PX_BF_ROUNDS 6/* * main interface */ char *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen); -unsigned px_gen_salt(const char *salt_type, char *dst); +unsigned px_gen_salt(const char *salt_type, char *dst, int rounds);+/* + * internal functions + *//* misc.c */
extern void px_crypt_to64(char *s, unsigned long v, int n);
@@ -59,6 +62,15 @@
#define _crypt_to64 px_crypt_to64
#define _crypt_a64 px_crypt_a64+/* crypt-gensalt.c */ +char *_crypt_gensalt_traditional_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_extended_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_md5_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_blowfish_rn(unsigned long count, + const char *input, int size, char *output, int output_size);#ifndef PX_SYSTEM_CRYPT
@@ -66,9 +78,6 @@
/* #define DISABLE_XDES *//* crypt-blowfish.c */
-char *_crypt_gensalt_blowfish_rn(unsigned long count,
- const char *input, int size,
- char *output, int output_size);
char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size);diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/px.h contrib/pgcrypto/px.h --- contrib/pgcrypto.orig/px.h Tue Aug 21 03:32:01 2001 +++ contrib/pgcrypto/px.h Wed Sep 19 13:38:42 2001 @@ -133,6 +133,8 @@ int px_find_cipher(const char *name, PX_Cipher **res); int px_find_combo(const char *name, PX_Combo **res);+int px_get_random_bytes(uint8 *dst, unsigned count); + const char *px_resolve_alias(const PX_Alias *aliases, const char *name);#define px_md_result_size(md) (md)->result_size(md) diff -urNX /home/marko/misc/diff-exclude contrib/pgcrypto.orig/random.c contrib/pgcrypto/random.c --- contrib/pgcrypto.orig/random.c Thu Jan 1 03:00:00 1970 +++ contrib/pgcrypto/random.c Thu Sep 20 11:39:49 2001 @@ -0,0 +1,127 @@ +/* + * random.c + * Random functions. + * + * Copyright (c) 2001 Marko Kreen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + + +#include <postgres.h> + +#include "px.h" + + +#ifdef RAND_DEV + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +static int +safe_read(int fd, void *buf, size_t count) +{ + int done = 0; + char *p = buf; + int res; + + while (count) { + res = read(fd, p, count); + if (res <= 0) { + if (errno == EINTR) + continue; + return -1; + } + p += res; + done += res; + count -= res; + } + return done; +} + +int +px_get_random_bytes(uint8 *dst, unsigned count) +{ + int fd; + int res; + + fd = open(RAND_DEV, O_RDONLY); + if (fd == -1) + return -1; + res = safe_read(fd, dst, count); + close(fd); + return res; +} + +#endif /* RAND_DEV */ + +#ifdef RAND_SILLY + +int px_get_random_bytes(char *dst, unsigned count) +{ + int i; + for (i = 0; i < count; i++) { + *dst++ = random(); + } + return i; +} + +#endif /* RAND_SILLY */ + +#ifdef RAND_OPENSSL + +#include <openssl/evp.h> +#include <openssl/blowfish.h> +#include <openssl/rand.h> +#include <openssl/err.h> + +static int openssl_random_init = 0; + +int px_get_random_bytes(uint8 *dst, unsigned count) +{ + int res; + + if (!openssl_random_init) { + if (RAND_get_rand_method() == NULL) { + RAND_set_rand_method(RAND_SSLeay()); + } + openssl_random_init = 1; + } + + /* + * OpenSSL random should re-feeded occasionally. + * From /dev/urandom preferrably. + */ + + res = RAND_bytes(dst, count); + if (res > 0) + return count; + + return -1; +} + +#endif /* RAND_OPENSSL */ +---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026