You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by rl...@apache.org on 2016/09/07 02:57:44 UTC

[06/13] incubator-hawq git commit: HAWQ-1007. Add the pgcrypto code into hawq

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgcrypto.sql.in
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgcrypto.sql.in b/contrib/pgcrypto/pgcrypto.sql.in
new file mode 100644
index 0000000..8388e86
--- /dev/null
+++ b/contrib/pgcrypto/pgcrypto.sql.in
@@ -0,0 +1,203 @@
+/* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.sql.in,v 1.15 2007/11/13 04:24:28 momjian Exp $ */
+
+-- Adjust this setting to control where the objects get created.
+SET search_path = public;
+
+CREATE OR REPLACE FUNCTION digest(text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_digest'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION digest(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_digest'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION hmac(text, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_hmac'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION hmac(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_hmac'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION crypt(text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_crypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION gen_salt(text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_gen_salt'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE OR REPLACE FUNCTION gen_salt(text, int4)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE OR REPLACE FUNCTION encrypt(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_encrypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION decrypt(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_decrypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION gen_random_bytes(int4)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_random_bytes'
+LANGUAGE 'C' VOLATILE STRICT;
+
+--
+-- pgp_sym_encrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt(text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_sym_encrypt(data, key, args)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt(text, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_sym_decrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt(bytea, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_sym_decrypt(data, key, args)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt(bytea, text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_encrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt(text, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_pub_encrypt(data, key, args)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt(text, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_pub_decrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt(bytea, bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_decrypt(data, key, psw)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_decrypt(data, key, psw, arg)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- PGP key ID
+--
+CREATE OR REPLACE FUNCTION pgp_key_id(bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp armor
+--
+CREATE OR REPLACE FUNCTION armor(bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_armor'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION dearmor(text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_dearmor'
+LANGUAGE C IMMUTABLE STRICT;
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-armor.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-armor.c b/contrib/pgcrypto/pgp-armor.c
new file mode 100644
index 0000000..87adf91
--- /dev/null
+++ b/contrib/pgcrypto/pgp-armor.c
@@ -0,0 +1,383 @@
+/*
+ * pgp-armor.c
+ *		PGP ascii-armor.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-armor.c
+ */
+
+#include "postgres.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+/*
+ * BASE64 - duplicated :(
+ */
+
+static const unsigned char _base64[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int
+b64_encode(const uint8 *src, unsigned len, uint8 *dst)
+{
+	uint8	   *p,
+			   *lend = dst + 76;
+	const uint8 *s,
+			   *end = src + len;
+	int			pos = 2;
+	unsigned long buf = 0;
+
+	s = src;
+	p = dst;
+
+	while (s < end)
+	{
+		buf |= *s << (pos << 3);
+		pos--;
+		s++;
+
+		/*
+		 * write it out
+		 */
+		if (pos < 0)
+		{
+			*p++ = _base64[(buf >> 18) & 0x3f];
+			*p++ = _base64[(buf >> 12) & 0x3f];
+			*p++ = _base64[(buf >> 6) & 0x3f];
+			*p++ = _base64[buf & 0x3f];
+
+			pos = 2;
+			buf = 0;
+		}
+		if (p >= lend)
+		{
+			*p++ = '\n';
+			lend = p + 76;
+		}
+	}
+	if (pos != 2)
+	{
+		*p++ = _base64[(buf >> 18) & 0x3f];
+		*p++ = _base64[(buf >> 12) & 0x3f];
+		*p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
+		*p++ = '=';
+	}
+
+	return p - dst;
+}
+
+/* probably should use lookup table */
+static int
+b64_decode(const uint8 *src, unsigned len, uint8 *dst)
+{
+	const uint8 *srcend = src + len,
+			   *s = src;
+	uint8	   *p = dst;
+	char		c;
+	unsigned	b = 0;
+	unsigned long buf = 0;
+	int			pos = 0,
+				end = 0;
+
+	while (s < srcend)
+	{
+		c = *s++;
+		if (c >= 'A' && c <= 'Z')
+			b = c - 'A';
+		else if (c >= 'a' && c <= 'z')
+			b = c - 'a' + 26;
+		else if (c >= '0' && c <= '9')
+			b = c - '0' + 52;
+		else if (c == '+')
+			b = 62;
+		else if (c == '/')
+			b = 63;
+		else if (c == '=')
+		{
+			/*
+			 * end sequence
+			 */
+			if (!end)
+			{
+				if (pos == 2)
+					end = 1;
+				else if (pos == 3)
+					end = 2;
+				else
+					return PXE_PGP_CORRUPT_ARMOR;
+			}
+			b = 0;
+		}
+		else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+			continue;
+		else
+			return PXE_PGP_CORRUPT_ARMOR;
+
+		/*
+		 * add it to buffer
+		 */
+		buf = (buf << 6) + b;
+		pos++;
+		if (pos == 4)
+		{
+			*p++ = (buf >> 16) & 255;
+			if (end == 0 || end > 1)
+				*p++ = (buf >> 8) & 255;
+			if (end == 0 || end > 2)
+				*p++ = buf & 255;
+			buf = 0;
+			pos = 0;
+		}
+	}
+
+	if (pos != 0)
+		return PXE_PGP_CORRUPT_ARMOR;
+	return p - dst;
+}
+
+static unsigned
+b64_enc_len(unsigned srclen)
+{
+	/*
+	 * 3 bytes will be converted to 4, linefeed after 76 chars
+	 */
+	return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
+}
+
+static unsigned
+b64_dec_len(unsigned srclen)
+{
+	return (srclen * 3) >> 2;
+}
+
+/*
+ * PGP armor
+ */
+
+static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n\n";
+static const char *armor_footer = "\n-----END PGP MESSAGE-----\n";
+
+/* CRC24 implementation from rfc2440 */
+#define CRC24_INIT 0x00b704ceL
+#define CRC24_POLY 0x01864cfbL
+static long
+crc24(const uint8 *data, unsigned len)
+{
+	unsigned	crc = CRC24_INIT;
+	int			i;
+
+	while (len--)
+	{
+		crc ^= (*data++) << 16;
+		for (i = 0; i < 8; i++)
+		{
+			crc <<= 1;
+			if (crc & 0x1000000)
+				crc ^= CRC24_POLY;
+		}
+	}
+	return crc & 0xffffffL;
+}
+
+int
+pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst)
+{
+	int			n;
+	uint8	   *pos = dst;
+	unsigned	crc = crc24(src, len);
+
+	n = strlen(armor_header);
+	memcpy(pos, armor_header, n);
+	pos += n;
+
+	n = b64_encode(src, len, pos);
+	pos += n;
+
+	if (*(pos - 1) != '\n')
+		*pos++ = '\n';
+
+	*pos++ = '=';
+	pos[3] = _base64[crc & 0x3f];
+	crc >>= 6;
+	pos[2] = _base64[crc & 0x3f];
+	crc >>= 6;
+	pos[1] = _base64[crc & 0x3f];
+	crc >>= 6;
+	pos[0] = _base64[crc & 0x3f];
+	pos += 4;
+
+	n = strlen(armor_footer);
+	memcpy(pos, armor_footer, n);
+	pos += n;
+
+	return pos - dst;
+}
+
+static const uint8 *
+find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
+{
+	const uint8 *p = data;
+
+	if (!strlen)
+		return NULL;
+	if (data_end - data < strlen)
+		return NULL;
+	while (p < data_end)
+	{
+		p = memchr(p, str[0], data_end - p);
+		if (p == NULL)
+			return NULL;
+		if (p + strlen > data_end)
+			return NULL;
+		if (memcmp(p, str, strlen) == 0)
+			return p;
+		p++;
+	}
+	return NULL;
+}
+
+static int
+find_header(const uint8 *data, const uint8 *datend,
+			const uint8 **start_p, int is_end)
+{
+	const uint8 *p = data;
+	static const char *start_sep = "-----BEGIN";
+	static const char *end_sep = "-----END";
+	const char *sep = is_end ? end_sep : start_sep;
+
+	/* find header line */
+	while (1)
+	{
+		p = find_str(p, datend, sep, strlen(sep));
+		if (p == NULL)
+			return PXE_PGP_CORRUPT_ARMOR;
+		/* it must start at beginning of line */
+		if (p == data || *(p - 1) == '\n')
+			break;
+		p += strlen(sep);
+	}
+	*start_p = p;
+	p += strlen(sep);
+
+	/* check if header text ok */
+	for (; p < datend && *p != '-'; p++)
+	{
+		/* various junk can be there, but definitely not line-feed	*/
+		if (*p >= ' ')
+			continue;
+		return PXE_PGP_CORRUPT_ARMOR;
+	}
+	if (datend - p < 5 || memcmp(p, sep, 5) != 0)
+		return PXE_PGP_CORRUPT_ARMOR;
+	p += 5;
+
+	/* check if at end of line */
+	if (p < datend)
+	{
+		if (*p != '\n' && *p != '\r')
+			return PXE_PGP_CORRUPT_ARMOR;
+		if (*p == '\r')
+			p++;
+		if (p < datend && *p == '\n')
+			p++;
+	}
+	return p - *start_p;
+}
+
+int
+pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
+{
+	const uint8 *p = src;
+	const uint8 *data_end = src + len;
+	long		crc;
+	const uint8 *base64_start,
+			   *armor_end;
+	const uint8 *base64_end = NULL;
+	uint8		buf[4];
+	int			hlen;
+	int			res = PXE_PGP_CORRUPT_ARMOR;
+
+	/* armor start */
+	hlen = find_header(src, data_end, &p, 0);
+	if (hlen <= 0)
+		goto out;
+	p += hlen;
+
+	/* armor end */
+	hlen = find_header(p, data_end, &armor_end, 1);
+	if (hlen <= 0)
+		goto out;
+
+	/* skip comments - find empty line */
+	while (p < armor_end && *p != '\n' && *p != '\r')
+	{
+		p = memchr(p, '\n', armor_end - p);
+		if (!p)
+			goto out;
+
+		/* step to start of next line */
+		p++;
+	}
+	base64_start = p;
+
+	/* find crc pos */
+	for (p = armor_end; p >= base64_start; p--)
+		if (*p == '=')
+		{
+			base64_end = p - 1;
+			break;
+		}
+	if (base64_end == NULL)
+		goto out;
+
+	/* decode crc */
+	if (b64_decode(p + 1, 4, buf) != 3)
+		goto out;
+	crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
+
+	/* decode data */
+	res = b64_decode(base64_start, base64_end - base64_start, dst);
+
+	/* check crc */
+	if (res >= 0 && crc24(dst, res) != crc)
+		res = PXE_PGP_CORRUPT_ARMOR;
+out:
+	return res;
+}
+
+unsigned
+pgp_armor_enc_len(unsigned len)
+{
+	return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
+}
+
+unsigned
+pgp_armor_dec_len(unsigned len)
+{
+	return b64_dec_len(len);
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-cfb.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-cfb.c b/contrib/pgcrypto/pgp-cfb.c
new file mode 100644
index 0000000..7cf9bf0
--- /dev/null
+++ b/contrib/pgcrypto/pgp-cfb.c
@@ -0,0 +1,265 @@
+/*
+ * pgp-cfb.c
+ *	  Implements both normal and PGP-specific CFB mode.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-cfb.c
+ */
+
+#include "postgres.h"
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+typedef int (*mix_data_t) (PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
+
+struct PGP_CFB
+{
+	PX_Cipher  *ciph;
+	int			block_size;
+	int			pos;
+	int			block_no;
+	int			resync;
+	uint8		fr[PGP_MAX_BLOCK];
+	uint8		fre[PGP_MAX_BLOCK];
+	uint8		encbuf[PGP_MAX_BLOCK];
+};
+
+int
+pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
+			   int resync, uint8 *iv)
+{
+	int			res;
+	PX_Cipher  *ciph;
+	PGP_CFB    *ctx;
+
+	res = pgp_load_cipher(algo, &ciph);
+	if (res < 0)
+		return res;
+
+	res = px_cipher_init(ciph, key, key_len, NULL);
+	if (res < 0)
+	{
+		px_cipher_free(ciph);
+		return res;
+	}
+
+	ctx = px_alloc(sizeof(*ctx));
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->ciph = ciph;
+	ctx->block_size = px_cipher_block_size(ciph);
+	ctx->resync = resync;
+
+	if (iv)
+		memcpy(ctx->fr, iv, ctx->block_size);
+
+	*ctx_p = ctx;
+	return 0;
+}
+
+void
+pgp_cfb_free(PGP_CFB *ctx)
+{
+	px_cipher_free(ctx->ciph);
+	memset(ctx, 0, sizeof(*ctx));
+	px_free(ctx);
+}
+
+/*
+ * Data processing for normal CFB.	(PGP_PKT_SYMENCRYPTED_DATA_MDC)
+ */
+static int
+mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+	int			i;
+
+	for (i = ctx->pos; i < ctx->pos + len; i++)
+		*dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+	ctx->pos += len;
+	return len;
+}
+
+static int
+mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+	int			i;
+
+	for (i = ctx->pos; i < ctx->pos + len; i++)
+	{
+		ctx->encbuf[i] = *data++;
+		*dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+	}
+	ctx->pos += len;
+	return len;
+}
+
+/*
+ * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
+ *
+ * The goal is to hide the horror from the rest of the code,
+ * thus its all concentrated here.
+ */
+static int
+mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+	int			i,
+				n;
+
+	/* block #2 is 2 bytes long */
+	if (ctx->block_no == 2)
+	{
+		n = 2 - ctx->pos;
+		if (len < n)
+			n = len;
+		for (i = ctx->pos; i < ctx->pos + n; i++)
+			*dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+
+		ctx->pos += n;
+		len -= n;
+
+		if (ctx->pos == 2)
+		{
+			memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
+			memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
+			ctx->pos = 0;
+			return n;
+		}
+	}
+	for (i = ctx->pos; i < ctx->pos + len; i++)
+		*dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+	ctx->pos += len;
+	return len;
+}
+
+static int
+mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+	int			i,
+				n;
+
+	/* block #2 is 2 bytes long */
+	if (ctx->block_no == 2)
+	{
+		n = 2 - ctx->pos;
+		if (len < n)
+			n = len;
+		for (i = ctx->pos; i < ctx->pos + n; i++)
+		{
+			ctx->encbuf[i] = *data++;
+			*dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+		}
+		ctx->pos += n;
+		len -= n;
+
+		if (ctx->pos == 2)
+		{
+			memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
+			memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
+			ctx->pos = 0;
+			return n;
+		}
+	}
+	for (i = ctx->pos; i < ctx->pos + len; i++)
+	{
+		ctx->encbuf[i] = *data++;
+		*dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+	}
+	ctx->pos += len;
+	return len;
+}
+
+/*
+ * common code for both encrypt and decrypt.
+ */
+static int
+cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
+			mix_data_t mix_data)
+{
+	int			n;
+	int			res;
+
+	while (len > 0 && ctx->pos > 0)
+	{
+		n = ctx->block_size - ctx->pos;
+		if (len < n)
+			n = len;
+
+		n = mix_data(ctx, data, n, dst);
+		data += n;
+		dst += n;
+		len -= n;
+
+		if (ctx->pos == ctx->block_size)
+		{
+			memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
+			ctx->pos = 0;
+		}
+	}
+
+	while (len > 0)
+	{
+		px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, ctx->fre);
+		if (ctx->block_no < 5)
+			ctx->block_no++;
+
+		n = ctx->block_size;
+		if (len < n)
+			n = len;
+
+		res = mix_data(ctx, data, n, dst);
+		data += res;
+		dst += res;
+		len -= res;
+
+		if (ctx->pos == ctx->block_size)
+		{
+			memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
+			ctx->pos = 0;
+		}
+	}
+	return 0;
+}
+
+/*
+ * public interface
+ */
+
+int
+pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+	mix_data_t	mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
+
+	return cfb_process(ctx, data, len, dst, mix);
+}
+
+int
+pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+	mix_data_t	mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
+
+	return cfb_process(ctx, data, len, dst, mix);
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-compress.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c
new file mode 100644
index 0000000..c592453
--- /dev/null
+++ b/contrib/pgcrypto/pgp-compress.c
@@ -0,0 +1,329 @@
+/*
+ * pgp-compress.c
+ *	  ZIP and ZLIB compression via zlib.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-compress.c
+ */
+
+#include "postgres.h"
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+
+/*
+ * Compressed pkt writer
+ */
+
+#ifdef HAVE_LIBZ
+
+#include <zlib.h>
+
+#define ZIP_OUT_BUF 8192
+#define ZIP_IN_BLOCK 8192
+
+struct ZipStat
+{
+	uint8		type;
+	int			buf_len;
+	int			hdr_done;
+	z_stream	stream;
+	uint8		buf[ZIP_OUT_BUF];
+};
+
+static void *
+z_alloc(void *priv, unsigned n_items, unsigned item_len)
+{
+	return px_alloc(n_items * item_len);
+}
+
+static void
+z_free(void *priv, void *addr)
+{
+	px_free(addr);
+}
+
+static int
+compress_init(PushFilter *next, void *init_arg, void **priv_p)
+{
+	int			res;
+	struct ZipStat *st;
+	PGP_Context *ctx = init_arg;
+	uint8		type = ctx->compress_algo;
+
+	if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
+		return PXE_PGP_UNSUPPORTED_COMPR;
+
+	/*
+	 * init
+	 */
+	st = px_alloc(sizeof(*st));
+	memset(st, 0, sizeof(*st));
+	st->buf_len = ZIP_OUT_BUF;
+	st->stream.zalloc = z_alloc;
+	st->stream.zfree = z_free;
+
+	if (type == PGP_COMPR_ZIP)
+		res = deflateInit2(&st->stream, ctx->compress_level,
+						   Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+	else
+		res = deflateInit(&st->stream, ctx->compress_level);
+	if (res != Z_OK)
+	{
+		px_free(st);
+		return PXE_PGP_COMPRESSION_ERROR;
+	}
+	*priv_p = st;
+
+	return ZIP_IN_BLOCK;
+}
+
+/* writes compressed data packet */
+
+/* can handle zero-len incoming data, but shouldn't */
+static int
+compress_process(PushFilter *next, void *priv, const uint8 *data, int len)
+{
+	int			res,
+				n_out;
+	struct ZipStat *st = priv;
+
+	/*
+	 * process data
+	 */
+	while (len > 0)
+	{
+		st->stream.next_in = (void *) data;
+		st->stream.avail_in = len;
+		st->stream.next_out = st->buf;
+		st->stream.avail_out = st->buf_len;
+		res = deflate(&st->stream, 0);
+		if (res != Z_OK)
+			return PXE_PGP_COMPRESSION_ERROR;
+
+		n_out = st->buf_len - st->stream.avail_out;
+		if (n_out > 0)
+		{
+			res = pushf_write(next, st->buf, n_out);
+			if (res < 0)
+				return res;
+		}
+		len = st->stream.avail_in;
+	}
+
+	return 0;
+}
+
+static int
+compress_flush(PushFilter *next, void *priv)
+{
+	int			res,
+				zres,
+				n_out;
+	struct ZipStat *st = priv;
+
+	st->stream.next_in = NULL;
+	st->stream.avail_in = 0;
+	while (1)
+	{
+		st->stream.next_out = st->buf;
+		st->stream.avail_out = st->buf_len;
+		zres = deflate(&st->stream, Z_FINISH);
+		if (zres != Z_STREAM_END && zres != Z_OK)
+			return PXE_PGP_COMPRESSION_ERROR;
+		n_out = st->buf_len - st->stream.avail_out;
+		if (n_out > 0)
+		{
+			res = pushf_write(next, st->buf, n_out);
+			if (res < 0)
+				return res;
+		}
+		if (zres == Z_STREAM_END)
+			break;
+	}
+	return 0;
+}
+
+static void
+compress_free(void *priv)
+{
+	struct ZipStat *st = priv;
+
+	deflateEnd(&st->stream);
+	memset(st, 0, sizeof(*st));
+	px_free(st);
+}
+
+static const PushFilterOps
+			compress_filter = {
+	compress_init, compress_process, compress_flush, compress_free
+};
+
+int
+pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
+{
+	return pushf_create(res, &compress_filter, ctx, dst);
+}
+
+/*
+ * Decompress
+ */
+struct DecomprData
+{
+	int			buf_len;		/* = ZIP_OUT_BUF */
+	int			buf_data;		/* available data */
+	uint8	   *pos;
+	z_stream	stream;
+	int			eof;
+	uint8		buf[ZIP_OUT_BUF];
+};
+
+static int
+decompress_init(void **priv_p, void *arg, PullFilter *src)
+{
+	PGP_Context *ctx = arg;
+	struct DecomprData *dec;
+	int			res;
+
+	if (ctx->compress_algo != PGP_COMPR_ZLIB
+		&& ctx->compress_algo != PGP_COMPR_ZIP)
+		return PXE_PGP_UNSUPPORTED_COMPR;
+
+	dec = px_alloc(sizeof(*dec));
+	memset(dec, 0, sizeof(*dec));
+	dec->buf_len = ZIP_OUT_BUF;
+	*priv_p = dec;
+
+	dec->stream.zalloc = z_alloc;
+	dec->stream.zfree = z_free;
+
+	if (ctx->compress_algo == PGP_COMPR_ZIP)
+		res = inflateInit2(&dec->stream, -15);
+	else
+		res = inflateInit(&dec->stream);
+	if (res != Z_OK)
+	{
+		px_free(dec);
+		px_debug("decompress_init: inflateInit error");
+		return PXE_PGP_COMPRESSION_ERROR;
+	}
+
+	return 0;
+}
+
+static int
+decompress_read(void *priv, PullFilter *src, int len,
+				uint8 **data_p, uint8 *buf, int buflen)
+{
+	int			res;
+	int			flush;
+	struct DecomprData *dec = priv;
+
+restart:
+	if (dec->buf_data > 0)
+	{
+		if (len > dec->buf_data)
+			len = dec->buf_data;
+		*data_p = dec->pos;
+		dec->pos += len;
+		dec->buf_data -= len;
+		return len;
+	}
+
+	if (dec->eof)
+		return 0;
+
+	if (dec->stream.avail_in == 0)
+	{
+		uint8	   *tmp;
+
+		res = pullf_read(src, 8192, &tmp);
+		if (res < 0)
+			return res;
+		dec->stream.next_in = tmp;
+		dec->stream.avail_in = res;
+	}
+
+	dec->stream.next_out = dec->buf;
+	dec->stream.avail_out = dec->buf_len;
+	dec->pos = dec->buf;
+
+	/*
+	 * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
+	 * it anyway (Z_NO_FLUSH), but seems to reserve the right not to.  So lets
+	 * follow the API.
+	 */
+	flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
+	res = inflate(&dec->stream, flush);
+	if (res != Z_OK && res != Z_STREAM_END)
+	{
+		px_debug("decompress_read: inflate error: %d", res);
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	dec->buf_data = dec->buf_len - dec->stream.avail_out;
+	if (res == Z_STREAM_END)
+		dec->eof = 1;
+	goto restart;
+}
+
+static void
+decompress_free(void *priv)
+{
+	struct DecomprData *dec = priv;
+
+	inflateEnd(&dec->stream);
+	memset(dec, 0, sizeof(*dec));
+	px_free(dec);
+}
+
+static const PullFilterOps
+			decompress_filter = {
+	decompress_init, decompress_read, decompress_free
+};
+
+int
+pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
+{
+	return pullf_create(res, &decompress_filter, ctx, src);
+}
+#else							/* !HAVE_ZLIB */
+
+int
+pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
+{
+	return PXE_PGP_UNSUPPORTED_COMPR;
+}
+
+int
+pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
+{
+	return PXE_PGP_UNSUPPORTED_COMPR;
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-decrypt.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-decrypt.c b/contrib/pgcrypto/pgp-decrypt.c
new file mode 100644
index 0000000..c9aa6cd
--- /dev/null
+++ b/contrib/pgcrypto/pgp-decrypt.c
@@ -0,0 +1,1188 @@
+/*
+ * pgp-decrypt.c
+ *	  OpenPGP decrypt.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-decrypt.c
+ */
+
+#include "postgres.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+#define NO_CTX_SIZE		0
+#define ALLOW_CTX_SIZE	1
+#define NO_COMPR		0
+#define ALLOW_COMPR		1
+#define NO_MDC			0
+#define NEED_MDC		1
+
+#define PKT_NORMAL 1
+#define PKT_STREAM 2
+#define PKT_CONTEXT 3
+
+#define MAX_CHUNK (16*1024*1024)
+
+static int
+parse_new_len(PullFilter *src, int *len_p)
+{
+	uint8		b;
+	int			len;
+	int			pkttype = PKT_NORMAL;
+
+	GETBYTE(src, b);
+	if (b <= 191)
+		len = b;
+	else if (b >= 192 && b <= 223)
+	{
+		len = ((unsigned) (b) - 192) << 8;
+		GETBYTE(src, b);
+		len += 192 + b;
+	}
+	else if (b == 255)
+	{
+		GETBYTE(src, b);
+		len = b;
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+	}
+	else
+	{
+		len = 1 << (b & 0x1F);
+		pkttype = PKT_STREAM;
+	}
+
+	if (len < 0 || len > MAX_CHUNK)
+	{
+		px_debug("parse_new_len: weird length");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	*len_p = len;
+	return pkttype;
+}
+
+static int
+parse_old_len(PullFilter *src, int *len_p, int lentype)
+{
+	uint8		b;
+	int			len;
+
+	GETBYTE(src, b);
+	len = b;
+
+	if (lentype == 1)
+	{
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+	}
+	else if (lentype == 2)
+	{
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+		GETBYTE(src, b);
+		len = (len << 8) | b;
+	}
+
+	if (len < 0 || len > MAX_CHUNK)
+	{
+		px_debug("parse_old_len: weird length");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	*len_p = len;
+	return PKT_NORMAL;
+}
+
+/* returns pkttype or 0 on eof */
+int
+pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
+{
+	int			lentype;
+	int			res;
+	uint8	   *p;
+
+	/* EOF is normal here, thus we dont use GETBYTE */
+	res = pullf_read(src, 1, &p);
+	if (res < 0)
+		return res;
+	if (res == 0)
+		return 0;
+
+	if ((*p & 0x80) == 0)
+	{
+		px_debug("pgp_parse_pkt_hdr: not pkt hdr");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	if (*p & 0x40)
+	{
+		*tag = *p & 0x3f;
+		res = parse_new_len(src, len_p);
+	}
+	else
+	{
+		lentype = *p & 3;
+		*tag = (*p >> 2) & 0x0F;
+		if (lentype == 3)
+			res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
+		else
+			res = parse_old_len(src, len_p, lentype);
+	}
+	return res;
+}
+
+/*
+ * Packet reader
+ */
+struct PktData
+{
+	int			type;
+	int			len;
+};
+
+static int
+pktreader_pull(void *priv, PullFilter *src, int len,
+			   uint8 **data_p, uint8 *buf, int buflen)
+{
+	int			res;
+	struct PktData *pkt = priv;
+
+	/* PKT_CONTEXT means: whatever there is */
+	if (pkt->type == PKT_CONTEXT)
+		return pullf_read(src, len, data_p);
+
+	if (pkt->len == 0)
+	{
+		/* this was last chunk in stream */
+		if (pkt->type == PKT_NORMAL)
+			return 0;
+
+		/* next chunk in stream */
+		res = parse_new_len(src, &pkt->len);
+		if (res < 0)
+			return res;
+		pkt->type = res;
+	}
+
+	if (len > pkt->len)
+		len = pkt->len;
+
+	res = pullf_read(src, len, data_p);
+	if (res > 0)
+		pkt->len -= res;
+
+	return res;
+}
+
+static void
+pktreader_free(void *priv)
+{
+	struct PktData *pkt = priv;
+
+	memset(pkt, 0, sizeof(*pkt));
+	px_free(pkt);
+}
+
+static struct PullFilterOps pktreader_filter = {
+	NULL, pktreader_pull, pktreader_free
+};
+
+/* needs helper function to pass several parameters */
+int
+pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
+					  int pkttype, PGP_Context *ctx)
+{
+	int			res;
+	struct PktData *pkt = px_alloc(sizeof(*pkt));
+
+	pkt->type = pkttype;
+	pkt->len = len;
+	res = pullf_create(pf_p, &pktreader_filter, pkt, src);
+	if (res < 0)
+		px_free(pkt);
+	return res;
+}
+
+/*
+ * Prefix check filter
+ */
+
+static int
+prefix_init(void **priv_p, void *arg, PullFilter *src)
+{
+	PGP_Context *ctx = arg;
+	int			len;
+	int			res;
+	uint8	   *buf;
+	uint8		tmpbuf[PGP_MAX_BLOCK + 2];
+
+	len = pgp_get_cipher_block_size(ctx->cipher_algo);
+	if (len > sizeof(tmpbuf))
+		return PXE_BUG;
+
+	res = pullf_read_max(src, len + 2, &buf, tmpbuf);
+	if (res < 0)
+		return res;
+	if (res != len + 2)
+	{
+		px_debug("prefix_init: short read");
+		memset(tmpbuf, 0, sizeof(tmpbuf));
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
+	{
+		px_debug("prefix_init: corrupt prefix");
+
+		/*
+		 * The original purpose of the 2-byte check was to show user a
+		 * friendly "wrong key" message. This made following possible:
+		 *
+		 * "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge
+		 * Mister and Robert Zuccherato
+		 *
+		 * To avoid being 'oracle', we delay reporting, which basically means
+		 * we prefer to run into corrupt packet header.
+		 *
+		 * We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is
+		 * possibility of attack via timing, so we don't.
+		 */
+		ctx->corrupt_prefix = 1;
+	}
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	return 0;
+}
+
+static struct PullFilterOps prefix_filter = {
+	prefix_init, NULL, NULL
+};
+
+
+/*
+ * Decrypt filter
+ */
+
+static int
+decrypt_init(void **priv_p, void *arg, PullFilter *src)
+{
+	PGP_CFB    *cfb = arg;
+
+	*priv_p = cfb;
+
+	/* we need to write somewhere, so ask for a buffer */
+	return 4096;
+}
+
+static int
+decrypt_read(void *priv, PullFilter *src, int len,
+			 uint8 **data_p, uint8 *buf, int buflen)
+{
+	PGP_CFB    *cfb = priv;
+	uint8	   *tmp;
+	int			res;
+
+	res = pullf_read(src, len, &tmp);
+	if (res > 0)
+	{
+		pgp_cfb_decrypt(cfb, tmp, res, buf);
+		*data_p = buf;
+	}
+	return res;
+}
+
+struct PullFilterOps pgp_decrypt_filter = {
+	decrypt_init, decrypt_read, NULL
+};
+
+
+/*
+ * MDC hasher filter
+ */
+
+static int
+mdc_init(void **priv_p, void *arg, PullFilter *src)
+{
+	PGP_Context *ctx = arg;
+
+	*priv_p = ctx;
+	return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
+}
+
+static void
+mdc_free(void *priv)
+{
+	PGP_Context *ctx = priv;
+
+	if (ctx->use_mdcbuf_filter)
+		return;
+	px_md_free(ctx->mdc_ctx);
+	ctx->mdc_ctx = NULL;
+}
+
+static int
+mdc_finish(PGP_Context *ctx, PullFilter *src,
+		   int len, uint8 **data_p)
+{
+	int			res;
+	uint8		hash[20];
+	uint8		tmpbuf[22];
+
+	if (len + 1 > sizeof(tmpbuf))
+		return PXE_BUG;
+
+	/* read data */
+	res = pullf_read_max(src, len + 1, data_p, tmpbuf);
+	if (res < 0)
+		return res;
+	if (res == 0)
+	{
+		if (ctx->mdc_checked == 0)
+		{
+			px_debug("no mdc");
+			return PXE_PGP_CORRUPT_DATA;
+		}
+		return 0;
+	}
+
+	/* safety check */
+	if (ctx->in_mdc_pkt > 1)
+	{
+		px_debug("mdc_finish: several times here?");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	ctx->in_mdc_pkt++;
+
+	/* is the packet sane? */
+	if (res != 20)
+	{
+		px_debug("mdc_finish: read failed, res=%d", res);
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	/*
+	 * ok, we got the hash, now check
+	 */
+	px_md_finish(ctx->mdc_ctx, hash);
+	res = memcmp(hash, *data_p, 20);
+	memset(hash, 0, 20);
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	if (res != 0)
+	{
+		px_debug("mdc_finish: mdc failed");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	ctx->mdc_checked = 1;
+	return len;
+}
+
+static int
+mdc_read(void *priv, PullFilter *src, int len,
+		 uint8 **data_p, uint8 *buf, int buflen)
+{
+	int			res;
+	PGP_Context *ctx = priv;
+
+	/* skip this filter? */
+	if (ctx->use_mdcbuf_filter)
+		return pullf_read(src, len, data_p);
+
+	if (ctx->in_mdc_pkt)
+		return mdc_finish(ctx, src, len, data_p);
+
+	res = pullf_read(src, len, data_p);
+	if (res < 0)
+		return res;
+	if (res == 0)
+	{
+		px_debug("mdc_read: unexpected eof");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	px_md_update(ctx->mdc_ctx, *data_p, res);
+
+	return res;
+}
+
+static struct PullFilterOps mdc_filter = {
+	mdc_init, mdc_read, mdc_free
+};
+
+
+/*
+ * Combined Pkt reader and MDC hasher.
+ *
+ * For the case of SYMENCRYPTED_MDC packet, where
+ * the data part has 'context length', which means
+ * that data packet ends 22 bytes before end of parent
+ * packet, which is silly.
+ */
+#define MDCBUF_LEN 8192
+struct MDCBufData
+{
+	PGP_Context *ctx;
+	int			eof;
+	int			buflen;
+	int			avail;
+	uint8	   *pos;
+	int			mdc_avail;
+	uint8		mdc_buf[22];
+	uint8		buf[MDCBUF_LEN];
+};
+
+static int
+mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
+{
+	PGP_Context *ctx = arg;
+	struct MDCBufData *st;
+
+	st = px_alloc(sizeof(*st));
+	memset(st, 0, sizeof(*st));
+	st->buflen = sizeof(st->buf);
+	st->ctx = ctx;
+	*priv_p = st;
+
+	/* take over the work of mdc_filter */
+	ctx->use_mdcbuf_filter = 1;
+
+	return 0;
+}
+
+static int
+mdcbuf_finish(struct MDCBufData * st)
+{
+	uint8		hash[20];
+	int			res;
+
+	st->eof = 1;
+
+	if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
+	{
+		px_debug("mdcbuf_finish: bad MDC pkt hdr");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
+	px_md_finish(st->ctx->mdc_ctx, hash);
+	res = memcmp(hash, st->mdc_buf + 2, 20);
+	memset(hash, 0, 20);
+	if (res)
+	{
+		px_debug("mdcbuf_finish: MDC does not match");
+		res = PXE_PGP_CORRUPT_DATA;
+	}
+	return res;
+}
+
+static void
+mdcbuf_load_data(struct MDCBufData * st, uint8 *src, int len)
+{
+	uint8	   *dst = st->pos + st->avail;
+
+	memcpy(dst, src, len);
+	px_md_update(st->ctx->mdc_ctx, src, len);
+	st->avail += len;
+}
+
+static void
+mdcbuf_load_mdc(struct MDCBufData * st, uint8 *src, int len)
+{
+	memmove(st->mdc_buf + st->mdc_avail, src, len);
+	st->mdc_avail += len;
+}
+
+static int
+mdcbuf_refill(struct MDCBufData * st, PullFilter *src)
+{
+	uint8	   *data;
+	int			res;
+	int			need;
+
+	/* put avail data in start */
+	if (st->avail > 0 && st->pos != st->buf)
+		memmove(st->buf, st->pos, st->avail);
+	st->pos = st->buf;
+
+	/* read new data */
+	need = st->buflen + 22 - st->avail - st->mdc_avail;
+	res = pullf_read(src, need, &data);
+	if (res < 0)
+		return res;
+	if (res == 0)
+		return mdcbuf_finish(st);
+
+	/* add to buffer */
+	if (res >= 22)
+	{
+		mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
+		st->mdc_avail = 0;
+
+		mdcbuf_load_data(st, data, res - 22);
+		mdcbuf_load_mdc(st, data + res - 22, 22);
+	}
+	else
+	{
+		int			canmove = st->mdc_avail + res - 22;
+
+		if (canmove > 0)
+		{
+			mdcbuf_load_data(st, st->mdc_buf, canmove);
+			st->mdc_avail -= canmove;
+			memmove(st->mdc_buf, st->mdc_buf + canmove, st->mdc_avail);
+		}
+		mdcbuf_load_mdc(st, data, res);
+	}
+	return 0;
+}
+
+static int
+mdcbuf_read(void *priv, PullFilter *src, int len,
+			uint8 **data_p, uint8 *buf, int buflen)
+{
+	struct MDCBufData *st = priv;
+	int			res;
+
+	if (!st->eof && len > st->avail)
+	{
+		res = mdcbuf_refill(st, src);
+		if (res < 0)
+			return res;
+	}
+
+	if (len > st->avail)
+		len = st->avail;
+
+	*data_p = st->pos;
+	st->pos += len;
+	st->avail -= len;
+	return len;
+}
+
+static void
+mdcbuf_free(void *priv)
+{
+	struct MDCBufData *st = priv;
+
+	px_md_free(st->ctx->mdc_ctx);
+	st->ctx->mdc_ctx = NULL;
+	memset(st, 0, sizeof(*st));
+	px_free(st);
+}
+
+static struct PullFilterOps mdcbuf_filter = {
+	mdcbuf_init, mdcbuf_read, mdcbuf_free
+};
+
+
+/*
+ * Decrypt separate session key
+ */
+static int
+decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
+{
+	int			res;
+	uint8		algo;
+	PGP_CFB    *cfb;
+
+	res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
+						 ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
+	if (res < 0)
+		return res;
+
+	pgp_cfb_decrypt(cfb, src, 1, &algo);
+	src++;
+	len--;
+
+	pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
+	pgp_cfb_free(cfb);
+	ctx->sess_key_len = len;
+	ctx->cipher_algo = algo;
+
+	if (pgp_get_cipher_key_size(algo) != len)
+	{
+		px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
+				 algo, pgp_get_cipher_key_size(algo), len);
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	return 0;
+}
+
+/*
+ * Handle key packet
+ */
+static int
+parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
+{
+	uint8	   *p;
+	int			res;
+	uint8		tmpbuf[PGP_MAX_KEY + 2];
+	uint8		ver;
+
+	GETBYTE(src, ver);
+	GETBYTE(src, ctx->s2k_cipher_algo);
+	if (ver != 4)
+	{
+		px_debug("bad key pkt ver");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	/*
+	 * read S2K info
+	 */
+	res = pgp_s2k_read(src, &ctx->s2k);
+	if (res < 0)
+		return res;
+	ctx->s2k_mode = ctx->s2k.mode;
+	ctx->s2k_digest_algo = ctx->s2k.digest_algo;
+
+	/*
+	 * generate key from password
+	 */
+	res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
+						  ctx->sym_key, ctx->sym_key_len);
+	if (res < 0)
+		return res;
+
+	/*
+	 * do we have separate session key?
+	 */
+	res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
+	if (res < 0)
+		return res;
+
+	if (res == 0)
+	{
+		/*
+		 * no, s2k key is session key
+		 */
+		memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
+		ctx->sess_key_len = ctx->s2k.key_len;
+		ctx->cipher_algo = ctx->s2k_cipher_algo;
+		res = 0;
+		ctx->use_sess_key = 0;
+	}
+	else
+	{
+		/*
+		 * yes, decrypt it
+		 */
+		if (res < 17 || res > PGP_MAX_KEY + 1)
+		{
+			px_debug("expect key, but bad data");
+			return PXE_PGP_CORRUPT_DATA;
+		}
+		ctx->use_sess_key = 1;
+		res = decrypt_key(ctx, p, res);
+	}
+
+	memset(tmpbuf, 0, sizeof(tmpbuf));
+	return res;
+}
+
+static int
+copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
+{
+	uint8	   *data_end = data + len;
+	uint8		tmpbuf[1024];
+	uint8	   *tmp_end = tmpbuf + sizeof(tmpbuf);
+	uint8	   *p;
+	int			res;
+
+	p = tmpbuf;
+	if (*got_cr)
+	{
+		if (*data != '\n')
+			*p++ = '\r';
+		*got_cr = 0;
+	}
+	while (data < data_end)
+	{
+		if (*data == '\r')
+		{
+			if (data + 1 < data_end)
+			{
+				if (*(data + 1) == '\n')
+					data++;
+			}
+			else
+			{
+				*got_cr = 1;
+				break;
+			}
+		}
+		*p++ = *data++;
+		if (p >= tmp_end)
+		{
+			res = mbuf_append(dst, tmpbuf, p - tmpbuf);
+			if (res < 0)
+				return res;
+			p = tmpbuf;
+		}
+	}
+	if (p - tmpbuf > 0)
+	{
+		res = mbuf_append(dst, tmpbuf, p - tmpbuf);
+		if (res < 0)
+			return res;
+	}
+	return 0;
+}
+
+static int
+parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+{
+	int			type;
+	int			name_len;
+	int			res;
+	uint8	   *buf;
+	uint8		tmpbuf[4];
+	int			got_cr = 0;
+
+	GETBYTE(pkt, type);
+	GETBYTE(pkt, name_len);
+
+	/* skip name */
+	while (name_len > 0)
+	{
+		res = pullf_read(pkt, name_len, &buf);
+		if (res < 0)
+			return res;
+		if (res == 0)
+			break;
+		name_len -= res;
+	}
+	if (name_len > 0)
+	{
+		px_debug("parse_literal_data: unexpected eof");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	/* skip date */
+	res = pullf_read_max(pkt, 4, &buf, tmpbuf);
+	if (res != 4)
+	{
+		px_debug("parse_literal_data: unexpected eof");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+	memset(tmpbuf, 0, 4);
+
+	/* check if text */
+	if (ctx->text_mode)
+		if (type != 't' && type != 'u')
+		{
+			px_debug("parse_literal_data: data type=%c", type);
+			return PXE_PGP_NOT_TEXT;
+		}
+
+	ctx->unicode_mode = (type == 'u') ? 1 : 0;
+
+	/* read data */
+	while (1)
+	{
+		res = pullf_read(pkt, 32 * 1024, &buf);
+		if (res <= 0)
+			break;
+
+		if (ctx->text_mode && ctx->convert_crlf)
+			res = copy_crlf(dst, buf, res, &got_cr);
+		else
+			res = mbuf_append(dst, buf, res);
+		if (res < 0)
+			break;
+	}
+	if (res >= 0 && got_cr)
+		res = mbuf_append(dst, (const uint8 *) "\r", 1);
+	return res;
+}
+
+/* process_data_packets and parse_compressed_data call each other */
+static int process_data_packets(PGP_Context *ctx, MBuf *dst,
+					 PullFilter *src, int allow_compr, int need_mdc);
+
+static int
+parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+{
+	int			res;
+	uint8		type;
+	PullFilter *pf_decompr;
+
+	GETBYTE(pkt, type);
+
+	ctx->compress_algo = type;
+	switch (type)
+	{
+		case PGP_COMPR_NONE:
+			res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC);
+			break;
+
+		case PGP_COMPR_ZIP:
+		case PGP_COMPR_ZLIB:
+			res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
+			if (res >= 0)
+			{
+				res = process_data_packets(ctx, dst, pf_decompr,
+										   NO_COMPR, NO_MDC);
+				pullf_free(pf_decompr);
+			}
+			break;
+
+		case PGP_COMPR_BZIP2:
+			px_debug("parse_compressed_data: bzip2 unsupported");
+			res = PXE_PGP_UNSUPPORTED_COMPR;
+			break;
+
+		default:
+			px_debug("parse_compressed_data: unknown compr type");
+			res = PXE_PGP_CORRUPT_DATA;
+	}
+
+	return res;
+}
+
+static int
+process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
+					 int allow_compr, int need_mdc)
+{
+	uint8		tag;
+	int			len,
+				res;
+	int			got_data = 0;
+	int			got_mdc = 0;
+	PullFilter *pkt = NULL;
+	uint8	   *tmp;
+
+	while (1)
+	{
+		res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
+		if (res <= 0)
+			break;
+
+
+		/* mdc packet should be last */
+		if (got_mdc)
+		{
+			px_debug("process_data_packets: data after mdc");
+			res = PXE_PGP_CORRUPT_DATA;
+			break;
+		}
+
+		/* context length inside SYMENC_MDC needs special handling */
+		if (need_mdc && res == PKT_CONTEXT)
+			res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
+		else
+			res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
+		if (res < 0)
+			break;
+
+		switch (tag)
+		{
+			case PGP_PKT_LITERAL_DATA:
+				got_data = 1;
+				res = parse_literal_data(ctx, dst, pkt);
+				break;
+			case PGP_PKT_COMPRESSED_DATA:
+				if (allow_compr == 0)
+				{
+					px_debug("process_data_packets: unexpected compression");
+					res = PXE_PGP_CORRUPT_DATA;
+				}
+				else if (got_data)
+				{
+					/*
+					 * compr data must be alone
+					 */
+					px_debug("process_data_packets: only one cmpr pkt allowed");
+					res = PXE_PGP_CORRUPT_DATA;
+				}
+				else
+				{
+					got_data = 1;
+					res = parse_compressed_data(ctx, dst, pkt);
+				}
+				break;
+			case PGP_PKT_MDC:
+				if (need_mdc == NO_MDC)
+				{
+					px_debug("process_data_packets: unexpected MDC");
+					res = PXE_PGP_CORRUPT_DATA;
+					break;
+				}
+
+				/* notify mdc_filter */
+				ctx->in_mdc_pkt = 1;
+
+				res = pullf_read(pkt, 8192, &tmp);
+				if (res > 0)
+					got_mdc = 1;
+				break;
+			default:
+				px_debug("process_data_packets: unexpected pkt tag=%d", tag);
+				res = PXE_PGP_CORRUPT_DATA;
+		}
+
+		pullf_free(pkt);
+		pkt = NULL;
+
+		if (res < 0)
+			break;
+	}
+
+	if (pkt)
+		pullf_free(pkt);
+
+	if (res < 0)
+		return res;
+
+	if (!got_data)
+	{
+		px_debug("process_data_packets: no data");
+		res = PXE_PGP_CORRUPT_DATA;
+	}
+	if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter)
+	{
+		px_debug("process_data_packets: got no mdc");
+		res = PXE_PGP_CORRUPT_DATA;
+	}
+	return res;
+}
+
+static int
+parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
+{
+	int			res;
+	PGP_CFB    *cfb = NULL;
+	PullFilter *pf_decrypt = NULL;
+	PullFilter *pf_prefix = NULL;
+
+	res = pgp_cfb_create(&cfb, ctx->cipher_algo,
+						 ctx->sess_key, ctx->sess_key_len, 1, NULL);
+	if (res < 0)
+		goto out;
+
+	res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
+	if (res < 0)
+		goto out;
+
+	res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
+	if (res < 0)
+		goto out;
+
+	res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);
+
+out:
+	if (pf_prefix)
+		pullf_free(pf_prefix);
+	if (pf_decrypt)
+		pullf_free(pf_decrypt);
+	if (cfb)
+		pgp_cfb_free(cfb);
+
+	return res;
+}
+
+static int
+parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
+{
+	int			res;
+	PGP_CFB    *cfb = NULL;
+	PullFilter *pf_decrypt = NULL;
+	PullFilter *pf_prefix = NULL;
+	PullFilter *pf_mdc = NULL;
+	uint8		ver;
+
+	GETBYTE(pkt, ver);
+	if (ver != 1)
+	{
+		px_debug("parse_symenc_mdc_data: pkt ver != 1");
+		return PXE_PGP_CORRUPT_DATA;
+	}
+
+	res = pgp_cfb_create(&cfb, ctx->cipher_algo,
+						 ctx->sess_key, ctx->sess_key_len, 0, NULL);
+	if (res < 0)
+		goto out;
+
+	res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
+	if (res < 0)
+		goto out;
+
+	res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
+	if (res < 0)
+		goto out;
+
+	res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
+	if (res < 0)
+		goto out;
+
+	res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);
+
+out:
+	if (pf_prefix)
+		pullf_free(pf_prefix);
+	if (pf_mdc)
+		pullf_free(pf_mdc);
+	if (pf_decrypt)
+		pullf_free(pf_decrypt);
+	if (cfb)
+		pgp_cfb_free(cfb);
+
+	return res;
+}
+
+/*
+ * skip over packet contents
+ */
+int
+pgp_skip_packet(PullFilter *pkt)
+{
+	int			res = 1;
+	uint8	   *tmp;
+
+	while (res > 0)
+		res = pullf_read(pkt, 32 * 1024, &tmp);
+	return res < 0 ? res : 0;
+}
+
+/*
+ * expect to be at packet end, any data is error
+ */
+int
+pgp_expect_packet_end(PullFilter *pkt)
+{
+	int			res = 1;
+	uint8	   *tmp;
+
+	while (res > 0)
+	{
+		res = pullf_read(pkt, 32 * 1024, &tmp);
+		if (res > 0)
+		{
+			px_debug("pgp_expect_packet_end: got data");
+			return PXE_PGP_CORRUPT_DATA;
+		}
+	}
+	return res < 0 ? res : 0;
+}
+
+int
+pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
+{
+	int			res;
+	PullFilter *src = NULL;
+	PullFilter *pkt = NULL;
+	uint8		tag;
+	int			len;
+	int			got_key = 0;
+	int			got_data = 0;
+
+	res = pullf_create_mbuf_reader(&src, msrc);
+
+	while (res >= 0)
+	{
+		res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
+		if (res <= 0)
+			break;
+
+		res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
+		if (res < 0)
+			break;
+
+		res = PXE_PGP_CORRUPT_DATA;
+		switch (tag)
+		{
+			case PGP_PKT_MARKER:
+				res = pgp_skip_packet(pkt);
+				break;
+			case PGP_PKT_PUBENCRYPTED_SESSKEY:
+				/* fixme: skip those */
+				res = pgp_parse_pubenc_sesskey(ctx, pkt);
+				got_key = 1;
+				break;
+			case PGP_PKT_SYMENCRYPTED_SESSKEY:
+				if (got_key)
+
+					/*
+					 * Theoretically, there could be several keys, both public
+					 * and symmetric, all of which encrypt same session key.
+					 * Decrypt should try with each one, before failing.
+					 */
+					px_debug("pgp_decrypt: using first of several keys");
+				else
+				{
+					got_key = 1;
+					res = parse_symenc_sesskey(ctx, pkt);
+				}
+				break;
+			case PGP_PKT_SYMENCRYPTED_DATA:
+				if (!got_key)
+					px_debug("pgp_decrypt: have data but no key");
+				else if (got_data)
+					px_debug("pgp_decrypt: got second data packet");
+				else
+				{
+					got_data = 1;
+					ctx->disable_mdc = 1;
+					res = parse_symenc_data(ctx, pkt, mdst);
+				}
+				break;
+			case PGP_PKT_SYMENCRYPTED_DATA_MDC:
+				if (!got_key)
+					px_debug("pgp_decrypt: have data but no key");
+				else if (got_data)
+					px_debug("pgp_decrypt: several data pkts not supported");
+				else
+				{
+					got_data = 1;
+					ctx->disable_mdc = 0;
+					res = parse_symenc_mdc_data(ctx, pkt, mdst);
+				}
+				break;
+			default:
+				px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
+		}
+		pullf_free(pkt);
+		pkt = NULL;
+	}
+
+	if (pkt)
+		pullf_free(pkt);
+
+	if (src)
+		pullf_free(src);
+
+	if (res < 0)
+		return res;
+
+	if (!got_data || ctx->corrupt_prefix)
+		res = PXE_PGP_CORRUPT_DATA;
+
+	return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-encrypt.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c
new file mode 100644
index 0000000..3b9b5d2
--- /dev/null
+++ b/contrib/pgcrypto/pgp-encrypt.c
@@ -0,0 +1,708 @@
+/*
+ * pgp-encrypt.c
+ *	  OpenPGP encrypt.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-encrypt.c
+ */
+
+#include "postgres.h"
+
+#include <time.h>
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+
+#define MDC_DIGEST_LEN 20
+#define STREAM_ID 0xE0
+#define STREAM_BLOCK_SHIFT	14
+
+static uint8 *
+render_newlen(uint8 *h, int len)
+{
+	if (len <= 191)
+	{
+		*h++ = len & 255;
+	}
+	else if (len > 191 && len <= 8383)
+	{
+		*h++ = ((len - 192) >> 8) + 192;
+		*h++ = (len - 192) & 255;
+	}
+	else
+	{
+		*h++ = 255;
+		*h++ = (len >> 24) & 255;
+		*h++ = (len >> 16) & 255;
+		*h++ = (len >> 8) & 255;
+		*h++ = len & 255;
+	}
+	return h;
+}
+
+static int
+write_tag_only(PushFilter *dst, int tag)
+{
+	uint8		hdr = 0xC0 | tag;
+
+	return pushf_write(dst, &hdr, 1);
+}
+
+static int
+write_normal_header(PushFilter *dst, int tag, int len)
+{
+	uint8		hdr[8];
+	uint8	   *h = hdr;
+
+	*h++ = 0xC0 | tag;
+	h = render_newlen(h, len);
+	return pushf_write(dst, hdr, h - hdr);
+}
+
+
+/*
+ * MAC writer
+ */
+
+static int
+mdc_init(PushFilter *dst, void *init_arg, void **priv_p)
+{
+	int			res;
+	PX_MD	   *md;
+
+	res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
+	if (res < 0)
+		return res;
+
+	*priv_p = md;
+	return 0;
+}
+
+static int
+mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+{
+	PX_MD	   *md = priv;
+
+	px_md_update(md, data, len);
+	return pushf_write(dst, data, len);
+}
+
+static int
+mdc_flush(PushFilter *dst, void *priv)
+{
+	int			res;
+	uint8		pkt[2 + MDC_DIGEST_LEN];
+	PX_MD	   *md = priv;
+
+	/*
+	 * create mdc pkt
+	 */
+	pkt[0] = 0xD3;
+	pkt[1] = 0x14;				/* MDC_DIGEST_LEN */
+	px_md_update(md, pkt, 2);
+	px_md_finish(md, pkt + 2);
+
+	res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN);
+	memset(pkt, 0, 2 + MDC_DIGEST_LEN);
+	return res;
+}
+
+static void
+mdc_free(void *priv)
+{
+	PX_MD	   *md = priv;
+
+	px_md_free(md);
+}
+
+static const PushFilterOps mdc_filter = {
+	mdc_init, mdc_write, mdc_flush, mdc_free
+};
+
+
+/*
+ * Encrypted pkt writer
+ */
+#define ENCBUF 8192
+struct EncStat
+{
+	PGP_CFB    *ciph;
+	uint8		buf[ENCBUF];
+};
+
+static int
+encrypt_init(PushFilter *next, void *init_arg, void **priv_p)
+{
+	struct EncStat *st;
+	PGP_Context *ctx = init_arg;
+	PGP_CFB    *ciph;
+	int			resync = 1;
+	int			res;
+
+	/* should we use newer packet format? */
+	if (ctx->disable_mdc == 0)
+	{
+		uint8		ver = 1;
+
+		resync = 0;
+		res = pushf_write(next, &ver, 1);
+		if (res < 0)
+			return res;
+	}
+	res = pgp_cfb_create(&ciph, ctx->cipher_algo,
+						 ctx->sess_key, ctx->sess_key_len, resync, NULL);
+	if (res < 0)
+		return res;
+
+	st = px_alloc(sizeof(*st));
+	memset(st, 0, sizeof(*st));
+	st->ciph = ciph;
+
+	*priv_p = st;
+	return ENCBUF;
+}
+
+static int
+encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len)
+{
+	int			res;
+	struct EncStat *st = priv;
+	int			avail = len;
+
+	while (avail > 0)
+	{
+		int			tmplen = avail > ENCBUF ? ENCBUF : avail;
+
+		res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
+		if (res < 0)
+			return res;
+
+		res = pushf_write(next, st->buf, tmplen);
+		if (res < 0)
+			return res;
+
+		data += tmplen;
+		avail -= tmplen;
+	}
+	return 0;
+}
+
+static void
+encrypt_free(void *priv)
+{
+	struct EncStat *st = priv;
+
+	memset(st, 0, sizeof(*st));
+	px_free(st);
+}
+
+static const PushFilterOps encrypt_filter = {
+	encrypt_init, encrypt_process, NULL, encrypt_free
+};
+
+/*
+ * Write Streamable pkts
+ */
+
+struct PktStreamStat
+{
+	int			final_done;
+	int			pkt_block;
+};
+
+static int
+pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
+{
+	struct PktStreamStat *st;
+
+	st = px_alloc(sizeof(*st));
+	st->final_done = 0;
+	st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
+	*priv_p = st;
+
+	return st->pkt_block;
+}
+
+static int
+pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
+{
+	int			res;
+	uint8		hdr[8];
+	uint8	   *h = hdr;
+	struct PktStreamStat *st = priv;
+
+	if (st->final_done)
+		return PXE_BUG;
+
+	if (len == st->pkt_block)
+		*h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
+	else
+	{
+		h = render_newlen(h, len);
+		st->final_done = 1;
+	}
+
+	res = pushf_write(next, hdr, h - hdr);
+	if (res < 0)
+		return res;
+
+	return pushf_write(next, data, len);
+}
+
+static int
+pkt_stream_flush(PushFilter *next, void *priv)
+{
+	int			res;
+	uint8		hdr[8];
+	uint8	   *h = hdr;
+	struct PktStreamStat *st = priv;
+
+	/* stream MUST end with normal packet. */
+	if (!st->final_done)
+	{
+		h = render_newlen(h, 0);
+		res = pushf_write(next, hdr, h - hdr);
+		if (res < 0)
+			return res;
+		st->final_done = 1;
+	}
+	return 0;
+}
+
+static void
+pkt_stream_free(void *priv)
+{
+	struct PktStreamStat *st = priv;
+
+	memset(st, 0, sizeof(*st));
+	px_free(st);
+}
+
+static const PushFilterOps pkt_stream_filter = {
+	pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
+};
+
+int
+pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
+{
+	int			res;
+
+	res = write_tag_only(dst, tag);
+	if (res < 0)
+		return res;
+
+	return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
+}
+
+/*
+ * Text conversion filter
+ */
+
+static int
+crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
+{
+	const uint8 *data_end = data + len;
+	const uint8 *p2,
+			   *p1 = data;
+	int			line_len;
+	static const uint8 crlf[] = {'\r', '\n'};
+	int			res = 0;
+
+	while (p1 < data_end)
+	{
+		p2 = memchr(p1, '\n', data_end - p1);
+		if (p2 == NULL)
+			p2 = data_end;
+
+		line_len = p2 - p1;
+
+		/* write data */
+		res = 0;
+		if (line_len > 0)
+		{
+			res = pushf_write(dst, p1, line_len);
+			if (res < 0)
+				break;
+			p1 += line_len;
+		}
+
+		/* write crlf */
+		while (p1 < data_end && *p1 == '\n')
+		{
+			res = pushf_write(dst, crlf, 2);
+			if (res < 0)
+				break;
+			p1++;
+		}
+	}
+	return res;
+}
+
+static const PushFilterOps crlf_filter = {
+	NULL, crlf_process, NULL, NULL
+};
+
+/*
+ * Initialize literal data packet
+ */
+static int
+init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+	int			res;
+	int			hdrlen;
+	uint8		hdr[6];
+	uint32		t;
+	PushFilter *pkt;
+	int			type;
+
+	/*
+	 * Create header
+	 */
+
+	if (ctx->text_mode)
+		type = ctx->unicode_mode ? 'u' : 't';
+	else
+		type = 'b';
+
+	/*
+	 * Store the creation time into packet. The goal is to have as few known
+	 * bytes as possible.
+	 */
+	t = (uint32) time(NULL);
+
+	hdr[0] = type;
+	hdr[1] = 0;
+	hdr[2] = (t >> 24) & 255;
+	hdr[3] = (t >> 16) & 255;
+	hdr[4] = (t >> 8) & 255;
+	hdr[5] = t & 255;
+	hdrlen = 6;
+
+	res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
+	if (res < 0)
+		return res;
+
+	res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
+	if (res < 0)
+		return res;
+
+	res = pushf_write(pkt, hdr, hdrlen);
+	if (res < 0)
+	{
+		pushf_free(pkt);
+		return res;
+	}
+
+	*pf_res = pkt;
+	return 0;
+}
+
+/*
+ * Initialize compression filter
+ */
+static int
+init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+	int			res;
+	uint8		type = ctx->compress_algo;
+	PushFilter *pkt;
+
+	res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
+	if (res < 0)
+		return res;
+
+	res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
+	if (res < 0)
+		return res;
+
+	res = pushf_write(pkt, &type, 1);
+	if (res >= 0)
+		res = pgp_compress_filter(pf_res, ctx, pkt);
+
+	if (res < 0)
+		pushf_free(pkt);
+
+	return res;
+}
+
+/*
+ * Initialize encdata packet
+ */
+static int
+init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+	int			res;
+	int			tag;
+
+	if (ctx->disable_mdc)
+		tag = PGP_PKT_SYMENCRYPTED_DATA;
+	else
+		tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
+
+	res = write_tag_only(dst, tag);
+	if (res < 0)
+		return res;
+
+	return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
+}
+
+/*
+ * write prefix
+ */
+static int
+write_prefix(PGP_Context *ctx, PushFilter *dst)
+{
+	uint8		prefix[PGP_MAX_BLOCK + 2];
+	int			res,
+				bs;
+
+	bs = pgp_get_cipher_block_size(ctx->cipher_algo);
+	res = px_get_random_bytes(prefix, bs);
+	if (res < 0)
+		return res;
+
+	prefix[bs + 0] = prefix[bs - 2];
+	prefix[bs + 1] = prefix[bs - 1];
+
+	res = pushf_write(dst, prefix, bs + 2);
+	memset(prefix, 0, bs + 2);
+	return res < 0 ? res : 0;
+}
+
+/*
+ * write symmetrically encrypted session key packet
+ */
+
+static int
+symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
+{
+	int			res;
+	PGP_CFB    *cfb;
+	uint8		algo = ctx->cipher_algo;
+
+	res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
+						 ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
+	if (res < 0)
+		return res;
+
+	pgp_cfb_encrypt(cfb, &algo, 1, dst);
+	pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
+
+	pgp_cfb_free(cfb);
+	return ctx->sess_key_len + 1;
+}
+
+/* 5.3: Symmetric-Key Encrypted Session-Key */
+static int
+write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
+{
+	uint8		pkt[256];
+	int			pktlen;
+	int			res;
+	uint8	   *p = pkt;
+
+	*p++ = 4;					/* 5.3 - version number  */
+	*p++ = ctx->s2k_cipher_algo;
+
+	*p++ = ctx->s2k.mode;
+	*p++ = ctx->s2k.digest_algo;
+	if (ctx->s2k.mode > 0)
+	{
+		memcpy(p, ctx->s2k.salt, 8);
+		p += 8;
+	}
+	if (ctx->s2k.mode == 3)
+		*p++ = ctx->s2k.iter;
+
+	if (ctx->use_sess_key)
+	{
+		res = symencrypt_sesskey(ctx, p);
+		if (res < 0)
+			return res;
+		p += res;
+	}
+
+	pktlen = p - pkt;
+	res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
+	if (res >= 0)
+		res = pushf_write(dst, pkt, pktlen);
+
+	memset(pkt, 0, pktlen);
+	return res;
+}
+
+/*
+ * key setup
+ */
+static int
+init_s2k_key(PGP_Context *ctx)
+{
+	int			res;
+
+	if (ctx->s2k_cipher_algo < 0)
+		ctx->s2k_cipher_algo = ctx->cipher_algo;
+
+	res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo);
+	if (res < 0)
+		return res;
+
+	return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
+						   ctx->sym_key, ctx->sym_key_len);
+}
+
+static int
+init_sess_key(PGP_Context *ctx)
+{
+	int			res;
+
+	if (ctx->use_sess_key || ctx->pub_key)
+	{
+		ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
+		res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
+		if (res < 0)
+			return res;
+	}
+	else
+	{
+		ctx->sess_key_len = ctx->s2k.key_len;
+		memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
+	}
+
+	return 0;
+}
+
+/*
+ * combine
+ */
+int
+pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
+{
+	int			res;
+	int			len;
+	uint8	   *buf;
+	PushFilter *pf,
+			   *pf_tmp;
+
+	/*
+	 * do we have any key
+	 */
+	if (!ctx->sym_key && !ctx->pub_key)
+		return PXE_ARGUMENT_ERROR;
+
+	/* MBuf writer */
+	res = pushf_create_mbuf_writer(&pf, dst);
+	if (res < 0)
+		goto out;
+
+	/*
+	 * initialize symkey
+	 */
+	if (ctx->sym_key)
+	{
+		res = init_s2k_key(ctx);
+		if (res < 0)
+			goto out;
+	}
+
+	res = init_sess_key(ctx);
+	if (res < 0)
+		goto out;
+
+	/*
+	 * write keypkt
+	 */
+	if (ctx->pub_key)
+		res = pgp_write_pubenc_sesskey(ctx, pf);
+	else
+		res = write_symenc_sesskey(ctx, pf);
+	if (res < 0)
+		goto out;
+
+	/* encrypted data pkt */
+	res = init_encdata_packet(&pf_tmp, ctx, pf);
+	if (res < 0)
+		goto out;
+	pf = pf_tmp;
+
+	/* encrypter */
+	res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
+	if (res < 0)
+		goto out;
+	pf = pf_tmp;
+
+	/* hasher */
+	if (ctx->disable_mdc == 0)
+	{
+		res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
+		if (res < 0)
+			goto out;
+		pf = pf_tmp;
+	}
+
+	/* prefix */
+	res = write_prefix(ctx, pf);
+	if (res < 0)
+		goto out;
+
+	/* compressor */
+	if (ctx->compress_algo > 0 && ctx->compress_level > 0)
+	{
+		res = init_compress(&pf_tmp, ctx, pf);
+		if (res < 0)
+			goto out;
+		pf = pf_tmp;
+	}
+
+	/* data streamer */
+	res = init_litdata_packet(&pf_tmp, ctx, pf);
+	if (res < 0)
+		goto out;
+	pf = pf_tmp;
+
+
+	/* text conversion? */
+	if (ctx->text_mode && ctx->convert_crlf)
+	{
+		res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
+		if (res < 0)
+			goto out;
+		pf = pf_tmp;
+	}
+
+	/*
+	 * chain complete
+	 */
+
+	len = mbuf_grab(src, mbuf_avail(src), &buf);
+	res = pushf_write(pf, buf, len);
+	if (res >= 0)
+		res = pushf_flush(pf);
+out:
+	pushf_free_all(pf);
+	return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-info.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-info.c b/contrib/pgcrypto/pgp-info.c
new file mode 100644
index 0000000..b75266f
--- /dev/null
+++ b/contrib/pgcrypto/pgp-info.c
@@ -0,0 +1,235 @@
+/*
+ * pgp-info.c
+ *	  Provide info about PGP data.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-info.c
+ */
+#include "postgres.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static int
+read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
+{
+	int			res;
+	PGP_PubKey *pk = NULL;
+
+	res = _pgp_read_public_key(pkt, &pk);
+	if (res < 0)
+		goto err;
+
+	/* skip secret key part, if it exists */
+	res = pgp_skip_packet(pkt);
+	if (res < 0)
+		goto err;
+
+	/* is it encryption key */
+	switch (pk->algo)
+	{
+		case PGP_PUB_ELG_ENCRYPT:
+		case PGP_PUB_RSA_ENCRYPT:
+		case PGP_PUB_RSA_ENCRYPT_SIGN:
+			memcpy(keyid_buf, pk->key_id, 8);
+			res = 1;
+			break;
+		default:
+			res = 0;
+	}
+
+err:
+	pgp_key_free(pk);
+	return res;
+}
+
+static int
+read_pubenc_keyid(PullFilter *pkt, uint8 *keyid_buf)
+{
+	uint8		ver;
+	int			res;
+
+	GETBYTE(pkt, ver);
+	if (ver != 3)
+		return -1;
+
+	res = pullf_read_fixed(pkt, 8, keyid_buf);
+	if (res < 0)
+		return res;
+
+	return pgp_skip_packet(pkt);
+}
+
+static const char hextbl[] = "0123456789ABCDEF";
+
+static int
+print_key(uint8 *keyid, char *dst)
+{
+	int			i;
+	unsigned	c;
+
+	for (i = 0; i < 8; i++)
+	{
+		c = keyid[i];
+		*dst++ = hextbl[(c >> 4) & 0x0F];
+		*dst++ = hextbl[c & 0x0F];
+	}
+	*dst = 0;
+	return 8 * 2;
+}
+
+static const uint8 any_key[] =
+{0, 0, 0, 0, 0, 0, 0, 0};
+
+/*
+ * dst should have room for 17 bytes
+ */
+int
+pgp_get_keyid(MBuf *pgp_data, char *dst)
+{
+	int			res;
+	PullFilter *src;
+	PullFilter *pkt = NULL;
+	int			len;
+	uint8		tag;
+	int			got_pub_key = 0,
+				got_symenc_key = 0,
+				got_pubenc_key = 0;
+	int			got_data = 0;
+	uint8		keyid_buf[8];
+	int			got_main_key = 0;
+
+
+	res = pullf_create_mbuf_reader(&src, pgp_data);
+	if (res < 0)
+		return res;
+
+	while (1)
+	{
+		res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
+		if (res <= 0)
+			break;
+		res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
+		if (res < 0)
+			break;
+
+		switch (tag)
+		{
+			case PGP_PKT_SECRET_KEY:
+			case PGP_PKT_PUBLIC_KEY:
+				/* main key is for signing, so ignore it */
+				if (!got_main_key)
+				{
+					got_main_key = 1;
+					res = pgp_skip_packet(pkt);
+				}
+				else
+					res = PXE_PGP_MULTIPLE_KEYS;
+				break;
+			case PGP_PKT_SECRET_SUBKEY:
+			case PGP_PKT_PUBLIC_SUBKEY:
+				res = read_pubkey_keyid(pkt, keyid_buf);
+				if (res < 0)
+					break;
+				if (res > 0)
+					got_pub_key++;
+				break;
+			case PGP_PKT_PUBENCRYPTED_SESSKEY:
+				got_pubenc_key++;
+				res = read_pubenc_keyid(pkt, keyid_buf);
+				break;
+			case PGP_PKT_SYMENCRYPTED_DATA:
+			case PGP_PKT_SYMENCRYPTED_DATA_MDC:
+				/* don't skip it, just stop */
+				got_data = 1;
+				break;
+			case PGP_PKT_SYMENCRYPTED_SESSKEY:
+				got_symenc_key++;
+				/* fallthru */
+			case PGP_PKT_SIGNATURE:
+			case PGP_PKT_MARKER:
+			case PGP_PKT_TRUST:
+			case PGP_PKT_USER_ID:
+			case PGP_PKT_USER_ATTR:
+			case PGP_PKT_PRIV_61:
+				res = pgp_skip_packet(pkt);
+				break;
+			default:
+				res = PXE_PGP_CORRUPT_DATA;
+		}
+
+		if (pkt)
+			pullf_free(pkt);
+		pkt = NULL;
+
+		if (res < 0 || got_data)
+			break;
+	}
+
+	pullf_free(src);
+	if (pkt)
+		pullf_free(pkt);
+
+	if (res < 0)
+		return res;
+
+	/* now check sanity */
+	if (got_pub_key && got_pubenc_key)
+		res = PXE_PGP_CORRUPT_DATA;
+
+	if (got_pub_key > 1)
+		res = PXE_PGP_MULTIPLE_KEYS;
+
+	if (got_pubenc_key > 1)
+		res = PXE_PGP_MULTIPLE_KEYS;
+
+	/*
+	 * if still ok, look what we got
+	 */
+	if (res >= 0)
+	{
+		if (got_pubenc_key || got_pub_key)
+		{
+			if (memcmp(keyid_buf, any_key, 8) == 0)
+			{
+				memcpy(dst, "ANYKEY", 7);
+				res = 6;
+			}
+			else
+				res = print_key(keyid_buf, dst);
+		}
+		else if (got_symenc_key)
+		{
+			memcpy(dst, "SYMKEY", 7);
+			res = 6;
+		}
+		else
+			res = PXE_PGP_NO_USABLE_KEY;
+	}
+
+	return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-mpi-internal.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-mpi-internal.c b/contrib/pgcrypto/pgp-mpi-internal.c
new file mode 100644
index 0000000..d0e5830
--- /dev/null
+++ b/contrib/pgcrypto/pgp-mpi-internal.c
@@ -0,0 +1,308 @@
+/*
+ * pgp-mpi-internal.c
+ *	  OpenPGP MPI functions.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-mpi-internal.c
+ */
+#include "postgres.h"
+
+#include "imath.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static mpz_t *
+mp_new()
+{
+	mpz_t	   *mp = mp_int_alloc();
+
+	mp_int_init_size(mp, 256);
+	return mp;
+}
+
+static void
+mp_clear_free(mpz_t *a)
+{
+	if (!a)
+		return;
+	/* fixme: no clear? */
+	mp_int_free(a);
+}
+
+
+static int
+mp_px_rand(uint32 bits, mpz_t *res)
+{
+	int			err;
+	unsigned	bytes = (bits + 7) / 8;
+	int			last_bits = bits & 7;
+	uint8	   *buf;
+
+	buf = px_alloc(bytes);
+	err = px_get_random_bytes(buf, bytes);
+	if (err < 0)
+	{
+		px_free(buf);
+		return err;
+	}
+
+	/* clear unnecessary bits and set last bit to one */
+	if (last_bits)
+	{
+		buf[0] >>= 8 - last_bits;
+		buf[0] |= 1 << (last_bits - 1);
+	}
+	else
+		buf[0] |= 1 << 7;
+
+	mp_int_read_unsigned(res, buf, bytes);
+
+	px_free(buf);
+
+	return 0;
+}
+
+static void
+mp_modmul(mpz_t *a, mpz_t *b, mpz_t *p, mpz_t *res)
+{
+	mpz_t	   *tmp = mp_new();
+
+	mp_int_mul(a, b, tmp);
+	mp_int_mod(tmp, p, res);
+	mp_clear_free(tmp);
+}
+
+static mpz_t *
+mpi_to_bn(PGP_MPI *n)
+{
+	mpz_t	   *bn = mp_new();
+
+	mp_int_read_unsigned(bn, n->data, n->bytes);
+
+	if (!bn)
+		return NULL;
+	if (mp_int_count_bits(bn) != n->bits)
+	{
+		px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
+				 n->bits, mp_int_count_bits(bn));
+		mp_clear_free(bn);
+		return NULL;
+	}
+	return bn;
+}
+
+static PGP_MPI *
+bn_to_mpi(mpz_t *bn)
+{
+	int			res;
+	PGP_MPI    *n;
+	int			bytes;
+
+	res = pgp_mpi_alloc(mp_int_count_bits(bn), &n);
+	if (res < 0)
+		return NULL;
+
+	bytes = (mp_int_count_bits(bn) + 7) / 8;
+	if (bytes != n->bytes)
+	{
+		px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
+				 bytes, n->bytes);
+		pgp_mpi_free(n);
+		return NULL;
+	}
+	mp_int_to_unsigned(bn, n->data, n->bytes);
+	return n;
+}
+
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'.	Following
+ * algorihm hovers 10-70 bits above gpg values.  And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow.  It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+	if (p_bits <= 5120)
+		return p_bits / 10 + 160;
+	else
+		return (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
+					PGP_MPI **c1_p, PGP_MPI **c2_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	int			k_bits;
+	mpz_t	   *m = mpi_to_bn(_m);
+	mpz_t	   *p = mpi_to_bn(pk->pub.elg.p);
+	mpz_t	   *g = mpi_to_bn(pk->pub.elg.g);
+	mpz_t	   *y = mpi_to_bn(pk->pub.elg.y);
+	mpz_t	   *k = mp_new();
+	mpz_t	   *yk = mp_new();
+	mpz_t	   *c1 = mp_new();
+	mpz_t	   *c2 = mp_new();
+
+	if (!m || !p || !g || !y || !k || !yk || !c1 || !c2)
+		goto err;
+
+	/*
+	 * generate k
+	 */
+	k_bits = decide_k_bits(mp_int_count_bits(p));
+	res = mp_px_rand(k_bits, k);
+	if (res < 0)
+		return res;
+
+	/*
+	 * c1 = g^k c2 = m * y^k
+	 */
+	mp_int_exptmod(g, k, p, c1);
+	mp_int_exptmod(y, k, p, yk);
+	mp_modmul(m, yk, p, c2);
+
+	/* result */
+	*c1_p = bn_to_mpi(c1);
+	*c2_p = bn_to_mpi(c2);
+	if (*c1_p && *c2_p)
+		res = 0;
+err:
+	mp_clear_free(c2);
+	mp_clear_free(c1);
+	mp_clear_free(yk);
+	mp_clear_free(k);
+	mp_clear_free(y);
+	mp_clear_free(g);
+	mp_clear_free(p);
+	mp_clear_free(m);
+	return res;
+}
+
+int
+pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
+					PGP_MPI **msg_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	mpz_t	   *c1 = mpi_to_bn(_c1);
+	mpz_t	   *c2 = mpi_to_bn(_c2);
+	mpz_t	   *p = mpi_to_bn(pk->pub.elg.p);
+	mpz_t	   *x = mpi_to_bn(pk->sec.elg.x);
+	mpz_t	   *c1x = mp_new();
+	mpz_t	   *div = mp_new();
+	mpz_t	   *m = mp_new();
+
+	if (!c1 || !c2 || !p || !x || !c1x || !div || !m)
+		goto err;
+
+	/*
+	 * m = c2 / (c1^x)
+	 */
+	mp_int_exptmod(c1, x, p, c1x);
+	mp_int_invmod(c1x, p, div);
+	mp_modmul(c2, div, p, m);
+
+	/* result */
+	*msg_p = bn_to_mpi(m);
+	if (*msg_p)
+		res = 0;
+err:
+	mp_clear_free(m);
+	mp_clear_free(div);
+	mp_clear_free(c1x);
+	mp_clear_free(x);
+	mp_clear_free(p);
+	mp_clear_free(c2);
+	mp_clear_free(c1);
+	return res;
+}
+
+int
+pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	mpz_t	   *m = mpi_to_bn(_m);
+	mpz_t	   *e = mpi_to_bn(pk->pub.rsa.e);
+	mpz_t	   *n = mpi_to_bn(pk->pub.rsa.n);
+	mpz_t	   *c = mp_new();
+
+	if (!m || !e || !n || !c)
+		goto err;
+
+	/*
+	 * c = m ^ e
+	 */
+	mp_int_exptmod(m, e, n, c);
+
+	*c_p = bn_to_mpi(c);
+	if (*c_p)
+		res = 0;
+err:
+	mp_clear_free(c);
+	mp_clear_free(n);
+	mp_clear_free(e);
+	mp_clear_free(m);
+	return res;
+}
+
+int
+pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	mpz_t	   *c = mpi_to_bn(_c);
+	mpz_t	   *d = mpi_to_bn(pk->sec.rsa.d);
+	mpz_t	   *n = mpi_to_bn(pk->pub.rsa.n);
+	mpz_t	   *m = mp_new();
+
+	if (!m || !d || !n || !c)
+		goto err;
+
+	/*
+	 * m = c ^ d
+	 */
+	mp_int_exptmod(c, d, n, m);
+
+	*m_p = bn_to_mpi(m);
+	if (*m_p)
+		res = 0;
+err:
+	mp_clear_free(m);
+	mp_clear_free(n);
+	mp_clear_free(d);
+	mp_clear_free(c);
+	return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-mpi-openssl.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-mpi-openssl.c b/contrib/pgcrypto/pgp-mpi-openssl.c
new file mode 100644
index 0000000..ed41e11
--- /dev/null
+++ b/contrib/pgcrypto/pgp-mpi-openssl.c
@@ -0,0 +1,285 @@
+/*
+ * pgp-mpi-openssl.c
+ *	  OpenPGP MPI functions using OpenSSL BIGNUM code.
+ *
+ * Copyright (c) 2005 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.
+ *
+ * contrib/pgcrypto/pgp-mpi-openssl.c
+ */
+#include "postgres.h"
+
+#include <openssl/bn.h>
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static BIGNUM *
+mpi_to_bn(PGP_MPI *n)
+{
+	BIGNUM	   *bn = BN_bin2bn(n->data, n->bytes, NULL);
+
+	if (!bn)
+		return NULL;
+	if (BN_num_bits(bn) != n->bits)
+	{
+		px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
+				 n->bits, BN_num_bits(bn));
+		BN_clear_free(bn);
+		return NULL;
+	}
+	return bn;
+}
+
+static PGP_MPI *
+bn_to_mpi(BIGNUM *bn)
+{
+	int			res;
+	PGP_MPI    *n;
+
+	res = pgp_mpi_alloc(BN_num_bits(bn), &n);
+	if (res < 0)
+		return NULL;
+
+	if (BN_num_bytes(bn) != n->bytes)
+	{
+		px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
+				 BN_num_bytes(bn), n->bytes);
+		pgp_mpi_free(n);
+		return NULL;
+	}
+	BN_bn2bin(bn, n->data);
+	return n;
+}
+
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'.	Following
+ * algorihm hovers 10-70 bits above gpg values.  And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow.  It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+	if (p_bits <= 5120)
+		return p_bits / 10 + 160;
+	else
+		return (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
+					PGP_MPI **c1_p, PGP_MPI **c2_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	int			k_bits;
+	BIGNUM	   *m = mpi_to_bn(_m);
+	BIGNUM	   *p = mpi_to_bn(pk->pub.elg.p);
+	BIGNUM	   *g = mpi_to_bn(pk->pub.elg.g);
+	BIGNUM	   *y = mpi_to_bn(pk->pub.elg.y);
+	BIGNUM	   *k = BN_new();
+	BIGNUM	   *yk = BN_new();
+	BIGNUM	   *c1 = BN_new();
+	BIGNUM	   *c2 = BN_new();
+	BN_CTX	   *tmp = BN_CTX_new();
+
+	if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp)
+		goto err;
+
+	/*
+	 * generate k
+	 */
+	k_bits = decide_k_bits(BN_num_bits(p));
+	if (!BN_rand(k, k_bits, 0, 0))
+		goto err;
+
+	/*
+	 * c1 = g^k c2 = m * y^k
+	 */
+	if (!BN_mod_exp(c1, g, k, p, tmp))
+		goto err;
+	if (!BN_mod_exp(yk, y, k, p, tmp))
+		goto err;
+	if (!BN_mod_mul(c2, m, yk, p, tmp))
+		goto err;
+
+	/* result */
+	*c1_p = bn_to_mpi(c1);
+	*c2_p = bn_to_mpi(c2);
+	if (*c1_p && *c2_p)
+		res = 0;
+err:
+	if (tmp)
+		BN_CTX_free(tmp);
+	if (c2)
+		BN_clear_free(c2);
+	if (c1)
+		BN_clear_free(c1);
+	if (yk)
+		BN_clear_free(yk);
+	if (k)
+		BN_clear_free(k);
+	if (y)
+		BN_clear_free(y);
+	if (g)
+		BN_clear_free(g);
+	if (p)
+		BN_clear_free(p);
+	if (m)
+		BN_clear_free(m);
+	return res;
+}
+
+int
+pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
+					PGP_MPI **msg_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	BIGNUM	   *c1 = mpi_to_bn(_c1);
+	BIGNUM	   *c2 = mpi_to_bn(_c2);
+	BIGNUM	   *p = mpi_to_bn(pk->pub.elg.p);
+	BIGNUM	   *x = mpi_to_bn(pk->sec.elg.x);
+	BIGNUM	   *c1x = BN_new();
+	BIGNUM	   *div = BN_new();
+	BIGNUM	   *m = BN_new();
+	BN_CTX	   *tmp = BN_CTX_new();
+
+	if (!c1 || !c2 || !p || !x || !c1x || !div || !m || !tmp)
+		goto err;
+
+	/*
+	 * m = c2 / (c1^x)
+	 */
+	if (!BN_mod_exp(c1x, c1, x, p, tmp))
+		goto err;
+	if (!BN_mod_inverse(div, c1x, p, tmp))
+		goto err;
+	if (!BN_mod_mul(m, c2, div, p, tmp))
+		goto err;
+
+	/* result */
+	*msg_p = bn_to_mpi(m);
+	if (*msg_p)
+		res = 0;
+err:
+	if (tmp)
+		BN_CTX_free(tmp);
+	if (m)
+		BN_clear_free(m);
+	if (div)
+		BN_clear_free(div);
+	if (c1x)
+		BN_clear_free(c1x);
+	if (x)
+		BN_clear_free(x);
+	if (p)
+		BN_clear_free(p);
+	if (c2)
+		BN_clear_free(c2);
+	if (c1)
+		BN_clear_free(c1);
+	return res;
+}
+
+int
+pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	BIGNUM	   *m = mpi_to_bn(_m);
+	BIGNUM	   *e = mpi_to_bn(pk->pub.rsa.e);
+	BIGNUM	   *n = mpi_to_bn(pk->pub.rsa.n);
+	BIGNUM	   *c = BN_new();
+	BN_CTX	   *tmp = BN_CTX_new();
+
+	if (!m || !e || !n || !c || !tmp)
+		goto err;
+
+	/*
+	 * c = m ^ e
+	 */
+	if (!BN_mod_exp(c, m, e, n, tmp))
+		goto err;
+
+	*c_p = bn_to_mpi(c);
+	if (*c_p)
+		res = 0;
+err:
+	if (tmp)
+		BN_CTX_free(tmp);
+	if (c)
+		BN_clear_free(c);
+	if (n)
+		BN_clear_free(n);
+	if (e)
+		BN_clear_free(e);
+	if (m)
+		BN_clear_free(m);
+	return res;
+}
+
+int
+pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
+{
+	int			res = PXE_PGP_MATH_FAILED;
+	BIGNUM	   *c = mpi_to_bn(_c);
+	BIGNUM	   *d = mpi_to_bn(pk->sec.rsa.d);
+	BIGNUM	   *n = mpi_to_bn(pk->pub.rsa.n);
+	BIGNUM	   *m = BN_new();
+	BN_CTX	   *tmp = BN_CTX_new();
+
+	if (!m || !d || !n || !c || !tmp)
+		goto err;
+
+	/*
+	 * m = c ^ d
+	 */
+	if (!BN_mod_exp(m, c, d, n, tmp))
+		goto err;
+
+	*m_p = bn_to_mpi(m);
+	if (*m_p)
+		res = 0;
+err:
+	if (tmp)
+		BN_CTX_free(tmp);
+	if (m)
+		BN_clear_free(m);
+	if (n)
+		BN_clear_free(n);
+	if (d)
+		BN_clear_free(d);
+	if (c)
+		BN_clear_free(c);
+	return res;
+}