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;
+}

Reply via email to