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