]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Big thanks to Solar Designer who pointed out a bug in bcrypt
authorBruce Momjian <bruce@momjian.us>
Sun, 23 Sep 2001 04:12:44 +0000 (04:12 +0000)
committerBruce Momjian <bruce@momjian.us>
Sun, 23 Sep 2001 04:12:44 +0000 (04:12 +0000)
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 Kreen

13 files changed:
contrib/pgcrypto/API [new file with mode: 0644]
contrib/pgcrypto/Makefile
contrib/pgcrypto/README.pgcrypto
contrib/pgcrypto/crypt-blowfish.c
contrib/pgcrypto/crypt-gensalt.c [new file with mode: 0644]
contrib/pgcrypto/openssl.c
contrib/pgcrypto/pgcrypto.c
contrib/pgcrypto/pgcrypto.h
contrib/pgcrypto/pgcrypto.sql.in
contrib/pgcrypto/px-crypt.c
contrib/pgcrypto/px-crypt.h
contrib/pgcrypto/px.h
contrib/pgcrypto/random.c [new file with mode: 0644]

diff --git a/contrib/pgcrypto/API b/contrib/pgcrypto/API
new file mode 100644 (file)
index 0000000..8127f70
--- /dev/null
@@ -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.
+
index 1e3d4bac639d778c405434238a2f60d196b28ad3..b8af281b9512f45272c9f415a908311207df6643 100644 (file)
@@ -1,5 +1,5 @@
 #
-# $Header: /cvsroot/pgsql/contrib/pgcrypto/Makefile,v 1.6 2001/09/16 16:11:09 petere Exp $
+# $Header: /cvsroot/pgsql/contrib/pgcrypto/Makefile,v 1.7 2001/09/23 04:12:44 momjian Exp $
 #
 
 subdir = contrib/pgcrypto
@@ -12,6 +12,18 @@ cryptolib = builtin
 # 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 @@ else
 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
index 7173710bc3fdb138fbac4a26c1a13a3989270252..c79f996a324b72a2b24c2b46af55a5e3af12d73b 100644 (file)
@@ -9,6 +9,13 @@ INSTALLATION
 
 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
 
@@ -73,6 +80,27 @@ gen_salt(type::text)::text
        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
 encrypt_iv(data::bytea, key::bytea, iv::bytea, type::text)::bytea
index 2979a71250bad3568f028daea8277fc98f423aa0..82056a806b61508a689f1f5262043426bf12fc19 100644 (file)
@@ -705,28 +705,3 @@ char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting,
        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 --git a/contrib/pgcrypto/crypt-gensalt.c b/contrib/pgcrypto/crypt-gensalt.c
new file mode 100644 (file)
index 0000000..8bb1714
--- /dev/null
@@ -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;
+}
+
index b4d1a0a5e9badb8993b893731bf3a779d3b2c240..6b2ae9c98a9881f8f6df2cbf9b0858a5df862d4f 100644 (file)
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: openssl.c,v 1.4 2001/08/21 00:42:41 momjian Exp $
+ * $Id: openssl.c,v 1.5 2001/09/23 04:12:44 momjian Exp $
  */
 
 #include <postgres.h>
@@ -35,7 +35,6 @@
 
 #include <openssl/evp.h>
 #include <openssl/blowfish.h>
-/*#include <openssl/crypto.h>*/
 
 static uint
 digest_result_size(PX_MD * h)
index 4a2f37d95bef1798c12abb4f55e62ee8765ad7a5..2bd9b21e167b173d6e61d65fe6681716b62790ef 100644 (file)
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: pgcrypto.c,v 1.8 2001/08/21 00:42:41 momjian Exp $
+ * $Id: pgcrypto.c,v 1.9 2001/09/23 04:12:44 momjian Exp $
  */
 
 #include <postgres.h>
@@ -200,7 +200,7 @@ pg_gen_salt(PG_FUNCTION_ARGS)
        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");
 
@@ -213,6 +213,41 @@ pg_gen_salt(PG_FUNCTION_ARGS)
        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;
+       memcpy(VARDATA(res), buf, len);
+
+       PG_FREE_IF_COPY(arg0, 0);
+
+       PG_RETURN_TEXT_P(res);
+}
+
 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
 PG_FUNCTION_INFO_V1(pg_crypt);
 
index 4c400243042b2e373b4e180228c77ae031df3099..1b49c8d895b70c7e50820150a762357ce4e51051 100644 (file)
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: pgcrypto.h,v 1.4 2001/08/21 00:42:41 momjian Exp $
+ * $Id: pgcrypto.h,v 1.5 2001/09/23 04:12:44 momjian Exp $
  */
 
 #ifndef _PG_CRYPTO_H
@@ -38,6 +38,7 @@ Datum         pg_digest_exists(PG_FUNCTION_ARGS);
 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);
index bed50c6946e13853ae4a04470f05d929a723c5a8..6cf54f1da6d07b07316319fe3054196a366ac173 100644 (file)
@@ -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);
 
 
 
@@ -36,6 +38,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@',
   'pg_encrypt' LANGUAGE 'C';
index 1d615a8a5a6710e33e54eed319b3cbca6265d105..7d767279b15bff9b5f02d3644f547c5da7541f8f 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: px-crypt.c,v 1.1 2001/08/21 01:32:01 momjian Exp $
+ * $Id: px-crypt.c,v 1.2 2001/09/23 04:12:44 momjian Exp $
  */
 
 #include <postgres.h>
+#include "px.h"
 #include "px-crypt.h"
 
 
@@ -62,12 +63,8 @@ run_crypt_bf(const char *psw, const char *salt,
                        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 @@ px_crypt(const char *psw, const char *salt,
  * 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;
index 506d922e864feac4ee54beb7f6a8acc94fd261dd..5edebb3d3be0e6d0a68079baa264fb265663b57a 100644 (file)
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: px-crypt.h,v 1.1 2001/08/21 01:32:01 momjian Exp $
+ * $Id: px-crypt.h,v 1.2 2001/09/23 04:12:44 momjian Exp $
  */
 
 #ifndef _PX_CRYPT_H
 /* 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 @@ extern char px_crypt_a64[];
 #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 @@ extern char px_crypt_a64[];
 /* #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);
 
index d9ee0d1db41adfee65b43fac8db44a19221f229f..d4cffc3c0692a50dba7553323dd04181908ade78 100644 (file)
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: px.h,v 1.1 2001/08/21 01:32:01 momjian Exp $
+ * $Id: px.h,v 1.2 2001/09/23 04:12:44 momjian Exp $
  */
 
 #ifndef __PX_H
@@ -133,6 +133,8 @@ 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);
 
+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 --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c
new file mode 100644 (file)
index 0000000..337d63e
--- /dev/null
@@ -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: random.c,v 1.1 2001/09/23 04:12:44 momjian Exp $
+ */
+
+
+#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 */
+