diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile index 82f2a8295e..81ad9b372e 100644 --- a/contrib/pgcrypto/Makefile +++ b/contrib/pgcrypto/Makefile @@ -1,23 +1,35 @@ # -# $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.19 2005/07/10 03:55:28 momjian Exp $ +# $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.20 2005/07/10 03:57:55 momjian Exp $ # INT_SRCS = md5.c sha1.c sha2.c internal.c blf.c rijndael.c \ - fortuna.c random.c + fortuna.c random.c pgp-mpi-internal.c INT_TESTS = sha2 -OSSL_SRCS = openssl.c +OSSL_SRCS = openssl.c pgp-mpi-openssl.c OSSL_TESTS = des 3des cast5 +ZLIB_OFF_CFLAGS = -DDISABLE_ZLIB +ZLIB_TST = pgp-compression +ZLIB_OFF_TST = pgp-zlib-DISABLED +PUBENC_ON = pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info +PUBENC_OFF = pgp-pubkey-DISABLED + CF_SRCS = $(if $(subst no,,$(with_openssl)), $(OSSL_SRCS), $(INT_SRCS)) CF_TESTS = $(if $(subst no,,$(with_openssl)), $(OSSL_TESTS), $(INT_TESTS)) -CF_CFLAGS = +CF_CFLAGS = $(if $(subst yes,,$(with_zlib)), $(ZLIB_OFF_CFLAGS)) +CF_PGP_TESTS = $(if $(subst no,,$(with_zlib)), $(ZLIB_TST), $(ZLIB_OFF_TST)) \ + $(if $(subst no,,$(with_openssl)), $(PUBENC_ON), $(PUBENC_OFF)) PG_CPPFLAGS = $(CF_CFLAGS) SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \ crypt-gensalt.c crypt-blowfish.c crypt-des.c \ - crypt-md5.c $(CF_SRCS) + crypt-md5.c $(CF_SRCS) \ + mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \ + pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \ + pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \ + pgp-pgsql.c MODULE_big = pgcrypto OBJS = $(SRCS:.c=.o) @@ -27,7 +39,8 @@ EXTRA_CLEAN = gen-rtab REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \ $(CF_TESTS) \ - crypt-des crypt-md5 crypt-blowfish crypt-xdes + crypt-des crypt-md5 crypt-blowfish crypt-xdes \ + pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) ifdef USE_PGXS diff --git a/contrib/pgcrypto/README.pgcrypto b/contrib/pgcrypto/README.pgcrypto index b828739160..5446c19a3b 100644 --- a/contrib/pgcrypto/README.pgcrypto +++ b/contrib/pgcrypto/README.pgcrypto @@ -11,10 +11,10 @@ Edit makefile, if you want to use any external library. NB! Default randomness source is libc random() function. This is so only to get pgcrypto build everywhere. Randomness is -needed for gen_salt() function. So if you plan using it, you -should definitely change that by editing Makefile. You should -be using urandom device if your OS supports it, otherwise link -pgcrypto against OpenSSL library and use its PRNG. +needed for gen_salt() and pgp_encrypt() functions. So if you plan +using those, you should definitely change that by editing Makefile. +You can should use urandom device if your OS supports it, otherwise +link pgcrypto against OpenSSL library and use its PRNG. After editing Makefile: @@ -108,6 +108,161 @@ gen_salt(type::text, rounds::int4)::text For maximum security, you should choose the 'bf' crypt and use maximum number of rounds you can still tolerate. +armor(bytea)::text +dearmor(text)::bytea + + Those wrap/unwrap data into PGP Ascii Armor which + is basically Base64 with CRC and additional formatting. + +pgp_sym_encrypt(data::text, key::text)::bytea +pgp_sym_encrypt(data::text, key::text, arg::text)::bytea +pgp_sym_encrypt_bytea(data::bytea, key::text)::bytea +pgp_sym_encrypt_bytea(data::bytea, key::text, arg::text)::bytea + +pgp_sym_decrypt(data::bytea, key::text)::text +pgp_sym_decrypt(data::bytea, key::text, arg::text)::text +pgp_sym_decrypt_bytea(data::text, key::text)::bytea +pgp_sym_decrypt_bytea(data::text, key::text, arg::text)::bytea + + Encrypt data into OpenPGP Symmetrically Encrypted Data + message. And decrypt it from it. + + Note that the pgp_sym_encrypt_bytea functions tag the data + as binary, as the pgp_sym_encrypt will tag the data as text. + You can not decrypt the binary data as text. But you can + decrypt text data as binary. This rule avoids having + broken textual data in PostgreSQL. + + Both encrypt and decrypt accept also third argument, which + is parameters to the function in following format: + + parm=val[,parm=val]... + + Example: + + select pgp_sym_encrypt('data', 'psw', + 'compress-algo=2, unicode-mode=1'); + + Accepted parameters are: + + cipher-algo: bf, aes, aes128, aes192, aes256 + Cipher algorithm to use. OpenSSL gives additional algorithms: + 3des, cast5 + Default: aes128 + + compress-algo: 0, 1, 2 + Which compression algorithm to use. + 0 - no compression + 1 - ZIP compression + 2 - ZLIB compression [=ZIP plus meta-data and block-CRC's] + Default: 0 + + compress-level: 0, 1-9 + How much to compress. Bigger level compresses smaller + but also slower. 0 disables compression. + Default: 6 + + convert-crlf: 0, 1 + Whether to convert \n into \r\n when encrypting and + \r\n to \n when decrypting. RFC2440 specifies that + text packets should use "\r\n" line-feeds. + Use this to get fully RFC-compliant behaviour. + Default: 0 + + disable-mdc: 0, 1 + Do not protect data with SHA-1. Note that SHA-1 protected + packet is from upcoming update to RFC2440. (Currently at + version RFC2440bis-13.) You need to disable it if you need + compatibility with ancient PGP products. Recent gnupg.org + and pgp.com software supports it fine. + Default: 0 + + enable-session-key: 0, 1 + Use separate session key. + Default: 0 + + s2k-mode: 0, 1, 3 + Which S2K algorithm to use. 0 is dangerous - without salt. + Default: 3 + + s2k-digest-algo: md5, sha1 + Which digest algorithm to use in S2K calculation. + Default: SHA-1 + + s2k-cipher-algo: bf, aes, aes128, aes192, aes256 + Which cipher to use for encrypting separate session key. + Default: same as cipher-algo. + + unicode-mode: 0, 1 + Whether to convert textual data from database internal + encoding to UTF-8 and back. + Default: 0 + + Only 'convert-crlf' applies to both encrypt and decrypt, + all others apply only to encrypt - decrypt gets the + settings from PGP data. + + +pgp_pub_encrypt(data::text, key::bytea)::bytea +pgp_pub_encrypt(data::text, key::bytea, arg::text)::bytea +pgp_pub_encrypt_bytea(data::bytea, bytea::text)::bytea +pgp_pub_encrypt_bytea(data::bytea, bytea::text, arg::text)::bytea + +pgp_pub_decrypt(data::bytea, key::bytea)::text +pgp_pub_decrypt(data::bytea, key::bytea, psw::text)::text +pgp_pub_decrypt(data::bytea, key::bytea, psw::text, arg::text)::text +pgp_pub_decrypt_bytea(data::text, key::bytea)::bytea +pgp_pub_decrypt_bytea(data::text, key::bytea, psw::text)::bytea +pgp_pub_decrypt_bytea(data::text, key::bytea, psw::text, arg::bytea)::bytea + + Encrypt data into OpenPGP Public-Key Encrypted Data + message. And decrypt it from it. The arg parameter is + described in pgp_sym_* section. + + The key must be a public-key packet for pgp_pub_encrypt + functions and a secret key packet for pgp_pub_decrypt + functions. Trying to encrypt with secret key gives a error. + While being technically possible, it is probably a sign of + user error and leaking secret keys. + + Here is a example how to generate them: + + Generate a new key: + + gpg --gen-key + + You need to pick "DSA and Elgamal" key type, others + are sign-only. + + List keys: + + gpg --list-secret-keys + + Export ascii-armored public key: + + gpg -a --export KEYID > public.key + + Export ascii-armored secret key: + + gpg -a --export-secret-keys KEYID > secret.key + + You need to use dearmor() on them before giving giving + them to pgp_pub_* functions. Ofcourse, if you can handle + binary data, you can drop "-a" from gpg. + + +pgp_key_id(key / data) + + It shows you either key ID if given PGP public or secret + key. Or it gives the key ID what was used for encrypting + the data, if given encrypted data. + + It can return 2 special key ID's: + + SYMKEY - it got symmetrically encrypted data. + ANYKEY - the data packet key ID is clear. That means + you should try all you secret keys on it. + encrypt(data::bytea, key::bytea, type::text)::bytea decrypt(data::bytea, key::bytea, type::text)::bytea encrypt_iv(data::bytea, key::bytea, iv::bytea, type::text)::bytea diff --git a/contrib/pgcrypto/pgcrypto.sql.in b/contrib/pgcrypto/pgcrypto.sql.in index 6179f62136..fb3949d56e 100644 --- a/contrib/pgcrypto/pgcrypto.sql.in +++ b/contrib/pgcrypto/pgcrypto.sql.in @@ -71,4 +71,141 @@ RETURNS bool AS 'MODULE_PATHNAME', 'pg_cipher_exists' LANGUAGE 'C' IMMUTABLE 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; diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c index 51f8306917..ca271e33a8 100644 --- a/contrib/pgcrypto/px.c +++ b/contrib/pgcrypto/px.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $PostgreSQL: pgsql/contrib/pgcrypto/px.c,v 1.11 2005/03/21 05:22:14 neilc Exp $ + * $PostgreSQL: pgsql/contrib/pgcrypto/px.c,v 1.12 2005/07/10 03:57:55 momjian Exp $ */ #include @@ -57,6 +57,37 @@ static const struct error_desc px_err_list[] = { {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"}, {PXE_MCRYPT_INTERNAL, "mcrypt internal error"}, {PXE_NO_RANDOM, "No strong random source"}, + {PXE_PGP_CORRUPT_DATA, "Wrong key or corrupt data"}, + {PXE_PGP_CORRUPT_ARMOR, "Corrupt ascii-armor"}, + {PXE_PGP_UNSUPPORTED_COMPR, "Unsupported compression algorithm"}, + {PXE_PGP_UNSUPPORTED_CIPHER, "Unsupported cipher algorithm"}, + {PXE_PGP_UNSUPPORTED_HASH, "Unsupported digest algorithm"}, + {PXE_PGP_COMPRESSION_ERROR, "Compression error"}, + {PXE_PGP_NOT_TEXT, "Not text data"}, + {PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"}, + {PXE_PGP_NO_BIGNUM, + "public-key functions disabled - " + "pgcrypto needs OpenSSL for bignums"}, + {PXE_PGP_MATH_FAILED, "Math operation failed"}, + {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"}, + {PXE_PGP_RSA_UNSUPPORTED, "pgcrypto does not support RSA keys"}, + {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"}, + {PXE_PGP_WRONG_KEYID, "Data is not encrypted with this key"}, + {PXE_PGP_MULTIPLE_KEYS, + "Several keys given - pgcrypto does not handle keyring"}, + {PXE_PGP_EXPECT_PUBLIC_KEY, "Refusing to encrypt with secret key"}, + {PXE_PGP_EXPECT_SECRET_KEY, "Cannot decrypt with public key"}, + {PXE_PGP_NOT_V4_KEYPKT, "Only V4 key packets are supported"}, + {PXE_PGP_KEYPKT_CORRUPT, "Corrupt key packet"}, + {PXE_PGP_NO_USABLE_KEY, "No usable key found (expecting Elgamal key)"}, + {PXE_PGP_NEED_SECRET_PSW, "Need password for secret key"}, + {PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"}, + {PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"}, + {PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"}, + + /* fake this as PXE_PGP_CORRUPT_DATA */ + {PXE_MBUF_SHORT_READ, "Corrupt data"}, + {0, NULL}, }; @@ -82,6 +113,25 @@ px_resolve_alias(const PX_Alias * list, const char *name) return name; } +static void (*debug_handler)(const char *) = NULL; + +void px_set_debug_handler(void (*handler)(const char *)) +{ + debug_handler = handler; +} + +void px_debug(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (debug_handler) { + char buf[512]; + vsnprintf(buf, sizeof(buf), fmt, ap); + debug_handler(buf); + } + va_end(ap); +} + /* * combo - cipher + padding (+ checksum) */ diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h index b584ae6b34..bf45705c5d 100644 --- a/contrib/pgcrypto/px.h +++ b/contrib/pgcrypto/px.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $PostgreSQL: pgsql/contrib/pgcrypto/px.h,v 1.13 2005/07/10 03:55:28 momjian Exp $ + * $PostgreSQL: pgsql/contrib/pgcrypto/px.h,v 1.14 2005/07/10 03:57:55 momjian Exp $ */ #ifndef __PX_H @@ -42,19 +42,20 @@ #error BYTE_ORDER must be defined as LITTLE_ENDIAN or BIG_ENDIAN #endif +/* keep debug messages? */ +#define PX_DEBUG +/* a way to disable palloc + * - useful if compiled into standalone + */ #ifndef PX_OWN_ALLOC - #define px_alloc(s) palloc(s) #define px_realloc(p, s) repalloc(p, s) #define px_free(p) pfree(p) - #else - void *px_alloc(size_t s); void *px_realloc(void *p, size_t s); void px_free(void *p); - #endif /* max len of 'type' parms */ @@ -85,6 +86,34 @@ void px_free(void *p); #define PXE_MCRYPT_INTERNAL -16 #define PXE_NO_RANDOM -17 +#define PXE_MBUF_SHORT_READ -50 + +#define PXE_PGP_CORRUPT_DATA -100 +#define PXE_PGP_CORRUPT_ARMOR -101 +#define PXE_PGP_UNSUPPORTED_COMPR -102 +#define PXE_PGP_UNSUPPORTED_CIPHER -103 +#define PXE_PGP_UNSUPPORTED_HASH -104 +#define PXE_PGP_COMPRESSION_ERROR -105 +#define PXE_PGP_NOT_TEXT -106 +#define PXE_PGP_UNEXPECTED_PKT -107 +#define PXE_PGP_NO_BIGNUM -108 +#define PXE_PGP_MATH_FAILED -109 +#define PXE_PGP_SHORT_ELGAMAL_KEY -110 +#define PXE_PGP_RSA_UNSUPPORTED -111 +#define PXE_PGP_UNKNOWN_PUBALGO -112 +#define PXE_PGP_WRONG_KEYID -113 +#define PXE_PGP_MULTIPLE_KEYS -114 +#define PXE_PGP_EXPECT_PUBLIC_KEY -115 +#define PXE_PGP_EXPECT_SECRET_KEY -116 +#define PXE_PGP_NOT_V4_KEYPKT -117 +#define PXE_PGP_KEYPKT_CORRUPT -118 +#define PXE_PGP_NO_USABLE_KEY -119 +#define PXE_PGP_NEED_SECRET_PSW -120 +#define PXE_PGP_BAD_S2K_MODE -121 +#define PXE_PGP_UNSUPPORTED_PUBALGO -122 +#define PXE_PGP_MULTIPLE_SUBKEYS -123 + + typedef struct px_digest PX_MD; typedef struct px_alias PX_Alias; typedef struct px_hmac PX_HMAC; @@ -103,7 +132,7 @@ struct px_digest union { unsigned code; - const void *ptr; + void *ptr; } p; }; @@ -178,6 +207,13 @@ const char *px_strerror(int err); const char *px_resolve_alias(const PX_Alias * aliases, const char *name); +void px_set_debug_handler(void (*handler)(const char *)); +#ifdef PX_DEBUG +void px_debug(const char *fmt, ...); +#else +#define px_debug(...) +#endif + #define px_md_result_size(md) (md)->result_size(md) #define px_md_block_size(md) (md)->block_size(md) #define px_md_reset(md) (md)->reset(md)