You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by rl...@apache.org on 2016/09/07 02:57:44 UTC
[06/13] incubator-hawq git commit: HAWQ-1007. Add the pgcrypto code
into hawq
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgcrypto.sql.in
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgcrypto.sql.in b/contrib/pgcrypto/pgcrypto.sql.in
new file mode 100644
index 0000000..8388e86
--- /dev/null
+++ b/contrib/pgcrypto/pgcrypto.sql.in
@@ -0,0 +1,203 @@
+/* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.sql.in,v 1.15 2007/11/13 04:24:28 momjian Exp $ */
+
+-- Adjust this setting to control where the objects get created.
+SET search_path = public;
+
+CREATE OR REPLACE FUNCTION digest(text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_digest'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION digest(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_digest'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION hmac(text, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_hmac'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION hmac(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_hmac'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION crypt(text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_crypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION gen_salt(text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_gen_salt'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE OR REPLACE FUNCTION gen_salt(text, int4)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE OR REPLACE FUNCTION encrypt(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_encrypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION decrypt(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_decrypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION gen_random_bytes(int4)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_random_bytes'
+LANGUAGE 'C' VOLATILE STRICT;
+
+--
+-- pgp_sym_encrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt(text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_sym_encrypt(data, key, args)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt(text, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_sym_decrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt(bytea, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_sym_decrypt(data, key, args)
+--
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt(bytea, text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_encrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt(text, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_pub_encrypt(data, key, args)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt(text, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_pub_decrypt(data, key)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt(bytea, bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_decrypt(data, key, psw)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_decrypt(data, key, psw, arg)
+--
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- PGP key ID
+--
+CREATE OR REPLACE FUNCTION pgp_key_id(bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp armor
+--
+CREATE OR REPLACE FUNCTION armor(bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_armor'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION dearmor(text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_dearmor'
+LANGUAGE C IMMUTABLE STRICT;
+
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-armor.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-armor.c b/contrib/pgcrypto/pgp-armor.c
new file mode 100644
index 0000000..87adf91
--- /dev/null
+++ b/contrib/pgcrypto/pgp-armor.c
@@ -0,0 +1,383 @@
+/*
+ * pgp-armor.c
+ * PGP ascii-armor.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-armor.c
+ */
+
+#include "postgres.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+/*
+ * BASE64 - duplicated :(
+ */
+
+static const unsigned char _base64[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int
+b64_encode(const uint8 *src, unsigned len, uint8 *dst)
+{
+ uint8 *p,
+ *lend = dst + 76;
+ const uint8 *s,
+ *end = src + len;
+ int pos = 2;
+ unsigned long buf = 0;
+
+ s = src;
+ p = dst;
+
+ while (s < end)
+ {
+ buf |= *s << (pos << 3);
+ pos--;
+ s++;
+
+ /*
+ * write it out
+ */
+ if (pos < 0)
+ {
+ *p++ = _base64[(buf >> 18) & 0x3f];
+ *p++ = _base64[(buf >> 12) & 0x3f];
+ *p++ = _base64[(buf >> 6) & 0x3f];
+ *p++ = _base64[buf & 0x3f];
+
+ pos = 2;
+ buf = 0;
+ }
+ if (p >= lend)
+ {
+ *p++ = '\n';
+ lend = p + 76;
+ }
+ }
+ if (pos != 2)
+ {
+ *p++ = _base64[(buf >> 18) & 0x3f];
+ *p++ = _base64[(buf >> 12) & 0x3f];
+ *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
+ *p++ = '=';
+ }
+
+ return p - dst;
+}
+
+/* probably should use lookup table */
+static int
+b64_decode(const uint8 *src, unsigned len, uint8 *dst)
+{
+ const uint8 *srcend = src + len,
+ *s = src;
+ uint8 *p = dst;
+ char c;
+ unsigned b = 0;
+ unsigned long buf = 0;
+ int pos = 0,
+ end = 0;
+
+ while (s < srcend)
+ {
+ c = *s++;
+ if (c >= 'A' && c <= 'Z')
+ b = c - 'A';
+ else if (c >= 'a' && c <= 'z')
+ b = c - 'a' + 26;
+ else if (c >= '0' && c <= '9')
+ b = c - '0' + 52;
+ else if (c == '+')
+ b = 62;
+ else if (c == '/')
+ b = 63;
+ else if (c == '=')
+ {
+ /*
+ * end sequence
+ */
+ if (!end)
+ {
+ if (pos == 2)
+ end = 1;
+ else if (pos == 3)
+ end = 2;
+ else
+ return PXE_PGP_CORRUPT_ARMOR;
+ }
+ b = 0;
+ }
+ else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ continue;
+ else
+ return PXE_PGP_CORRUPT_ARMOR;
+
+ /*
+ * add it to buffer
+ */
+ buf = (buf << 6) + b;
+ pos++;
+ if (pos == 4)
+ {
+ *p++ = (buf >> 16) & 255;
+ if (end == 0 || end > 1)
+ *p++ = (buf >> 8) & 255;
+ if (end == 0 || end > 2)
+ *p++ = buf & 255;
+ buf = 0;
+ pos = 0;
+ }
+ }
+
+ if (pos != 0)
+ return PXE_PGP_CORRUPT_ARMOR;
+ return p - dst;
+}
+
+static unsigned
+b64_enc_len(unsigned srclen)
+{
+ /*
+ * 3 bytes will be converted to 4, linefeed after 76 chars
+ */
+ return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
+}
+
+static unsigned
+b64_dec_len(unsigned srclen)
+{
+ return (srclen * 3) >> 2;
+}
+
+/*
+ * PGP armor
+ */
+
+static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n\n";
+static const char *armor_footer = "\n-----END PGP MESSAGE-----\n";
+
+/* CRC24 implementation from rfc2440 */
+#define CRC24_INIT 0x00b704ceL
+#define CRC24_POLY 0x01864cfbL
+static long
+crc24(const uint8 *data, unsigned len)
+{
+ unsigned crc = CRC24_INIT;
+ int i;
+
+ while (len--)
+ {
+ crc ^= (*data++) << 16;
+ for (i = 0; i < 8; i++)
+ {
+ crc <<= 1;
+ if (crc & 0x1000000)
+ crc ^= CRC24_POLY;
+ }
+ }
+ return crc & 0xffffffL;
+}
+
+int
+pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst)
+{
+ int n;
+ uint8 *pos = dst;
+ unsigned crc = crc24(src, len);
+
+ n = strlen(armor_header);
+ memcpy(pos, armor_header, n);
+ pos += n;
+
+ n = b64_encode(src, len, pos);
+ pos += n;
+
+ if (*(pos - 1) != '\n')
+ *pos++ = '\n';
+
+ *pos++ = '=';
+ pos[3] = _base64[crc & 0x3f];
+ crc >>= 6;
+ pos[2] = _base64[crc & 0x3f];
+ crc >>= 6;
+ pos[1] = _base64[crc & 0x3f];
+ crc >>= 6;
+ pos[0] = _base64[crc & 0x3f];
+ pos += 4;
+
+ n = strlen(armor_footer);
+ memcpy(pos, armor_footer, n);
+ pos += n;
+
+ return pos - dst;
+}
+
+static const uint8 *
+find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
+{
+ const uint8 *p = data;
+
+ if (!strlen)
+ return NULL;
+ if (data_end - data < strlen)
+ return NULL;
+ while (p < data_end)
+ {
+ p = memchr(p, str[0], data_end - p);
+ if (p == NULL)
+ return NULL;
+ if (p + strlen > data_end)
+ return NULL;
+ if (memcmp(p, str, strlen) == 0)
+ return p;
+ p++;
+ }
+ return NULL;
+}
+
+static int
+find_header(const uint8 *data, const uint8 *datend,
+ const uint8 **start_p, int is_end)
+{
+ const uint8 *p = data;
+ static const char *start_sep = "-----BEGIN";
+ static const char *end_sep = "-----END";
+ const char *sep = is_end ? end_sep : start_sep;
+
+ /* find header line */
+ while (1)
+ {
+ p = find_str(p, datend, sep, strlen(sep));
+ if (p == NULL)
+ return PXE_PGP_CORRUPT_ARMOR;
+ /* it must start at beginning of line */
+ if (p == data || *(p - 1) == '\n')
+ break;
+ p += strlen(sep);
+ }
+ *start_p = p;
+ p += strlen(sep);
+
+ /* check if header text ok */
+ for (; p < datend && *p != '-'; p++)
+ {
+ /* various junk can be there, but definitely not line-feed */
+ if (*p >= ' ')
+ continue;
+ return PXE_PGP_CORRUPT_ARMOR;
+ }
+ if (datend - p < 5 || memcmp(p, sep, 5) != 0)
+ return PXE_PGP_CORRUPT_ARMOR;
+ p += 5;
+
+ /* check if at end of line */
+ if (p < datend)
+ {
+ if (*p != '\n' && *p != '\r')
+ return PXE_PGP_CORRUPT_ARMOR;
+ if (*p == '\r')
+ p++;
+ if (p < datend && *p == '\n')
+ p++;
+ }
+ return p - *start_p;
+}
+
+int
+pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
+{
+ const uint8 *p = src;
+ const uint8 *data_end = src + len;
+ long crc;
+ const uint8 *base64_start,
+ *armor_end;
+ const uint8 *base64_end = NULL;
+ uint8 buf[4];
+ int hlen;
+ int res = PXE_PGP_CORRUPT_ARMOR;
+
+ /* armor start */
+ hlen = find_header(src, data_end, &p, 0);
+ if (hlen <= 0)
+ goto out;
+ p += hlen;
+
+ /* armor end */
+ hlen = find_header(p, data_end, &armor_end, 1);
+ if (hlen <= 0)
+ goto out;
+
+ /* skip comments - find empty line */
+ while (p < armor_end && *p != '\n' && *p != '\r')
+ {
+ p = memchr(p, '\n', armor_end - p);
+ if (!p)
+ goto out;
+
+ /* step to start of next line */
+ p++;
+ }
+ base64_start = p;
+
+ /* find crc pos */
+ for (p = armor_end; p >= base64_start; p--)
+ if (*p == '=')
+ {
+ base64_end = p - 1;
+ break;
+ }
+ if (base64_end == NULL)
+ goto out;
+
+ /* decode crc */
+ if (b64_decode(p + 1, 4, buf) != 3)
+ goto out;
+ crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
+
+ /* decode data */
+ res = b64_decode(base64_start, base64_end - base64_start, dst);
+
+ /* check crc */
+ if (res >= 0 && crc24(dst, res) != crc)
+ res = PXE_PGP_CORRUPT_ARMOR;
+out:
+ return res;
+}
+
+unsigned
+pgp_armor_enc_len(unsigned len)
+{
+ return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
+}
+
+unsigned
+pgp_armor_dec_len(unsigned len)
+{
+ return b64_dec_len(len);
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-cfb.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-cfb.c b/contrib/pgcrypto/pgp-cfb.c
new file mode 100644
index 0000000..7cf9bf0
--- /dev/null
+++ b/contrib/pgcrypto/pgp-cfb.c
@@ -0,0 +1,265 @@
+/*
+ * pgp-cfb.c
+ * Implements both normal and PGP-specific CFB mode.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-cfb.c
+ */
+
+#include "postgres.h"
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+typedef int (*mix_data_t) (PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
+
+struct PGP_CFB
+{
+ PX_Cipher *ciph;
+ int block_size;
+ int pos;
+ int block_no;
+ int resync;
+ uint8 fr[PGP_MAX_BLOCK];
+ uint8 fre[PGP_MAX_BLOCK];
+ uint8 encbuf[PGP_MAX_BLOCK];
+};
+
+int
+pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
+ int resync, uint8 *iv)
+{
+ int res;
+ PX_Cipher *ciph;
+ PGP_CFB *ctx;
+
+ res = pgp_load_cipher(algo, &ciph);
+ if (res < 0)
+ return res;
+
+ res = px_cipher_init(ciph, key, key_len, NULL);
+ if (res < 0)
+ {
+ px_cipher_free(ciph);
+ return res;
+ }
+
+ ctx = px_alloc(sizeof(*ctx));
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->ciph = ciph;
+ ctx->block_size = px_cipher_block_size(ciph);
+ ctx->resync = resync;
+
+ if (iv)
+ memcpy(ctx->fr, iv, ctx->block_size);
+
+ *ctx_p = ctx;
+ return 0;
+}
+
+void
+pgp_cfb_free(PGP_CFB *ctx)
+{
+ px_cipher_free(ctx->ciph);
+ memset(ctx, 0, sizeof(*ctx));
+ px_free(ctx);
+}
+
+/*
+ * Data processing for normal CFB. (PGP_PKT_SYMENCRYPTED_DATA_MDC)
+ */
+static int
+mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+ int i;
+
+ for (i = ctx->pos; i < ctx->pos + len; i++)
+ *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+ ctx->pos += len;
+ return len;
+}
+
+static int
+mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+ int i;
+
+ for (i = ctx->pos; i < ctx->pos + len; i++)
+ {
+ ctx->encbuf[i] = *data++;
+ *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+ }
+ ctx->pos += len;
+ return len;
+}
+
+/*
+ * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
+ *
+ * The goal is to hide the horror from the rest of the code,
+ * thus its all concentrated here.
+ */
+static int
+mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+ int i,
+ n;
+
+ /* block #2 is 2 bytes long */
+ if (ctx->block_no == 2)
+ {
+ n = 2 - ctx->pos;
+ if (len < n)
+ n = len;
+ for (i = ctx->pos; i < ctx->pos + n; i++)
+ *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+
+ ctx->pos += n;
+ len -= n;
+
+ if (ctx->pos == 2)
+ {
+ memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
+ memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
+ ctx->pos = 0;
+ return n;
+ }
+ }
+ for (i = ctx->pos; i < ctx->pos + len; i++)
+ *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+ ctx->pos += len;
+ return len;
+}
+
+static int
+mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+ int i,
+ n;
+
+ /* block #2 is 2 bytes long */
+ if (ctx->block_no == 2)
+ {
+ n = 2 - ctx->pos;
+ if (len < n)
+ n = len;
+ for (i = ctx->pos; i < ctx->pos + n; i++)
+ {
+ ctx->encbuf[i] = *data++;
+ *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+ }
+ ctx->pos += n;
+ len -= n;
+
+ if (ctx->pos == 2)
+ {
+ memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
+ memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
+ ctx->pos = 0;
+ return n;
+ }
+ }
+ for (i = ctx->pos; i < ctx->pos + len; i++)
+ {
+ ctx->encbuf[i] = *data++;
+ *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+ }
+ ctx->pos += len;
+ return len;
+}
+
+/*
+ * common code for both encrypt and decrypt.
+ */
+static int
+cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
+ mix_data_t mix_data)
+{
+ int n;
+ int res;
+
+ while (len > 0 && ctx->pos > 0)
+ {
+ n = ctx->block_size - ctx->pos;
+ if (len < n)
+ n = len;
+
+ n = mix_data(ctx, data, n, dst);
+ data += n;
+ dst += n;
+ len -= n;
+
+ if (ctx->pos == ctx->block_size)
+ {
+ memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
+ ctx->pos = 0;
+ }
+ }
+
+ while (len > 0)
+ {
+ px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, ctx->fre);
+ if (ctx->block_no < 5)
+ ctx->block_no++;
+
+ n = ctx->block_size;
+ if (len < n)
+ n = len;
+
+ res = mix_data(ctx, data, n, dst);
+ data += res;
+ dst += res;
+ len -= res;
+
+ if (ctx->pos == ctx->block_size)
+ {
+ memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
+ ctx->pos = 0;
+ }
+ }
+ return 0;
+}
+
+/*
+ * public interface
+ */
+
+int
+pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+ mix_data_t mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
+
+ return cfb_process(ctx, data, len, dst, mix);
+}
+
+int
+pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+ mix_data_t mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
+
+ return cfb_process(ctx, data, len, dst, mix);
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-compress.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c
new file mode 100644
index 0000000..c592453
--- /dev/null
+++ b/contrib/pgcrypto/pgp-compress.c
@@ -0,0 +1,329 @@
+/*
+ * pgp-compress.c
+ * ZIP and ZLIB compression via zlib.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-compress.c
+ */
+
+#include "postgres.h"
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+
+/*
+ * Compressed pkt writer
+ */
+
+#ifdef HAVE_LIBZ
+
+#include <zlib.h>
+
+#define ZIP_OUT_BUF 8192
+#define ZIP_IN_BLOCK 8192
+
+struct ZipStat
+{
+ uint8 type;
+ int buf_len;
+ int hdr_done;
+ z_stream stream;
+ uint8 buf[ZIP_OUT_BUF];
+};
+
+static void *
+z_alloc(void *priv, unsigned n_items, unsigned item_len)
+{
+ return px_alloc(n_items * item_len);
+}
+
+static void
+z_free(void *priv, void *addr)
+{
+ px_free(addr);
+}
+
+static int
+compress_init(PushFilter *next, void *init_arg, void **priv_p)
+{
+ int res;
+ struct ZipStat *st;
+ PGP_Context *ctx = init_arg;
+ uint8 type = ctx->compress_algo;
+
+ if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
+ return PXE_PGP_UNSUPPORTED_COMPR;
+
+ /*
+ * init
+ */
+ st = px_alloc(sizeof(*st));
+ memset(st, 0, sizeof(*st));
+ st->buf_len = ZIP_OUT_BUF;
+ st->stream.zalloc = z_alloc;
+ st->stream.zfree = z_free;
+
+ if (type == PGP_COMPR_ZIP)
+ res = deflateInit2(&st->stream, ctx->compress_level,
+ Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+ else
+ res = deflateInit(&st->stream, ctx->compress_level);
+ if (res != Z_OK)
+ {
+ px_free(st);
+ return PXE_PGP_COMPRESSION_ERROR;
+ }
+ *priv_p = st;
+
+ return ZIP_IN_BLOCK;
+}
+
+/* writes compressed data packet */
+
+/* can handle zero-len incoming data, but shouldn't */
+static int
+compress_process(PushFilter *next, void *priv, const uint8 *data, int len)
+{
+ int res,
+ n_out;
+ struct ZipStat *st = priv;
+
+ /*
+ * process data
+ */
+ while (len > 0)
+ {
+ st->stream.next_in = (void *) data;
+ st->stream.avail_in = len;
+ st->stream.next_out = st->buf;
+ st->stream.avail_out = st->buf_len;
+ res = deflate(&st->stream, 0);
+ if (res != Z_OK)
+ return PXE_PGP_COMPRESSION_ERROR;
+
+ n_out = st->buf_len - st->stream.avail_out;
+ if (n_out > 0)
+ {
+ res = pushf_write(next, st->buf, n_out);
+ if (res < 0)
+ return res;
+ }
+ len = st->stream.avail_in;
+ }
+
+ return 0;
+}
+
+static int
+compress_flush(PushFilter *next, void *priv)
+{
+ int res,
+ zres,
+ n_out;
+ struct ZipStat *st = priv;
+
+ st->stream.next_in = NULL;
+ st->stream.avail_in = 0;
+ while (1)
+ {
+ st->stream.next_out = st->buf;
+ st->stream.avail_out = st->buf_len;
+ zres = deflate(&st->stream, Z_FINISH);
+ if (zres != Z_STREAM_END && zres != Z_OK)
+ return PXE_PGP_COMPRESSION_ERROR;
+ n_out = st->buf_len - st->stream.avail_out;
+ if (n_out > 0)
+ {
+ res = pushf_write(next, st->buf, n_out);
+ if (res < 0)
+ return res;
+ }
+ if (zres == Z_STREAM_END)
+ break;
+ }
+ return 0;
+}
+
+static void
+compress_free(void *priv)
+{
+ struct ZipStat *st = priv;
+
+ deflateEnd(&st->stream);
+ memset(st, 0, sizeof(*st));
+ px_free(st);
+}
+
+static const PushFilterOps
+ compress_filter = {
+ compress_init, compress_process, compress_flush, compress_free
+};
+
+int
+pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
+{
+ return pushf_create(res, &compress_filter, ctx, dst);
+}
+
+/*
+ * Decompress
+ */
+struct DecomprData
+{
+ int buf_len; /* = ZIP_OUT_BUF */
+ int buf_data; /* available data */
+ uint8 *pos;
+ z_stream stream;
+ int eof;
+ uint8 buf[ZIP_OUT_BUF];
+};
+
+static int
+decompress_init(void **priv_p, void *arg, PullFilter *src)
+{
+ PGP_Context *ctx = arg;
+ struct DecomprData *dec;
+ int res;
+
+ if (ctx->compress_algo != PGP_COMPR_ZLIB
+ && ctx->compress_algo != PGP_COMPR_ZIP)
+ return PXE_PGP_UNSUPPORTED_COMPR;
+
+ dec = px_alloc(sizeof(*dec));
+ memset(dec, 0, sizeof(*dec));
+ dec->buf_len = ZIP_OUT_BUF;
+ *priv_p = dec;
+
+ dec->stream.zalloc = z_alloc;
+ dec->stream.zfree = z_free;
+
+ if (ctx->compress_algo == PGP_COMPR_ZIP)
+ res = inflateInit2(&dec->stream, -15);
+ else
+ res = inflateInit(&dec->stream);
+ if (res != Z_OK)
+ {
+ px_free(dec);
+ px_debug("decompress_init: inflateInit error");
+ return PXE_PGP_COMPRESSION_ERROR;
+ }
+
+ return 0;
+}
+
+static int
+decompress_read(void *priv, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+{
+ int res;
+ int flush;
+ struct DecomprData *dec = priv;
+
+restart:
+ if (dec->buf_data > 0)
+ {
+ if (len > dec->buf_data)
+ len = dec->buf_data;
+ *data_p = dec->pos;
+ dec->pos += len;
+ dec->buf_data -= len;
+ return len;
+ }
+
+ if (dec->eof)
+ return 0;
+
+ if (dec->stream.avail_in == 0)
+ {
+ uint8 *tmp;
+
+ res = pullf_read(src, 8192, &tmp);
+ if (res < 0)
+ return res;
+ dec->stream.next_in = tmp;
+ dec->stream.avail_in = res;
+ }
+
+ dec->stream.next_out = dec->buf;
+ dec->stream.avail_out = dec->buf_len;
+ dec->pos = dec->buf;
+
+ /*
+ * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
+ * it anyway (Z_NO_FLUSH), but seems to reserve the right not to. So lets
+ * follow the API.
+ */
+ flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
+ res = inflate(&dec->stream, flush);
+ if (res != Z_OK && res != Z_STREAM_END)
+ {
+ px_debug("decompress_read: inflate error: %d", res);
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ dec->buf_data = dec->buf_len - dec->stream.avail_out;
+ if (res == Z_STREAM_END)
+ dec->eof = 1;
+ goto restart;
+}
+
+static void
+decompress_free(void *priv)
+{
+ struct DecomprData *dec = priv;
+
+ inflateEnd(&dec->stream);
+ memset(dec, 0, sizeof(*dec));
+ px_free(dec);
+}
+
+static const PullFilterOps
+ decompress_filter = {
+ decompress_init, decompress_read, decompress_free
+};
+
+int
+pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
+{
+ return pullf_create(res, &decompress_filter, ctx, src);
+}
+#else /* !HAVE_ZLIB */
+
+int
+pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
+{
+ return PXE_PGP_UNSUPPORTED_COMPR;
+}
+
+int
+pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
+{
+ return PXE_PGP_UNSUPPORTED_COMPR;
+}
+
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-decrypt.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-decrypt.c b/contrib/pgcrypto/pgp-decrypt.c
new file mode 100644
index 0000000..c9aa6cd
--- /dev/null
+++ b/contrib/pgcrypto/pgp-decrypt.c
@@ -0,0 +1,1188 @@
+/*
+ * pgp-decrypt.c
+ * OpenPGP decrypt.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-decrypt.c
+ */
+
+#include "postgres.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+#define NO_CTX_SIZE 0
+#define ALLOW_CTX_SIZE 1
+#define NO_COMPR 0
+#define ALLOW_COMPR 1
+#define NO_MDC 0
+#define NEED_MDC 1
+
+#define PKT_NORMAL 1
+#define PKT_STREAM 2
+#define PKT_CONTEXT 3
+
+#define MAX_CHUNK (16*1024*1024)
+
+static int
+parse_new_len(PullFilter *src, int *len_p)
+{
+ uint8 b;
+ int len;
+ int pkttype = PKT_NORMAL;
+
+ GETBYTE(src, b);
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b <= 223)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else if (b == 255)
+ {
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+ else
+ {
+ len = 1 << (b & 0x1F);
+ pkttype = PKT_STREAM;
+ }
+
+ if (len < 0 || len > MAX_CHUNK)
+ {
+ px_debug("parse_new_len: weird length");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ *len_p = len;
+ return pkttype;
+}
+
+static int
+parse_old_len(PullFilter *src, int *len_p, int lentype)
+{
+ uint8 b;
+ int len;
+
+ GETBYTE(src, b);
+ len = b;
+
+ if (lentype == 1)
+ {
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+ else if (lentype == 2)
+ {
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ if (len < 0 || len > MAX_CHUNK)
+ {
+ px_debug("parse_old_len: weird length");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ *len_p = len;
+ return PKT_NORMAL;
+}
+
+/* returns pkttype or 0 on eof */
+int
+pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
+{
+ int lentype;
+ int res;
+ uint8 *p;
+
+ /* EOF is normal here, thus we dont use GETBYTE */
+ res = pullf_read(src, 1, &p);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ return 0;
+
+ if ((*p & 0x80) == 0)
+ {
+ px_debug("pgp_parse_pkt_hdr: not pkt hdr");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (*p & 0x40)
+ {
+ *tag = *p & 0x3f;
+ res = parse_new_len(src, len_p);
+ }
+ else
+ {
+ lentype = *p & 3;
+ *tag = (*p >> 2) & 0x0F;
+ if (lentype == 3)
+ res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
+ else
+ res = parse_old_len(src, len_p, lentype);
+ }
+ return res;
+}
+
+/*
+ * Packet reader
+ */
+struct PktData
+{
+ int type;
+ int len;
+};
+
+static int
+pktreader_pull(void *priv, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+{
+ int res;
+ struct PktData *pkt = priv;
+
+ /* PKT_CONTEXT means: whatever there is */
+ if (pkt->type == PKT_CONTEXT)
+ return pullf_read(src, len, data_p);
+
+ if (pkt->len == 0)
+ {
+ /* this was last chunk in stream */
+ if (pkt->type == PKT_NORMAL)
+ return 0;
+
+ /* next chunk in stream */
+ res = parse_new_len(src, &pkt->len);
+ if (res < 0)
+ return res;
+ pkt->type = res;
+ }
+
+ if (len > pkt->len)
+ len = pkt->len;
+
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ pkt->len -= res;
+
+ return res;
+}
+
+static void
+pktreader_free(void *priv)
+{
+ struct PktData *pkt = priv;
+
+ memset(pkt, 0, sizeof(*pkt));
+ px_free(pkt);
+}
+
+static struct PullFilterOps pktreader_filter = {
+ NULL, pktreader_pull, pktreader_free
+};
+
+/* needs helper function to pass several parameters */
+int
+pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
+ int pkttype, PGP_Context *ctx)
+{
+ int res;
+ struct PktData *pkt = px_alloc(sizeof(*pkt));
+
+ pkt->type = pkttype;
+ pkt->len = len;
+ res = pullf_create(pf_p, &pktreader_filter, pkt, src);
+ if (res < 0)
+ px_free(pkt);
+ return res;
+}
+
+/*
+ * Prefix check filter
+ */
+
+static int
+prefix_init(void **priv_p, void *arg, PullFilter *src)
+{
+ PGP_Context *ctx = arg;
+ int len;
+ int res;
+ uint8 *buf;
+ uint8 tmpbuf[PGP_MAX_BLOCK + 2];
+
+ len = pgp_get_cipher_block_size(ctx->cipher_algo);
+ if (len > sizeof(tmpbuf))
+ return PXE_BUG;
+
+ res = pullf_read_max(src, len + 2, &buf, tmpbuf);
+ if (res < 0)
+ return res;
+ if (res != len + 2)
+ {
+ px_debug("prefix_init: short read");
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
+ {
+ px_debug("prefix_init: corrupt prefix");
+
+ /*
+ * The original purpose of the 2-byte check was to show user a
+ * friendly "wrong key" message. This made following possible:
+ *
+ * "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge
+ * Mister and Robert Zuccherato
+ *
+ * To avoid being 'oracle', we delay reporting, which basically means
+ * we prefer to run into corrupt packet header.
+ *
+ * We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is
+ * possibility of attack via timing, so we don't.
+ */
+ ctx->corrupt_prefix = 1;
+ }
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ return 0;
+}
+
+static struct PullFilterOps prefix_filter = {
+ prefix_init, NULL, NULL
+};
+
+
+/*
+ * Decrypt filter
+ */
+
+static int
+decrypt_init(void **priv_p, void *arg, PullFilter *src)
+{
+ PGP_CFB *cfb = arg;
+
+ *priv_p = cfb;
+
+ /* we need to write somewhere, so ask for a buffer */
+ return 4096;
+}
+
+static int
+decrypt_read(void *priv, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+{
+ PGP_CFB *cfb = priv;
+ uint8 *tmp;
+ int res;
+
+ res = pullf_read(src, len, &tmp);
+ if (res > 0)
+ {
+ pgp_cfb_decrypt(cfb, tmp, res, buf);
+ *data_p = buf;
+ }
+ return res;
+}
+
+struct PullFilterOps pgp_decrypt_filter = {
+ decrypt_init, decrypt_read, NULL
+};
+
+
+/*
+ * MDC hasher filter
+ */
+
+static int
+mdc_init(void **priv_p, void *arg, PullFilter *src)
+{
+ PGP_Context *ctx = arg;
+
+ *priv_p = ctx;
+ return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
+}
+
+static void
+mdc_free(void *priv)
+{
+ PGP_Context *ctx = priv;
+
+ if (ctx->use_mdcbuf_filter)
+ return;
+ px_md_free(ctx->mdc_ctx);
+ ctx->mdc_ctx = NULL;
+}
+
+static int
+mdc_finish(PGP_Context *ctx, PullFilter *src,
+ int len, uint8 **data_p)
+{
+ int res;
+ uint8 hash[20];
+ uint8 tmpbuf[22];
+
+ if (len + 1 > sizeof(tmpbuf))
+ return PXE_BUG;
+
+ /* read data */
+ res = pullf_read_max(src, len + 1, data_p, tmpbuf);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ {
+ if (ctx->mdc_checked == 0)
+ {
+ px_debug("no mdc");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ return 0;
+ }
+
+ /* safety check */
+ if (ctx->in_mdc_pkt > 1)
+ {
+ px_debug("mdc_finish: several times here?");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ ctx->in_mdc_pkt++;
+
+ /* is the packet sane? */
+ if (res != 20)
+ {
+ px_debug("mdc_finish: read failed, res=%d", res);
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ /*
+ * ok, we got the hash, now check
+ */
+ px_md_finish(ctx->mdc_ctx, hash);
+ res = memcmp(hash, *data_p, 20);
+ memset(hash, 0, 20);
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ if (res != 0)
+ {
+ px_debug("mdc_finish: mdc failed");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ ctx->mdc_checked = 1;
+ return len;
+}
+
+static int
+mdc_read(void *priv, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+{
+ int res;
+ PGP_Context *ctx = priv;
+
+ /* skip this filter? */
+ if (ctx->use_mdcbuf_filter)
+ return pullf_read(src, len, data_p);
+
+ if (ctx->in_mdc_pkt)
+ return mdc_finish(ctx, src, len, data_p);
+
+ res = pullf_read(src, len, data_p);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ {
+ px_debug("mdc_read: unexpected eof");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ px_md_update(ctx->mdc_ctx, *data_p, res);
+
+ return res;
+}
+
+static struct PullFilterOps mdc_filter = {
+ mdc_init, mdc_read, mdc_free
+};
+
+
+/*
+ * Combined Pkt reader and MDC hasher.
+ *
+ * For the case of SYMENCRYPTED_MDC packet, where
+ * the data part has 'context length', which means
+ * that data packet ends 22 bytes before end of parent
+ * packet, which is silly.
+ */
+#define MDCBUF_LEN 8192
+struct MDCBufData
+{
+ PGP_Context *ctx;
+ int eof;
+ int buflen;
+ int avail;
+ uint8 *pos;
+ int mdc_avail;
+ uint8 mdc_buf[22];
+ uint8 buf[MDCBUF_LEN];
+};
+
+static int
+mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
+{
+ PGP_Context *ctx = arg;
+ struct MDCBufData *st;
+
+ st = px_alloc(sizeof(*st));
+ memset(st, 0, sizeof(*st));
+ st->buflen = sizeof(st->buf);
+ st->ctx = ctx;
+ *priv_p = st;
+
+ /* take over the work of mdc_filter */
+ ctx->use_mdcbuf_filter = 1;
+
+ return 0;
+}
+
+static int
+mdcbuf_finish(struct MDCBufData * st)
+{
+ uint8 hash[20];
+ int res;
+
+ st->eof = 1;
+
+ if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
+ {
+ px_debug("mdcbuf_finish: bad MDC pkt hdr");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
+ px_md_finish(st->ctx->mdc_ctx, hash);
+ res = memcmp(hash, st->mdc_buf + 2, 20);
+ memset(hash, 0, 20);
+ if (res)
+ {
+ px_debug("mdcbuf_finish: MDC does not match");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ return res;
+}
+
+static void
+mdcbuf_load_data(struct MDCBufData * st, uint8 *src, int len)
+{
+ uint8 *dst = st->pos + st->avail;
+
+ memcpy(dst, src, len);
+ px_md_update(st->ctx->mdc_ctx, src, len);
+ st->avail += len;
+}
+
+static void
+mdcbuf_load_mdc(struct MDCBufData * st, uint8 *src, int len)
+{
+ memmove(st->mdc_buf + st->mdc_avail, src, len);
+ st->mdc_avail += len;
+}
+
+static int
+mdcbuf_refill(struct MDCBufData * st, PullFilter *src)
+{
+ uint8 *data;
+ int res;
+ int need;
+
+ /* put avail data in start */
+ if (st->avail > 0 && st->pos != st->buf)
+ memmove(st->buf, st->pos, st->avail);
+ st->pos = st->buf;
+
+ /* read new data */
+ need = st->buflen + 22 - st->avail - st->mdc_avail;
+ res = pullf_read(src, need, &data);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ return mdcbuf_finish(st);
+
+ /* add to buffer */
+ if (res >= 22)
+ {
+ mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
+ st->mdc_avail = 0;
+
+ mdcbuf_load_data(st, data, res - 22);
+ mdcbuf_load_mdc(st, data + res - 22, 22);
+ }
+ else
+ {
+ int canmove = st->mdc_avail + res - 22;
+
+ if (canmove > 0)
+ {
+ mdcbuf_load_data(st, st->mdc_buf, canmove);
+ st->mdc_avail -= canmove;
+ memmove(st->mdc_buf, st->mdc_buf + canmove, st->mdc_avail);
+ }
+ mdcbuf_load_mdc(st, data, res);
+ }
+ return 0;
+}
+
+static int
+mdcbuf_read(void *priv, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+{
+ struct MDCBufData *st = priv;
+ int res;
+
+ if (!st->eof && len > st->avail)
+ {
+ res = mdcbuf_refill(st, src);
+ if (res < 0)
+ return res;
+ }
+
+ if (len > st->avail)
+ len = st->avail;
+
+ *data_p = st->pos;
+ st->pos += len;
+ st->avail -= len;
+ return len;
+}
+
+static void
+mdcbuf_free(void *priv)
+{
+ struct MDCBufData *st = priv;
+
+ px_md_free(st->ctx->mdc_ctx);
+ st->ctx->mdc_ctx = NULL;
+ memset(st, 0, sizeof(*st));
+ px_free(st);
+}
+
+static struct PullFilterOps mdcbuf_filter = {
+ mdcbuf_init, mdcbuf_read, mdcbuf_free
+};
+
+
+/*
+ * Decrypt separate session key
+ */
+static int
+decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
+{
+ int res;
+ uint8 algo;
+ PGP_CFB *cfb;
+
+ res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
+ ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
+ if (res < 0)
+ return res;
+
+ pgp_cfb_decrypt(cfb, src, 1, &algo);
+ src++;
+ len--;
+
+ pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
+ pgp_cfb_free(cfb);
+ ctx->sess_key_len = len;
+ ctx->cipher_algo = algo;
+
+ if (pgp_get_cipher_key_size(algo) != len)
+ {
+ px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
+ algo, pgp_get_cipher_key_size(algo), len);
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ return 0;
+}
+
+/*
+ * Handle key packet
+ */
+static int
+parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
+{
+ uint8 *p;
+ int res;
+ uint8 tmpbuf[PGP_MAX_KEY + 2];
+ uint8 ver;
+
+ GETBYTE(src, ver);
+ GETBYTE(src, ctx->s2k_cipher_algo);
+ if (ver != 4)
+ {
+ px_debug("bad key pkt ver");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ /*
+ * read S2K info
+ */
+ res = pgp_s2k_read(src, &ctx->s2k);
+ if (res < 0)
+ return res;
+ ctx->s2k_mode = ctx->s2k.mode;
+ ctx->s2k_digest_algo = ctx->s2k.digest_algo;
+
+ /*
+ * generate key from password
+ */
+ res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
+ ctx->sym_key, ctx->sym_key_len);
+ if (res < 0)
+ return res;
+
+ /*
+ * do we have separate session key?
+ */
+ res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
+ if (res < 0)
+ return res;
+
+ if (res == 0)
+ {
+ /*
+ * no, s2k key is session key
+ */
+ memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
+ ctx->sess_key_len = ctx->s2k.key_len;
+ ctx->cipher_algo = ctx->s2k_cipher_algo;
+ res = 0;
+ ctx->use_sess_key = 0;
+ }
+ else
+ {
+ /*
+ * yes, decrypt it
+ */
+ if (res < 17 || res > PGP_MAX_KEY + 1)
+ {
+ px_debug("expect key, but bad data");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ ctx->use_sess_key = 1;
+ res = decrypt_key(ctx, p, res);
+ }
+
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ return res;
+}
+
+static int
+copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
+{
+ uint8 *data_end = data + len;
+ uint8 tmpbuf[1024];
+ uint8 *tmp_end = tmpbuf + sizeof(tmpbuf);
+ uint8 *p;
+ int res;
+
+ p = tmpbuf;
+ if (*got_cr)
+ {
+ if (*data != '\n')
+ *p++ = '\r';
+ *got_cr = 0;
+ }
+ while (data < data_end)
+ {
+ if (*data == '\r')
+ {
+ if (data + 1 < data_end)
+ {
+ if (*(data + 1) == '\n')
+ data++;
+ }
+ else
+ {
+ *got_cr = 1;
+ break;
+ }
+ }
+ *p++ = *data++;
+ if (p >= tmp_end)
+ {
+ res = mbuf_append(dst, tmpbuf, p - tmpbuf);
+ if (res < 0)
+ return res;
+ p = tmpbuf;
+ }
+ }
+ if (p - tmpbuf > 0)
+ {
+ res = mbuf_append(dst, tmpbuf, p - tmpbuf);
+ if (res < 0)
+ return res;
+ }
+ return 0;
+}
+
+static int
+parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+{
+ int type;
+ int name_len;
+ int res;
+ uint8 *buf;
+ uint8 tmpbuf[4];
+ int got_cr = 0;
+
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, name_len);
+
+ /* skip name */
+ while (name_len > 0)
+ {
+ res = pullf_read(pkt, name_len, &buf);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ break;
+ name_len -= res;
+ }
+ if (name_len > 0)
+ {
+ px_debug("parse_literal_data: unexpected eof");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ /* skip date */
+ res = pullf_read_max(pkt, 4, &buf, tmpbuf);
+ if (res != 4)
+ {
+ px_debug("parse_literal_data: unexpected eof");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ memset(tmpbuf, 0, 4);
+
+ /* check if text */
+ if (ctx->text_mode)
+ if (type != 't' && type != 'u')
+ {
+ px_debug("parse_literal_data: data type=%c", type);
+ return PXE_PGP_NOT_TEXT;
+ }
+
+ ctx->unicode_mode = (type == 'u') ? 1 : 0;
+
+ /* read data */
+ while (1)
+ {
+ res = pullf_read(pkt, 32 * 1024, &buf);
+ if (res <= 0)
+ break;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ res = copy_crlf(dst, buf, res, &got_cr);
+ else
+ res = mbuf_append(dst, buf, res);
+ if (res < 0)
+ break;
+ }
+ if (res >= 0 && got_cr)
+ res = mbuf_append(dst, (const uint8 *) "\r", 1);
+ return res;
+}
+
+/* process_data_packets and parse_compressed_data call each other */
+static int process_data_packets(PGP_Context *ctx, MBuf *dst,
+ PullFilter *src, int allow_compr, int need_mdc);
+
+static int
+parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+{
+ int res;
+ uint8 type;
+ PullFilter *pf_decompr;
+
+ GETBYTE(pkt, type);
+
+ ctx->compress_algo = type;
+ switch (type)
+ {
+ case PGP_COMPR_NONE:
+ res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC);
+ break;
+
+ case PGP_COMPR_ZIP:
+ case PGP_COMPR_ZLIB:
+ res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
+ if (res >= 0)
+ {
+ res = process_data_packets(ctx, dst, pf_decompr,
+ NO_COMPR, NO_MDC);
+ pullf_free(pf_decompr);
+ }
+ break;
+
+ case PGP_COMPR_BZIP2:
+ px_debug("parse_compressed_data: bzip2 unsupported");
+ res = PXE_PGP_UNSUPPORTED_COMPR;
+ break;
+
+ default:
+ px_debug("parse_compressed_data: unknown compr type");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ return res;
+}
+
+static int
+process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
+ int allow_compr, int need_mdc)
+{
+ uint8 tag;
+ int len,
+ res;
+ int got_data = 0;
+ int got_mdc = 0;
+ PullFilter *pkt = NULL;
+ uint8 *tmp;
+
+ while (1)
+ {
+ res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
+ if (res <= 0)
+ break;
+
+
+ /* mdc packet should be last */
+ if (got_mdc)
+ {
+ px_debug("process_data_packets: data after mdc");
+ res = PXE_PGP_CORRUPT_DATA;
+ break;
+ }
+
+ /* context length inside SYMENC_MDC needs special handling */
+ if (need_mdc && res == PKT_CONTEXT)
+ res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
+ else
+ res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
+ if (res < 0)
+ break;
+
+ switch (tag)
+ {
+ case PGP_PKT_LITERAL_DATA:
+ got_data = 1;
+ res = parse_literal_data(ctx, dst, pkt);
+ break;
+ case PGP_PKT_COMPRESSED_DATA:
+ if (allow_compr == 0)
+ {
+ px_debug("process_data_packets: unexpected compression");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ else if (got_data)
+ {
+ /*
+ * compr data must be alone
+ */
+ px_debug("process_data_packets: only one cmpr pkt allowed");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ else
+ {
+ got_data = 1;
+ res = parse_compressed_data(ctx, dst, pkt);
+ }
+ break;
+ case PGP_PKT_MDC:
+ if (need_mdc == NO_MDC)
+ {
+ px_debug("process_data_packets: unexpected MDC");
+ res = PXE_PGP_CORRUPT_DATA;
+ break;
+ }
+
+ /* notify mdc_filter */
+ ctx->in_mdc_pkt = 1;
+
+ res = pullf_read(pkt, 8192, &tmp);
+ if (res > 0)
+ got_mdc = 1;
+ break;
+ default:
+ px_debug("process_data_packets: unexpected pkt tag=%d", tag);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ pullf_free(pkt);
+ pkt = NULL;
+
+ if (res < 0)
+ break;
+ }
+
+ if (pkt)
+ pullf_free(pkt);
+
+ if (res < 0)
+ return res;
+
+ if (!got_data)
+ {
+ px_debug("process_data_packets: no data");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter)
+ {
+ px_debug("process_data_packets: got no mdc");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ return res;
+}
+
+static int
+parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
+{
+ int res;
+ PGP_CFB *cfb = NULL;
+ PullFilter *pf_decrypt = NULL;
+ PullFilter *pf_prefix = NULL;
+
+ res = pgp_cfb_create(&cfb, ctx->cipher_algo,
+ ctx->sess_key, ctx->sess_key_len, 1, NULL);
+ if (res < 0)
+ goto out;
+
+ res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
+ if (res < 0)
+ goto out;
+
+ res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
+ if (res < 0)
+ goto out;
+
+ res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);
+
+out:
+ if (pf_prefix)
+ pullf_free(pf_prefix);
+ if (pf_decrypt)
+ pullf_free(pf_decrypt);
+ if (cfb)
+ pgp_cfb_free(cfb);
+
+ return res;
+}
+
+static int
+parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
+{
+ int res;
+ PGP_CFB *cfb = NULL;
+ PullFilter *pf_decrypt = NULL;
+ PullFilter *pf_prefix = NULL;
+ PullFilter *pf_mdc = NULL;
+ uint8 ver;
+
+ GETBYTE(pkt, ver);
+ if (ver != 1)
+ {
+ px_debug("parse_symenc_mdc_data: pkt ver != 1");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+
+ res = pgp_cfb_create(&cfb, ctx->cipher_algo,
+ ctx->sess_key, ctx->sess_key_len, 0, NULL);
+ if (res < 0)
+ goto out;
+
+ res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
+ if (res < 0)
+ goto out;
+
+ res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
+ if (res < 0)
+ goto out;
+
+ res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
+ if (res < 0)
+ goto out;
+
+ res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);
+
+out:
+ if (pf_prefix)
+ pullf_free(pf_prefix);
+ if (pf_mdc)
+ pullf_free(pf_mdc);
+ if (pf_decrypt)
+ pullf_free(pf_decrypt);
+ if (cfb)
+ pgp_cfb_free(cfb);
+
+ return res;
+}
+
+/*
+ * skip over packet contents
+ */
+int
+pgp_skip_packet(PullFilter *pkt)
+{
+ int res = 1;
+ uint8 *tmp;
+
+ while (res > 0)
+ res = pullf_read(pkt, 32 * 1024, &tmp);
+ return res < 0 ? res : 0;
+}
+
+/*
+ * expect to be at packet end, any data is error
+ */
+int
+pgp_expect_packet_end(PullFilter *pkt)
+{
+ int res = 1;
+ uint8 *tmp;
+
+ while (res > 0)
+ {
+ res = pullf_read(pkt, 32 * 1024, &tmp);
+ if (res > 0)
+ {
+ px_debug("pgp_expect_packet_end: got data");
+ return PXE_PGP_CORRUPT_DATA;
+ }
+ }
+ return res < 0 ? res : 0;
+}
+
+int
+pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
+{
+ int res;
+ PullFilter *src = NULL;
+ PullFilter *pkt = NULL;
+ uint8 tag;
+ int len;
+ int got_key = 0;
+ int got_data = 0;
+
+ res = pullf_create_mbuf_reader(&src, msrc);
+
+ while (res >= 0)
+ {
+ res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
+ if (res <= 0)
+ break;
+
+ res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
+ if (res < 0)
+ break;
+
+ res = PXE_PGP_CORRUPT_DATA;
+ switch (tag)
+ {
+ case PGP_PKT_MARKER:
+ res = pgp_skip_packet(pkt);
+ break;
+ case PGP_PKT_PUBENCRYPTED_SESSKEY:
+ /* fixme: skip those */
+ res = pgp_parse_pubenc_sesskey(ctx, pkt);
+ got_key = 1;
+ break;
+ case PGP_PKT_SYMENCRYPTED_SESSKEY:
+ if (got_key)
+
+ /*
+ * Theoretically, there could be several keys, both public
+ * and symmetric, all of which encrypt same session key.
+ * Decrypt should try with each one, before failing.
+ */
+ px_debug("pgp_decrypt: using first of several keys");
+ else
+ {
+ got_key = 1;
+ res = parse_symenc_sesskey(ctx, pkt);
+ }
+ break;
+ case PGP_PKT_SYMENCRYPTED_DATA:
+ if (!got_key)
+ px_debug("pgp_decrypt: have data but no key");
+ else if (got_data)
+ px_debug("pgp_decrypt: got second data packet");
+ else
+ {
+ got_data = 1;
+ ctx->disable_mdc = 1;
+ res = parse_symenc_data(ctx, pkt, mdst);
+ }
+ break;
+ case PGP_PKT_SYMENCRYPTED_DATA_MDC:
+ if (!got_key)
+ px_debug("pgp_decrypt: have data but no key");
+ else if (got_data)
+ px_debug("pgp_decrypt: several data pkts not supported");
+ else
+ {
+ got_data = 1;
+ ctx->disable_mdc = 0;
+ res = parse_symenc_mdc_data(ctx, pkt, mdst);
+ }
+ break;
+ default:
+ px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
+ }
+ pullf_free(pkt);
+ pkt = NULL;
+ }
+
+ if (pkt)
+ pullf_free(pkt);
+
+ if (src)
+ pullf_free(src);
+
+ if (res < 0)
+ return res;
+
+ if (!got_data || ctx->corrupt_prefix)
+ res = PXE_PGP_CORRUPT_DATA;
+
+ return res;
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-encrypt.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c
new file mode 100644
index 0000000..3b9b5d2
--- /dev/null
+++ b/contrib/pgcrypto/pgp-encrypt.c
@@ -0,0 +1,708 @@
+/*
+ * pgp-encrypt.c
+ * OpenPGP encrypt.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-encrypt.c
+ */
+
+#include "postgres.h"
+
+#include <time.h>
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+
+#define MDC_DIGEST_LEN 20
+#define STREAM_ID 0xE0
+#define STREAM_BLOCK_SHIFT 14
+
+static uint8 *
+render_newlen(uint8 *h, int len)
+{
+ if (len <= 191)
+ {
+ *h++ = len & 255;
+ }
+ else if (len > 191 && len <= 8383)
+ {
+ *h++ = ((len - 192) >> 8) + 192;
+ *h++ = (len - 192) & 255;
+ }
+ else
+ {
+ *h++ = 255;
+ *h++ = (len >> 24) & 255;
+ *h++ = (len >> 16) & 255;
+ *h++ = (len >> 8) & 255;
+ *h++ = len & 255;
+ }
+ return h;
+}
+
+static int
+write_tag_only(PushFilter *dst, int tag)
+{
+ uint8 hdr = 0xC0 | tag;
+
+ return pushf_write(dst, &hdr, 1);
+}
+
+static int
+write_normal_header(PushFilter *dst, int tag, int len)
+{
+ uint8 hdr[8];
+ uint8 *h = hdr;
+
+ *h++ = 0xC0 | tag;
+ h = render_newlen(h, len);
+ return pushf_write(dst, hdr, h - hdr);
+}
+
+
+/*
+ * MAC writer
+ */
+
+static int
+mdc_init(PushFilter *dst, void *init_arg, void **priv_p)
+{
+ int res;
+ PX_MD *md;
+
+ res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
+ if (res < 0)
+ return res;
+
+ *priv_p = md;
+ return 0;
+}
+
+static int
+mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+{
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+}
+
+static int
+mdc_flush(PushFilter *dst, void *priv)
+{
+ int res;
+ uint8 pkt[2 + MDC_DIGEST_LEN];
+ PX_MD *md = priv;
+
+ /*
+ * create mdc pkt
+ */
+ pkt[0] = 0xD3;
+ pkt[1] = 0x14; /* MDC_DIGEST_LEN */
+ px_md_update(md, pkt, 2);
+ px_md_finish(md, pkt + 2);
+
+ res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN);
+ memset(pkt, 0, 2 + MDC_DIGEST_LEN);
+ return res;
+}
+
+static void
+mdc_free(void *priv)
+{
+ PX_MD *md = priv;
+
+ px_md_free(md);
+}
+
+static const PushFilterOps mdc_filter = {
+ mdc_init, mdc_write, mdc_flush, mdc_free
+};
+
+
+/*
+ * Encrypted pkt writer
+ */
+#define ENCBUF 8192
+struct EncStat
+{
+ PGP_CFB *ciph;
+ uint8 buf[ENCBUF];
+};
+
+static int
+encrypt_init(PushFilter *next, void *init_arg, void **priv_p)
+{
+ struct EncStat *st;
+ PGP_Context *ctx = init_arg;
+ PGP_CFB *ciph;
+ int resync = 1;
+ int res;
+
+ /* should we use newer packet format? */
+ if (ctx->disable_mdc == 0)
+ {
+ uint8 ver = 1;
+
+ resync = 0;
+ res = pushf_write(next, &ver, 1);
+ if (res < 0)
+ return res;
+ }
+ res = pgp_cfb_create(&ciph, ctx->cipher_algo,
+ ctx->sess_key, ctx->sess_key_len, resync, NULL);
+ if (res < 0)
+ return res;
+
+ st = px_alloc(sizeof(*st));
+ memset(st, 0, sizeof(*st));
+ st->ciph = ciph;
+
+ *priv_p = st;
+ return ENCBUF;
+}
+
+static int
+encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len)
+{
+ int res;
+ struct EncStat *st = priv;
+ int avail = len;
+
+ while (avail > 0)
+ {
+ int tmplen = avail > ENCBUF ? ENCBUF : avail;
+
+ res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
+ if (res < 0)
+ return res;
+
+ res = pushf_write(next, st->buf, tmplen);
+ if (res < 0)
+ return res;
+
+ data += tmplen;
+ avail -= tmplen;
+ }
+ return 0;
+}
+
+static void
+encrypt_free(void *priv)
+{
+ struct EncStat *st = priv;
+
+ memset(st, 0, sizeof(*st));
+ px_free(st);
+}
+
+static const PushFilterOps encrypt_filter = {
+ encrypt_init, encrypt_process, NULL, encrypt_free
+};
+
+/*
+ * Write Streamable pkts
+ */
+
+struct PktStreamStat
+{
+ int final_done;
+ int pkt_block;
+};
+
+static int
+pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
+{
+ struct PktStreamStat *st;
+
+ st = px_alloc(sizeof(*st));
+ st->final_done = 0;
+ st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
+ *priv_p = st;
+
+ return st->pkt_block;
+}
+
+static int
+pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
+{
+ int res;
+ uint8 hdr[8];
+ uint8 *h = hdr;
+ struct PktStreamStat *st = priv;
+
+ if (st->final_done)
+ return PXE_BUG;
+
+ if (len == st->pkt_block)
+ *h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
+ else
+ {
+ h = render_newlen(h, len);
+ st->final_done = 1;
+ }
+
+ res = pushf_write(next, hdr, h - hdr);
+ if (res < 0)
+ return res;
+
+ return pushf_write(next, data, len);
+}
+
+static int
+pkt_stream_flush(PushFilter *next, void *priv)
+{
+ int res;
+ uint8 hdr[8];
+ uint8 *h = hdr;
+ struct PktStreamStat *st = priv;
+
+ /* stream MUST end with normal packet. */
+ if (!st->final_done)
+ {
+ h = render_newlen(h, 0);
+ res = pushf_write(next, hdr, h - hdr);
+ if (res < 0)
+ return res;
+ st->final_done = 1;
+ }
+ return 0;
+}
+
+static void
+pkt_stream_free(void *priv)
+{
+ struct PktStreamStat *st = priv;
+
+ memset(st, 0, sizeof(*st));
+ px_free(st);
+}
+
+static const PushFilterOps pkt_stream_filter = {
+ pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
+};
+
+int
+pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
+{
+ int res;
+
+ res = write_tag_only(dst, tag);
+ if (res < 0)
+ return res;
+
+ return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
+}
+
+/*
+ * Text conversion filter
+ */
+
+static int
+crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
+{
+ const uint8 *data_end = data + len;
+ const uint8 *p2,
+ *p1 = data;
+ int line_len;
+ static const uint8 crlf[] = {'\r', '\n'};
+ int res = 0;
+
+ while (p1 < data_end)
+ {
+ p2 = memchr(p1, '\n', data_end - p1);
+ if (p2 == NULL)
+ p2 = data_end;
+
+ line_len = p2 - p1;
+
+ /* write data */
+ res = 0;
+ if (line_len > 0)
+ {
+ res = pushf_write(dst, p1, line_len);
+ if (res < 0)
+ break;
+ p1 += line_len;
+ }
+
+ /* write crlf */
+ while (p1 < data_end && *p1 == '\n')
+ {
+ res = pushf_write(dst, crlf, 2);
+ if (res < 0)
+ break;
+ p1++;
+ }
+ }
+ return res;
+}
+
+static const PushFilterOps crlf_filter = {
+ NULL, crlf_process, NULL, NULL
+};
+
+/*
+ * Initialize literal data packet
+ */
+static int
+init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+ int res;
+ int hdrlen;
+ uint8 hdr[6];
+ uint32 t;
+ PushFilter *pkt;
+ int type;
+
+ /*
+ * Create header
+ */
+
+ if (ctx->text_mode)
+ type = ctx->unicode_mode ? 'u' : 't';
+ else
+ type = 'b';
+
+ /*
+ * Store the creation time into packet. The goal is to have as few known
+ * bytes as possible.
+ */
+ t = (uint32) time(NULL);
+
+ hdr[0] = type;
+ hdr[1] = 0;
+ hdr[2] = (t >> 24) & 255;
+ hdr[3] = (t >> 16) & 255;
+ hdr[4] = (t >> 8) & 255;
+ hdr[5] = t & 255;
+ hdrlen = 6;
+
+ res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
+ if (res < 0)
+ return res;
+
+ res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
+ if (res < 0)
+ return res;
+
+ res = pushf_write(pkt, hdr, hdrlen);
+ if (res < 0)
+ {
+ pushf_free(pkt);
+ return res;
+ }
+
+ *pf_res = pkt;
+ return 0;
+}
+
+/*
+ * Initialize compression filter
+ */
+static int
+init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+ int res;
+ uint8 type = ctx->compress_algo;
+ PushFilter *pkt;
+
+ res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
+ if (res < 0)
+ return res;
+
+ res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
+ if (res < 0)
+ return res;
+
+ res = pushf_write(pkt, &type, 1);
+ if (res >= 0)
+ res = pgp_compress_filter(pf_res, ctx, pkt);
+
+ if (res < 0)
+ pushf_free(pkt);
+
+ return res;
+}
+
+/*
+ * Initialize encdata packet
+ */
+static int
+init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+ int res;
+ int tag;
+
+ if (ctx->disable_mdc)
+ tag = PGP_PKT_SYMENCRYPTED_DATA;
+ else
+ tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
+
+ res = write_tag_only(dst, tag);
+ if (res < 0)
+ return res;
+
+ return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
+}
+
+/*
+ * write prefix
+ */
+static int
+write_prefix(PGP_Context *ctx, PushFilter *dst)
+{
+ uint8 prefix[PGP_MAX_BLOCK + 2];
+ int res,
+ bs;
+
+ bs = pgp_get_cipher_block_size(ctx->cipher_algo);
+ res = px_get_random_bytes(prefix, bs);
+ if (res < 0)
+ return res;
+
+ prefix[bs + 0] = prefix[bs - 2];
+ prefix[bs + 1] = prefix[bs - 1];
+
+ res = pushf_write(dst, prefix, bs + 2);
+ memset(prefix, 0, bs + 2);
+ return res < 0 ? res : 0;
+}
+
+/*
+ * write symmetrically encrypted session key packet
+ */
+
+static int
+symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
+{
+ int res;
+ PGP_CFB *cfb;
+ uint8 algo = ctx->cipher_algo;
+
+ res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
+ ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
+ if (res < 0)
+ return res;
+
+ pgp_cfb_encrypt(cfb, &algo, 1, dst);
+ pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
+
+ pgp_cfb_free(cfb);
+ return ctx->sess_key_len + 1;
+}
+
+/* 5.3: Symmetric-Key Encrypted Session-Key */
+static int
+write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
+{
+ uint8 pkt[256];
+ int pktlen;
+ int res;
+ uint8 *p = pkt;
+
+ *p++ = 4; /* 5.3 - version number */
+ *p++ = ctx->s2k_cipher_algo;
+
+ *p++ = ctx->s2k.mode;
+ *p++ = ctx->s2k.digest_algo;
+ if (ctx->s2k.mode > 0)
+ {
+ memcpy(p, ctx->s2k.salt, 8);
+ p += 8;
+ }
+ if (ctx->s2k.mode == 3)
+ *p++ = ctx->s2k.iter;
+
+ if (ctx->use_sess_key)
+ {
+ res = symencrypt_sesskey(ctx, p);
+ if (res < 0)
+ return res;
+ p += res;
+ }
+
+ pktlen = p - pkt;
+ res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
+ if (res >= 0)
+ res = pushf_write(dst, pkt, pktlen);
+
+ memset(pkt, 0, pktlen);
+ return res;
+}
+
+/*
+ * key setup
+ */
+static int
+init_s2k_key(PGP_Context *ctx)
+{
+ int res;
+
+ if (ctx->s2k_cipher_algo < 0)
+ ctx->s2k_cipher_algo = ctx->cipher_algo;
+
+ res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo);
+ if (res < 0)
+ return res;
+
+ return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
+ ctx->sym_key, ctx->sym_key_len);
+}
+
+static int
+init_sess_key(PGP_Context *ctx)
+{
+ int res;
+
+ if (ctx->use_sess_key || ctx->pub_key)
+ {
+ ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
+ res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
+ if (res < 0)
+ return res;
+ }
+ else
+ {
+ ctx->sess_key_len = ctx->s2k.key_len;
+ memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
+ }
+
+ return 0;
+}
+
+/*
+ * combine
+ */
+int
+pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
+{
+ int res;
+ int len;
+ uint8 *buf;
+ PushFilter *pf,
+ *pf_tmp;
+
+ /*
+ * do we have any key
+ */
+ if (!ctx->sym_key && !ctx->pub_key)
+ return PXE_ARGUMENT_ERROR;
+
+ /* MBuf writer */
+ res = pushf_create_mbuf_writer(&pf, dst);
+ if (res < 0)
+ goto out;
+
+ /*
+ * initialize symkey
+ */
+ if (ctx->sym_key)
+ {
+ res = init_s2k_key(ctx);
+ if (res < 0)
+ goto out;
+ }
+
+ res = init_sess_key(ctx);
+ if (res < 0)
+ goto out;
+
+ /*
+ * write keypkt
+ */
+ if (ctx->pub_key)
+ res = pgp_write_pubenc_sesskey(ctx, pf);
+ else
+ res = write_symenc_sesskey(ctx, pf);
+ if (res < 0)
+ goto out;
+
+ /* encrypted data pkt */
+ res = init_encdata_packet(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+
+ /* encrypter */
+ res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+
+ /* hasher */
+ if (ctx->disable_mdc == 0)
+ {
+ res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
+ /* prefix */
+ res = write_prefix(ctx, pf);
+ if (res < 0)
+ goto out;
+
+ /* compressor */
+ if (ctx->compress_algo > 0 && ctx->compress_level > 0)
+ {
+ res = init_compress(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
+ /* data streamer */
+ res = init_litdata_packet(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+
+
+ /* text conversion? */
+ if (ctx->text_mode && ctx->convert_crlf)
+ {
+ res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
+ /*
+ * chain complete
+ */
+
+ len = mbuf_grab(src, mbuf_avail(src), &buf);
+ res = pushf_write(pf, buf, len);
+ if (res >= 0)
+ res = pushf_flush(pf);
+out:
+ pushf_free_all(pf);
+ return res;
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-info.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-info.c b/contrib/pgcrypto/pgp-info.c
new file mode 100644
index 0000000..b75266f
--- /dev/null
+++ b/contrib/pgcrypto/pgp-info.c
@@ -0,0 +1,235 @@
+/*
+ * pgp-info.c
+ * Provide info about PGP data.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-info.c
+ */
+#include "postgres.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static int
+read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
+{
+ int res;
+ PGP_PubKey *pk = NULL;
+
+ res = _pgp_read_public_key(pkt, &pk);
+ if (res < 0)
+ goto err;
+
+ /* skip secret key part, if it exists */
+ res = pgp_skip_packet(pkt);
+ if (res < 0)
+ goto err;
+
+ /* is it encryption key */
+ switch (pk->algo)
+ {
+ case PGP_PUB_ELG_ENCRYPT:
+ case PGP_PUB_RSA_ENCRYPT:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ memcpy(keyid_buf, pk->key_id, 8);
+ res = 1;
+ break;
+ default:
+ res = 0;
+ }
+
+err:
+ pgp_key_free(pk);
+ return res;
+}
+
+static int
+read_pubenc_keyid(PullFilter *pkt, uint8 *keyid_buf)
+{
+ uint8 ver;
+ int res;
+
+ GETBYTE(pkt, ver);
+ if (ver != 3)
+ return -1;
+
+ res = pullf_read_fixed(pkt, 8, keyid_buf);
+ if (res < 0)
+ return res;
+
+ return pgp_skip_packet(pkt);
+}
+
+static const char hextbl[] = "0123456789ABCDEF";
+
+static int
+print_key(uint8 *keyid, char *dst)
+{
+ int i;
+ unsigned c;
+
+ for (i = 0; i < 8; i++)
+ {
+ c = keyid[i];
+ *dst++ = hextbl[(c >> 4) & 0x0F];
+ *dst++ = hextbl[c & 0x0F];
+ }
+ *dst = 0;
+ return 8 * 2;
+}
+
+static const uint8 any_key[] =
+{0, 0, 0, 0, 0, 0, 0, 0};
+
+/*
+ * dst should have room for 17 bytes
+ */
+int
+pgp_get_keyid(MBuf *pgp_data, char *dst)
+{
+ int res;
+ PullFilter *src;
+ PullFilter *pkt = NULL;
+ int len;
+ uint8 tag;
+ int got_pub_key = 0,
+ got_symenc_key = 0,
+ got_pubenc_key = 0;
+ int got_data = 0;
+ uint8 keyid_buf[8];
+ int got_main_key = 0;
+
+
+ res = pullf_create_mbuf_reader(&src, pgp_data);
+ if (res < 0)
+ return res;
+
+ while (1)
+ {
+ res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
+ if (res <= 0)
+ break;
+ res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
+ if (res < 0)
+ break;
+
+ switch (tag)
+ {
+ case PGP_PKT_SECRET_KEY:
+ case PGP_PKT_PUBLIC_KEY:
+ /* main key is for signing, so ignore it */
+ if (!got_main_key)
+ {
+ got_main_key = 1;
+ res = pgp_skip_packet(pkt);
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ break;
+ case PGP_PKT_SECRET_SUBKEY:
+ case PGP_PKT_PUBLIC_SUBKEY:
+ res = read_pubkey_keyid(pkt, keyid_buf);
+ if (res < 0)
+ break;
+ if (res > 0)
+ got_pub_key++;
+ break;
+ case PGP_PKT_PUBENCRYPTED_SESSKEY:
+ got_pubenc_key++;
+ res = read_pubenc_keyid(pkt, keyid_buf);
+ break;
+ case PGP_PKT_SYMENCRYPTED_DATA:
+ case PGP_PKT_SYMENCRYPTED_DATA_MDC:
+ /* don't skip it, just stop */
+ got_data = 1;
+ break;
+ case PGP_PKT_SYMENCRYPTED_SESSKEY:
+ got_symenc_key++;
+ /* fallthru */
+ case PGP_PKT_SIGNATURE:
+ case PGP_PKT_MARKER:
+ case PGP_PKT_TRUST:
+ case PGP_PKT_USER_ID:
+ case PGP_PKT_USER_ATTR:
+ case PGP_PKT_PRIV_61:
+ res = pgp_skip_packet(pkt);
+ break;
+ default:
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (pkt)
+ pullf_free(pkt);
+ pkt = NULL;
+
+ if (res < 0 || got_data)
+ break;
+ }
+
+ pullf_free(src);
+ if (pkt)
+ pullf_free(pkt);
+
+ if (res < 0)
+ return res;
+
+ /* now check sanity */
+ if (got_pub_key && got_pubenc_key)
+ res = PXE_PGP_CORRUPT_DATA;
+
+ if (got_pub_key > 1)
+ res = PXE_PGP_MULTIPLE_KEYS;
+
+ if (got_pubenc_key > 1)
+ res = PXE_PGP_MULTIPLE_KEYS;
+
+ /*
+ * if still ok, look what we got
+ */
+ if (res >= 0)
+ {
+ if (got_pubenc_key || got_pub_key)
+ {
+ if (memcmp(keyid_buf, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ res = 6;
+ }
+ else
+ res = print_key(keyid_buf, dst);
+ }
+ else if (got_symenc_key)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ res = 6;
+ }
+ else
+ res = PXE_PGP_NO_USABLE_KEY;
+ }
+
+ return res;
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-mpi-internal.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-mpi-internal.c b/contrib/pgcrypto/pgp-mpi-internal.c
new file mode 100644
index 0000000..d0e5830
--- /dev/null
+++ b/contrib/pgcrypto/pgp-mpi-internal.c
@@ -0,0 +1,308 @@
+/*
+ * pgp-mpi-internal.c
+ * OpenPGP MPI functions.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-mpi-internal.c
+ */
+#include "postgres.h"
+
+#include "imath.h"
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static mpz_t *
+mp_new()
+{
+ mpz_t *mp = mp_int_alloc();
+
+ mp_int_init_size(mp, 256);
+ return mp;
+}
+
+static void
+mp_clear_free(mpz_t *a)
+{
+ if (!a)
+ return;
+ /* fixme: no clear? */
+ mp_int_free(a);
+}
+
+
+static int
+mp_px_rand(uint32 bits, mpz_t *res)
+{
+ int err;
+ unsigned bytes = (bits + 7) / 8;
+ int last_bits = bits & 7;
+ uint8 *buf;
+
+ buf = px_alloc(bytes);
+ err = px_get_random_bytes(buf, bytes);
+ if (err < 0)
+ {
+ px_free(buf);
+ return err;
+ }
+
+ /* clear unnecessary bits and set last bit to one */
+ if (last_bits)
+ {
+ buf[0] >>= 8 - last_bits;
+ buf[0] |= 1 << (last_bits - 1);
+ }
+ else
+ buf[0] |= 1 << 7;
+
+ mp_int_read_unsigned(res, buf, bytes);
+
+ px_free(buf);
+
+ return 0;
+}
+
+static void
+mp_modmul(mpz_t *a, mpz_t *b, mpz_t *p, mpz_t *res)
+{
+ mpz_t *tmp = mp_new();
+
+ mp_int_mul(a, b, tmp);
+ mp_int_mod(tmp, p, res);
+ mp_clear_free(tmp);
+}
+
+static mpz_t *
+mpi_to_bn(PGP_MPI *n)
+{
+ mpz_t *bn = mp_new();
+
+ mp_int_read_unsigned(bn, n->data, n->bytes);
+
+ if (!bn)
+ return NULL;
+ if (mp_int_count_bits(bn) != n->bits)
+ {
+ px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
+ n->bits, mp_int_count_bits(bn));
+ mp_clear_free(bn);
+ return NULL;
+ }
+ return bn;
+}
+
+static PGP_MPI *
+bn_to_mpi(mpz_t *bn)
+{
+ int res;
+ PGP_MPI *n;
+ int bytes;
+
+ res = pgp_mpi_alloc(mp_int_count_bits(bn), &n);
+ if (res < 0)
+ return NULL;
+
+ bytes = (mp_int_count_bits(bn) + 7) / 8;
+ if (bytes != n->bytes)
+ {
+ px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
+ bytes, n->bytes);
+ pgp_mpi_free(n);
+ return NULL;
+ }
+ mp_int_to_unsigned(bn, n->data, n->bytes);
+ return n;
+}
+
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'. Following
+ * algorihm hovers 10-70 bits above gpg values. And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow. It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+ if (p_bits <= 5120)
+ return p_bits / 10 + 160;
+ else
+ return (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
+ PGP_MPI **c1_p, PGP_MPI **c2_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ int k_bits;
+ mpz_t *m = mpi_to_bn(_m);
+ mpz_t *p = mpi_to_bn(pk->pub.elg.p);
+ mpz_t *g = mpi_to_bn(pk->pub.elg.g);
+ mpz_t *y = mpi_to_bn(pk->pub.elg.y);
+ mpz_t *k = mp_new();
+ mpz_t *yk = mp_new();
+ mpz_t *c1 = mp_new();
+ mpz_t *c2 = mp_new();
+
+ if (!m || !p || !g || !y || !k || !yk || !c1 || !c2)
+ goto err;
+
+ /*
+ * generate k
+ */
+ k_bits = decide_k_bits(mp_int_count_bits(p));
+ res = mp_px_rand(k_bits, k);
+ if (res < 0)
+ return res;
+
+ /*
+ * c1 = g^k c2 = m * y^k
+ */
+ mp_int_exptmod(g, k, p, c1);
+ mp_int_exptmod(y, k, p, yk);
+ mp_modmul(m, yk, p, c2);
+
+ /* result */
+ *c1_p = bn_to_mpi(c1);
+ *c2_p = bn_to_mpi(c2);
+ if (*c1_p && *c2_p)
+ res = 0;
+err:
+ mp_clear_free(c2);
+ mp_clear_free(c1);
+ mp_clear_free(yk);
+ mp_clear_free(k);
+ mp_clear_free(y);
+ mp_clear_free(g);
+ mp_clear_free(p);
+ mp_clear_free(m);
+ return res;
+}
+
+int
+pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
+ PGP_MPI **msg_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ mpz_t *c1 = mpi_to_bn(_c1);
+ mpz_t *c2 = mpi_to_bn(_c2);
+ mpz_t *p = mpi_to_bn(pk->pub.elg.p);
+ mpz_t *x = mpi_to_bn(pk->sec.elg.x);
+ mpz_t *c1x = mp_new();
+ mpz_t *div = mp_new();
+ mpz_t *m = mp_new();
+
+ if (!c1 || !c2 || !p || !x || !c1x || !div || !m)
+ goto err;
+
+ /*
+ * m = c2 / (c1^x)
+ */
+ mp_int_exptmod(c1, x, p, c1x);
+ mp_int_invmod(c1x, p, div);
+ mp_modmul(c2, div, p, m);
+
+ /* result */
+ *msg_p = bn_to_mpi(m);
+ if (*msg_p)
+ res = 0;
+err:
+ mp_clear_free(m);
+ mp_clear_free(div);
+ mp_clear_free(c1x);
+ mp_clear_free(x);
+ mp_clear_free(p);
+ mp_clear_free(c2);
+ mp_clear_free(c1);
+ return res;
+}
+
+int
+pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ mpz_t *m = mpi_to_bn(_m);
+ mpz_t *e = mpi_to_bn(pk->pub.rsa.e);
+ mpz_t *n = mpi_to_bn(pk->pub.rsa.n);
+ mpz_t *c = mp_new();
+
+ if (!m || !e || !n || !c)
+ goto err;
+
+ /*
+ * c = m ^ e
+ */
+ mp_int_exptmod(m, e, n, c);
+
+ *c_p = bn_to_mpi(c);
+ if (*c_p)
+ res = 0;
+err:
+ mp_clear_free(c);
+ mp_clear_free(n);
+ mp_clear_free(e);
+ mp_clear_free(m);
+ return res;
+}
+
+int
+pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ mpz_t *c = mpi_to_bn(_c);
+ mpz_t *d = mpi_to_bn(pk->sec.rsa.d);
+ mpz_t *n = mpi_to_bn(pk->pub.rsa.n);
+ mpz_t *m = mp_new();
+
+ if (!m || !d || !n || !c)
+ goto err;
+
+ /*
+ * m = c ^ d
+ */
+ mp_int_exptmod(c, d, n, m);
+
+ *m_p = bn_to_mpi(m);
+ if (*m_p)
+ res = 0;
+err:
+ mp_clear_free(m);
+ mp_clear_free(n);
+ mp_clear_free(d);
+ mp_clear_free(c);
+ return res;
+}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/801100ed/contrib/pgcrypto/pgp-mpi-openssl.c
----------------------------------------------------------------------
diff --git a/contrib/pgcrypto/pgp-mpi-openssl.c b/contrib/pgcrypto/pgp-mpi-openssl.c
new file mode 100644
index 0000000..ed41e11
--- /dev/null
+++ b/contrib/pgcrypto/pgp-mpi-openssl.c
@@ -0,0 +1,285 @@
+/*
+ * pgp-mpi-openssl.c
+ * OpenPGP MPI functions using OpenSSL BIGNUM code.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-mpi-openssl.c
+ */
+#include "postgres.h"
+
+#include <openssl/bn.h>
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static BIGNUM *
+mpi_to_bn(PGP_MPI *n)
+{
+ BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL);
+
+ if (!bn)
+ return NULL;
+ if (BN_num_bits(bn) != n->bits)
+ {
+ px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
+ n->bits, BN_num_bits(bn));
+ BN_clear_free(bn);
+ return NULL;
+ }
+ return bn;
+}
+
+static PGP_MPI *
+bn_to_mpi(BIGNUM *bn)
+{
+ int res;
+ PGP_MPI *n;
+
+ res = pgp_mpi_alloc(BN_num_bits(bn), &n);
+ if (res < 0)
+ return NULL;
+
+ if (BN_num_bytes(bn) != n->bytes)
+ {
+ px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
+ BN_num_bytes(bn), n->bytes);
+ pgp_mpi_free(n);
+ return NULL;
+ }
+ BN_bn2bin(bn, n->data);
+ return n;
+}
+
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'. Following
+ * algorihm hovers 10-70 bits above gpg values. And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow. It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+ if (p_bits <= 5120)
+ return p_bits / 10 + 160;
+ else
+ return (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
+ PGP_MPI **c1_p, PGP_MPI **c2_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ int k_bits;
+ BIGNUM *m = mpi_to_bn(_m);
+ BIGNUM *p = mpi_to_bn(pk->pub.elg.p);
+ BIGNUM *g = mpi_to_bn(pk->pub.elg.g);
+ BIGNUM *y = mpi_to_bn(pk->pub.elg.y);
+ BIGNUM *k = BN_new();
+ BIGNUM *yk = BN_new();
+ BIGNUM *c1 = BN_new();
+ BIGNUM *c2 = BN_new();
+ BN_CTX *tmp = BN_CTX_new();
+
+ if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp)
+ goto err;
+
+ /*
+ * generate k
+ */
+ k_bits = decide_k_bits(BN_num_bits(p));
+ if (!BN_rand(k, k_bits, 0, 0))
+ goto err;
+
+ /*
+ * c1 = g^k c2 = m * y^k
+ */
+ if (!BN_mod_exp(c1, g, k, p, tmp))
+ goto err;
+ if (!BN_mod_exp(yk, y, k, p, tmp))
+ goto err;
+ if (!BN_mod_mul(c2, m, yk, p, tmp))
+ goto err;
+
+ /* result */
+ *c1_p = bn_to_mpi(c1);
+ *c2_p = bn_to_mpi(c2);
+ if (*c1_p && *c2_p)
+ res = 0;
+err:
+ if (tmp)
+ BN_CTX_free(tmp);
+ if (c2)
+ BN_clear_free(c2);
+ if (c1)
+ BN_clear_free(c1);
+ if (yk)
+ BN_clear_free(yk);
+ if (k)
+ BN_clear_free(k);
+ if (y)
+ BN_clear_free(y);
+ if (g)
+ BN_clear_free(g);
+ if (p)
+ BN_clear_free(p);
+ if (m)
+ BN_clear_free(m);
+ return res;
+}
+
+int
+pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
+ PGP_MPI **msg_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ BIGNUM *c1 = mpi_to_bn(_c1);
+ BIGNUM *c2 = mpi_to_bn(_c2);
+ BIGNUM *p = mpi_to_bn(pk->pub.elg.p);
+ BIGNUM *x = mpi_to_bn(pk->sec.elg.x);
+ BIGNUM *c1x = BN_new();
+ BIGNUM *div = BN_new();
+ BIGNUM *m = BN_new();
+ BN_CTX *tmp = BN_CTX_new();
+
+ if (!c1 || !c2 || !p || !x || !c1x || !div || !m || !tmp)
+ goto err;
+
+ /*
+ * m = c2 / (c1^x)
+ */
+ if (!BN_mod_exp(c1x, c1, x, p, tmp))
+ goto err;
+ if (!BN_mod_inverse(div, c1x, p, tmp))
+ goto err;
+ if (!BN_mod_mul(m, c2, div, p, tmp))
+ goto err;
+
+ /* result */
+ *msg_p = bn_to_mpi(m);
+ if (*msg_p)
+ res = 0;
+err:
+ if (tmp)
+ BN_CTX_free(tmp);
+ if (m)
+ BN_clear_free(m);
+ if (div)
+ BN_clear_free(div);
+ if (c1x)
+ BN_clear_free(c1x);
+ if (x)
+ BN_clear_free(x);
+ if (p)
+ BN_clear_free(p);
+ if (c2)
+ BN_clear_free(c2);
+ if (c1)
+ BN_clear_free(c1);
+ return res;
+}
+
+int
+pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ BIGNUM *m = mpi_to_bn(_m);
+ BIGNUM *e = mpi_to_bn(pk->pub.rsa.e);
+ BIGNUM *n = mpi_to_bn(pk->pub.rsa.n);
+ BIGNUM *c = BN_new();
+ BN_CTX *tmp = BN_CTX_new();
+
+ if (!m || !e || !n || !c || !tmp)
+ goto err;
+
+ /*
+ * c = m ^ e
+ */
+ if (!BN_mod_exp(c, m, e, n, tmp))
+ goto err;
+
+ *c_p = bn_to_mpi(c);
+ if (*c_p)
+ res = 0;
+err:
+ if (tmp)
+ BN_CTX_free(tmp);
+ if (c)
+ BN_clear_free(c);
+ if (n)
+ BN_clear_free(n);
+ if (e)
+ BN_clear_free(e);
+ if (m)
+ BN_clear_free(m);
+ return res;
+}
+
+int
+pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
+{
+ int res = PXE_PGP_MATH_FAILED;
+ BIGNUM *c = mpi_to_bn(_c);
+ BIGNUM *d = mpi_to_bn(pk->sec.rsa.d);
+ BIGNUM *n = mpi_to_bn(pk->pub.rsa.n);
+ BIGNUM *m = BN_new();
+ BN_CTX *tmp = BN_CTX_new();
+
+ if (!m || !d || !n || !c || !tmp)
+ goto err;
+
+ /*
+ * m = c ^ d
+ */
+ if (!BN_mod_exp(m, c, d, n, tmp))
+ goto err;
+
+ *m_p = bn_to_mpi(m);
+ if (*m_p)
+ res = 0;
+err:
+ if (tmp)
+ BN_CTX_free(tmp);
+ if (m)
+ BN_clear_free(m);
+ if (n)
+ BN_clear_free(n);
+ if (d)
+ BN_clear_free(d);
+ if (c)
+ BN_clear_free(c);
+ return res;
+}