From 2518e273340406033e65816cff6380e20860af0e Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 21 Aug 2001 00:42:41 +0000
Subject: [PATCH] /contrib/pgcrypto:

* remove support for encode() as it is in main tree now
* remove krb5.c
* new 'PX library' architecture
* remove BSD license from my code to let the general
  PostgreSQL one to apply
* md5, sha1: ANSIfy, use const where appropriate
* various other formatting and clarity changes
* hmac()
* UN*X-like crypt() - system or internal crypt
* Internal crypt: DES, Extended DES, MD5, Blowfish
  crypt-des.c, crypt-md5.c from FreeBSD
  crypt-blowfish.c from Solar Designer
* gen_salt() for crypt() -  Blowfish, MD5, DES, Extended DES
* encrypt(), decrypt(), encrypt_iv(), decrypt_iv()
* Cipher support in mhash.c, openssl.c
* internal: Blowfish, Rijndael-128 ciphers
* blf.[ch], rijndael.[ch] from OpenBSD
* there will be generated file rijndael-tbl.inc.

Marko Kreen
---
 contrib/pgcrypto/Makefile        |  29 +-
 contrib/pgcrypto/README.pgcrypto | 198 +++++++++---
 contrib/pgcrypto/internal.c      | 510 ++++++++++++++++++++++++++++---
 contrib/pgcrypto/md5.c           |  25 +-
 contrib/pgcrypto/md5.h           |   5 +-
 contrib/pgcrypto/mhash.c         | 309 +++++++++++++++++--
 contrib/pgcrypto/openssl.c       | 388 +++++++++++++++++++++--
 contrib/pgcrypto/pgcrypto.c      | 470 +++++++++++++++++++++++++---
 contrib/pgcrypto/pgcrypto.h      |  31 +-
 contrib/pgcrypto/pgcrypto.sql.in |  56 +++-
 contrib/pgcrypto/sha1.c          |  21 +-
 contrib/pgcrypto/sha1.h          |   6 +-
 12 files changed, 1791 insertions(+), 257 deletions(-)

diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index 408e1c85f60..ef9a30eb63f 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -1,20 +1,23 @@
 #
-# $Header: /cvsroot/pgsql/contrib/pgcrypto/Makefile,v 1.4 2001/06/18 21:38:02 momjian Exp $
+# $Header: /cvsroot/pgsql/contrib/pgcrypto/Makefile,v 1.5 2001/08/21 00:42:41 momjian Exp $
 #
 
 subdir = contrib/pgcrypto
 top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 
-# either 'builtin', 'mhash', 'openssl', 'krb5'
+# either 'builtin', 'mhash', 'openssl'
 cryptolib = builtin
 
+# either 'builtin', 'system'
+cryptsrc = builtin
+
 ##########################
 
 ifeq ($(cryptolib), builtin)
 CRYPTO_CFLAGS =
 CRYPTO_LDFLAGS =
-SRCS = md5.c sha1.c internal.c
+SRCS = md5.c sha1.c internal.c blf.c rijndael.c
 endif
 
 ifeq ($(cryptolib), openssl)
@@ -25,18 +28,18 @@ endif
 
 ifeq ($(cryptolib), mhash)
 CRYPTO_CFLAGS = -I/usr/local/include
-CRYPTO_LDFLAGS = -L/usr/local/lib -lmhash
+CRYPTO_LDFLAGS = -L/usr/local/lib -lmcrypt -lmhash -lltdl
 SRCS = mhash.c
 endif
 
-ifeq ($(cryptolib), krb5)
-CRYPTO_CFLAGS = -I/usr/include
-CRYPTO_LDFLAGS = -ldes
-SRCS = krb.c
+ifeq ($(cryptsrc), builtin)
+SRCS += crypt-blowfish.c crypt-des.c crypt-md5.c 
+else
+CRYPTO_CFLAGS += -DPX_SYSTEM_CRYPT
 endif
 
 NAME	:= pgcrypto
-SRCS	+= pgcrypto.c encode.c
+SRCS	+= pgcrypto.c px.c px-hmac.c px-crypt.c misc.c
 OBJS	:= $(SRCS:.c=.o)
 SHLIB_LINK := $(CRYPTO_LDFLAGS)
 SO_MAJOR_VERSION = 0
@@ -52,6 +55,12 @@ include $(top_srcdir)/src/Makefile.shlib
 $(NAME).sql: $(NAME).sql.in
 	sed 's,@MODULE_FILENAME@,$(libdir)/contrib/pgcrypto$(DLSUFFIX),g' $< >$@
 
+rijndael.o: rijndael.tbl
+
+rijndael.tbl:
+	$(CC) $(CPPFLAGS) $(CFLAGS) -DPRINT_TABS rijndael.c -o gen-rtab
+	./gen-rtab > rijndael.tbl
+
 install: all installdirs
 	$(INSTALL_SHLIB) $(shlib)	$(DESTDIR)$(libdir)/contrib/pgcrypto$(DLSUFFIX)
 	$(INSTALL_DATA) $(NAME).sql	$(DESTDIR)$(datadir)/contrib/$(NAME).sql
@@ -64,4 +73,4 @@ uninstall: uninstall-lib
 	rm -f $(DESTDIR)$(libdir)/contrib/pgcrypto$(DLSUFFIX) $(datadir)/contrib/$(NAME).sql $(docdir)/contrib/README.$(NAME)
 
 clean distclean maintainer-clean: clean-lib
-	rm -f $(OBJS) $(NAME).sql
+	rm -f $(OBJS) $(NAME).sql gen-rtab
diff --git a/contrib/pgcrypto/README.pgcrypto b/contrib/pgcrypto/README.pgcrypto
index 1a4c90d0b5b..7173710bc3f 100644
--- a/contrib/pgcrypto/README.pgcrypto
+++ b/contrib/pgcrypto/README.pgcrypto
@@ -1,56 +1,184 @@
 
-DESCRIPTION
+pgcrypto 0.4 - cryptographic functions for PostgreSQL.
+======================================================
+by Marko Kreen <marko@l-t.ee>
 
-  Here are various cryptographic and otherwise useful
-  functions for PostgreSQL.
 
-    encode(data, type)
-        encodes binary data into ASCII-only representation.
-	Types supported are 'hex' and 'base64'.
+INSTALLATION
+============
 
-    decode(data, type)
-    	decodes the data processed by encode()
+Edit makefile, if you want to use any external library.
 
-    digest(data::text, hash_name::text)
-	which returns cryptographic checksum over data by
-	specified algorithm. eg
+make
+make install
 
-	> select encode(digest('blah', 'sha1'), 'hex');
-	5bf1fd927dfb8679496a2e6cf00cbe50c1c87145
+SQL FUNCTIONS
+=============
 
-    digest_exists(hash_name::text)::bool
-	which reports if particular hash type exists.
+	If any of arguments are NULL they return NULL.
 
-  If any of arguments are NULL they return NULL.
+digest(data::bytea, type::text)::bytea
 
-HASHES
+	Type is here the algorithm to use. E.g. 'md5', 'sha1', ...
+	Returns binary hash.
 
-  For choosing library you must edit Makefile.
+digest_exists(type::text)::bool
 
-  standalone (default):
-	MD5, SHA1
+	Returns BOOL whether given hash exists.
 
-	(the code is from KAME project.  Actually I hate code
-	duplication, but I also want to quarantee that MD5 and
-	SHA1 exist)
+hmac(data::bytea, key::bytea, type::text)::bytea
 
-  mhash (0.8.1):
-	MD5, SHA1, CRC32, CRC32B, GOST, TIGER, RIPEMD160,
-	HAVAL(256,224,192,160,128)
+	Calculates Hashed MAC over data.  type is the same as
+	in digest().  Returns binary hash.  Similar to digest()
+	but noone can alter data and re-calculate hash without
+	knowing key.  If the key is larger than hash blocksize
+	it will first hashed and the hash will be used as key.
+	
+	[ HMAC is described in RFC2104. ]
 
-  openssl:
-	MD5, SHA1, RIPEMD160, MD2
+hmac_exists(type::text)::bool
+	Returns BOOL.  It is separate function because all hashes
+	cannot be used in HMAC.
 
-  kerberos5 (heimdal):
-	MD5, SHA1
+crypt(password::text, salt::text)::text
 
-ENCRYPTION
+	Calculates UN*X crypt(3) style hash.  Useful for storing
+	passwords.  For generating salt you should use the
+	gen_salt() function.  Usage:
 
-  There is experimental version out with encryption, HMAC
-  and UN*X crypt() support in
+	New password:
+	
+	  UPDATE .. SET pswhash = crypt(new_psw, gen_salt('md5'));
+	
+	Authentication:
 
-    http://www.l-t.ee/marko/pgsql/
+	  SELECT pswhash = crypt(given_psw, pswhash) WHERE .. ;
+	
+	returns BOOL whether the given_psw is correct.  DES crypt
+	has max key of 8 bytes, MD5 has max key at least 2^32-1
+	bytes but may be larger on some platforms...
 
-  Current latest release is pgcrypto-0.3.tar.gz.
+	Builtin crypt() supports DES, Extended DES, MD5 and Blowfish
+	(variant 2a) algorithms.
+
+gen_salt(type::text)::text
+
+	Generates a new random salt for usage in crypt().  Type
+	
+	'des'	- Old UNIX, not recommended
+	'md5'	- md5-based crypt()
+	'xdes'	- 'Extended DES'
+	'bf'	- Blowfish-based, variant 2a
+
+	When you use --enable-system-crypt then note that system
+	libcrypt may not support them all.
+
+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
+decrypt_iv(data::bytea, key::bytea, iv::bytea, type::text)::bytea
+
+	Encrypt/decrypt data with cipher, padding data if needed.
+
+	Pseudo-noteup:
+
+	algo ['-' mode] ['/pad:' padding]
+
+	Supported algorithms:
+	
+		bf		- Blowfish
+		aes, rijndael	- Rijndael-128
+
+	Others depend on library and are not tested enough, so
+	play on your own risk.
+
+	Modes: 'cbc' (default), 'ecb'.  Again, library may support
+	more.
+
+	Padding is 'pkcs' (default), 'none'.  'none' is mostly for
+	testing ciphers, you should not need it.
+
+	So, example:
+
+		encrypt(data, 'fooz', 'bf')
+	
+	is equal to
+
+		encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')
+
+	IV is initial value for mode, defaults to all zeroes.
+	It is ignored for ECB.  It is clipped or padded with zeroes
+	if not exactly block size.
+
+
+ALGORITHMS
+==========
+
+The standard functionality at the moment consist of
+
+Hashes: md5, sha1
+Ciphers: bf, aes
+Modes: cbc, ecb
+
+TODO: write stardard names for optional ciphers too.
+
+LIBRARIES
+=========
+
+* crypt()
+
+    internal: des, xdes, md5, bf
+
+    -lcrypt: ??? (whatever you have)
+
+* other:
+
+[ This only list of stuff libraries claim to support.  So
+  pgcrypto may work with all of them.  But ATM tested aree only the
+  standard ciphers.  On others pgcrypto and library may mess something
+  up. You have been warned.  ]
+
+internal (default):
+    Hashes: MD5, SHA1
+    Ciphers: Blowfish, Rijndael-128
+
+
+OpenSSL (0.9.6):
+    Hashes:	MD5, SHA1, RIPEMD160, MD2   
+    Ciphers:	DES, DESX, DES3, RC5, RC4, RC2, IDEA,
+		Blowfish, CAST5
+    License:	BSD-like with strong advertisement
+    Url:	http://www.openssl.org/
+
+
+mhash (0.8.9) + mcrypt (2.4.11):
+    Hashes:	MD5, SHA1, CRC32, CRC32B, GOST, TIGER, RIPEMD160,
+		HAVAL(256,224,192,160,128)
+    Ciphers:	DES, DES3, CAST-128(CAST5), CAST-256, xTEA, 3-way,
+    		SKIPJACK, Blowfish, Twofish, LOKI97, RC2, RC4, RC6,
+		Rijndael-128/192/256, MARS, PANAMA, WAKE, Serpent, IDEA, GOST,
+		SAFER, SAFER+, Enigma
+    License:	LGPL
+    Url:	http://mcrypt.sourceforge.org/
+    Url:	http://mhash.sourceforge.org/
+
+CREDITS
+=======
+
+I have used code from following sources:
+
+DES crypt() by David Burren and others	FreeBSD libcrypt
+MD5 crypt() by Poul-Henning Kamp	FreeBSD libcrypt
+Blowfish crypt() by Solar Designer	www.openwall.com
+Blowfish cipher by Niels Provos		OpenBSD sys/crypto
+Rijndael cipher by Brian Gladman	OpenBSD sys/crypto
+MD5 and SHA1 by WIDE Project		KAME kame/sys/crypto
+
+LEGALESE
+========
+
+* I owe a beer to Poul-Henning.
+
+* This product includes software developed by Niels Provos.
 
 
diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c
index 2d4a52717e0..1debd2b3884 100644
--- a/contrib/pgcrypto/internal.c
+++ b/contrib/pgcrypto/internal.c
@@ -2,7 +2,7 @@
  * internal.c
  *		Wrapper for builtin functions
  *
- * Copyright (c) 2000 Marko Kreen
+ * Copyright (c) 2001 Marko Kreen
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,18 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: internal.c,v 1.3 2001/03/22 03:59:10 momjian Exp $
+ * $Id: internal.c,v 1.4 2001/08/21 00:42:41 momjian Exp $
  */
 
-#include "postgres.h"
 
-#include "pgcrypto.h"
+#include <postgres.h>
+
+#include "px.h"
 
 #include "md5.h"
 #include "sha1.h"
+#include "blf.h"
+#include "rijndael.h"
 
 #ifndef MD5_DIGEST_LENGTH
 #define MD5_DIGEST_LENGTH 16
@@ -48,67 +51,496 @@
 #endif
 #endif
 
-static uint
-			pg_md5_len(pg_digest * h);
-static uint8 *
-			pg_md5_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf);
+#define SHA1_BLOCK_SIZE 64
+#define MD5_BLOCK_SIZE 64
 
-static uint
-			pg_sha1_len(pg_digest * h);
-static uint8 *
-			pg_sha1_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf);
-
-static pg_digest
-			int_digest_list[] = {
-	{"md5", pg_md5_len, pg_md5_digest, {0}},
-	{"sha1", pg_sha1_len, pg_sha1_digest, {0}},
-	{NULL, NULL, NULL, {0}}
+static void init_md5(PX_MD * h);
+static void init_sha1(PX_MD * h);
+
+static struct int_digest
+{
+	char	   *name;
+	void		(*init) (PX_MD * h);
+} int_digest_list[] =
+{
+	{ "md5", init_md5 },
+	{ "sha1", init_sha1 },
+	{ NULL, NULL }
 };
 
+/* MD5 */
+
 static uint
-pg_md5_len(pg_digest * h)
+int_md5_len(PX_MD * h)
 {
 	return MD5_DIGEST_LENGTH;
 }
 
-static uint8 *
-pg_md5_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf)
+static uint
+int_md5_block_len(PX_MD * h)
+{
+	return MD5_BLOCK_SIZE;
+}
+
+static void
+int_md5_update(PX_MD * h, const uint8 * data, uint dlen)
 {
-	MD5_CTX		ctx;
+	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+
+	MD5Update(ctx, data, dlen);
+}
+
+static void
+int_md5_reset(PX_MD * h)
+{
+	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+
+	MD5Init(ctx);
+}
+
+static void
+int_md5_finish(PX_MD * h, uint8 * dst)
+{
+	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+
+	MD5Final(dst, ctx);
+}
 
-	MD5Init(&ctx);
-	MD5Update(&ctx, src, len);
-	MD5Final(buf, &ctx);
+static void
+int_md5_free(PX_MD * h)
+{
+	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
 
-	return buf;
+	px_free(ctx);
+	px_free(h);
 }
 
+/* SHA1 */
+
 static uint
-pg_sha1_len(pg_digest * h)
+int_sha1_len(PX_MD * h)
 {
 	return SHA1_DIGEST_LENGTH;
 }
 
-static uint8 *
-pg_sha1_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf)
+static uint
+int_sha1_block_len(PX_MD * h)
+{
+	return SHA1_BLOCK_SIZE;
+}
+
+static void
+int_sha1_update(PX_MD * h, const uint8 * data, uint dlen)
+{
+	SHA1_CTX   *ctx = (SHA1_CTX *) h->p.ptr;
+
+	SHA1Update(ctx, (const char *)data, dlen);
+}
+
+static void
+int_sha1_reset(PX_MD * h)
+{
+	SHA1_CTX   *ctx = (SHA1_CTX *) h->p.ptr;
+
+	SHA1Init(ctx);
+}
+
+static void
+int_sha1_finish(PX_MD * h, uint8 * dst)
+{
+	SHA1_CTX   *ctx = (SHA1_CTX *) h->p.ptr;
+
+	SHA1Final(dst, ctx);
+}
+
+static void
+int_sha1_free(PX_MD * h)
+{
+	SHA1_CTX   *ctx = (SHA1_CTX *) h->p.ptr;
+
+	px_free(ctx);
+	px_free(h);
+}
+
+/* init functions */
+
+static void
+init_md5(PX_MD * md)
+{
+	MD5_CTX    *ctx;
+
+	ctx = px_alloc(sizeof(*ctx));
+
+	md->p.ptr = ctx;
+
+	md->result_size = int_md5_len;
+	md->block_size = int_md5_block_len;
+	md->reset = int_md5_reset;
+	md->update = int_md5_update;
+	md->finish = int_md5_finish;
+	md->free = int_md5_free;
+
+	md->reset(md);
+}
+
+static void
+init_sha1(PX_MD * md)
+{
+	SHA1_CTX   *ctx;
+
+	ctx = px_alloc(sizeof(*ctx));
+
+	md->p.ptr = ctx;
+
+	md->result_size = int_sha1_len;
+	md->block_size = int_sha1_block_len;
+	md->reset = int_sha1_reset;
+	md->update = int_sha1_update;
+	md->finish = int_sha1_finish;
+	md->free = int_sha1_free;
+
+	md->reset(md);
+}
+
+/*
+ * ciphers generally
+ */
+
+#define INT_MAX_KEY		(512/8)
+#define INT_MAX_IV		(128/8)
+
+struct int_ctx {
+	uint8 keybuf[INT_MAX_KEY];
+	uint8 iv[INT_MAX_IV];
+	union {
+		blf_ctx bf;
+		rijndael_ctx rj;
+	} ctx;
+	uint keylen;
+	int is_init;
+	int mode;
+};
+
+static void intctx_free(PX_Cipher *c)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+	if (cx) {
+		memset(cx, 0, sizeof *cx);
+		px_free(cx);
+	}
+	px_free(c);
+}
+
+/*
+ * AES/rijndael
+ */
+
+#define MODE_ECB 0
+#define MODE_CBC 1
+
+static uint rj_block_size(PX_Cipher *c)
+{
+	return 128/8;
+}
+
+static uint rj_key_size(PX_Cipher *c)
+{
+	return 256/8;
+}
+
+static uint rj_iv_size(PX_Cipher *c)
+{
+	return 128/8;
+}
+
+static int rj_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+
+	if (klen <= 128/8)
+		cx->keylen = 128/8;
+	else if (klen <= 192/8)
+		cx->keylen = 192/8;
+	else if (klen <= 256/8)
+		cx->keylen = 256/8;
+	else
+		return -1;
+
+	memcpy(&cx->keybuf, key, klen);
+
+	if (iv)
+		memcpy(cx->iv, iv, 128/8);
+
+	return 0;
+}
+
+static int rj_real_init(struct int_ctx *cx, int dir)
+{
+	aes_set_key(&cx->ctx.rj, cx->keybuf, cx->keylen*8, dir);
+	return 0;
+}
+
+static int rj_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+	
+	if (!cx->is_init) {
+		if (rj_real_init(cx, 1))
+			return -1;
+	}
+	
+	if (dlen == 0)
+		return 0;
+
+	if ((dlen & 15) || (((unsigned)res) & 3))
+		return -1;
+
+	memcpy(res, data, dlen);
+
+	if (cx->mode == MODE_CBC) {
+		aes_cbc_encrypt(&cx->ctx.rj, cx->iv, res, dlen);
+		memcpy(cx->iv, res + dlen - 16, 16);
+	} else
+		aes_ecb_encrypt(&cx->ctx.rj, res, dlen);
+	
+	return 0;
+}
+
+static int rj_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+	
+	if (!cx->is_init)
+		if (rj_real_init(cx, 0))
+			return -1;
+
+	if (dlen == 0)
+		return 0;
+
+	if ((dlen & 15) || (((unsigned)res) & 3))
+		return -1;
+
+	memcpy(res, data, dlen);
+
+	if (cx->mode == MODE_CBC) {
+		aes_cbc_decrypt(&cx->ctx.rj, cx->iv, res, dlen);
+		memcpy(cx->iv, data + dlen - 16, 16);
+	} else
+		aes_ecb_decrypt(&cx->ctx.rj, res, dlen);
+	
+	return 0;
+}
+
+/*
+ * initializers
+ */
+
+static PX_Cipher * rj_load(int mode)
+{
+	PX_Cipher *c;
+	struct int_ctx *cx;
+	
+	c = px_alloc(sizeof *c);
+	memset(c, 0, sizeof *c);
+
+	c->block_size = rj_block_size;
+	c->key_size = rj_key_size;
+	c->iv_size = rj_iv_size;
+	c->init = rj_init;
+	c->encrypt = rj_encrypt;
+	c->decrypt = rj_decrypt;
+	c->free = intctx_free;
+
+	cx = px_alloc(sizeof *cx);
+	memset(cx, 0, sizeof *cx);
+	cx->mode = mode;
+
+	c->ptr = cx;
+	return c;
+}
+
+/*
+ * blowfish
+ */
+
+static uint bf_block_size(PX_Cipher *c)
+{
+	return 8;
+}
+
+static uint bf_key_size(PX_Cipher *c)
+{
+	return BLF_MAXKEYLEN;
+}
+
+static uint bf_iv_size(PX_Cipher *c)
+{
+	return 8;
+}
+
+static int bf_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+
+	blf_key(&cx->ctx.bf, key, klen);
+	if (iv)
+		memcpy(cx->iv, iv, 8);
+
+	return 0;
+}
+
+static int bf_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+
+	if (dlen == 0)
+		return 0;
+	
+	if ((dlen & 7) || (((unsigned)res) & 3))
+		return -1;
+
+	memcpy(res, data, dlen);
+	switch (cx->mode) {
+	case MODE_ECB:
+		blf_ecb_encrypt(&cx->ctx.bf, res, dlen);
+		break;
+	case MODE_CBC:
+		blf_cbc_encrypt(&cx->ctx.bf, cx->iv, res, dlen);
+		memcpy(cx->iv, res + dlen - 8, 8);
+	}
+	return 0;
+}
+
+static int bf_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	struct int_ctx *cx = (struct int_ctx *)c->ptr;
+
+	if (dlen == 0)
+		return 0;
+
+	if ((dlen & 7) || (((unsigned)res) & 3))
+		return -1;
+
+	memcpy(res, data, dlen);
+	switch (cx->mode) {
+	case MODE_ECB:
+		blf_ecb_decrypt(&cx->ctx.bf, res, dlen);
+		break;
+	case MODE_CBC:
+		blf_cbc_decrypt(&cx->ctx.bf, cx->iv, res, dlen);
+		memcpy(cx->iv, data + dlen - 8, 8);
+	}
+	return 0;
+}
+
+static PX_Cipher * bf_load(int mode)
+{
+	PX_Cipher *c;
+	struct int_ctx *cx;
+	
+	c = px_alloc(sizeof *c);
+	memset(c, 0, sizeof *c);
+
+	c->block_size = bf_block_size;
+	c->key_size = bf_key_size;
+	c->iv_size = bf_iv_size;
+	c->init = bf_init;
+	c->encrypt = bf_encrypt;
+	c->decrypt = bf_decrypt;
+	c->free = intctx_free;
+
+	cx = px_alloc(sizeof *cx);
+	memset(cx, 0, sizeof *cx);
+	cx->mode = mode;
+	c->ptr = cx;
+	return c;
+}
+
+/* ciphers */
+
+static PX_Cipher * rj_128_ecb()
+{
+	return rj_load(MODE_ECB);
+}
+
+static PX_Cipher * rj_128_cbc()
 {
-	SHA1_CTX	ctx;
+	return rj_load(MODE_CBC);
+}
 
-	SHA1Init(&ctx);
-	SHA1Update(&ctx, src, len);
-	SHA1Final(buf, &ctx);
+static PX_Cipher * bf_ecb_load()
+{
+	return bf_load(MODE_ECB);
+}
 
-	return buf;
+static PX_Cipher * bf_cbc_load()
+{
+	return bf_load(MODE_CBC);
 }
 
+static struct {
+	char *name;
+	PX_Cipher *(*load)(void);
+} int_ciphers [] = {
+	{ "bf-cbc", bf_cbc_load },
+	{ "bf-ecb", bf_ecb_load },
+	{ "aes-128-cbc", rj_128_cbc },
+	{ "aes-128-ecb", rj_128_ecb },
+	{ NULL, NULL }
+};
+
+static PX_Alias int_aliases [] = {
+	{ "bf", "bf-cbc" },
+	{ "blowfish", "bf-cbc" },
+	{ "aes", "aes-128-cbc" },
+	{ "aes-ecb", "aes-128-ecb" },
+	{ "aes-cbc", "aes-128-cbc" },
+	{ "aes-128", "aes-128-cbc" },
+	{ "rijndael", "aes-128-cbc" },
+	{ "rijndael-128", "aes-128-cbc" },
+	{ NULL, NULL }
+};
 
-pg_digest  *
-pg_find_digest(pg_digest * h, char *name)
+/* PUBLIC FUNCTIONS */
+
+int
+px_find_digest(const char *name, PX_MD ** res)
 {
-	pg_digest  *p;
+	struct int_digest *p;
+	PX_MD	   *h;
 
 	for (p = int_digest_list; p->name; p++)
 		if (!strcasecmp(p->name, name))
-			return p;
-	return NULL;
+		{
+			h = px_alloc(sizeof(*h));
+			p->init(h);
+
+			*res = h;
+
+			return 0;
+		}
+	return -1;
+}
+
+int
+px_find_cipher(const char *name, PX_Cipher **res)
+{
+	int i;
+	PX_Cipher *c = NULL;
+
+	name = px_resolve_alias(int_aliases, name);
+
+	for (i = 0; int_ciphers[i].name; i++)
+		if (!strcmp(int_ciphers[i].name, name)) {
+			c = int_ciphers[i].load();
+			break;
+		}
+
+	if (c == NULL)
+		return -1;
+
+	*res = c;
+	return 0;
 }
+
+
diff --git a/contrib/pgcrypto/md5.c b/contrib/pgcrypto/md5.c
index a5cfae34970..3ae9d099824 100644
--- a/contrib/pgcrypto/md5.c
+++ b/contrib/pgcrypto/md5.c
@@ -1,4 +1,4 @@
-/*	$Id: md5.c,v 1.5 2001/03/22 03:59:10 momjian Exp $	*/
+/*	$Id: md5.c,v 1.6 2001/08/21 00:42:41 momjian Exp $	*/
 /*	   $KAME: md5.c,v 1.3 2000/02/22 14:01:17 itojun Exp $	   */
 
 /*
@@ -128,8 +128,7 @@ static const uint8 md5_paddat[MD5_BUFLEN] = {
 static void md5_calc(uint8 *, md5_ctxt *);
 
 void
-md5_init(ctxt)
-md5_ctxt   *ctxt;
+md5_init(md5_ctxt *ctxt)
 {
 	ctxt->md5_n = 0;
 	ctxt->md5_i = 0;
@@ -141,10 +140,7 @@ md5_ctxt   *ctxt;
 }
 
 void
-md5_loop(ctxt, input, len)
-md5_ctxt   *ctxt;
-uint8	   *input;
-unsigned int len;				/* number of bytes */
+md5_loop(md5_ctxt *ctxt, const uint8 *input, unsigned len)
 {
 	unsigned int gap,
 				i;
@@ -173,8 +169,7 @@ unsigned int len;				/* number of bytes */
 }
 
 void
-md5_pad(ctxt)
-md5_ctxt   *ctxt;
+md5_pad(md5_ctxt *ctxt)
 {
 	unsigned int gap;
 
@@ -216,9 +211,7 @@ md5_ctxt   *ctxt;
 }
 
 void
-md5_result(digest, ctxt)
-uint8	   *digest;
-md5_ctxt   *ctxt;
+md5_result(uint8 *digest, md5_ctxt *ctxt)
 {
 	/* 4 byte words */
 #if BYTE_ORDER == LITTLE_ENDIAN
@@ -245,14 +238,11 @@ md5_ctxt   *ctxt;
 }
 
 #if BYTE_ORDER == BIG_ENDIAN
-uint32		X[16];
-
+static uint32		X[16];
 #endif
 
 static void
-md5_calc(b64, ctxt)
-uint8	   *b64;
-md5_ctxt   *ctxt;
+md5_calc(uint8 *b64, md5_ctxt *ctxt)
 {
 	uint32		A = ctxt->md5_sta;
 	uint32		B = ctxt->md5_stb;
@@ -261,7 +251,6 @@ md5_ctxt   *ctxt;
 
 #if BYTE_ORDER == LITTLE_ENDIAN
 	uint32	   *X = (uint32 *) b64;
-
 #endif
 #if BYTE_ORDER == BIG_ENDIAN
 	/* 4 byte words */
diff --git a/contrib/pgcrypto/md5.h b/contrib/pgcrypto/md5.h
index 54ca2558dff..868f8a233a0 100644
--- a/contrib/pgcrypto/md5.h
+++ b/contrib/pgcrypto/md5.h
@@ -1,4 +1,4 @@
-/*	$Id: md5.h,v 1.4 2001/03/22 03:59:10 momjian Exp $	*/
+/*	$Id: md5.h,v 1.5 2001/08/21 00:42:41 momjian Exp $	*/
 /*	   $KAME: md5.h,v 1.3 2000/02/22 14:01:18 itojun Exp $	   */
 
 /*
@@ -62,7 +62,7 @@ typedef struct
 }			md5_ctxt;
 
 extern void md5_init(md5_ctxt *);
-extern void md5_loop(md5_ctxt *, uint8 *, unsigned int);
+extern void md5_loop(md5_ctxt *, const uint8 *, unsigned int);
 extern void md5_pad(md5_ctxt *);
 extern void md5_result(uint8 *, md5_ctxt *);
 
@@ -75,5 +75,4 @@ do {				\
 	md5_pad((y));		\
 	md5_result((x), (y));	\
 } while (0)
-
 #endif	 /* ! _NETINET6_MD5_H_ */
diff --git a/contrib/pgcrypto/mhash.c b/contrib/pgcrypto/mhash.c
index d6ada96d149..36d70471a99 100644
--- a/contrib/pgcrypto/mhash.c
+++ b/contrib/pgcrypto/mhash.c
@@ -1,8 +1,8 @@
 /*
  * mhash.c
- *		Wrapper for mhash library.
+ *		Wrapper for mhash and mcrypt libraries.
  *
- * Copyright (c) 2000 Marko Kreen
+ * Copyright (c) 2001 Marko Kreen
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,48 +26,177 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: mhash.c,v 1.3 2001/03/22 03:59:10 momjian Exp $
+ * $Id: mhash.c,v 1.4 2001/08/21 00:42:41 momjian Exp $
  */
 
-#include "postgres.h"
+#include <postgres.h>
 
-#include "pgcrypto.h"
+#include "px.h"
 
 #include <mhash.h>
+#include <mcrypt.h>
+
+#define MAX_KEY_LENGTH 512
+#define MAX_IV_LENGTH 128
+
+#define DEF_KEY_LEN 16
 
-static uint
-			pg_mhash_len(pg_digest * hash);
-static uint8 *pg_mhash_digest(pg_digest * hash, uint8 *src,
-				uint len, uint8 *buf);
+
+/* DIGEST */
 
 static uint
-pg_mhash_len(pg_digest * h)
+digest_result_size(PX_MD * h)
 {
-	return mhash_get_block_size(h->misc.code);
+	MHASH		mh = (MHASH) h->p.ptr;
+	hashid		id = mhash_get_mhash_algo(mh);
+
+	return mhash_get_block_size(id);
 }
 
-static uint8 *
-pg_mhash_digest(pg_digest * h, uint8 *src, uint len, uint8 *dst)
+static uint
+digest_block_size(PX_MD * h)
 {
-	uint8	   *res;
+	MHASH		mh = (MHASH) h->p.ptr;
+	hashid		id = mhash_get_mhash_algo(mh);
 
-	MHASH		mh = mhash_init(h->misc.code);
+	return mhash_get_hash_pblock(id);
+}
 
-	mhash(mh, src, len);
-	res = mhash_end(mh);
+static void
+digest_reset(PX_MD * h)
+{
+	MHASH		mh = (MHASH) h->p.ptr;
+	hashid		id = mhash_get_mhash_algo(mh);
+	uint8	   *res = mhash_end(mh);
 
-	memcpy(dst, res, mhash_get_block_size(h->misc.code));
 	mhash_free(res);
+	mh = mhash_init(id);
+	h->p.ptr = mh;
+}
+
+static void
+digest_update(PX_MD * h, const uint8 * data, uint dlen)
+{
+	MHASH		mh = (MHASH) h->p.ptr;
+
+	mhash(mh, data, dlen);
+}
+
+static void
+digest_finish(PX_MD * h, uint8 * dst)
+{
+	MHASH		mh = (MHASH) h->p.ptr;
+	uint		hlen = digest_result_size(h);
+	hashid		id = mhash_get_mhash_algo(mh);
+	uint8	   *buf = mhash_end(mh);
+
+	memcpy(dst, buf, hlen);
+	mhash_free(buf);
+
+	mh = mhash_init(id);
+	h->p.ptr = mh;
+}
+
+static void
+digest_free(PX_MD * h)
+{
+	MHASH		mh = (MHASH) h->p.ptr;
+	uint8	   *buf = mhash_end(mh);
+
+	mhash_free(buf);
+
+	px_free(h);
+}
+
+/* ENCRYPT / DECRYPT */
+
+static uint
+cipher_block_size(PX_Cipher *c)
+{
+	MCRYPT ctx = (MCRYPT)c->ptr;
+	return mcrypt_enc_get_block_size(ctx);
+}
+
+static uint
+cipher_key_size(PX_Cipher *c)
+{
+	MCRYPT ctx = (MCRYPT)c->ptr;
+	return mcrypt_enc_get_key_size(ctx);
+}
+
+static uint
+cipher_iv_size(PX_Cipher *c)
+{
+	MCRYPT ctx = (MCRYPT)c->ptr;
+	return mcrypt_enc_mode_has_iv(ctx)
+		? mcrypt_enc_get_iv_size(ctx) : 0;
+}
+
+static int
+cipher_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+	int err;
+	MCRYPT ctx = (MCRYPT)c->ptr;
+
+	err = mcrypt_generic_init(ctx, (char *)key, klen, (char*)iv);
+	if (err < 0)
+		elog(ERROR, "mcrypt_generic_init error: %s", mcrypt_strerror(err));
+
+	c->pstat = 1;
+	return 0;
+}
+
+static int
+cipher_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	int err;
+	MCRYPT ctx = (MCRYPT)c->ptr;
 
-	return dst;
+	memcpy(res, data, dlen);
+
+	err = mcrypt_generic(ctx, res, dlen);
+	if (err < 0)
+		elog(ERROR, "mcrypt_generic error: %s", mcrypt_strerror(err));
+	return 0;
+}
+
+static int
+cipher_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	int err;
+	MCRYPT ctx = (MCRYPT)c->ptr;
+
+	memcpy(res, data, dlen);
+
+	err = mdecrypt_generic(ctx, res, dlen);
+	if (err < 0)
+		elog(ERROR, "mdecrypt_generic error: %s", mcrypt_strerror(err));
+	return 0;
+}
+
+
+static void
+cipher_free(PX_Cipher *c)
+{
+	MCRYPT ctx = (MCRYPT)c->ptr;
+
+	if (c->pstat)
+		mcrypt_generic_end(ctx);
+	else
+		mcrypt_module_close(ctx);
+	
+	px_free(c);
 }
 
-pg_digest  *
-pg_find_digest(pg_digest * h, char *name)
+/* Helper functions */
+
+static int
+find_hashid(const char *name)
 {
+	int			res = -1;
 	size_t		hnum,
-				i,
-				b;
+				b,
+				i;
 	char	   *mname;
 
 	hnum = mhash_count();
@@ -80,12 +209,134 @@ pg_find_digest(pg_digest * h, char *name)
 		free(mname);
 		if (!b)
 		{
-			h->name = mhash_get_hash_name(i);
-			h->length = pg_mhash_len;
-			h->digest = pg_mhash_digest;
-			h->misc.code = i;
-			return h;
+			res = i;
+			break;
 		}
 	}
-	return NULL;
+
+	return res;
 }
+
+static char *modes[] = {
+	"ecb", "cbc", "cfb", "ofb", "nofb", "stream",
+	"ofb64", "cfb64", NULL
+};
+
+static PX_Alias aliases[] = {
+	{"bf", "blowfish" },
+	{"3des", "tripledes" },
+	{"des3", "tripledes" },
+	{"aes", "rijndael-128" },
+	{"rijndael", "rijndael-128" },
+	{"aes-128", "rijndael-128" },
+	{"aes-192", "rijndael-192" },
+	{"aes-256", "rijndael-256" },
+	{ NULL, NULL }
+};
+
+static PX_Alias mode_aliases[] = {
+#if 0 /* N/A */
+	{ "cfb", "ncfb" },
+	{ "ofb", "nofb" },
+	{ "cfb64", "ncfb" },
+#endif
+	/* { "ofb64", "nofb" }, not sure it works */
+	{ "cfb8", "cfb" },
+	{ "ofb8", "ofb" },
+	{ NULL, NULL }
+};
+
+static int is_mode(char *s)
+{
+	char **p;
+	
+	if (*s >= '0' && *s <= '9')
+		return 0;
+
+	for (p = modes; *p; p++)
+		if (!strcmp(s, *p))
+			return 1;
+
+	return 0;
+}
+
+/* PUBLIC FUNCTIONS */
+
+int
+px_find_digest(const char *name, PX_MD **res)
+{
+	PX_MD	   *h;
+	MHASH		mh;
+	int			i;
+
+	i = find_hashid(name);
+	if (i < 0)
+		return -1;
+
+	mh = mhash_init(i);
+	h = px_alloc(sizeof(*h));
+	h->p.ptr = (void *) mh;
+
+	h->result_size = digest_result_size;
+	h->block_size = digest_block_size;
+	h->reset = digest_reset;
+	h->update = digest_update;
+	h->finish = digest_finish;
+	h->free = digest_free;
+
+	*res = h;
+	return 0;
+}
+
+
+int
+px_find_cipher(const char *name, PX_Cipher **res)
+{
+	char nbuf[PX_MAX_NAMELEN + 1];
+	const char *mode = NULL;
+	char *p;
+	MCRYPT ctx;
+
+	PX_Cipher *c;
+
+	strcpy(nbuf, name);
+	
+	if ((p = strrchr(nbuf, '-')) != NULL) {
+		if (is_mode(p + 1)) {
+			mode = p + 1;
+			*p = 0;
+		}
+	}
+
+	name = px_resolve_alias(aliases, nbuf);
+
+	if (!mode) {
+		mode = "cbc";
+		/*
+		if (mcrypt_module_is_block_algorithm(name, NULL))
+			mode = "cbc";
+		else
+			mode = "stream";
+		*/
+	}
+	mode = px_resolve_alias(mode_aliases, mode);
+	
+	ctx = mcrypt_module_open((char*)name, NULL, (char*)mode, NULL);
+	if (ctx == (void*)MCRYPT_FAILED)
+		return -1;
+
+	c = palloc(sizeof *c);
+	c->iv_size = cipher_iv_size;
+	c->key_size = cipher_key_size;
+	c->block_size = cipher_block_size;
+	c->init = cipher_init;
+	c->encrypt = cipher_encrypt;
+	c->decrypt = cipher_decrypt;
+	c->free = cipher_free;
+	c->ptr = ctx;
+	c->pstat = 0;
+
+	*res = c;
+	return 0;
+}
+
diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index 866d26f0ffc..b4d1a0a5e9b 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -2,7 +2,7 @@
  * openssl.c
  *		Wrapper for OpenSSL library.
  *
- * Copyright (c) 2000 Marko Kreen
+ * Copyright (c) 2001 Marko Kreen
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,60 +26,388 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: openssl.c,v 1.3 2001/03/22 03:59:10 momjian Exp $
+ * $Id: openssl.c,v 1.4 2001/08/21 00:42:41 momjian Exp $
  */
 
-#include "postgres.h"
+#include <postgres.h>
 
-#include "pgcrypto.h"
+#include "px.h"
 
-#include <evp.h>
+#include <openssl/evp.h>
+#include <openssl/blowfish.h>
+/*#include <openssl/crypto.h>*/
 
 static uint
-			pg_ossl_len(pg_digest * h);
-static uint8 *
-			pg_ossl_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf);
+digest_result_size(PX_MD * h)
+{
+	return EVP_MD_CTX_size((EVP_MD_CTX *) h->p.ptr);
+}
 
 static uint
-pg_ossl_len(pg_digest * h)
+digest_block_size(PX_MD * h)
 {
-	return EVP_MD_size((EVP_MD *) h->misc.ptr);
+	return EVP_MD_CTX_block_size((EVP_MD_CTX *) h->p.ptr);
+}
+
+static void
+digest_reset(PX_MD * h)
+{
+	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+	const EVP_MD *md;
+
+	md = EVP_MD_CTX_md(ctx);
+
+	EVP_DigestInit(ctx, md);
 }
 
-static uint8 *
-pg_ossl_digest(pg_digest * h, uint8 *src, uint len, uint8 *buf)
+static void
+digest_update(PX_MD * h, const uint8 * data, uint dlen)
 {
-	EVP_MD	   *md = (EVP_MD *) h->misc.ptr;
-	EVP_MD_CTX	ctx;
+	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+
+	EVP_DigestUpdate(ctx, data, dlen);
+}
 
-	EVP_DigestInit(&ctx, md);
-	EVP_DigestUpdate(&ctx, src, len);
-	EVP_DigestFinal(&ctx, buf, NULL);
+static void
+digest_finish(PX_MD * h, uint8 * dst)
+{
+	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
 
-	return buf;
+	EVP_DigestFinal(ctx, dst, NULL);
 }
 
-static int	pg_openssl_initialized = 0;
+static void
+digest_free(PX_MD * h)
+{
+	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+
+	px_free(ctx);
+	px_free(h);
+}
+
+/* CIPHERS */
+
+/*
+ * The problem with OpenSSL is that the EVP* family
+ * of functions does not allow enough flexibility
+ * and forces some of the parameters (keylen,
+ * padding) to SSL defaults.
+ */
+
+
+typedef struct {
+	union {
+		struct {
+			BF_KEY key;
+			int num;
+		} bf;
+		EVP_CIPHER_CTX evp_ctx;
+	} u;
+	const EVP_CIPHER *evp_ciph;
+	uint8 key[EVP_MAX_KEY_LENGTH];
+	uint8 iv[EVP_MAX_IV_LENGTH];
+	uint klen;
+	uint init;
+} ossldata;
+
+/* generic EVP */
+
+static uint
+gen_evp_block_size(PX_Cipher *c)
+{
+	ossldata *od = (ossldata *)c->ptr;
+	return EVP_CIPHER_block_size(od->evp_ciph);
+}
+
+static uint
+gen_evp_key_size(PX_Cipher *c)
+{
+	ossldata *od = (ossldata *)c->ptr;
+	return EVP_CIPHER_key_length(od->evp_ciph);
+}
+
+static uint
+gen_evp_iv_size(PX_Cipher *c)
+{
+	uint ivlen;
+	ossldata *od = (ossldata *)c->ptr;
+	ivlen = EVP_CIPHER_iv_length(od->evp_ciph);
+	return ivlen;
+}
+
+static void
+gen_evp_free(PX_Cipher *c)
+{
+	ossldata *od = (ossldata*)c->ptr;
+	memset(od, 0, sizeof(*od));
+	pfree(od);
+	pfree(c);
+}
+
+/* fun */
+
+static int
+gen_evp_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+	ossldata *od = (ossldata*)c->ptr;
+	uint bs = gen_evp_block_size(c);
+	if (iv) {
+		memcpy(od->iv, iv, bs);
+	} else
+		memset(od->iv, 0, bs);
+	memcpy(od->key, key, klen);
+	od->klen = klen;
+	od->init = 0;
+	return 0;
+}
+
+static void
+_gen_init(PX_Cipher *c, int enc)
+{
+	ossldata *od = c->ptr;
+	
+	od->evp_ciph->init(&od->u.evp_ctx, od->key, od->iv, enc);
+	od->init = 1;
+	od->u.evp_ctx.encrypt = enc;
+}
+
+static int
+gen_evp_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	if (!od->init)
+		_gen_init(c, 1);
+	od->evp_ciph->do_cipher(&od->u.evp_ctx, res, data, dlen);
+	return 0;
+}
+
+static int
+gen_evp_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	if (!od->init)
+		_gen_init(c, 0);
+	od->evp_ciph->do_cipher(&od->u.evp_ctx, res, data, dlen);
+	return 0;
+}
+
+/* Blowfish */
+
+static int
+bf_init(PX_Cipher *c, const uint8 *key, uint klen, const uint8 *iv)
+{
+	ossldata *od = c->ptr;
+	BF_set_key(&od->u.bf.key, klen, key);
+	if (iv) {
+		memcpy(od->iv, iv, BF_BLOCK);
+	} else
+		memset(od->iv, 0, BF_BLOCK);
+	od->u.bf.num = 0;
+	return 0;
+}
 
-pg_digest  *
-pg_find_digest(pg_digest * h, char *name)
+static int
+bf_ecb_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	uint bs = gen_evp_block_size(c), i;
+	ossldata *od = c->ptr;
+	for (i = 0; i < dlen / bs; i++)
+		BF_ecb_encrypt(data+i*bs, res+i*bs, &od->u.bf.key, BF_ENCRYPT);
+	return 0;
+}
+
+static int
+bf_ecb_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	uint bs = gen_evp_block_size(c), i;
+	ossldata *od = c->ptr;
+	for (i = 0; i < dlen / bs; i++)
+		BF_ecb_encrypt(data+i*bs, res+i*bs, &od->u.bf.key, BF_DECRYPT);
+	return 0;
+}
+
+static int
+bf_cbc_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_ENCRYPT);
+	return 0;
+}
+
+static int
+bf_cbc_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_DECRYPT);
+	return 0;
+}
+
+static int
+bf_cfb64_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv,
+			&od->u.bf.num, BF_ENCRYPT);
+	return 0;
+}
+
+static int
+bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv,
+			&od->u.bf.num, BF_DECRYPT);
+	return 0;
+}
+
+static int
+bf_ofb64_encrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	BF_ofb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, &od->u.bf.num);
+	return 0;
+}
+
+static int
+bf_ofb64_decrypt(PX_Cipher *c, const uint8 *data, uint dlen, uint8 *res)
+{
+	ossldata *od = c->ptr;
+	BF_ofb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, &od->u.bf.num);
+	return 0;
+}
+
+/*
+ * aliases
+ */
+
+static PX_Alias ossl_aliases [] = {
+	{ "bf", "bf-cbc" },
+	{ "blowfish", "bf-cbc" },
+	{ "blowfish-cbc", "bf-cbc" },
+	{ "blowfish-ecb", "bf-ecb" },
+	{ "blowfish-cfb", "bf-cfb" },
+	{ "blowfish-ofb", "bf-ofb" },
+	{ NULL }
+};
+
+/*
+static PX_Alias ossl_mode_aliases [] = {
+	{ "cfb64", "cfb" },
+	{ "ofb64", "ofb" },
+	{ NULL }
+};*/
+
+/*
+ * Special handlers
+ */
+struct {
+	char *name;
+	PX_Cipher cf;
+} spec_types [] = {
+  { "bf-cbc", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+		bf_init, bf_cbc_encrypt, bf_cbc_decrypt, gen_evp_free}},
+  { "bf-ecb", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+	        bf_init, bf_ecb_encrypt, bf_ecb_decrypt, gen_evp_free}},
+  { "bf-cfb", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+		  bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt, gen_evp_free}},
+  { "bf-ofb", { gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+		  bf_init, bf_ofb64_encrypt, bf_ofb64_decrypt, gen_evp_free}},
+  { NULL }
+};
+
+/*
+ * Generic EVP_* functions handler
+ */
+static PX_Cipher gen_evp_handler = {
+	gen_evp_block_size, gen_evp_key_size, gen_evp_iv_size,
+	gen_evp_init, gen_evp_encrypt, gen_evp_decrypt, gen_evp_free
+};
+
+static int px_openssl_initialized = 0;
+
+/* ATM not needed
+static void *o_alloc(uint s) { return px_alloc(s); }
+static void *o_realloc(void *p) { return px_realloc(p); }
+static void o_free(void *p) { px_free(p); }
+*/
+
+/* PUBLIC functions */
+
+int
+px_find_digest(const char *name, PX_MD **res)
 {
 	const EVP_MD *md;
+	EVP_MD_CTX *ctx;
+	PX_MD	   *h;
 
-	if (!pg_openssl_initialized)
+	if (!px_openssl_initialized)
 	{
-		OpenSSL_add_all_digests();
-		pg_openssl_initialized = 1;
+		px_openssl_initialized = 1;
+		/*CRYPTO_set_mem_functions(o_alloc, o_realloc, o_free);*/
+		OpenSSL_add_all_algorithms();
 	}
 
 	md = EVP_get_digestbyname(name);
 	if (md == NULL)
-		return NULL;
+		return -1;
 
-	h->name = name;
-	h->length = pg_ossl_len;
-	h->digest = pg_ossl_digest;
-	h->misc.ptr = (void *) md;
+	ctx = px_alloc(sizeof(*ctx));
+	EVP_DigestInit(ctx, md);
 
-	return h;
+	h = px_alloc(sizeof(*h));
+	h->result_size = digest_result_size;
+	h->block_size = digest_block_size;
+	h->reset = digest_reset;
+	h->update = digest_update;
+	h->finish = digest_finish;
+	h->free = digest_free;
+	h->p.ptr = (void *) ctx;
+
+	*res = h;
+	return 0;
 }
+
+
+int
+px_find_cipher(const char *name, PX_Cipher **res)
+{
+	uint i;
+	PX_Cipher *c = NULL, *csrc;
+	ossldata *od;
+
+	const EVP_CIPHER *evp_c;
+
+	if (!px_openssl_initialized) {
+		px_openssl_initialized = 1;
+		/*CRYPTO_set_mem_functions(o_alloc, o_realloc, o_free);*/
+		OpenSSL_add_all_algorithms();
+	}
+
+	name = px_resolve_alias(ossl_aliases, name);
+	evp_c = EVP_get_cipherbyname(name);
+	if (evp_c == NULL)
+		return -1;
+
+	od = px_alloc(sizeof(*od));
+	memset(od, 0, sizeof(*od));
+	od->evp_ciph = evp_c;
+	
+	csrc = NULL;
+
+	for (i = 0; spec_types[i].name; i++)
+		if (!strcmp(name, spec_types[i].name)) {
+			csrc = &spec_types[i].cf;
+			break;
+		}
+	
+	if (csrc == NULL)
+		csrc = &gen_evp_handler;
+
+	c = px_alloc(sizeof(*c));
+	memcpy(c, csrc, sizeof(*c));
+	c->ptr = od;
+	
+	*res = c;
+	return 0;
+}
+
diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c
index 31e5a845bd6..4a2f37d95be 100644
--- a/contrib/pgcrypto/pgcrypto.c
+++ b/contrib/pgcrypto/pgcrypto.c
@@ -1,8 +1,8 @@
 /*
  * pgcrypto.c
- *		Cryptographic digests for PostgreSQL.
+ *		Various cryptographic stuff for PostgreSQL.
  *
- * Copyright (c) 2000 Marko Kreen
+ * Copyright (c) 2001 Marko Kreen
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,113 +26,487 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: pgcrypto.c,v 1.7 2001/03/22 03:59:10 momjian Exp $
+ * $Id: pgcrypto.c,v 1.8 2001/08/21 00:42:41 momjian Exp $
  */
 
-#include "postgres.h"
-
-#include "utils/builtins.h"
+#include <postgres.h>
+#include <fmgr.h>
+#include <ctype.h>
 
+#include "px.h"
+#include "px-crypt.h"
 #include "pgcrypto.h"
 
-/*
- * NAMEDATALEN is used for hash names
- */
-#if NAMEDATALEN < 16
-#error "NAMEDATALEN < 16: too small"
-#endif
-
-
-/* exported functions */
-Datum		digest(PG_FUNCTION_ARGS);
-Datum		digest_exists(PG_FUNCTION_ARGS);
-
 /* private stuff */
-static pg_digest *
-			find_digest(pg_digest * hbuf, text *name, int silent);
 
+typedef int (*PFN) (const char *name, void **res);
+static void *
+			find_provider(text * name, PFN pf, char *desc, int silent);
 
 /* SQL function: hash(text, text) returns text */
-PG_FUNCTION_INFO_V1(digest);
+PG_FUNCTION_INFO_V1(pg_digest);
 
 Datum
-digest(PG_FUNCTION_ARGS)
+pg_digest(PG_FUNCTION_ARGS)
 {
-	text	   *arg;
+	bytea	   *arg;
 	text	   *name;
 	uint		len,
 				hlen;
-	pg_digest  *h,
-				_hbuf;
-	text	   *res;
+	PX_MD	   *md;
+	bytea	   *res;
 
 	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
 		PG_RETURN_NULL();
 
 	name = PG_GETARG_TEXT_P(1);
-	h = find_digest(&_hbuf, name, 0);	/* will give error if fails */
 
-	hlen = h->length(h);
+	/* will give error if fails */
+	md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
+
+	hlen = px_md_result_size(md);
 
 	res = (text *) palloc(hlen + VARHDRSZ);
 	VARATT_SIZEP(res) = hlen + VARHDRSZ;
 
-	arg = PG_GETARG_TEXT_P(0);
+	arg = PG_GETARG_BYTEA_P(0);
 	len = VARSIZE(arg) - VARHDRSZ;
 
-	h->digest(h, VARDATA(arg), len, VARDATA(res));
+	px_md_update(md, VARDATA(arg), len);
+	px_md_finish(md, VARDATA(res));
+	px_md_free(md);
 
 	PG_FREE_IF_COPY(arg, 0);
 	PG_FREE_IF_COPY(name, 1);
 
-	PG_RETURN_TEXT_P(res);
+	PG_RETURN_BYTEA_P(res);
 }
 
 /* check if given hash exists */
-PG_FUNCTION_INFO_V1(digest_exists);
+PG_FUNCTION_INFO_V1(pg_digest_exists);
 
 Datum
-digest_exists(PG_FUNCTION_ARGS)
+pg_digest_exists(PG_FUNCTION_ARGS)
 {
 	text	   *name;
-	pg_digest	_hbuf,
-			   *res;
+	PX_MD	   *res;
 
 	if (PG_ARGISNULL(0))
 		PG_RETURN_NULL();
 
 	name = PG_GETARG_TEXT_P(0);
 
-	res = find_digest(&_hbuf, name, 1);
+	res = find_provider(name, (PFN) px_find_digest, "Digest", 1);
 
 	PG_FREE_IF_COPY(name, 0);
 
-	if (res != NULL)
+	if (res == NULL)
+		PG_RETURN_BOOL(false);
+
+	res->free(res);
+
+	PG_RETURN_BOOL(true);
+}
+
+/* SQL function: hmac(data:text, key:text, type:text) */
+PG_FUNCTION_INFO_V1(pg_hmac);
+
+Datum
+pg_hmac(PG_FUNCTION_ARGS)
+{
+	bytea	   *arg;
+	bytea	   *key;
+	text	   *name;
+	uint		len,
+				hlen,
+				klen;
+	PX_HMAC    *h;
+	bytea	   *res;
+
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
+		PG_RETURN_NULL();
+
+	name = PG_GETARG_TEXT_P(2);
+
+	/* will give error if fails */
+	h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
+
+	hlen = px_hmac_result_size(h);
+
+	res = (text *) palloc(hlen + VARHDRSZ);
+	VARATT_SIZEP(res) = hlen + VARHDRSZ;
+
+	arg = PG_GETARG_BYTEA_P(0);
+	key = PG_GETARG_BYTEA_P(1);
+	len = VARSIZE(arg) - VARHDRSZ;
+	klen = VARSIZE(key) - VARHDRSZ;
+
+	px_hmac_init(h, VARDATA(key), klen);
+	px_hmac_update(h, VARDATA(arg), len);
+	px_hmac_finish(h, VARDATA(res));
+	px_hmac_free(h);
+
+	PG_FREE_IF_COPY(arg, 0);
+	PG_FREE_IF_COPY(key, 1);
+	PG_FREE_IF_COPY(name, 2);
+
+	PG_RETURN_BYTEA_P(res);
+}
+
+/* check if given hmac type exists */
+PG_FUNCTION_INFO_V1(pg_hmac_exists);
+
+Datum
+pg_hmac_exists(PG_FUNCTION_ARGS)
+{
+	text	   *name;
+	PX_HMAC    *h;
+
+	if (PG_ARGISNULL(0))
+		PG_RETURN_NULL();
+
+	name = PG_GETARG_TEXT_P(0);
+
+	h = find_provider(name, (PFN) px_find_hmac, "HMAC", 1);
+
+	PG_FREE_IF_COPY(name, 0);
+
+	if (h != NULL)
+	{
+		px_hmac_free(h);
 		PG_RETURN_BOOL(true);
+	}
 	PG_RETURN_BOOL(false);
 }
 
-static pg_digest *
-find_digest(pg_digest * hbuf, text *name, int silent)
+
+/* SQL function: pg_gen_salt(text) returns text */
+PG_FUNCTION_INFO_V1(pg_gen_salt);
+
+Datum
+pg_gen_salt(PG_FUNCTION_ARGS)
+{
+	text	   *arg0;
+	uint		len;
+	text	   *res;
+	char		buf[PX_MAX_SALT_LEN + 1];
+
+	if (PG_ARGISNULL(0))
+		PG_RETURN_NULL();
+
+	arg0 = PG_GETARG_TEXT_P(0);
+
+	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);
+	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_crypt(psw:text, salt:text) returns text */
+PG_FUNCTION_INFO_V1(pg_crypt);
+
+Datum
+pg_crypt(PG_FUNCTION_ARGS)
+{
+	text	   *arg0;
+	text	   *arg1;
+	uint		len0,
+				len1,
+				clen;
+	char	   *buf0,
+			   *buf1,
+			   *cres,
+			   *resbuf;
+	text	   *res;
+
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+		PG_RETURN_NULL();
+
+	arg0 = PG_GETARG_TEXT_P(0);
+	arg1 = PG_GETARG_TEXT_P(1);
+	len0 = VARSIZE(arg0) - VARHDRSZ;
+	len1 = VARSIZE(arg1) - VARHDRSZ;
+
+	buf0 = palloc(len0 + 1);
+	buf1 = palloc(len1 + 1);
+
+	memcpy(buf0, VARDATA(arg0), len0);
+	memcpy(buf1, VARDATA(arg1), len1);
+
+	buf0[len0] = '\0';
+	buf1[len1] = '\0';
+
+	resbuf = palloc(PX_MAX_CRYPT);
+
+	memset(resbuf, 0, PX_MAX_CRYPT);
+
+	cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
+
+	pfree(buf0);
+	pfree(buf1);
+
+	if (cres == NULL)
+		elog(ERROR, "crypt(3) returned NULL");
+
+	clen = strlen(cres);
+
+	res = (text *) palloc(clen + VARHDRSZ);
+	VARATT_SIZEP(res) = clen + VARHDRSZ;
+	memcpy(VARDATA(res), cres, clen);
+	pfree(resbuf);
+
+	PG_FREE_IF_COPY(arg0, 0);
+	PG_FREE_IF_COPY(arg1, 1);
+
+	PG_RETURN_TEXT_P(res);
+}
+
+/* SQL function: pg_encrypt(text, text, text) returns text */
+PG_FUNCTION_INFO_V1(pg_encrypt);
+
+Datum
+pg_encrypt(PG_FUNCTION_ARGS)
+{
+	int err;
+	bytea *data, *key, *res;
+	text *type;
+	PX_Combo *c;
+	uint dlen, klen, rlen;
+	
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
+		PG_RETURN_NULL();
+	
+	type = PG_GETARG_TEXT_P(2);
+	c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
+
+	data = PG_GETARG_BYTEA_P(0);
+	key = PG_GETARG_BYTEA_P(1);
+	dlen = VARSIZE(data) - VARHDRSZ;
+	klen = VARSIZE(key) - VARHDRSZ;
+
+	rlen = px_combo_encrypt_len(c, dlen);
+	res = palloc(VARHDRSZ + rlen);
+
+	err = px_combo_init(c, VARDATA(key), klen, NULL, 0);
+	if (!err)
+		err = px_combo_encrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
+	px_combo_free(c);
+
+	PG_FREE_IF_COPY(data, 0);
+	PG_FREE_IF_COPY(key, 1);
+	PG_FREE_IF_COPY(type, 2);
+	
+	if (err) {
+		pfree(res);
+		elog(ERROR, "encrypt error: %d", err);
+	}
+
+	VARATT_SIZEP(res) = VARHDRSZ + rlen;
+	PG_RETURN_BYTEA_P(res);
+}
+
+/* SQL function: pg_decrypt(text, text, text) returns text */
+PG_FUNCTION_INFO_V1(pg_decrypt);
+
+Datum
+pg_decrypt(PG_FUNCTION_ARGS)
+{
+	int err;
+	bytea *data, *key, *res;
+	text *type;
+	PX_Combo *c;
+	uint dlen, klen, rlen;
+	
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
+		PG_RETURN_NULL();
+	
+	type = PG_GETARG_TEXT_P(2);
+	c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
+
+	data = PG_GETARG_BYTEA_P(0);
+	key = PG_GETARG_BYTEA_P(1);
+	dlen = VARSIZE(data) - VARHDRSZ;
+	klen = VARSIZE(key) - VARHDRSZ;
+
+	rlen = px_combo_decrypt_len(c, dlen);
+	res = palloc(VARHDRSZ + rlen);
+
+	err = px_combo_init(c, VARDATA(key), klen, NULL, 0);
+	if (!err)
+		err = px_combo_decrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
+
+	px_combo_free(c);
+
+	if (err)
+		elog(ERROR, "decrypt error: %d", err);
+
+	VARATT_SIZEP(res) = VARHDRSZ + rlen;
+
+	PG_FREE_IF_COPY(data, 0);
+	PG_FREE_IF_COPY(key, 1);
+	PG_FREE_IF_COPY(type, 2);
+
+	PG_RETURN_BYTEA_P(res);
+}
+
+/* SQL function: pg_encrypt(text, text, text) returns text */
+PG_FUNCTION_INFO_V1(pg_encrypt_iv);
+
+Datum
+pg_encrypt_iv(PG_FUNCTION_ARGS)
 {
-	pg_digest  *p;
-	char		buf[NAMEDATALEN];
+	int err;
+	bytea *data, *key, *iv, *res;
+	text *type;
+	PX_Combo *c;
+	uint dlen, klen, ivlen, rlen;
+	
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1)
+			|| PG_ARGISNULL(2) || PG_ARGISNULL(3))
+		PG_RETURN_NULL();
+	
+	type = PG_GETARG_TEXT_P(3);
+	c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
+
+	data = PG_GETARG_BYTEA_P(0);
+	key = PG_GETARG_BYTEA_P(1);
+	iv = PG_GETARG_BYTEA_P(2);
+	dlen = VARSIZE(data) - VARHDRSZ;
+	klen = VARSIZE(key) - VARHDRSZ;
+	ivlen = VARSIZE(iv) - VARHDRSZ;
+
+	rlen = px_combo_encrypt_len(c, dlen);
+	res = palloc(VARHDRSZ + rlen);
+
+	err = px_combo_init(c, VARDATA(key), klen, VARDATA(iv), ivlen);
+	if (!err)
+		px_combo_encrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
+
+	px_combo_free(c);
+
+	if (err)
+		elog(ERROR, "encrypt_iv error: %d", err);
+
+	VARATT_SIZEP(res) = VARHDRSZ + rlen;
+
+	PG_FREE_IF_COPY(data, 0);
+	PG_FREE_IF_COPY(key, 1);
+	PG_FREE_IF_COPY(iv, 2);
+	PG_FREE_IF_COPY(type, 3);
+
+	PG_RETURN_BYTEA_P(res);
+}
+
+/* SQL function: pg_decrypt_iv(text, text, text) returns text */
+PG_FUNCTION_INFO_V1(pg_decrypt_iv);
+
+Datum
+pg_decrypt_iv(PG_FUNCTION_ARGS)
+{
+	int err;
+	bytea *data, *key, *iv, *res;
+	text *type;
+	PX_Combo *c;
+	uint dlen, klen, rlen, ivlen;
+	
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1)
+			|| PG_ARGISNULL(2) || PG_ARGISNULL(3))
+		PG_RETURN_NULL();
+	
+	type = PG_GETARG_TEXT_P(3);
+	c = find_provider(type, (PFN)px_find_combo, "Cipher", 0);
+
+	data = PG_GETARG_BYTEA_P(0);
+	key = PG_GETARG_BYTEA_P(1);
+	iv = PG_GETARG_BYTEA_P(2);
+	dlen = VARSIZE(data) - VARHDRSZ;
+	klen = VARSIZE(key) - VARHDRSZ;
+	ivlen = VARSIZE(iv) - VARHDRSZ;
+
+	rlen = px_combo_decrypt_len(c, dlen);
+	res = palloc(VARHDRSZ + rlen);
+
+	err = px_combo_init(c, VARDATA(key), klen, VARDATA(iv), ivlen);
+	if (!err)
+		px_combo_decrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
+
+	px_combo_free(c);
+
+	if (err)
+		elog(ERROR, "decrypt_iv error: %d", err);
+	
+	VARATT_SIZEP(res) = VARHDRSZ + rlen;
+
+	PG_FREE_IF_COPY(data, 0);
+	PG_FREE_IF_COPY(key, 1);
+	PG_FREE_IF_COPY(iv, 2);
+	PG_FREE_IF_COPY(type, 3);
+
+	PG_RETURN_BYTEA_P(res);
+}
+
+/* SQL function: pg_decrypt(text, text, text) returns text */
+PG_FUNCTION_INFO_V1(pg_cipher_exists);
+
+Datum
+pg_cipher_exists(PG_FUNCTION_ARGS)
+{
+	text *arg;
+	PX_Combo *c;
+
+	if (PG_ARGISNULL(0))
+		PG_RETURN_NULL();
+
+	arg = PG_GETARG_TEXT_P(0);
+
+	c = find_provider(arg, (PFN)px_find_combo, "Cipher", 1);
+	if (c != NULL)
+		px_combo_free(c);
+
+	PG_RETURN_BOOL((c != NULL) ? true : false);
+}
+
+
+static void *
+find_provider(text * name,
+			  PFN provider_lookup,
+			  char *desc, int silent)
+{
+	void	   *res;
+	char		buf[PX_MAX_NAMELEN + 1],
+			   *p;
 	uint		len;
+	uint		i;
+	int			err;
 
 	len = VARSIZE(name) - VARHDRSZ;
-	if (len >= NAMEDATALEN)
+	if (len > PX_MAX_NAMELEN)
 	{
 		if (silent)
 			return NULL;
-		elog(ERROR, "Hash type does not exist (name too long)");
+		elog(ERROR, "%s type does not exist (name too long)", desc);
 	}
 
-	memcpy(buf, VARDATA(name), len);
+	p = VARDATA(name);
+	for (i = 0; i < len; i++)
+		buf[i] = tolower(p[i]);
 	buf[len] = 0;
 
-	p = pg_find_digest(hbuf, buf);
+	err = provider_lookup(buf, &res);
+
+	if (err && !silent)
+		elog(ERROR, "%s type does not exist: '%s'", desc, buf);
 
-	if (p == NULL && !silent)
-		elog(ERROR, "Hash type does not exist: '%s'", buf);
-	return p;
+	return err ? NULL : res;
 }
diff --git a/contrib/pgcrypto/pgcrypto.h b/contrib/pgcrypto/pgcrypto.h
index 1700b89b158..4c400243042 100644
--- a/contrib/pgcrypto/pgcrypto.h
+++ b/contrib/pgcrypto/pgcrypto.h
@@ -26,27 +26,24 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: pgcrypto.h,v 1.3 2001/03/22 03:59:10 momjian Exp $
+ * $Id: pgcrypto.h,v 1.4 2001/08/21 00:42:41 momjian Exp $
  */
 
 #ifndef _PG_CRYPTO_H
 #define _PG_CRYPTO_H
 
-typedef struct _pg_digest pg_digest;
-struct _pg_digest
-{
-	char	   *name;
-	uint		(*length) (pg_digest * h);
-	uint8	   *(*digest) (pg_digest * h, uint8 *data,
-									   uint dlen, uint8 *buf);
-	/* private */
-	union
-	{
-		uint		code;
-		const void *ptr;
-	}			misc;
-};
-
-extern pg_digest *pg_find_digest(pg_digest * hbuf, char *name);
+/* exported functions */
+Datum		pg_digest(PG_FUNCTION_ARGS);
+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_crypt(PG_FUNCTION_ARGS);
+Datum		pg_encrypt(PG_FUNCTION_ARGS);
+Datum		pg_decrypt(PG_FUNCTION_ARGS);
+Datum		pg_encrypt_iv(PG_FUNCTION_ARGS);
+Datum		pg_decrypt_iv(PG_FUNCTION_ARGS);
+Datum		pg_cipher_exists(PG_FUNCTION_ARGS);
 
 #endif
+
diff --git a/contrib/pgcrypto/pgcrypto.sql.in b/contrib/pgcrypto/pgcrypto.sql.in
index 222b2769fa1..bed50c6946e 100644
--- a/contrib/pgcrypto/pgcrypto.sql.in
+++ b/contrib/pgcrypto/pgcrypto.sql.in
@@ -1,23 +1,59 @@
 
--- drop function digest(text, text);
+-- drop function digest(bytea, text);
 -- drop function digest_exists(text);
--- drop function encode(text, text);
--- drop function decode(text, text);
+-- drop function hmac(bytea, bytea, text);
+-- drop function hmac_exists(text);
+-- drop function crypt(text, text);
+-- drop function gen_salt(text);
+-- 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);
 
 
-CREATE FUNCTION digest(text, text) RETURNS text
+
+CREATE FUNCTION digest(bytea, text) RETURNS bytea
   AS '@MODULE_FILENAME@',
-  'digest' LANGUAGE 'C';
+  'pg_digest' LANGUAGE 'C';
 
 CREATE FUNCTION digest_exists(text) RETURNS bool
   AS '@MODULE_FILENAME@',
-  'digest_exists' LANGUAGE 'C';
+  'pg_digest_exists' LANGUAGE 'C';
+
+CREATE FUNCTION hmac(bytea, bytea, text) RETURNS bytea
+  AS '@MODULE_FILENAME@',
+  'pg_hmac' LANGUAGE 'C';
+
+CREATE FUNCTION hmac_exists(text) RETURNS bool
+  AS '@MODULE_FILENAME@',
+  'pg_hmac_exists' LANGUAGE 'C';
+
+CREATE FUNCTION crypt(text, text) RETURNS text
+  AS '@MODULE_FILENAME@',
+  'pg_crypt' LANGUAGE 'C';
+
+CREATE FUNCTION gen_salt(text) RETURNS text
+  AS '@MODULE_FILENAME@',
+  'pg_gen_salt' LANGUAGE 'C';
+
+CREATE FUNCTION encrypt(bytea, bytea, text) RETURNS bytea
+  AS '@MODULE_FILENAME@',
+  'pg_encrypt' LANGUAGE 'C';
+
+CREATE FUNCTION decrypt(bytea, bytea, text) RETURNS bytea
+  AS '@MODULE_FILENAME@',
+  'pg_decrypt' LANGUAGE 'C';
+
+CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text) RETURNS bytea
+  AS '@MODULE_FILENAME@',
+  'pg_encrypt_iv' LANGUAGE 'C';
 
-CREATE FUNCTION encode(text, text) RETURNS text
+CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text) RETURNS bytea
   AS '@MODULE_FILENAME@',
-  'encode' LANGUAGE 'C';
+  'pg_decrypt_iv' LANGUAGE 'C';
 
-CREATE FUNCTION decode(text, text) RETURNS text
+CREATE FUNCTION cipher_exists(text) RETURNS bool
   AS '@MODULE_FILENAME@',
-  'decode' LANGUAGE 'C';
+  'pg_cipher_exists' LANGUAGE 'C';
+
 
diff --git a/contrib/pgcrypto/sha1.c b/contrib/pgcrypto/sha1.c
index db9f1a17c60..98ad552182f 100644
--- a/contrib/pgcrypto/sha1.c
+++ b/contrib/pgcrypto/sha1.c
@@ -1,4 +1,4 @@
-/*	$Id: sha1.c,v 1.5 2001/03/22 03:59:10 momjian Exp $ */
+/*	$Id: sha1.c,v 1.6 2001/08/21 00:42:41 momjian Exp $ */
 /*	   $KAME: sha1.c,v 1.3 2000/02/22 14:01:18 itojun Exp $    */
 
 /*
@@ -85,8 +85,7 @@ static uint32 _K[] = {0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6};
 static void sha1_step(struct sha1_ctxt *);
 
 static void
-sha1_step(ctxt)
-struct sha1_ctxt *ctxt;
+sha1_step(struct sha1_ctxt *ctxt)
 {
 	uint32		a,
 				b,
@@ -231,8 +230,7 @@ struct sha1_ctxt *ctxt;
 /*------------------------------------------------------------*/
 
 void
-sha1_init(ctxt)
-struct sha1_ctxt *ctxt;
+sha1_init(struct sha1_ctxt *ctxt)
 {
 	bzero(ctxt, sizeof(struct sha1_ctxt));
 	H(0) = 0x67452301;
@@ -243,8 +241,7 @@ struct sha1_ctxt *ctxt;
 }
 
 void
-sha1_pad(ctxt)
-struct sha1_ctxt *ctxt;
+sha1_pad(struct sha1_ctxt *ctxt)
 {
 	size_t		padlen;			/* pad length in bytes */
 	size_t		padstart;
@@ -287,10 +284,7 @@ struct sha1_ctxt *ctxt;
 }
 
 void
-sha1_loop(ctxt, input0, len)
-struct sha1_ctxt *ctxt;
-const caddr_t input0;
-size_t		len;
+sha1_loop(struct sha1_ctxt *ctxt, const uint8 *input0, size_t len)
 {
 	const uint8 *input;
 	size_t		gaplen;
@@ -318,9 +312,7 @@ size_t		len;
 }
 
 void
-sha1_result(ctxt, digest0)
-struct sha1_ctxt *ctxt;
-caddr_t		digest0;
+sha1_result(struct sha1_ctxt *ctxt, uint8 *digest0)
 {
 	uint8	   *digest;
 
@@ -351,5 +343,4 @@ caddr_t		digest0;
 	digest[19] = ctxt->h.b8[16];
 #endif
 }
-
 #endif	 /* unsupported */
diff --git a/contrib/pgcrypto/sha1.h b/contrib/pgcrypto/sha1.h
index cddc8651e4f..c83bd7191a5 100644
--- a/contrib/pgcrypto/sha1.h
+++ b/contrib/pgcrypto/sha1.h
@@ -1,4 +1,4 @@
-/*	$Id: sha1.h,v 1.4 2001/03/22 03:59:10 momjian Exp $ */
+/*	$Id: sha1.h,v 1.5 2001/08/21 00:42:41 momjian Exp $ */
 /*	   $KAME: sha1.h,v 1.4 2000/02/22 14:01:18 itojun Exp $    */
 
 /*
@@ -60,8 +60,8 @@ struct sha1_ctxt
 
 extern void sha1_init(struct sha1_ctxt *);
 extern void sha1_pad(struct sha1_ctxt *);
-extern void sha1_loop(struct sha1_ctxt *, const caddr_t, size_t);
-extern void sha1_result(struct sha1_ctxt *, caddr_t);
+extern void sha1_loop(struct sha1_ctxt *, const uint8 *, size_t);
+extern void sha1_result(struct sha1_ctxt *, uint8 *);
 
 /* compatibilty with other SHA1 source codes */
 typedef struct sha1_ctxt SHA1_CTX;
-- 
GitLab