diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
commit | 311bcfc6b3acdd6fd152798c7f287ddf74fa2a98 (patch) | |
tree | 0ec307299b1dada3701e42f4ca6eda57d708261e /contrib/pgcrypto | |
parent | Initial commit. (diff) | |
download | postgresql-15-upstream.tar.xz postgresql-15-upstream.zip |
Adding upstream version 15.4.upstream/15.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/pgcrypto')
87 files changed, 17956 insertions, 0 deletions
diff --git a/contrib/pgcrypto/.gitignore b/contrib/pgcrypto/.gitignore new file mode 100644 index 0000000..5dcb3ff --- /dev/null +++ b/contrib/pgcrypto/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile new file mode 100644 index 0000000..7fb59f5 --- /dev/null +++ b/contrib/pgcrypto/Makefile @@ -0,0 +1,69 @@ +# contrib/pgcrypto/Makefile + +ZLIB_TST = pgp-compression +ZLIB_OFF_TST = pgp-zlib-DISABLED + +CF_PGP_TESTS = $(if $(subst no,,$(with_zlib)), $(ZLIB_TST), $(ZLIB_OFF_TST)) + +OBJS = \ + $(WIN32RES) \ + crypt-blowfish.o \ + crypt-des.o \ + crypt-gensalt.o \ + crypt-md5.o \ + mbuf.o \ + openssl.o \ + pgcrypto.o \ + pgp-armor.o \ + pgp-cfb.o \ + pgp-compress.o \ + pgp-decrypt.o \ + pgp-encrypt.o \ + pgp-info.o \ + pgp-mpi.o \ + pgp-mpi-openssl.o \ + pgp-pgsql.o \ + pgp-pubdec.o \ + pgp-pubenc.o \ + pgp-pubkey.o \ + pgp-s2k.o \ + pgp.o \ + px-crypt.o \ + px-hmac.o \ + px.o + +MODULE_big = pgcrypto + +EXTENSION = pgcrypto +DATA = pgcrypto--1.3.sql pgcrypto--1.2--1.3.sql pgcrypto--1.1--1.2.sql \ + pgcrypto--1.0--1.1.sql +PGFILEDESC = "pgcrypto - cryptographic functions" + +REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \ + sha2 des 3des cast5 \ + crypt-des crypt-md5 crypt-blowfish crypt-xdes \ + pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \ + pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info + +EXTRA_CLEAN = gen-rtab + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/pgcrypto +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +# Add libraries that pgcrypto depends (or might depend) on into the +# shared library link. (The order in which you list them here doesn't +# matter.) +SHLIB_LINK += $(filter -lcrypto -lz, $(LIBS)) +ifeq ($(PORTNAME), win32) +SHLIB_LINK += $(filter -leay32, $(LIBS)) +# those must be at the end +SHLIB_LINK += -lws2_32 +endif diff --git a/contrib/pgcrypto/crypt-blowfish.c b/contrib/pgcrypto/crypt-blowfish.c new file mode 100644 index 0000000..a663852 --- /dev/null +++ b/contrib/pgcrypto/crypt-blowfish.c @@ -0,0 +1,756 @@ +/* + * contrib/pgcrypto/crypt-blowfish.c + * + * This code comes from John the Ripper password cracker, with reentrant + * and crypt(3) interfaces added, but optimizations specific to password + * cracking removed. + * + * Written by Solar Designer <solar at openwall.com> in 1998-2002 and + * placed in the public domain. + * + * There's absolutely no warranty. + * + * It is my intent that you should be able to use this on your system, + * as a part of a software package, or anywhere else to improve security, + * ensure compatibility, or for any other purpose. I would appreciate + * it if you give credit where it is due and keep your modifications in + * the public domain as well, but I don't require that in order to let + * you place this code and any modifications you make under a license + * of your choice. + * + * This implementation is compatible with OpenBSD bcrypt.c (version 2a) + * by Niels Provos <provos at citi.umich.edu>, and uses some of his + * ideas. The password hashing algorithm was designed by David Mazieres + * <dm at lcs.mit.edu>. + * + * There's a paper on the algorithm that explains its design decisions: + * + * http://www.usenix.org/events/usenix99/provos.html + * + * Some of the tricks in BF_ROUND might be inspired by Eric Young's + * Blowfish library (I can't be sure if I would think of something if I + * hadn't seen his code). + */ + +#include "postgres.h" +#include "miscadmin.h" + +#include "px-crypt.h" +#include "px.h" + +#ifdef __i386__ +#define BF_ASM 0 /* 1 */ +#define BF_SCALE 1 +#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) +#define BF_ASM 0 +#define BF_SCALE 1 +#else +#define BF_ASM 0 +#define BF_SCALE 0 +#endif + +typedef unsigned int BF_word; +typedef signed int BF_word_signed; + +/* Number of Blowfish rounds, this is also hardcoded into a few places */ +#define BF_N 16 + +typedef BF_word BF_key[BF_N + 2]; + +typedef struct +{ + BF_word S[4][0x100]; + BF_key P; +} BF_ctx; + +/* + * Magic IV for 64 Blowfish encryptions that we do at the end. + * The string is "OrpheanBeholderScryDoubt" on big-endian. + */ +static BF_word BF_magic_w[6] = { + 0x4F727068, 0x65616E42, 0x65686F6C, + 0x64657253, 0x63727944, 0x6F756274 +}; + +/* + * P-box and S-box tables initialized with digits of Pi. + */ +static BF_ctx BF_init_state = { + { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + }, { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + }, { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + }, { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + } + }, { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + } +}; + +static unsigned char BF_itoa64[64 + 1] = +"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static unsigned char BF_atoi64[0x60] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, + 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, + 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 +}; + +#define BF_safe_atoi64(dst, src) \ +do { \ + tmp = (unsigned char)(src); \ + if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ + tmp = BF_atoi64[tmp]; \ + if (tmp > 63) return -1; \ + (dst) = tmp; \ +} while (0) + +static int +BF_decode(BF_word *dst, const char *src, int size) +{ + unsigned char *dptr = (unsigned char *) dst; + unsigned char *end = dptr + size; + const unsigned char *sptr = (const unsigned char *) src; + unsigned int tmp, + c1, + c2, + c3, + c4; + + do + { + BF_safe_atoi64(c1, *sptr++); + BF_safe_atoi64(c2, *sptr++); + *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); + if (dptr >= end) + break; + + BF_safe_atoi64(c3, *sptr++); + *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); + if (dptr >= end) + break; + + BF_safe_atoi64(c4, *sptr++); + *dptr++ = ((c3 & 0x03) << 6) | c4; + } while (dptr < end); + + return 0; +} + +static void +BF_encode(char *dst, const BF_word *src, int size) +{ + const unsigned char *sptr = (const unsigned char *) src; + const unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *) dst; + unsigned int c1, + c2; + + do + { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) + { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) + { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +static void +BF_swap(BF_word *x, int count) +{ + /* Swap on little-endian hardware, else do nothing */ +#ifndef WORDS_BIGENDIAN + BF_word tmp; + + do + { + tmp = *x; + tmp = (tmp << 16) | (tmp >> 16); + *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); + } while (--count); +#endif +} + +#if BF_SCALE +/* Architectures which can shift addresses left by 2 bits with no extra cost */ +#define BF_ROUND(L, R, N) \ + tmp1 = (L) & 0xFF; \ + tmp2 = (L) >> 8; \ + tmp2 &= 0xFF; \ + tmp3 = (L) >> 16; \ + tmp3 &= 0xFF; \ + tmp4 = (L) >> 24; \ + tmp1 = data.ctx.S[3][tmp1]; \ + tmp2 = data.ctx.S[2][tmp2]; \ + tmp3 = data.ctx.S[1][tmp3]; \ + tmp3 += data.ctx.S[0][tmp4]; \ + tmp3 ^= tmp2; \ + (R) ^= data.ctx.P[(N) + 1]; \ + tmp3 += tmp1; \ + (R) ^= tmp3 +#else +/* Architectures with no complicated addressing modes supported */ +#define BF_INDEX(S, i) \ + (*((BF_word *)(((unsigned char *)(S)) + (i)))) +#define BF_ROUND(L, R, N) \ + tmp1 = (L) & 0xFF; \ + tmp1 <<= 2; \ + tmp2 = (L) >> 6; \ + tmp2 &= 0x3FC; \ + tmp3 = (L) >> 14; \ + tmp3 &= 0x3FC; \ + tmp4 = (L) >> 22; \ + tmp4 &= 0x3FC; \ + tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ + tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ + tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ + tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ + tmp3 ^= tmp2; \ + (R) ^= data.ctx.P[(N) + 1]; \ + tmp3 += tmp1; \ + (R) ^= tmp3 +#endif + +/* + * Encrypt one block, BF_N is hardcoded here. + */ +#define BF_ENCRYPT \ + L ^= data.ctx.P[0]; \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + tmp4 = R; \ + R = L; \ + L = tmp4 ^ data.ctx.P[BF_N + 1] + +#if BF_ASM + +extern void _BF_body_r(BF_ctx *ctx); + +#define BF_body() \ + _BF_body_r(&data.ctx) +#else + +#define BF_body() \ +do { \ + L = R = 0; \ + ptr = data.ctx.P; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.P[BF_N + 2]); \ +\ + ptr = data.ctx.S[0]; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.S[3][0xFF]); \ +} while (0) +#endif + +static void +BF_set_key(const char *key, BF_key expanded, BF_key initial, + int sign_extension_bug) +{ + const char *ptr = key; + int i, + j; + BF_word tmp; + + for (i = 0; i < BF_N + 2; i++) + { + tmp = 0; + for (j = 0; j < 4; j++) + { + tmp <<= 8; + if (sign_extension_bug) + tmp |= (BF_word_signed) (signed char) *ptr; + else + tmp |= (unsigned char) *ptr; + + if (!*ptr) + ptr = key; + else + ptr++; + } + + expanded[i] = tmp; + initial[i] = BF_init_state.P[i] ^ tmp; + } +} + +char * +_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size) +{ + struct + { + BF_ctx ctx; + BF_key expanded_key; + union + { + BF_word salt[4]; + BF_word output[6]; + } binary; + } data; + BF_word L, + R; + BF_word tmp1, + tmp2, + tmp3, + tmp4; + BF_word *ptr; + BF_word count; + int i; + + if (size < 7 + 22 + 31 + 1) + return NULL; + + /* + * Blowfish salt value must be formatted as follows: "$2a$" or "$2x$", a + * two digit cost parameter, "$", and 22 digits from the alphabet + * "./0-9A-Za-z". -- from the PHP crypt docs. Apparently we enforce a few + * more restrictions on the count in the salt as well. + */ + if (strlen(setting) < 29) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + + if (setting[0] != '$' || + setting[1] != '2' || + (setting[2] != 'a' && setting[2] != 'x') || + setting[3] != '$' || + setting[4] < '0' || setting[4] > '3' || + setting[5] < '0' || setting[5] > '9' || + (setting[4] == '3' && setting[5] > '1') || + setting[6] != '$') + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + } + + count = (BF_word) 1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); + if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) + { + px_memset(data.binary.salt, 0, sizeof(data.binary.salt)); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + } + BF_swap(data.binary.salt, 4); + + BF_set_key(key, data.expanded_key, data.ctx.P, setting[2] == 'x'); + + memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); + + L = R = 0; + for (i = 0; i < BF_N + 2; i += 2) + { + L ^= data.binary.salt[i & 2]; + R ^= data.binary.salt[(i & 2) + 1]; + BF_ENCRYPT; + data.ctx.P[i] = L; + data.ctx.P[i + 1] = R; + } + + ptr = data.ctx.S[0]; + do + { + ptr += 4; + L ^= data.binary.salt[(BF_N + 2) & 3]; + R ^= data.binary.salt[(BF_N + 3) & 3]; + BF_ENCRYPT; + *(ptr - 4) = L; + *(ptr - 3) = R; + + L ^= data.binary.salt[(BF_N + 4) & 3]; + R ^= data.binary.salt[(BF_N + 5) & 3]; + BF_ENCRYPT; + *(ptr - 2) = L; + *(ptr - 1) = R; + } while (ptr < &data.ctx.S[3][0xFF]); + + do + { + CHECK_FOR_INTERRUPTS(); + + data.ctx.P[0] ^= data.expanded_key[0]; + data.ctx.P[1] ^= data.expanded_key[1]; + data.ctx.P[2] ^= data.expanded_key[2]; + data.ctx.P[3] ^= data.expanded_key[3]; + data.ctx.P[4] ^= data.expanded_key[4]; + data.ctx.P[5] ^= data.expanded_key[5]; + data.ctx.P[6] ^= data.expanded_key[6]; + data.ctx.P[7] ^= data.expanded_key[7]; + data.ctx.P[8] ^= data.expanded_key[8]; + data.ctx.P[9] ^= data.expanded_key[9]; + data.ctx.P[10] ^= data.expanded_key[10]; + data.ctx.P[11] ^= data.expanded_key[11]; + data.ctx.P[12] ^= data.expanded_key[12]; + data.ctx.P[13] ^= data.expanded_key[13]; + data.ctx.P[14] ^= data.expanded_key[14]; + data.ctx.P[15] ^= data.expanded_key[15]; + data.ctx.P[16] ^= data.expanded_key[16]; + data.ctx.P[17] ^= data.expanded_key[17]; + + BF_body(); + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + data.ctx.P[0] ^= tmp1; + data.ctx.P[1] ^= tmp2; + data.ctx.P[2] ^= tmp3; + data.ctx.P[3] ^= tmp4; + data.ctx.P[4] ^= tmp1; + data.ctx.P[5] ^= tmp2; + data.ctx.P[6] ^= tmp3; + data.ctx.P[7] ^= tmp4; + data.ctx.P[8] ^= tmp1; + data.ctx.P[9] ^= tmp2; + data.ctx.P[10] ^= tmp3; + data.ctx.P[11] ^= tmp4; + data.ctx.P[12] ^= tmp1; + data.ctx.P[13] ^= tmp2; + data.ctx.P[14] ^= tmp3; + data.ctx.P[15] ^= tmp4; + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + + BF_body(); + } while (--count); + + for (i = 0; i < 6; i += 2) + { + L = BF_magic_w[i]; + R = BF_magic_w[i + 1]; + + count = 64; + do + { + BF_ENCRYPT; + } while (--count); + + data.binary.output[i] = L; + data.binary.output[i + 1] = R; + } + + memcpy(output, setting, 7 + 22 - 1); + output[7 + 22 - 1] = BF_itoa64[(int) + BF_atoi64[(int) setting[7 + 22 - 1] - 0x20] & 0x30]; + +/* This has to be bug-compatible with the original implementation, so + * only encode 23 of the 24 bytes. :-) */ + BF_swap(data.binary.output, 6); + BF_encode(&output[7 + 22], data.binary.output, 23); + output[7 + 22 + 31] = '\0'; + +/* Overwrite the most obvious sensitive data we have on the stack. Note + * that this does not guarantee there's no sensitive data left on the + * stack and/or in registers; I'm not aware of portable code that does. */ + px_memset(&data, 0, sizeof(data)); + + return output; +} diff --git a/contrib/pgcrypto/crypt-des.c b/contrib/pgcrypto/crypt-des.c new file mode 100644 index 0000000..98c30ea --- /dev/null +++ b/contrib/pgcrypto/crypt-des.c @@ -0,0 +1,791 @@ +/* + * FreeSec: libcrypt for NetBSD + * + * contrib/pgcrypto/crypt-des.c + * + * Copyright (c) 1994 David Burren + * All rights reserved. + * + * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet + * this file should now *only* export crypt(), in order to make + * binaries of libcrypt exportable from the USA + * + * Adapted for FreeBSD-4.0 by Mark R V Murray + * this file should now *only* export px_crypt_des(), in order to make + * a module that can be optionally included in libcrypt. + * + * 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. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * $FreeBSD: src/secure/lib/libcrypt/crypt-des.c,v 1.12 1999/09/20 12:39:20 markm Exp $ + * + * This is an original implementation of the DES and the crypt(3) interfaces + * by David Burren <davidb@werj.com.au>. + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + * B. Schneier, Applied Cryptography: protocols, algorithms, + * and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author). A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * ARCHITECTURE ASSUMPTIONS: + * It is assumed that the 8-byte arrays passed by reference can be + * addressed as arrays of uint32's (ie. the CPU is not picky about + * alignment). + */ + +#include "postgres.h" +#include "miscadmin.h" +#include "port/pg_bswap.h" + +#include "px-crypt.h" + +#define _PASSWORD_EFMT1 '_' + +static const char _crypt_a64[] = +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static uint8 IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static uint8 inv_key_perm[64]; +static uint8 u_key_perm[56]; +static uint8 key_perm[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +static uint8 key_shifts[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static uint8 inv_comp_perm[56]; +static uint8 comp_perm[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * No E box is used, as it's replaced by some ANDs, shifts, and ORs. + */ + +static uint8 u_sbox[8][64]; +static uint8 sbox[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +static uint8 un_pbox[32]; +static uint8 pbox[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +static uint32 _crypt_bits32[32] = +{ + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +static uint8 _crypt_bits8[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + +static uint32 saltbits; +static long old_salt; +static uint32 *bits28, + *bits24; +static uint8 init_perm[64], + final_perm[64]; +static uint32 en_keysl[16], + en_keysr[16]; +static uint32 de_keysl[16], + de_keysr[16]; +static int des_initialised = 0; +static uint8 m_sbox[4][4096]; +static uint32 psbox[4][256]; +static uint32 ip_maskl[8][256], + ip_maskr[8][256]; +static uint32 fp_maskl[8][256], + fp_maskr[8][256]; +static uint32 key_perm_maskl[8][128], + key_perm_maskr[8][128]; +static uint32 comp_maskl[8][128], + comp_maskr[8][128]; +static uint32 old_rawkey0, + old_rawkey1; + +static inline int +ascii_to_bin(char ch) +{ + if (ch > 'z') + return 0; + if (ch >= 'a') + return (ch - 'a' + 38); + if (ch > 'Z') + return 0; + if (ch >= 'A') + return (ch - 'A' + 12); + if (ch > '9') + return 0; + if (ch >= '.') + return (ch - '.'); + return 0; +} + +static void +des_init(void) +{ + int i, + j, + b, + k, + inbit, + obit; + uint32 *p, + *il, + *ir, + *fl, + *fr; + + old_rawkey0 = old_rawkey1 = 0L; + saltbits = 0L; + old_salt = 0L; + bits24 = (bits28 = _crypt_bits32 + 4) + 4; + + /* + * Invert the S-boxes, reordering the input bits. + */ + for (i = 0; i < 8; i++) + for (j = 0; j < 64; j++) + { + b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf); + u_sbox[i][j] = sbox[i][b]; + } + + /* + * Convert the inverted S-boxes into 4 arrays of 8 bits. Each will handle + * 12 bits of the S-box input. + */ + for (b = 0; b < 4; b++) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + m_sbox[b][(i << 6) | j] = + (u_sbox[(b << 1)][i] << 4) | + u_sbox[(b << 1) + 1][j]; + + /* + * Set up the initial & final permutations into a useful form, and + * initialise the inverted key permutation. + */ + for (i = 0; i < 64; i++) + { + init_perm[final_perm[i] = IP[i] - 1] = i; + inv_key_perm[i] = 255; + } + + /* + * Invert the key permutation and initialise the inverted key compression + * permutation. + */ + for (i = 0; i < 56; i++) + { + u_key_perm[i] = key_perm[i] - 1; + inv_key_perm[key_perm[i] - 1] = i; + inv_comp_perm[i] = 255; + } + + /* + * Invert the key compression permutation. + */ + for (i = 0; i < 48; i++) + inv_comp_perm[comp_perm[i] - 1] = i; + + /* + * Set up the OR-mask arrays for the initial and final permutations, and + * for the key initial and compression permutations. + */ + for (k = 0; k < 8; k++) + { + for (i = 0; i < 256; i++) + { + *(il = &ip_maskl[k][i]) = 0L; + *(ir = &ip_maskr[k][i]) = 0L; + *(fl = &fp_maskl[k][i]) = 0L; + *(fr = &fp_maskr[k][i]) = 0L; + for (j = 0; j < 8; j++) + { + inbit = 8 * k + j; + if (i & _crypt_bits8[j]) + { + if ((obit = init_perm[inbit]) < 32) + *il |= _crypt_bits32[obit]; + else + *ir |= _crypt_bits32[obit - 32]; + if ((obit = final_perm[inbit]) < 32) + *fl |= _crypt_bits32[obit]; + else + *fr |= _crypt_bits32[obit - 32]; + } + } + } + for (i = 0; i < 128; i++) + { + *(il = &key_perm_maskl[k][i]) = 0L; + *(ir = &key_perm_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) + { + inbit = 8 * k + j; + if (i & _crypt_bits8[j + 1]) + { + if ((obit = inv_key_perm[inbit]) == 255) + continue; + if (obit < 28) + *il |= bits28[obit]; + else + *ir |= bits28[obit - 28]; + } + } + *(il = &comp_maskl[k][i]) = 0L; + *(ir = &comp_maskr[k][i]) = 0L; + for (j = 0; j < 7; j++) + { + inbit = 7 * k + j; + if (i & _crypt_bits8[j + 1]) + { + if ((obit = inv_comp_perm[inbit]) == 255) + continue; + if (obit < 24) + *il |= bits24[obit]; + else + *ir |= bits24[obit - 24]; + } + } + } + } + + /* + * Invert the P-box permutation, and convert into OR-masks for handling + * the output of the S-box arrays setup above. + */ + for (i = 0; i < 32; i++) + un_pbox[pbox[i] - 1] = i; + + for (b = 0; b < 4; b++) + for (i = 0; i < 256; i++) + { + *(p = &psbox[b][i]) = 0L; + for (j = 0; j < 8; j++) + { + if (i & _crypt_bits8[j]) + *p |= _crypt_bits32[un_pbox[8 * b + j]]; + } + } + + des_initialised = 1; +} + +static void +setup_salt(long salt) +{ + uint32 obit, + saltbit; + int i; + + if (salt == old_salt) + return; + old_salt = salt; + + saltbits = 0L; + saltbit = 1; + obit = 0x800000; + for (i = 0; i < 24; i++) + { + if (salt & saltbit) + saltbits |= obit; + saltbit <<= 1; + obit >>= 1; + } +} + +static int +des_setkey(const char *key) +{ + uint32 k0, + k1, + rawkey0, + rawkey1; + int shifts, + round; + + if (!des_initialised) + des_init(); + + rawkey0 = pg_ntoh32(*(const uint32 *) key); + rawkey1 = pg_ntoh32(*(const uint32 *) (key + 4)); + + if ((rawkey0 | rawkey1) + && rawkey0 == old_rawkey0 + && rawkey1 == old_rawkey1) + { + /* + * Already setup for this key. This optimization fails on a zero key + * (which is weak and has bad parity anyway) in order to simplify the + * starting conditions. + */ + return 0; + } + old_rawkey0 = rawkey0; + old_rawkey1 = rawkey1; + + /* + * Do key permutation and split into two 28-bit subkeys. + */ + k0 = key_perm_maskl[0][rawkey0 >> 25] + | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskl[4][rawkey1 >> 25] + | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; + k1 = key_perm_maskr[0][rawkey0 >> 25] + | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] + | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] + | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] + | key_perm_maskr[4][rawkey1 >> 25] + | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] + | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] + | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; + + /* + * Rotate subkeys and do compression permutation. + */ + shifts = 0; + for (round = 0; round < 16; round++) + { + uint32 t0, + t1; + + shifts += key_shifts[round]; + + t0 = (k0 << shifts) | (k0 >> (28 - shifts)); + t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + + de_keysl[15 - round] = + en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] + | comp_maskl[1][(t0 >> 14) & 0x7f] + | comp_maskl[2][(t0 >> 7) & 0x7f] + | comp_maskl[3][t0 & 0x7f] + | comp_maskl[4][(t1 >> 21) & 0x7f] + | comp_maskl[5][(t1 >> 14) & 0x7f] + | comp_maskl[6][(t1 >> 7) & 0x7f] + | comp_maskl[7][t1 & 0x7f]; + + de_keysr[15 - round] = + en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] + | comp_maskr[1][(t0 >> 14) & 0x7f] + | comp_maskr[2][(t0 >> 7) & 0x7f] + | comp_maskr[3][t0 & 0x7f] + | comp_maskr[4][(t1 >> 21) & 0x7f] + | comp_maskr[5][(t1 >> 14) & 0x7f] + | comp_maskr[6][(t1 >> 7) & 0x7f] + | comp_maskr[7][t1 & 0x7f]; + } + return 0; +} + +static int +do_des(uint32 l_in, uint32 r_in, uint32 *l_out, uint32 *r_out, int count) +{ + /* + * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format. + */ + uint32 l, + r, + *kl, + *kr, + *kl1, + *kr1; + uint32 f, + r48l, + r48r; + int round; + + if (count == 0) + return 1; + else if (count > 0) + { + /* + * Encrypting + */ + kl1 = en_keysl; + kr1 = en_keysr; + } + else + { + /* + * Decrypting + */ + count = -count; + kl1 = de_keysl; + kr1 = de_keysr; + } + + /* + * Do initial permutation (IP). + */ + l = ip_maskl[0][l_in >> 24] + | ip_maskl[1][(l_in >> 16) & 0xff] + | ip_maskl[2][(l_in >> 8) & 0xff] + | ip_maskl[3][l_in & 0xff] + | ip_maskl[4][r_in >> 24] + | ip_maskl[5][(r_in >> 16) & 0xff] + | ip_maskl[6][(r_in >> 8) & 0xff] + | ip_maskl[7][r_in & 0xff]; + r = ip_maskr[0][l_in >> 24] + | ip_maskr[1][(l_in >> 16) & 0xff] + | ip_maskr[2][(l_in >> 8) & 0xff] + | ip_maskr[3][l_in & 0xff] + | ip_maskr[4][r_in >> 24] + | ip_maskr[5][(r_in >> 16) & 0xff] + | ip_maskr[6][(r_in >> 8) & 0xff] + | ip_maskr[7][r_in & 0xff]; + + while (count--) + { + CHECK_FOR_INTERRUPTS(); + + /* + * Do each round. + */ + kl = kl1; + kr = kr1; + round = 16; + while (round--) + { + /* + * Expand R to 48 bits (simulate the E-box). + */ + r48l = ((r & 0x00000001) << 23) + | ((r & 0xf8000000) >> 9) + | ((r & 0x1f800000) >> 11) + | ((r & 0x01f80000) >> 13) + | ((r & 0x001f8000) >> 15); + + r48r = ((r & 0x0001f800) << 7) + | ((r & 0x00001f80) << 5) + | ((r & 0x000001f8) << 3) + | ((r & 0x0000001f) << 1) + | ((r & 0x80000000) >> 31); + + /* + * Do salting for crypt() and friends, and XOR with the permuted + * key. + */ + f = (r48l ^ r48r) & saltbits; + r48l ^= f ^ *kl++; + r48r ^= f ^ *kr++; + + /* + * Do sbox lookups (which shrink it back to 32 bits) and do the + * pbox permutation at the same time. + */ + f = psbox[0][m_sbox[0][r48l >> 12]] + | psbox[1][m_sbox[1][r48l & 0xfff]] + | psbox[2][m_sbox[2][r48r >> 12]] + | psbox[3][m_sbox[3][r48r & 0xfff]]; + + /* + * Now that we've permuted things, complete f(). + */ + f ^= l; + l = r; + r = f; + } + r = l; + l = f; + } + + /* + * Do final permutation (inverse of IP). + */ + *l_out = fp_maskl[0][l >> 24] + | fp_maskl[1][(l >> 16) & 0xff] + | fp_maskl[2][(l >> 8) & 0xff] + | fp_maskl[3][l & 0xff] + | fp_maskl[4][r >> 24] + | fp_maskl[5][(r >> 16) & 0xff] + | fp_maskl[6][(r >> 8) & 0xff] + | fp_maskl[7][r & 0xff]; + *r_out = fp_maskr[0][l >> 24] + | fp_maskr[1][(l >> 16) & 0xff] + | fp_maskr[2][(l >> 8) & 0xff] + | fp_maskr[3][l & 0xff] + | fp_maskr[4][r >> 24] + | fp_maskr[5][(r >> 16) & 0xff] + | fp_maskr[6][(r >> 8) & 0xff] + | fp_maskr[7][r & 0xff]; + return 0; +} + +static int +des_cipher(const char *in, char *out, long salt, int count) +{ + uint32 buffer[2]; + uint32 l_out, + r_out, + rawl, + rawr; + int retval; + + if (!des_initialised) + des_init(); + + setup_salt(salt); + + /* copy data to avoid assuming input is word-aligned */ + memcpy(buffer, in, sizeof(buffer)); + + rawl = pg_ntoh32(buffer[0]); + rawr = pg_ntoh32(buffer[1]); + + retval = do_des(rawl, rawr, &l_out, &r_out, count); + if (retval) + return retval; + + buffer[0] = pg_hton32(l_out); + buffer[1] = pg_hton32(r_out); + + /* copy data to avoid assuming output is word-aligned */ + memcpy(out, buffer, sizeof(buffer)); + + return retval; +} + +char * +px_crypt_des(const char *key, const char *setting) +{ + int i; + uint32 count, + salt, + l, + r0, + r1, + keybuf[2]; + char *p; + uint8 *q; + static char output[21]; + + if (!des_initialised) + des_init(); + + + /* + * Copy the key, shifting each character up by one bit and padding with + * zeros. + */ + q = (uint8 *) keybuf; + while (q - (uint8 *) keybuf - 8) + { + *q++ = *key << 1; + if (*key != '\0') + key++; + } + if (des_setkey((char *) keybuf)) + return NULL; + +#ifndef DISABLE_XDES + if (*setting == _PASSWORD_EFMT1) + { + /* + * "new"-style: setting must be a 9-character (underscore, then 4 + * bytes of count, then 4 bytes of salt) string. See CRYPT(3) under + * the "Extended crypt" heading for further details. + * + * Unlimited characters of the input key are used. This is known as + * the "Extended crypt" DES method. + * + */ + if (strlen(setting) < 9) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + + for (i = 1, count = 0L; i < 5; i++) + count |= ascii_to_bin(setting[i]) << (i - 1) * 6; + + for (i = 5, salt = 0L; i < 9; i++) + salt |= ascii_to_bin(setting[i]) << (i - 5) * 6; + + while (*key) + { + /* + * Encrypt the key with itself. + */ + if (des_cipher((char *) keybuf, (char *) keybuf, 0L, 1)) + return NULL; + + /* + * And XOR with the next 8 characters of the key. + */ + q = (uint8 *) keybuf; + while (q - (uint8 *) keybuf - 8 && *key) + *q++ ^= *key++ << 1; + + if (des_setkey((char *) keybuf)) + return NULL; + } + strlcpy(output, setting, 10); + + /* + * Double check that we weren't given a short setting. If we were, the + * above code will probably have created weird values for count and + * salt, but we don't really care. Just make sure the output string + * doesn't have an extra NUL in it. + */ + p = output + strlen(output); + } + else +#endif /* !DISABLE_XDES */ + { + /* + * "old"-style: setting - 2 bytes of salt key - only up to the first 8 + * characters of the input key are used. + */ + count = 25; + + if (strlen(setting) < 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + + salt = (ascii_to_bin(setting[1]) << 6) + | ascii_to_bin(setting[0]); + + output[0] = setting[0]; + + /* + * If the encrypted password that the salt was extracted from is only + * 1 character long, the salt will be corrupted. We need to ensure + * that the output string doesn't have an extra NUL in it! + */ + output[1] = setting[1] ? setting[1] : output[0]; + + p = output + 2; + } + setup_salt(salt); + + /* + * Do it. + */ + if (do_des(0L, 0L, &r0, &r1, count)) + return NULL; + + /* + * Now encode the result... + */ + l = (r0 >> 8); + *p++ = _crypt_a64[(l >> 18) & 0x3f]; + *p++ = _crypt_a64[(l >> 12) & 0x3f]; + *p++ = _crypt_a64[(l >> 6) & 0x3f]; + *p++ = _crypt_a64[l & 0x3f]; + + l = (r0 << 16) | ((r1 >> 16) & 0xffff); + *p++ = _crypt_a64[(l >> 18) & 0x3f]; + *p++ = _crypt_a64[(l >> 12) & 0x3f]; + *p++ = _crypt_a64[(l >> 6) & 0x3f]; + *p++ = _crypt_a64[l & 0x3f]; + + l = r1 << 2; + *p++ = _crypt_a64[(l >> 12) & 0x3f]; + *p++ = _crypt_a64[(l >> 6) & 0x3f]; + *p++ = _crypt_a64[l & 0x3f]; + *p = 0; + + return output; +} diff --git a/contrib/pgcrypto/crypt-gensalt.c b/contrib/pgcrypto/crypt-gensalt.c new file mode 100644 index 0000000..740f361 --- /dev/null +++ b/contrib/pgcrypto/crypt-gensalt.c @@ -0,0 +1,187 @@ +/* + * Written by Solar Designer and placed in the public domain. + * See crypt_blowfish.c for more information. + * + * contrib/pgcrypto/crypt-gensalt.c + * + * This file contains salt generation functions for the traditional and + * other common crypt(3) algorithms, except for bcrypt which is defined + * entirely in crypt_blowfish.c. + * + * Put bcrypt generator also here as crypt-blowfish.c + * may not be compiled always. -- marko + */ + +#include "postgres.h" + +#include "px-crypt.h" + +typedef unsigned int BF_word; + +static unsigned char _crypt_itoa64[64 + 1] = +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +char * +_crypt_gensalt_traditional_rn(unsigned long count, + const char *input, int size, char *output, int output_size) +{ + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) + { + if (output_size > 0) + output[0] = '\0'; + return NULL; + } + + output[0] = _crypt_itoa64[(unsigned int) input[0] & 0x3f]; + output[1] = _crypt_itoa64[(unsigned int) input[1] & 0x3f]; + output[2] = '\0'; + + return output; +} + +char * +_crypt_gensalt_extended_rn(unsigned long count, + const char *input, int size, char *output, int output_size) +{ + unsigned long value; + +/* Even iteration counts make it easier to detect weak DES keys from a look + * at the hash, so they should be avoided */ + if (size < 3 || output_size < 1 + 4 + 4 + 1 || + (count && (count > 0xffffff || !(count & 1)))) + { + if (output_size > 0) + output[0] = '\0'; + return NULL; + } + + if (!count) + count = 725; + + output[0] = '_'; + output[1] = _crypt_itoa64[count & 0x3f]; + output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; + output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; + output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; + value = (unsigned long) (unsigned char) input[0] | + ((unsigned long) (unsigned char) input[1] << 8) | + ((unsigned long) (unsigned char) input[2] << 16); + output[5] = _crypt_itoa64[value & 0x3f]; + output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[9] = '\0'; + + return output; +} + +char * +_crypt_gensalt_md5_rn(unsigned long count, + const char *input, int size, char *output, int output_size) +{ + unsigned long value; + + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) + { + if (output_size > 0) + output[0] = '\0'; + return NULL; + } + + output[0] = '$'; + output[1] = '1'; + output[2] = '$'; + value = (unsigned long) (unsigned char) input[0] | + ((unsigned long) (unsigned char) input[1] << 8) | + ((unsigned long) (unsigned char) input[2] << 16); + output[3] = _crypt_itoa64[value & 0x3f]; + output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[7] = '\0'; + + if (size >= 6 && output_size >= 3 + 4 + 4 + 1) + { + value = (unsigned long) (unsigned char) input[3] | + ((unsigned long) (unsigned char) input[4] << 8) | + ((unsigned long) (unsigned char) input[5] << 16); + output[7] = _crypt_itoa64[value & 0x3f]; + output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[11] = '\0'; + } + + return output; +} + + + +static unsigned char BF_itoa64[64 + 1] = +"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static void +BF_encode(char *dst, const BF_word *src, int size) +{ + const unsigned char *sptr = (const unsigned char *) src; + const unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *) dst; + unsigned int c1, + c2; + + do + { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) + { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) + { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +char * +_crypt_gensalt_blowfish_rn(unsigned long count, + const char *input, int size, char *output, int output_size) +{ + if (size < 16 || output_size < 7 + 22 + 1 || + (count && (count < 4 || count > 31))) + { + if (output_size > 0) + output[0] = '\0'; + return NULL; + } + + if (!count) + count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = 'a'; + output[3] = '$'; + output[4] = '0' + count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (const BF_word *) input, 16); + output[7 + 22] = '\0'; + + return output; +} diff --git a/contrib/pgcrypto/crypt-md5.c b/contrib/pgcrypto/crypt-md5.c new file mode 100644 index 0000000..d38721a --- /dev/null +++ b/contrib/pgcrypto/crypt-md5.c @@ -0,0 +1,169 @@ +/* + * File imported from FreeBSD, original by Poul-Henning Kamp. + * + * $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $ + * + * contrib/pgcrypto/crypt-md5.c + */ + +#include "postgres.h" + +#include "px-crypt.h" +#include "px.h" + +#define MD5_SIZE 16 + +static const char _crypt_a64[] = +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void +_crypt_to64(char *s, unsigned long v, int n) +{ + while (--n >= 0) + { + *s++ = _crypt_a64[v & 0x3f]; + v >>= 6; + } +} + +/* + * UNIX password + */ + +char * +px_crypt_md5(const char *pw, const char *salt, char *passwd, unsigned dstlen) +{ + static char *magic = "$1$"; /* This string is magic for this algorithm. + * Having it this way, we can get better later + * on */ + static char *p; + static const char *sp, + *ep; + unsigned char final[MD5_SIZE]; + int sl, + pl, + i; + PX_MD *ctx, + *ctx1; + int err; + unsigned long l; + + if (!passwd || dstlen < 120) + return NULL; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if (strncmp(sp, magic, strlen(magic)) == 0) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + /* we need two PX_MD objects */ + err = px_find_digest("md5", &ctx); + if (err) + return NULL; + err = px_find_digest("md5", &ctx1); + if (err) + { + /* this path is possible under low-memory circumstances */ + px_md_free(ctx); + return NULL; + } + + /* The password first, since that is what is most unknown */ + px_md_update(ctx, (const uint8 *) pw, strlen(pw)); + + /* Then our magic string */ + px_md_update(ctx, (uint8 *) magic, strlen(magic)); + + /* Then the raw salt */ + px_md_update(ctx, (const uint8 *) sp, sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + px_md_update(ctx1, (const uint8 *) pw, strlen(pw)); + px_md_update(ctx1, (const uint8 *) sp, sl); + px_md_update(ctx1, (const uint8 *) pw, strlen(pw)); + px_md_finish(ctx1, final); + for (pl = strlen(pw); pl > 0; pl -= MD5_SIZE) + px_md_update(ctx, final, pl > MD5_SIZE ? MD5_SIZE : pl); + + /* Don't leave anything around in vm they could use. */ + px_memset(final, 0, sizeof final); + + /* Then something really weird... */ + for (i = strlen(pw); i; i >>= 1) + if (i & 1) + px_md_update(ctx, final, 1); + else + px_md_update(ctx, (const uint8 *) pw, 1); + + /* Now make the output string */ + strcpy(passwd, magic); + strncat(passwd, sp, sl); + strcat(passwd, "$"); + + px_md_finish(ctx, final); + + /* + * and now, just to make sure things don't run too fast On a 60 Mhz + * Pentium this takes 34 msec, so you would need 30 seconds to build a + * 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) + { + px_md_reset(ctx1); + if (i & 1) + px_md_update(ctx1, (const uint8 *) pw, strlen(pw)); + else + px_md_update(ctx1, final, MD5_SIZE); + + if (i % 3) + px_md_update(ctx1, (const uint8 *) sp, sl); + + if (i % 7) + px_md_update(ctx1, (const uint8 *) pw, strlen(pw)); + + if (i & 1) + px_md_update(ctx1, final, MD5_SIZE); + else + px_md_update(ctx1, (const uint8 *) pw, strlen(pw)); + px_md_finish(ctx1, final); + } + + p = passwd + strlen(passwd); + + l = (final[0] << 16) | (final[6] << 8) | final[12]; + _crypt_to64(p, l, 4); + p += 4; + l = (final[1] << 16) | (final[7] << 8) | final[13]; + _crypt_to64(p, l, 4); + p += 4; + l = (final[2] << 16) | (final[8] << 8) | final[14]; + _crypt_to64(p, l, 4); + p += 4; + l = (final[3] << 16) | (final[9] << 8) | final[15]; + _crypt_to64(p, l, 4); + p += 4; + l = (final[4] << 16) | (final[10] << 8) | final[5]; + _crypt_to64(p, l, 4); + p += 4; + l = final[11]; + _crypt_to64(p, l, 2); + p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + px_memset(final, 0, sizeof final); + + px_md_free(ctx1); + px_md_free(ctx); + + return passwd; +} diff --git a/contrib/pgcrypto/expected/3des.out b/contrib/pgcrypto/expected/3des.out new file mode 100644 index 0000000..ee15489 --- /dev/null +++ b/contrib/pgcrypto/expected/3des.out @@ -0,0 +1,65 @@ +-- +-- 3DES cipher +-- +-- test vector from somewhere +SELECT encrypt('\x8000000000000000', + '\x010101010101010101010101010101010101010101010101', + '3des-ecb/pad:none'); + encrypt +-------------------- + \x95f8a5e5dd31d900 +(1 row) + +select encrypt('', 'foo', '3des'); + encrypt +-------------------- + \x752111e37a2d7ac3 +(1 row) + +-- 10 bytes key +select encrypt('foo', '0123456789', '3des'); + encrypt +-------------------- + \xd2fb8baa1717cb02 +(1 row) + +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', '3des'); + encrypt +-------------------- + \xa44360e699269817 +(1 row) + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', '3des'), '0123456', '3des'), 'escape'); + encode +-------- + foo +(1 row) + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', '3des'); + encrypt_iv +-------------------- + \x50735067b073bb93 +(1 row) + +select encode(decrypt_iv('\x50735067b073bb93', '0123456', 'abcd', '3des'), 'escape'); + encode +-------- + foo +(1 row) + +-- long message +select encrypt('Lets try a longer message.', '0123456789012345678901', '3des'); + encrypt +-------------------------------------------------------------------- + \xb71e3422269d0ded19468f33d65cd663c28e0871984792a7b3ba0ddcecec8d2c +(1 row) + +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789012345678901', '3des'), '0123456789012345678901', '3des'), 'escape'); + encode +---------------------------- + Lets try a longer message. +(1 row) + diff --git a/contrib/pgcrypto/expected/blowfish.out b/contrib/pgcrypto/expected/blowfish.out new file mode 100644 index 0000000..f0346a7 --- /dev/null +++ b/contrib/pgcrypto/expected/blowfish.out @@ -0,0 +1,142 @@ +-- +-- Blowfish cipher +-- +-- some standard Blowfish testvalues +SELECT encrypt('\x0000000000000000', '\x0000000000000000', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x4ef997456198dd78 +(1 row) + +SELECT encrypt('\xffffffffffffffff', '\xffffffffffffffff', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x51866fd5b85ecb8a +(1 row) + +SELECT encrypt('\x1000000000000001', '\x3000000000000000', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x7d856f9a613063f2 +(1 row) + +SELECT encrypt('\x1111111111111111', '\x1111111111111111', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x2466dd878b963c9d +(1 row) + +SELECT encrypt('\x0123456789abcdef', '\xfedcba9876543210', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x0aceab0fc6a0a28d +(1 row) + +SELECT encrypt('\x01a1d6d039776742', '\xfedcba9876543210', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x3273b8badc9e9e15 +(1 row) + +SELECT encrypt('\xffffffffffffffff', '\x0000000000000000', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x014933e0cdaff6e4 +(1 row) + +-- setkey +SELECT encrypt('\xfedcba9876543210', '\xf0e1d2c3b4a5968778695a4b3c2d1e0f', 'bf-ecb/pad:none'); + encrypt +-------------------- + \x93142887ee3be15c +(1 row) + +-- with padding +SELECT encrypt('\x01234567890123456789', '\x33443344334433443344334433443344', 'bf-ecb'); + encrypt +------------------------------------ + \x0d04a43a20456dee5ede6ed9e4dcaaa6 +(1 row) + +-- cbc +-- 28 bytes key +SELECT encrypt('\x6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5', + '\x37363534333231204e6f77206973207468652074696d6520666f7220', + 'bf-cbc'); + encrypt +-------------------------------------------------------------------- + \x4f2beb748c4f689ec755edb9dc252a41b93a3786850b4c75d6a702b6a8e48825 +(1 row) + +-- 29 bytes key +SELECT encrypt('\x6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc', + '\x37363534333231204e6f77206973207468652074696d6520666f722000', + 'bf-cbc'); + encrypt +------------------------------------------------------------------------------------ + \x3ea6357a0ee7fad6d0c4b63464f2aafa40c2e91b4b7e1bba8114932fd92b5c8f111e7e50e7b2e541 +(1 row) + +-- blowfish-448 +SELECT encrypt('\xfedcba9876543210', + '\xf0e1d2c3b4a5968778695a4b3c2d1e0f001122334455667704689104c2fd3b2f584023641aba61761f1f1f1f0e0e0e0effffffffffffffff', + 'bf-ecb/pad:none'); + encrypt +-------------------- + \xc04504012e4e1f53 +(1 row) + +-- empty data +select encrypt('', 'foo', 'bf'); + encrypt +-------------------- + \x1871949bb2311c8e +(1 row) + +-- 10 bytes key +select encrypt('foo', '0123456789', 'bf'); + encrypt +-------------------- + \x42f58af3b2c03f46 +(1 row) + +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', 'bf'); + encrypt +-------------------- + \x86ab6f0bc72b5f22 +(1 row) + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'bf'), '0123456', 'bf'), 'escape'); + encode +-------- + foo +(1 row) + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'bf'); + encrypt_iv +-------------------- + \x95c7e89322525d59 +(1 row) + +select encode(decrypt_iv('\x95c7e89322525d59', '0123456', 'abcd', 'bf'), 'escape'); + encode +-------- + foo +(1 row) + +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'bf'); + encrypt +-------------------------------------------------------------------- + \xa76059f7a1b627b5b84080d9beb337714c7a7f8b70300023e5feb6dfa6813536 +(1 row) + +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'bf'), '0123456789', 'bf'), 'escape'); + encode +---------------------------- + Lets try a longer message. +(1 row) + diff --git a/contrib/pgcrypto/expected/blowfish_1.out b/contrib/pgcrypto/expected/blowfish_1.out new file mode 100644 index 0000000..e52abf1 --- /dev/null +++ b/contrib/pgcrypto/expected/blowfish_1.out @@ -0,0 +1,62 @@ +-- +-- Blowfish cipher +-- +-- some standard Blowfish testvalues +SELECT encrypt('\x0000000000000000', '\x0000000000000000', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +SELECT encrypt('\xffffffffffffffff', '\xffffffffffffffff', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +SELECT encrypt('\x1000000000000001', '\x3000000000000000', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +SELECT encrypt('\x1111111111111111', '\x1111111111111111', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +SELECT encrypt('\x0123456789abcdef', '\xfedcba9876543210', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +SELECT encrypt('\x01a1d6d039776742', '\xfedcba9876543210', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +SELECT encrypt('\xffffffffffffffff', '\x0000000000000000', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +-- setkey +SELECT encrypt('\xfedcba9876543210', '\xf0e1d2c3b4a5968778695a4b3c2d1e0f', 'bf-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +-- with padding +SELECT encrypt('\x01234567890123456789', '\x33443344334433443344334433443344', 'bf-ecb'); +ERROR: encrypt error: Cipher cannot be initialized +-- cbc +-- 28 bytes key +SELECT encrypt('\x6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5', + '\x37363534333231204e6f77206973207468652074696d6520666f7220', + 'bf-cbc'); +ERROR: encrypt error: Key was too big +-- 29 bytes key +SELECT encrypt('\x6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc', + '\x37363534333231204e6f77206973207468652074696d6520666f722000', + 'bf-cbc'); +ERROR: encrypt error: Key was too big +-- blowfish-448 +SELECT encrypt('\xfedcba9876543210', + '\xf0e1d2c3b4a5968778695a4b3c2d1e0f001122334455667704689104c2fd3b2f584023641aba61761f1f1f1f0e0e0e0effffffffffffffff', + 'bf-ecb/pad:none'); +ERROR: encrypt error: Key was too big +-- empty data +select encrypt('', 'foo', 'bf'); +ERROR: encrypt error: Cipher cannot be initialized +-- 10 bytes key +select encrypt('foo', '0123456789', 'bf'); +ERROR: encrypt error: Cipher cannot be initialized +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', 'bf'); +ERROR: encrypt error: Key was too big +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'bf'), '0123456', 'bf'), 'escape'); +ERROR: encrypt error: Cipher cannot be initialized +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'bf'); +ERROR: encrypt_iv error: Cipher cannot be initialized +select encode(decrypt_iv('\x95c7e89322525d59', '0123456', 'abcd', 'bf'), 'escape'); +ERROR: decrypt_iv error: Cipher cannot be initialized +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'bf'); +ERROR: encrypt error: Cipher cannot be initialized +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'bf'), '0123456789', 'bf'), 'escape'); +ERROR: encrypt error: Cipher cannot be initialized diff --git a/contrib/pgcrypto/expected/cast5.out b/contrib/pgcrypto/expected/cast5.out new file mode 100644 index 0000000..8a4da98 --- /dev/null +++ b/contrib/pgcrypto/expected/cast5.out @@ -0,0 +1,73 @@ +-- +-- Cast5 cipher +-- +-- test vectors from RFC2144 +-- 128 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x0123456712345678234567893456789A', 'cast5-ecb/pad:none'); + encrypt +-------------------- + \x238b4fe5847e44b2 +(1 row) + +-- 80 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x01234567123456782345', 'cast5-ecb/pad:none'); + encrypt +-------------------- + \xeb6a711a2c02271b +(1 row) + +-- 40 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x0123456712', 'cast5-ecb/pad:none'); + encrypt +-------------------- + \x7ac816d16e9b302e +(1 row) + +-- cbc +-- empty data +select encrypt('', 'foo', 'cast5'); + encrypt +-------------------- + \xa48bd1aabde4de10 +(1 row) + +-- 10 bytes key +select encrypt('foo', '0123456789', 'cast5'); + encrypt +-------------------- + \xb07f19255e60cb6d +(1 row) + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'cast5'), '0123456', 'cast5'), 'escape'); + encode +-------- + foo +(1 row) + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'cast5'); + encrypt_iv +-------------------- + \x384a970695ce016a +(1 row) + +select encode(decrypt_iv('\x384a970695ce016a', '0123456', 'abcd', 'cast5'), 'escape'); + encode +-------- + foo +(1 row) + +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'cast5'); + encrypt +-------------------------------------------------------------------- + \x04fcffc91533e1505dadcb10766d9fed0937818e663e402384e049942ba60fff +(1 row) + +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'cast5'), '0123456789', 'cast5'), 'escape'); + encode +---------------------------- + Lets try a longer message. +(1 row) + diff --git a/contrib/pgcrypto/expected/cast5_1.out b/contrib/pgcrypto/expected/cast5_1.out new file mode 100644 index 0000000..175e0b0 --- /dev/null +++ b/contrib/pgcrypto/expected/cast5_1.out @@ -0,0 +1,33 @@ +-- +-- Cast5 cipher +-- +-- test vectors from RFC2144 +-- 128 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x0123456712345678234567893456789A', 'cast5-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +-- 80 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x01234567123456782345', 'cast5-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +-- 40 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x0123456712', 'cast5-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +-- cbc +-- empty data +select encrypt('', 'foo', 'cast5'); +ERROR: encrypt error: Cipher cannot be initialized +-- 10 bytes key +select encrypt('foo', '0123456789', 'cast5'); +ERROR: encrypt error: Cipher cannot be initialized +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'cast5'), '0123456', 'cast5'), 'escape'); +ERROR: encrypt error: Cipher cannot be initialized +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'cast5'); +ERROR: encrypt_iv error: Cipher cannot be initialized +select encode(decrypt_iv('\x384a970695ce016a', '0123456', 'abcd', 'cast5'), 'escape'); +ERROR: decrypt_iv error: Cipher cannot be initialized +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'cast5'); +ERROR: encrypt error: Cipher cannot be initialized +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'cast5'), '0123456789', 'cast5'), 'escape'); +ERROR: encrypt error: Cipher cannot be initialized diff --git a/contrib/pgcrypto/expected/crypt-blowfish.out b/contrib/pgcrypto/expected/crypt-blowfish.out new file mode 100644 index 0000000..d79b0c0 --- /dev/null +++ b/contrib/pgcrypto/expected/crypt-blowfish.out @@ -0,0 +1,36 @@ +-- +-- crypt() and gen_salt(): bcrypt +-- +SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); + crypt +-------------------------------------------------------------- + $2a$06$RQiOJ.3ELirrXwxIZY8q0OlGbBEpDmx7IRZlNYvGJ1SHXwNi2cEKK +(1 row) + +SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); + crypt +-------------------------------------------------------------- + $2a$06$RQiOJ.3ELirrXwxIZY8q0OR3CVJrAfda1z26CCHPnB6mmVZD8p0/C +(1 row) + +-- error, salt too short: +SELECT crypt('foox', '$2a$'); +ERROR: invalid salt +-- error, first digit of count in salt invalid +SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O'); +ERROR: invalid salt +-- error, count in salt too small +SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O'); +ERROR: invalid salt +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); +UPDATE ctest SET salt = gen_salt('bf', 8); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + worked +-------- + t +(1 row) + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/expected/crypt-des.out b/contrib/pgcrypto/expected/crypt-des.out new file mode 100644 index 0000000..a462dcd --- /dev/null +++ b/contrib/pgcrypto/expected/crypt-des.out @@ -0,0 +1,31 @@ +-- +-- crypt() and gen_salt(): crypt-des +-- +SELECT crypt('', 'NB'); + crypt +--------------- + NBPx/38Y48kHg +(1 row) + +SELECT crypt('foox', 'NB'); + crypt +--------------- + NB53EGGqrrb5E +(1 row) + +-- We are supposed to pass in a 2-character salt. +-- error since salt is too short: +SELECT crypt('password', 'a'); +ERROR: invalid salt +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); +UPDATE ctest SET salt = gen_salt('des'); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + worked +-------- + t +(1 row) + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/expected/crypt-md5.out b/contrib/pgcrypto/expected/crypt-md5.out new file mode 100644 index 0000000..a1c8304 --- /dev/null +++ b/contrib/pgcrypto/expected/crypt-md5.out @@ -0,0 +1,27 @@ +-- +-- crypt() and gen_salt(): md5 +-- +SELECT crypt('', '$1$Szzz0yzz'); + crypt +------------------------------------ + $1$Szzz0yzz$To38XrR3BsbXQW2ZpfKjF1 +(1 row) + +SELECT crypt('foox', '$1$Szzz0yzz'); + crypt +------------------------------------ + $1$Szzz0yzz$IYL49cd3t9bllsA7Jmz1M1 +(1 row) + +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); +UPDATE ctest SET salt = gen_salt('md5'); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + worked +-------- + t +(1 row) + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/expected/crypt-xdes.out b/contrib/pgcrypto/expected/crypt-xdes.out new file mode 100644 index 0000000..8cf9075 --- /dev/null +++ b/contrib/pgcrypto/expected/crypt-xdes.out @@ -0,0 +1,51 @@ +-- +-- crypt() and gen_salt(): extended des +-- +SELECT crypt('', '_J9..j2zz'); + crypt +---------------------- + _J9..j2zzR/nIRDK3pPc +(1 row) + +SELECT crypt('foox', '_J9..j2zz'); + crypt +---------------------- + _J9..j2zzAYKMvO2BYRY +(1 row) + +-- check XDES handling of keys longer than 8 chars +SELECT crypt('longlongpassword', '_J9..j2zz'); + crypt +---------------------- + _J9..j2zz4BeseiQNwUg +(1 row) + +-- error, salt too short +SELECT crypt('foox', '_J9..BWH'); +ERROR: invalid salt +-- error, count specified in the second argument is 0 +SELECT crypt('password', '_........'); +ERROR: crypt(3) returned NULL +-- error, count will wind up still being 0 due to invalid encoding +-- of the count: only chars ``./0-9A-Za-z' are valid +SELECT crypt('password', '_..!!!!!!'); +ERROR: crypt(3) returned NULL +-- count should be non-zero here, will work +SELECT crypt('password', '_/!!!!!!!'); + crypt +---------------------- + _/!!!!!!!zqM49hRzxko +(1 row) + +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); +UPDATE ctest SET salt = gen_salt('xdes', 1001); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + worked +-------- + t +(1 row) + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/expected/des.out b/contrib/pgcrypto/expected/des.out new file mode 100644 index 0000000..fdbaea2 --- /dev/null +++ b/contrib/pgcrypto/expected/des.out @@ -0,0 +1,58 @@ +-- +-- DES cipher +-- +-- no official test vectors atm +-- from blowfish.sql +SELECT encrypt('\x0123456789abcdef', '\xfedcba9876543210', 'des-ecb/pad:none'); + encrypt +-------------------- + \xed39d950fa74bcc4 +(1 row) + +-- empty data +select encrypt('', 'foo', 'des'); + encrypt +-------------------- + \x752111e37a2d7ac3 +(1 row) + +-- 8 bytes key +select encrypt('foo', '01234589', 'des'); + encrypt +-------------------- + \xdec0f9c602b647a8 +(1 row) + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'des'), '0123456', 'des'), 'escape'); + encode +-------- + foo +(1 row) + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'des'); + encrypt_iv +-------------------- + \x50735067b073bb93 +(1 row) + +select encode(decrypt_iv('\x50735067b073bb93', '0123456', 'abcd', 'des'), 'escape'); + encode +-------- + foo +(1 row) + +-- long message +select encrypt('Lets try a longer message.', '01234567', 'des'); + encrypt +-------------------------------------------------------------------- + \x5ad146043e5f30967e06a0fcbae602daf4ff2a5fd0ed12d6c5913cf85f1e36ca +(1 row) + +select encode(decrypt(encrypt('Lets try a longer message.', '01234567', 'des'), '01234567', 'des'), 'escape'); + encode +---------------------------- + Lets try a longer message. +(1 row) + diff --git a/contrib/pgcrypto/expected/des_1.out b/contrib/pgcrypto/expected/des_1.out new file mode 100644 index 0000000..5a76154 --- /dev/null +++ b/contrib/pgcrypto/expected/des_1.out @@ -0,0 +1,26 @@ +-- +-- DES cipher +-- +-- no official test vectors atm +-- from blowfish.sql +SELECT encrypt('\x0123456789abcdef', '\xfedcba9876543210', 'des-ecb/pad:none'); +ERROR: encrypt error: Cipher cannot be initialized +-- empty data +select encrypt('', 'foo', 'des'); +ERROR: encrypt error: Cipher cannot be initialized +-- 8 bytes key +select encrypt('foo', '01234589', 'des'); +ERROR: encrypt error: Cipher cannot be initialized +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'des'), '0123456', 'des'), 'escape'); +ERROR: encrypt error: Cipher cannot be initialized +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'des'); +ERROR: encrypt_iv error: Cipher cannot be initialized +select encode(decrypt_iv('\x50735067b073bb93', '0123456', 'abcd', 'des'), 'escape'); +ERROR: decrypt_iv error: Cipher cannot be initialized +-- long message +select encrypt('Lets try a longer message.', '01234567', 'des'); +ERROR: encrypt error: Cipher cannot be initialized +select encode(decrypt(encrypt('Lets try a longer message.', '01234567', 'des'), '01234567', 'des'), 'escape'); +ERROR: encrypt error: Cipher cannot be initialized diff --git a/contrib/pgcrypto/expected/hmac-md5.out b/contrib/pgcrypto/expected/hmac-md5.out new file mode 100644 index 0000000..0d8d761 --- /dev/null +++ b/contrib/pgcrypto/expected/hmac-md5.out @@ -0,0 +1,72 @@ +-- +-- HMAC-MD5 +-- +SELECT hmac( +'Hi There', +'\x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'::bytea, +'md5'); + hmac +------------------------------------ + \x9294727a3638bb1c13f48ef8158bfc9d +(1 row) + +-- 2 +SELECT hmac( +'Jefe', +'what do ya want for nothing?', +'md5'); + hmac +------------------------------------ + \x813aead7c4a34bff01a16d61368e7c13 +(1 row) + +-- 3 +SELECT hmac( +'\xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'::bytea, +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'md5'); + hmac +------------------------------------ + \x56be34521d144c88dbb8c733f0e8b3f6 +(1 row) + +-- 4 +SELECT hmac( +'\xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'::bytea, +'\x0102030405060708090a0b0c0d0e0f10111213141516171819'::bytea, +'md5'); + hmac +------------------------------------ + \x697eaf0aca3a3aea3a75164746ffaa79 +(1 row) + +-- 5 +SELECT hmac( +'Test With Truncation', +'\x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'::bytea, +'md5'); + hmac +------------------------------------ + \x56461ef2342edc00f9bab995690efd4c +(1 row) + +-- 6 +SELECT hmac( +'Test Using Larger Than Block-Size Key - Hash Key First', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'md5'); + hmac +------------------------------------ + \x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd +(1 row) + +-- 7 +SELECT hmac( +'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'md5'); + hmac +------------------------------------ + \x6f630fad67cda0ee1fb1f562db3aa53e +(1 row) + diff --git a/contrib/pgcrypto/expected/hmac-sha1.out b/contrib/pgcrypto/expected/hmac-sha1.out new file mode 100644 index 0000000..a7d4c38 --- /dev/null +++ b/contrib/pgcrypto/expected/hmac-sha1.out @@ -0,0 +1,72 @@ +-- +-- HMAC-SHA1 +-- +SELECT hmac( +'Hi There', +'\x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'::bytea, +'sha1'); + hmac +-------------------------------------------- + \x675b0b3a1b4ddf4e124872da6c2f632bfed957e9 +(1 row) + +-- 2 +SELECT hmac( +'Jefe', +'what do ya want for nothing?', +'sha1'); + hmac +-------------------------------------------- + \x156d4c35468a0339f3fa57a067bf47f814eb7a57 +(1 row) + +-- 3 +SELECT hmac( +'\xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'::bytea, +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'sha1'); + hmac +-------------------------------------------- + \xd730594d167e35d5956fd8003d0db3d3f46dc7bb +(1 row) + +-- 4 +SELECT hmac( +'\xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'::bytea, +'\x0102030405060708090a0b0c0d0e0f10111213141516171819'::bytea, +'sha1'); + hmac +-------------------------------------------- + \x4c9007f4026250c6bc8414f9bf50c86c2d7235da +(1 row) + +-- 5 +SELECT hmac( +'Test With Truncation', +'\x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'::bytea, +'sha1'); + hmac +-------------------------------------------- + \x37268b7e21e84da5720c53c4ba03ad1104039fa7 +(1 row) + +-- 6 +SELECT hmac( +'Test Using Larger Than Block-Size Key - Hash Key First', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'sha1'); + hmac +-------------------------------------------- + \xaa4ae5e15272d00e95705637ce8a3b55ed402112 +(1 row) + +-- 7 +SELECT hmac( +'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'sha1'); + hmac +-------------------------------------------- + \xe8e99d0f45237d786d6bbaa7965c7808bbff1a91 +(1 row) + diff --git a/contrib/pgcrypto/expected/init.out b/contrib/pgcrypto/expected/init.out new file mode 100644 index 0000000..d1341a6 --- /dev/null +++ b/contrib/pgcrypto/expected/init.out @@ -0,0 +1,13 @@ +-- +-- init pgcrypto +-- +CREATE EXTENSION pgcrypto; +-- check error handling +select gen_salt('foo'); +ERROR: gen_salt: Unknown salt algorithm +select digest('foo', 'foo'); +ERROR: Cannot use "foo": No such hash algorithm +select hmac('foo', 'foo', 'foo'); +ERROR: Cannot use "foo": No such hash algorithm +select encrypt('foo', 'foo', 'foo'); +ERROR: Cannot use "foo": No such cipher algorithm diff --git a/contrib/pgcrypto/expected/md5.out b/contrib/pgcrypto/expected/md5.out new file mode 100644 index 0000000..1790594 --- /dev/null +++ b/contrib/pgcrypto/expected/md5.out @@ -0,0 +1,45 @@ +-- +-- MD5 message digest +-- +SELECT digest('', 'md5'); + digest +------------------------------------ + \xd41d8cd98f00b204e9800998ecf8427e +(1 row) + +SELECT digest('a', 'md5'); + digest +------------------------------------ + \x0cc175b9c0f1b6a831c399e269772661 +(1 row) + +SELECT digest('abc', 'md5'); + digest +------------------------------------ + \x900150983cd24fb0d6963f7d28e17f72 +(1 row) + +SELECT digest('message digest', 'md5'); + digest +------------------------------------ + \xf96b697d7cb7938d525a2f31aaf161d0 +(1 row) + +SELECT digest('abcdefghijklmnopqrstuvwxyz', 'md5'); + digest +------------------------------------ + \xc3fcd3d76192e4007dfb496cca67e13b +(1 row) + +SELECT digest('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'md5'); + digest +------------------------------------ + \xd174ab98d277d9f5a5611c2c9f419d9f +(1 row) + +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'md5'); + digest +------------------------------------ + \x57edf4a22be3c955ac49da2e2107b67a +(1 row) + diff --git a/contrib/pgcrypto/expected/pgp-armor.out b/contrib/pgcrypto/expected/pgp-armor.out new file mode 100644 index 0000000..0f5ff46 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-armor.out @@ -0,0 +1,370 @@ +-- +-- PGP Armor +-- +select armor(''); + armor +----------------------------- + -----BEGIN PGP MESSAGE-----+ + + + =twTO + + -----END PGP MESSAGE----- + + +(1 row) + +select armor('test'); + armor +----------------------------- + -----BEGIN PGP MESSAGE-----+ + + + dGVzdA== + + =+G7Q + + -----END PGP MESSAGE----- + + +(1 row) + +select encode(dearmor(armor('')), 'escape'); + encode +-------- + +(1 row) + +select encode(dearmor(armor('zooka')), 'escape'); + encode +-------- + zooka +(1 row) + +select armor('0123456789abcdef0123456789abcdef0123456789abcdef +0123456789abcdef0123456789abcdef0123456789abcdef'); + armor +------------------------------------------------------------------------------ + -----BEGIN PGP MESSAGE----- + + + + MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmCjAxMjM0NTY3+ + ODlhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmMDEyMzQ1Njc4OWFiY2RlZg== + + =JFw5 + + -----END PGP MESSAGE----- + + +(1 row) + +-- lots formatting +select encode(dearmor(' a pgp msg: + +-----BEGIN PGP MESSAGE----- +Comment: Some junk + +em9va2E= + + =D5cR + +-----END PGP MESSAGE-----'), 'escape'); + encode +-------- + zooka +(1 row) + +-- lots messages +select encode(dearmor(' +wrong packet: + -----BEGIN PGP MESSAGE----- + + d3Jvbmc= + =vCYP + -----END PGP MESSAGE----- + +right packet: +-----BEGIN PGP MESSAGE----- + +cmlnaHQ= +=nbpj +-----END PGP MESSAGE----- + +use only first packet +-----BEGIN PGP MESSAGE----- + +d3Jvbmc= +=vCYP +-----END PGP MESSAGE----- +'), 'escape'); + encode +-------- + right +(1 row) + +-- bad crc +select dearmor(' +-----BEGIN PGP MESSAGE----- + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); +ERROR: Corrupt ascii-armor +-- corrupt (no space after the colon) +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +foo: + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); +ERROR: Corrupt ascii-armor +-- corrupt (no empty line) +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); +ERROR: Corrupt ascii-armor +-- no headers +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +-----+------- +(0 rows) + +-- header with empty value +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +foo: + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +-----+------- + foo | +(1 row) + +-- simple +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +fookey: foovalue +barkey: barvalue + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +--------+---------- + fookey | foovalue + barkey | barvalue +(2 rows) + +-- insane keys, part 1 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +insane:key : + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +-------------+------- + insane:key | +(1 row) + +-- insane keys, part 2 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +insane:key : text value here + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +-------------+----------------- + insane:key | text value here +(1 row) + +-- long value +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +long: this value is more than 76 characters long, but it should still parse correctly as that''s permitted by RFC 4880 + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +------+----------------------------------------------------------------------------------------------------------------- + long | this value is more than 76 characters long, but it should still parse correctly as that's permitted by RFC 4880 +(1 row) + +-- long value, split up +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +long: this value is more than 76 characters long, but it should still +long: parse correctly as that''s permitted by RFC 4880 + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +------+------------------------------------------------------------------ + long | this value is more than 76 characters long, but it should still + long | parse correctly as that's permitted by RFC 4880 +(2 rows) + +-- long value, split up, part 2 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +long: this value is more than +long: 76 characters long, but it should still +long: parse correctly as that''s permitted by RFC 4880 + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +------+------------------------------------------------- + long | this value is more than + long | 76 characters long, but it should still + long | parse correctly as that's permitted by RFC 4880 +(3 rows) + +-- long value, split up, part 3 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +emptykey: +long: this value is more than +emptykey: +long: 76 characters long, but it should still +emptykey: +long: parse correctly as that''s permitted by RFC 4880 +emptykey: + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + key | value +----------+------------------------------------------------- + emptykey | + long | this value is more than + emptykey | + long | 76 characters long, but it should still + emptykey | + long | parse correctly as that's permitted by RFC 4880 + emptykey | +(7 rows) + +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.blowfish.sha1.mdc.s2k3.z0 + +jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS +yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE= +=JcP+ +-----END PGP MESSAGE----- +'); + key | value +---------+-------------------------------- + Comment | dat1.blowfish.sha1.mdc.s2k3.z0 +(1 row) + +-- test CR+LF line endings +select * from pgp_armor_headers(replace(' +-----BEGIN PGP MESSAGE----- +fookey: foovalue +barkey: barvalue + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +', E'\n', E'\r\n')); + key | value +--------+---------- + fookey | foovalue + barkey | barvalue +(2 rows) + +-- test header generation +select armor('zooka', array['foo'], array['bar']); + armor +----------------------------- + -----BEGIN PGP MESSAGE-----+ + foo: bar + + + + em9va2E= + + =D5cR + + -----END PGP MESSAGE----- + + +(1 row) + +select armor('zooka', array['Version', 'Comment'], array['Created by pgcrypto', 'PostgreSQL, the world''s most advanced open source database']); + armor +--------------------------------------------------------------------- + -----BEGIN PGP MESSAGE----- + + Version: Created by pgcrypto + + Comment: PostgreSQL, the world's most advanced open source database+ + + + em9va2E= + + =D5cR + + -----END PGP MESSAGE----- + + +(1 row) + +select * from pgp_armor_headers( + armor('zooka', array['Version', 'Comment'], + array['Created by pgcrypto', 'PostgreSQL, the world''s most advanced open source database'])); + key | value +---------+------------------------------------------------------------ + Version | Created by pgcrypto + Comment | PostgreSQL, the world's most advanced open source database +(2 rows) + +-- error/corner cases +select armor('', array['foo'], array['too', 'many']); +ERROR: mismatched array dimensions +select armor('', array['too', 'many'], array['foo']); +ERROR: mismatched array dimensions +select armor('', array[['']], array['foo']); +ERROR: wrong number of array subscripts +select armor('', array['foo'], array[['']]); +ERROR: wrong number of array subscripts +select armor('', array[null], array['foo']); +ERROR: null value not allowed for header key +select armor('', array['foo'], array[null]); +ERROR: null value not allowed for header value +select armor('', '[0:0]={"foo"}', array['foo']); + armor +----------------------------- + -----BEGIN PGP MESSAGE-----+ + foo: foo + + + + =twTO + + -----END PGP MESSAGE----- + + +(1 row) + +select armor('', array['foo'], '[0:0]={"foo"}'); + armor +----------------------------- + -----BEGIN PGP MESSAGE-----+ + foo: foo + + + + =twTO + + -----END PGP MESSAGE----- + + +(1 row) + +select armor('', array[E'embedded\nnewline'], array['foo']); +ERROR: header key must not contain newlines +select armor('', array['foo'], array[E'embedded\nnewline']); +ERROR: header value must not contain newlines +select armor('', array['embedded: colon+space'], array['foo']); +ERROR: header key must not contain ": " diff --git a/contrib/pgcrypto/expected/pgp-compression.out b/contrib/pgcrypto/expected/pgp-compression.out new file mode 100644 index 0000000..d4c57fe --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-compression.out @@ -0,0 +1,80 @@ +-- +-- PGP compression support +-- +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0ECQMCsci6AdHnELlh0kQB4jFcVwHMJg0Bulop7m3Mi36s15TAhBo0AnzIrRFrdLVCkKohsS6+ +DMcmR53SXfLoDJOv/M8uKj3QSq7oWNIp95pxfA== +=tbSn +-----END PGP MESSAGE----- +'), 'key', 'expect-compress-algo=1'); + pgp_sym_decrypt +----------------- + Secret message +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=0'), + 'key', 'expect-compress-algo=0'); + pgp_sym_decrypt +----------------- + Secret message +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=1'), + 'key', 'expect-compress-algo=1'); + pgp_sym_decrypt +----------------- + Secret message +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=2'), + 'key', 'expect-compress-algo=2'); + pgp_sym_decrypt +----------------- + Secret message +(1 row) + +-- level=0 should turn compression off +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', + 'compress-algo=2, compress-level=0'), + 'key', 'expect-compress-algo=0'); + pgp_sym_decrypt +----------------- + Secret message +(1 row) + +-- check corner case involving an input string of 16kB, as per bug #16476. +SELECT setseed(0); + setseed +--------- + +(1 row) + +WITH random_string AS +( + -- This generates a random string of 16366 bytes. This is chosen + -- as random so that it does not get compressed, and the decompression + -- would work on a string with the same length as the origin, making the + -- test behavior more predictible. lpad() ensures that the generated + -- hexadecimal value is completed by extra zero characters if random() + -- has generated a value strictly lower than 16. + SELECT string_agg(decode(lpad(to_hex((random()*256)::int), 2, '0'), 'hex'), '') as bytes + FROM generate_series(0, 16365) +) +SELECT bytes = + pgp_sym_decrypt_bytea( + pgp_sym_encrypt_bytea(bytes, 'key', + 'compress-algo=1,compress-level=1'), + 'key', 'expect-compress-algo=1') + AS is_same + FROM random_string; + is_same +--------- + t +(1 row) + diff --git a/contrib/pgcrypto/expected/pgp-decrypt.out b/contrib/pgcrypto/expected/pgp-decrypt.out new file mode 100644 index 0000000..eb049ba --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-decrypt.out @@ -0,0 +1,419 @@ +-- +-- pgp decrypt tests +-- +-- Checking ciphers +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.blowfish.sha1.mdc.s2k3.z0 + +jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS +yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE= +=JcP+ +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCci97v0Q6Z0Zg0kQBsVf5Oe3iC+FBzUmuMV9KxmAyOMyjCc/5i8f1Eest +UTAsG35A1vYs02VARKzGz6xI2UHwFUirP+brPBg3Ee7muOx8pA== +=XtrP +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCI7YQpWqp3D1g0kQBCjB7GlX7+SQeXNleXeXQ78ZAPNliquGDq9u378zI +5FPTqAhIB2/2fjY8QEIs1ai00qphjX2NitxV/3Wn+6dufB4Q4g== +=rCZt +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMC4f/5djqCC1Rg0kQBTHEPsD+Sw7biBsM2er3vKyGPAQkuTBGKC5ie7hT/ +lceMfQdbAg6oTFyJpk/wH18GzRDphCofg0X8uLgkAKMrpcmgog== +=fB6S +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking MDC modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.nomdc.s2k3.z0 + +jA0EBwMCnv07rlXqWctgyS2Dm2JfOKCRL4sLSLJUC8RS2cH7cIhKSuLitOtyquB+ +u9YkgfJfsuRJmgQ9tmo= +=60ui +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEeP3idNjQ1Bg0kQBf4G0wX+2QNzLh2YNwYkQgQkfYhn/hLXjV4nK9nsE +8Ex1Dsdt5UPvOz8W8VKQRS6loOfOe+yyXil8W3IYFwUpdDUi+Q== +=moGf +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking hashes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.md5.mdc.s2k3.z0 + +jA0EBwMClrXXtOXetohg0kQBn0Kl1ymevQZRHkdoYRHgzCwSQEiss7zYff2UNzgO +KyRrHf7zEBuZiZ2AG34jNVMOLToj1jJUg5zTSdecUzQVCykWTA== +=NyLk +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCApbdlrURoWJg0kQBzHM/E0o7djY82bNuspjxjAcPFrrtp0uvDdMQ4z2m +/PM8jhgI5vxFYfNQjLl8y3fHYIomk9YflN9K/Q13iq8A8sjeTw== +=FxbQ +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking S2K modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k0.z0 + +jAQEBwAC0kQBKTaLAKE3xzps+QIZowqRNb2eAdzBw2LxEW2YD5PgNlbhJdGg+dvw +Ah9GXjGS1TVALzTImJbz1uHUZRfhJlFbc5yGQw== +=YvkV +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k1.z0 + +jAwEBwEC/QTByBLI3b/SRAHPxKzI6SZBo5lAEOD+EsvKQWO4adL9tDY+++Iqy1xK +4IaWXVKEj9R2Lr2xntWWMGZtcKtjD2lFFRXXd9dZp1ZThNDz +=dbXm +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEq4Su3ZqNEJg0kQB4QG5jBTKF0i04xtH+avzmLhstBNRxvV3nsmB3cwl +z+9ZaA/XdSx5ZiFnMym8P6r8uY9rLjjNptvvRHlxIReF+p9MNg== +=VJKg +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k0.z0 + +jAQECAAC0kQBBDnQWkgsx9YFaqDfWmpsiyAJ6y2xG/sBvap1dySYEMuZ+wJTXQ9E +Cr3i2M7TgVZ0M4jp4QL0adG1lpN5iK7aQeOwMw== +=cg+i +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k1.z0 + +jAwECAECruOfyNDFiTnSRAEVoGXm4A9UZKkWljdzjEO/iaE7mIraltIpQMkiqCh9 +7h8uZ2u9uRBOv222fZodGvc6bvq/4R4hAa/6qSHtm8mdmvGt +=aHmC +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCjFn6SRi3SONg0kQBqtSHPaD0m7rXfDAhCWU/ypAsI93GuHGRyM99cvMv +q6eF6859ZVnli3BFSDSk3a4e/pXhglxmDYCfjAXkozKNYLo6yw== +=K0LS +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k0.z0 + +jAQECQAC0kQB4L1eMbani07XF2ZYiXNK9LW3v8w41oUPl7dStmrJPQFwsdxmrDHu +rQr3WbdKdY9ufjOE5+mXI+EFkSPrF9rL9NCq6w== +=RGts +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k1.z0 + +jAwECQECKHhrou7ZOIXSRAHWIVP+xjVQcjAVBTt+qh9SNzYe248xFTwozkwev3mO ++KVJW0qhk0An+Y2KF99/bYFl9cL5D3Tl43fC8fXGl3x3m7pR +=SUrU +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMCjc8lwZu8Fz1g0kQBkEzjImi21liep5jj+3dAJ2aZFfUkohi8b3n9z+7+ +4+NRzL7cMW2RLAFnJbiqXDlRHMwleeuLN1up2WIxsxtYYuaBjA== +=XZrG +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking longer passwords +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCx6dBiuqrYNRg0kQBEo63AvA1SCslxP7ayanLf1H0/hlk2nONVhTwVEWi +tTGup1mMz6Cfh1uDRErUuXpx9A0gdMu7zX0o5XjrL7WGDAZdSw== +=XKKG +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCBDvYuS990iFg0kQBW31UK5OiCjWf5x6KJ8qNNT2HZWQCjCBZMU0XsOC6 +CMxFKadf144H/vpoV9GA0f22keQgCl0EsTE4V4lweVOPTKCMJg== +=gWDh +-----END PGP MESSAGE----- +'), '0123456789abcdefghij2jk4h5g2j54khg23h54g2kh54g2khj54g23hj54'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCqXbFafC+ofVg0kQBejyiPqH0QMERVGfmPOjtAxvyG5KDIJPYojTgVSDt +FwsDabdQUz5O7bgNSnxfmyw1OifGF+W2bIn/8W+0rDf8u3+O+Q== +=OxOF +-----END PGP MESSAGE----- +'), 'x'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking various data +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCGJ+SpuOysINg0kQBJfSjzsW0x4OVcAyr17O7FBvMTwIGeGcJd99oTQU8 +Xtx3kDqnhUq9Z1fS3qPbi5iNP2A9NxOBxPWz2JzxhydANlgbxg== +=W/ik +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + digest +-------------------------------------------- + \x0225e3ede6f2587b076d021a189ff60aad67e066 +(1 row) + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat2.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCvdpDvidNzMxg0jUBvj8eS2+1t/9/zgemxvhtc0fvdKGGbjH7dleaTJRB +SaV9L04ky1qECNDx3XjnoKLC+H7IOQ== +=Fxen +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + digest +-------------------------------------------- + \xda39a3ee5e6b4b0d3255bfef95601890afd80709 +(1 row) + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat3.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCxQvxJZ3G/HRg0lgBeYmTa7/uDAjPyFwSX4CYBgpZWVn/JS8JzILrcWF8 +gFnkUKIE0PSaYFp+Yi1VlRfUtRQ/X/LYNGa7tWZS+4VQajz2Xtz4vUeAEiYFYPXk +73Hb8m1yRhQK +=ivrD +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + digest +-------------------------------------------- + \x5e5c135efc0dd00633efc6dfd6e731ea408a5b4c +(1 row) + +-- Checking CRLF +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=0'), 'sha1'); + digest +-------------------------------------------- + \x9353062be7720f1446d30b9e75573a4833886784 +(1 row) + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=1'), 'sha1'); + digest +-------------------------------------------- + \x7efefcab38467f7484d6fa43dc86cf5281bd78e2 +(1 row) + +-- check BUG #11905, problem with messages 6 less than a power of 2. +select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',65530); + ?column? +---------- + t +(1 row) + +-- Negative tests +-- Decryption with a certain incorrect key yields an apparent Literal Data +-- packet reporting its content to be binary data. Ciphertext source: +-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave +-- rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV +VsxxqLSPzNLAeIspJk5G +=mSd/ +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); +NOTICE: dbg: prefix_init: corrupt prefix +NOTICE: dbg: parse_literal_data: data type=b +NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr +ERROR: Wrong key or corrupt data +-- Routine text/binary mismatch. +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1'); +NOTICE: dbg: parse_literal_data: data type=b +ERROR: Not text data +-- Decryption with a certain incorrect key yields an apparent BZip2-compressed +-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key') +-- until the random prefix gave rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP +GXsd65oYJZp3Khz0qfyn +=Nmpq +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); +NOTICE: dbg: prefix_init: corrupt prefix +NOTICE: dbg: parse_compressed_data: bzip2 unsupported +NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr +ERROR: Wrong key or corrupt data +-- Routine use of BZip2 compression. Ciphertext source: +-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \ +-- --personal-cipher-preferences aes --no-emit-version --batch \ +-- --symmetric --passphrase key --armor +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe +QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R +UCAAw2JRIISttRHMfDpDuZJpvYo= +=AZ9M +-----END PGP MESSAGE----- +'), 'key', 'debug=1'); +NOTICE: dbg: parse_compressed_data: bzip2 unsupported +ERROR: Unsupported compression algorithm diff --git a/contrib/pgcrypto/expected/pgp-decrypt_1.out b/contrib/pgcrypto/expected/pgp-decrypt_1.out new file mode 100644 index 0000000..80a4c48 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-decrypt_1.out @@ -0,0 +1,415 @@ +-- +-- pgp decrypt tests +-- +-- Checking ciphers +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.blowfish.sha1.mdc.s2k3.z0 + +jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS +yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE= +=JcP+ +-----END PGP MESSAGE----- +'), 'foobar'); +ERROR: Wrong key or corrupt data +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCci97v0Q6Z0Zg0kQBsVf5Oe3iC+FBzUmuMV9KxmAyOMyjCc/5i8f1Eest +UTAsG35A1vYs02VARKzGz6xI2UHwFUirP+brPBg3Ee7muOx8pA== +=XtrP +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCI7YQpWqp3D1g0kQBCjB7GlX7+SQeXNleXeXQ78ZAPNliquGDq9u378zI +5FPTqAhIB2/2fjY8QEIs1ai00qphjX2NitxV/3Wn+6dufB4Q4g== +=rCZt +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMC4f/5djqCC1Rg0kQBTHEPsD+Sw7biBsM2er3vKyGPAQkuTBGKC5ie7hT/ +lceMfQdbAg6oTFyJpk/wH18GzRDphCofg0X8uLgkAKMrpcmgog== +=fB6S +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking MDC modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.nomdc.s2k3.z0 + +jA0EBwMCnv07rlXqWctgyS2Dm2JfOKCRL4sLSLJUC8RS2cH7cIhKSuLitOtyquB+ +u9YkgfJfsuRJmgQ9tmo= +=60ui +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEeP3idNjQ1Bg0kQBf4G0wX+2QNzLh2YNwYkQgQkfYhn/hLXjV4nK9nsE +8Ex1Dsdt5UPvOz8W8VKQRS6loOfOe+yyXil8W3IYFwUpdDUi+Q== +=moGf +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking hashes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.md5.mdc.s2k3.z0 + +jA0EBwMClrXXtOXetohg0kQBn0Kl1ymevQZRHkdoYRHgzCwSQEiss7zYff2UNzgO +KyRrHf7zEBuZiZ2AG34jNVMOLToj1jJUg5zTSdecUzQVCykWTA== +=NyLk +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCApbdlrURoWJg0kQBzHM/E0o7djY82bNuspjxjAcPFrrtp0uvDdMQ4z2m +/PM8jhgI5vxFYfNQjLl8y3fHYIomk9YflN9K/Q13iq8A8sjeTw== +=FxbQ +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking S2K modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k0.z0 + +jAQEBwAC0kQBKTaLAKE3xzps+QIZowqRNb2eAdzBw2LxEW2YD5PgNlbhJdGg+dvw +Ah9GXjGS1TVALzTImJbz1uHUZRfhJlFbc5yGQw== +=YvkV +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k1.z0 + +jAwEBwEC/QTByBLI3b/SRAHPxKzI6SZBo5lAEOD+EsvKQWO4adL9tDY+++Iqy1xK +4IaWXVKEj9R2Lr2xntWWMGZtcKtjD2lFFRXXd9dZp1ZThNDz +=dbXm +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEq4Su3ZqNEJg0kQB4QG5jBTKF0i04xtH+avzmLhstBNRxvV3nsmB3cwl +z+9ZaA/XdSx5ZiFnMym8P6r8uY9rLjjNptvvRHlxIReF+p9MNg== +=VJKg +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k0.z0 + +jAQECAAC0kQBBDnQWkgsx9YFaqDfWmpsiyAJ6y2xG/sBvap1dySYEMuZ+wJTXQ9E +Cr3i2M7TgVZ0M4jp4QL0adG1lpN5iK7aQeOwMw== +=cg+i +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k1.z0 + +jAwECAECruOfyNDFiTnSRAEVoGXm4A9UZKkWljdzjEO/iaE7mIraltIpQMkiqCh9 +7h8uZ2u9uRBOv222fZodGvc6bvq/4R4hAa/6qSHtm8mdmvGt +=aHmC +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCjFn6SRi3SONg0kQBqtSHPaD0m7rXfDAhCWU/ypAsI93GuHGRyM99cvMv +q6eF6859ZVnli3BFSDSk3a4e/pXhglxmDYCfjAXkozKNYLo6yw== +=K0LS +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k0.z0 + +jAQECQAC0kQB4L1eMbani07XF2ZYiXNK9LW3v8w41oUPl7dStmrJPQFwsdxmrDHu +rQr3WbdKdY9ufjOE5+mXI+EFkSPrF9rL9NCq6w== +=RGts +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k1.z0 + +jAwECQECKHhrou7ZOIXSRAHWIVP+xjVQcjAVBTt+qh9SNzYe248xFTwozkwev3mO ++KVJW0qhk0An+Y2KF99/bYFl9cL5D3Tl43fC8fXGl3x3m7pR +=SUrU +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMCjc8lwZu8Fz1g0kQBkEzjImi21liep5jj+3dAJ2aZFfUkohi8b3n9z+7+ +4+NRzL7cMW2RLAFnJbiqXDlRHMwleeuLN1up2WIxsxtYYuaBjA== +=XZrG +-----END PGP MESSAGE----- +'), 'foobar'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking longer passwords +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCx6dBiuqrYNRg0kQBEo63AvA1SCslxP7ayanLf1H0/hlk2nONVhTwVEWi +tTGup1mMz6Cfh1uDRErUuXpx9A0gdMu7zX0o5XjrL7WGDAZdSw== +=XKKG +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCBDvYuS990iFg0kQBW31UK5OiCjWf5x6KJ8qNNT2HZWQCjCBZMU0XsOC6 +CMxFKadf144H/vpoV9GA0f22keQgCl0EsTE4V4lweVOPTKCMJg== +=gWDh +-----END PGP MESSAGE----- +'), '0123456789abcdefghij2jk4h5g2j54khg23h54g2kh54g2khj54g23hj54'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCqXbFafC+ofVg0kQBejyiPqH0QMERVGfmPOjtAxvyG5KDIJPYojTgVSDt +FwsDabdQUz5O7bgNSnxfmyw1OifGF+W2bIn/8W+0rDf8u3+O+Q== +=OxOF +-----END PGP MESSAGE----- +'), 'x'); + pgp_sym_decrypt +----------------- + Secret message. +(1 row) + +-- Checking various data +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCGJ+SpuOysINg0kQBJfSjzsW0x4OVcAyr17O7FBvMTwIGeGcJd99oTQU8 +Xtx3kDqnhUq9Z1fS3qPbi5iNP2A9NxOBxPWz2JzxhydANlgbxg== +=W/ik +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + digest +-------------------------------------------- + \x0225e3ede6f2587b076d021a189ff60aad67e066 +(1 row) + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat2.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCvdpDvidNzMxg0jUBvj8eS2+1t/9/zgemxvhtc0fvdKGGbjH7dleaTJRB +SaV9L04ky1qECNDx3XjnoKLC+H7IOQ== +=Fxen +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + digest +-------------------------------------------- + \xda39a3ee5e6b4b0d3255bfef95601890afd80709 +(1 row) + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat3.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCxQvxJZ3G/HRg0lgBeYmTa7/uDAjPyFwSX4CYBgpZWVn/JS8JzILrcWF8 +gFnkUKIE0PSaYFp+Yi1VlRfUtRQ/X/LYNGa7tWZS+4VQajz2Xtz4vUeAEiYFYPXk +73Hb8m1yRhQK +=ivrD +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + digest +-------------------------------------------- + \x5e5c135efc0dd00633efc6dfd6e731ea408a5b4c +(1 row) + +-- Checking CRLF +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=0'), 'sha1'); + digest +-------------------------------------------- + \x9353062be7720f1446d30b9e75573a4833886784 +(1 row) + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=1'), 'sha1'); + digest +-------------------------------------------- + \x7efefcab38467f7484d6fa43dc86cf5281bd78e2 +(1 row) + +-- check BUG #11905, problem with messages 6 less than a power of 2. +select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',65530); + ?column? +---------- + t +(1 row) + +-- Negative tests +-- Decryption with a certain incorrect key yields an apparent Literal Data +-- packet reporting its content to be binary data. Ciphertext source: +-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave +-- rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV +VsxxqLSPzNLAeIspJk5G +=mSd/ +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); +NOTICE: dbg: prefix_init: corrupt prefix +NOTICE: dbg: parse_literal_data: data type=b +NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr +ERROR: Wrong key or corrupt data +-- Routine text/binary mismatch. +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1'); +NOTICE: dbg: parse_literal_data: data type=b +ERROR: Not text data +-- Decryption with a certain incorrect key yields an apparent BZip2-compressed +-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key') +-- until the random prefix gave rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP +GXsd65oYJZp3Khz0qfyn +=Nmpq +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); +NOTICE: dbg: prefix_init: corrupt prefix +NOTICE: dbg: parse_compressed_data: bzip2 unsupported +NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr +ERROR: Wrong key or corrupt data +-- Routine use of BZip2 compression. Ciphertext source: +-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \ +-- --personal-cipher-preferences aes --no-emit-version --batch \ +-- --symmetric --passphrase key --armor +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe +QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R +UCAAw2JRIISttRHMfDpDuZJpvYo= +=AZ9M +-----END PGP MESSAGE----- +'), 'key', 'debug=1'); +NOTICE: dbg: parse_compressed_data: bzip2 unsupported +ERROR: Unsupported compression algorithm diff --git a/contrib/pgcrypto/expected/pgp-encrypt.out b/contrib/pgcrypto/expected/pgp-encrypt.out new file mode 100644 index 0000000..77e45ab --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-encrypt.out @@ -0,0 +1,208 @@ +-- +-- PGP encrypt +-- +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), 'key'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- check whether the defaults are ok +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), + 'key', 'expect-cipher-algo=aes128, + expect-disable-mdc=0, + expect-sess-key=0, + expect-s2k-mode=3, + expect-s2k-digest-algo=sha1, + expect-compress-algo=0 + '); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- maybe the expect- stuff simply does not work +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), + 'key', 'expect-cipher-algo=bf, + expect-disable-mdc=1, + expect-sess-key=1, + expect-s2k-mode=0, + expect-s2k-digest-algo=md5, + expect-compress-algo=1 + '); +NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7 +NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3 +NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2 +NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0 +NOTICE: pgp_decrypt: unexpected disable_mdc: expected 1 got 0 +NOTICE: pgp_decrypt: unexpected compress_algo: expected 1 got 0 + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- bytea as text +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('Binary', 'baz'), 'baz'); +ERROR: Not text data +-- text as bytea +select encode(pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'), 'escape'); + encode +-------- + Text +(1 row) + +-- algorithm change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'), + 'key', 'expect-cipher-algo=bf'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes'), + 'key', 'expect-cipher-algo=aes128'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'), + 'key', 'expect-cipher-algo=aes192'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- s2k change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=0'), + 'key', 'expect-s2k-mode=0'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=1'), + 'key', 'expect-s2k-mode=1'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'), + 'key', 'expect-s2k-mode=3'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- s2k count change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'), + 'key', 'expect-s2k-count=1024'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- s2k_count rounds up +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'), + 'key', 'expect-s2k-count=65000000'); +NOTICE: pgp_decrypt: unexpected s2k_count: expected 65000000 got 65011712 + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- s2k digest change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), + 'key', 'expect-s2k-digest-algo=md5'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'), + 'key', 'expect-s2k-digest-algo=sha1'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- sess key +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=0'), + 'key', 'expect-sess-key=0'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1'), + 'key', 'expect-sess-key=1'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=bf'), + 'key', 'expect-sess-key=1, expect-cipher-algo=bf'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes192'), + 'key', 'expect-sess-key=1, expect-cipher-algo=aes192'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes256'), + 'key', 'expect-sess-key=1, expect-cipher-algo=aes256'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- no mdc +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'disable-mdc=1'), + 'key', 'expect-disable-mdc=1'); + pgp_sym_decrypt +----------------- + Secret. +(1 row) + +-- crlf +select pgp_sym_decrypt_bytea( + pgp_sym_encrypt(E'1\n2\n3\r\n', 'key', 'convert-crlf=1'), + 'key'); + pgp_sym_decrypt_bytea +------------------------ + \x310d0a320d0a330d0d0a +(1 row) + +-- conversion should be lossless +select digest(pgp_sym_decrypt( + pgp_sym_encrypt(E'\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'), + 'key', 'convert-crlf=1'), 'sha1') as result, + digest(E'\r\n0\n1\r\r\n\n2\r', 'sha1') as expect; + result | expect +--------------------------------------------+-------------------------------------------- + \x47bde5d88d6ef8770572b9cbb4278b402aa69966 | \x47bde5d88d6ef8770572b9cbb4278b402aa69966 +(1 row) + diff --git a/contrib/pgcrypto/expected/pgp-info.out b/contrib/pgcrypto/expected/pgp-info.out new file mode 100644 index 0000000..9064838 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-info.out @@ -0,0 +1,79 @@ +-- +-- PGP info functions +-- +-- pgp_key_id +select pgp_key_id(dearmor(pubkey)) from keytbl where id=1; + pgp_key_id +------------------ + D936CF64BB73F466 +(1 row) + +select pgp_key_id(dearmor(pubkey)) from keytbl where id=2; + pgp_key_id +------------------ + 2C226E1FFE5CC7D4 +(1 row) + +select pgp_key_id(dearmor(pubkey)) from keytbl where id=3; + pgp_key_id +------------------ + B68504FD128E1FF9 +(1 row) + +select pgp_key_id(dearmor(pubkey)) from keytbl where id=4; -- should fail +ERROR: No encryption key found +select pgp_key_id(dearmor(pubkey)) from keytbl where id=5; + pgp_key_id +------------------ + D936CF64BB73F466 +(1 row) + +select pgp_key_id(dearmor(pubkey)) from keytbl where id=6; + pgp_key_id +------------------ + FD0206C409B74875 +(1 row) + +select pgp_key_id(dearmor(seckey)) from keytbl where id=1; + pgp_key_id +------------------ + D936CF64BB73F466 +(1 row) + +select pgp_key_id(dearmor(seckey)) from keytbl where id=2; + pgp_key_id +------------------ + 2C226E1FFE5CC7D4 +(1 row) + +select pgp_key_id(dearmor(seckey)) from keytbl where id=3; + pgp_key_id +------------------ + B68504FD128E1FF9 +(1 row) + +select pgp_key_id(dearmor(seckey)) from keytbl where id=4; -- should fail +ERROR: No encryption key found +select pgp_key_id(dearmor(seckey)) from keytbl where id=5; + pgp_key_id +------------------ + D936CF64BB73F466 +(1 row) + +select pgp_key_id(dearmor(seckey)) from keytbl where id=6; + pgp_key_id +------------------ + FD0206C409B74875 +(1 row) + +select pgp_key_id(dearmor(data)) as data_key_id +from encdata order by id; + data_key_id +------------------ + D936CF64BB73F466 + 2C226E1FFE5CC7D4 + B68504FD128E1FF9 + FD0206C409B74875 + FD0206C409B74875 +(5 rows) + diff --git a/contrib/pgcrypto/expected/pgp-pubkey-decrypt.out b/contrib/pgcrypto/expected/pgp-pubkey-decrypt.out new file mode 100644 index 0000000..b4b6810 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-decrypt.out @@ -0,0 +1,656 @@ +-- +-- PGP Public Key Encryption +-- +-- As most of the low-level stuff is tested in symmetric key +-- tests, here's only public-key specific tests +create table keytbl ( + id int4, + name text, + pubkey text, + seckey text +); +create table encdata ( + id int4, + data text +); +insert into keytbl (id, name, pubkey, seckey) +values (1, 'elg1024', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQLQfRWxnYW1hbCAx +MDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJCyCFIAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAniI9W2bC3CxARTpYrev7ihreDzFc +AJ9WYLQxDQAi5Ec9AQoodPkIagzZ4LkBDQRCyCFKEAQAh5SNbbJMAsJ+sQbcWEzd +ku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioymlDwraTKUAfuCZgNcg/0P +sxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlPiO0wt1lLX+SubktqbYxI ++h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSgMERiNzF0acZUYmc0e+/9 +6gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxsnKjUaw/qyoaFcNMzb4sF +k8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey9ifh8rZfu57UbdwdHa0v +iWc4DilhiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCfdPom+HlNVE9F +ig3hGY1Rb4NEk1gAn1u9IuQB+BgDP40YHHz6bKWS/x80 +=RWci +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQAAAnj4i4st+s+C6 +WKTIDcL1Iy0Saq8lCp60H0VsZ2FtYWwgMTAyNCA8dGVzdEBleGFtcGxlLm9yZz6I +XgQTEQIAHgUCQsghSAIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRAcKbwNGBdz +ZDrbAJ9cp6AsjOhiLxwznsMJheGf4xkH8wCfUPjMCLm4tAEnyYn2hDNt7CB8B6Kd +ATEEQsghShAEAIeUjW2yTALCfrEG3FhM3ZLvAHWAec2O0Mn/RDr59IN/W8wDYcZp +m+oG0ZUDdIqMppQ8K2kylAH7gmYDXIP9D7MRRm/Zw3L4yFfKnVaZ6tT7szBbgW5h +iOsHoOz49NXZT4jtMLdZS1/krm5Lam2MSPod9XN0Q2asY/igIMUfGDRjAAMGA/sE +LNh3tWefqeDkoDBEYjcxdGnGVGJnNHvv/eoHy9H7dyD/kkhaOoRAa5ClYWSqD0kk +a+SqTWhKG4XcbJyo1GsP6sqGhXDTM2+LBZPMKuVJQpEfoe9ruob/BbpXglfEiVE9 +VNiY7ZVyUdj3svYn4fK2X7ue1G3cHR2tL4lnOA4pYQAA9030E4u2ZKOfJBpUM+EM +m9VmsGjaQZV4teB0R/q3W8sRIYhJBBgRAgAJBQJCyCFKAhsMAAoJEBwpvA0YF3Nk +7a8AniFFotw1x2X+oryu3Q3nNtmxoKHpAJ9HU7jw7ydg33dI9J8gVkrmsSZ2/w== +=nvqq +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (2, 'elg2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIgoRBAC1onBpxKYgDvrgCaUWPY34947X3ogxGOfCN0p6Eqrx+2PUhm4n +vFvmczpMT4iDc0mUO+iwnwsEkXQI1eC99g8c0jnZAvzJZ5miAHL8hukMAMfDkYke +5aVvcPPc8uPDlItpszGmH0rM0V9TIt/i9QEXetpyNWhk4jj5qnohYhLeZwCgkOdO +RFAdNi4vfFPivvtAp2ffjU8D/R3x/UJCvkzi7i9rQHGo313xxmQu5BuqIjANBUij +8IE7LRPI/Qhg2hYy3sTJwImDi7VkS+fuvNVk0d6MTWplAXYU96bn12JaD21R9sKl +Fzcc+0iZI1wYA1PczisUkoTISE+dQFUsoGHfpDLhoBuesXQrhBavI8t8VPd+nkdt +J+oKA/9iRQ87FzxdYTkh2drrv69FZHc3Frsjw9nPcBq/voAvXH0MRilqyCg7HpW/ +T9naeOERksa+Rj4R57IF1l4e5oiiGJo9QmaKZcsCsXrREJCycrlEtMqXfSPy+bi5 +0yDZE/Qm1dwu13+OXOsRvkoNYjO8Mzo9K8wU12hMqN0a2bu6a7QjRWxnYW1hbCAy +MDQ4IDx0ZXN0MjA0OEBleGFtcGxlLm9yZz6IXgQTEQIAHgUCQsgiCgIbAwYLCQgH +AwIDFQIDAxYCAQIeAQIXgAAKCRBI6c1W/qZo29PDAKCG724enIxRog1j+aeCp/uq +or6mbwCePuKy2/1kD1FvnhkZ/R5fpm+pdm25Ag0EQsgiIhAIAJI3Gb2Ehtz1taQ9 +AhPY4Avad2BsqD3S5X/R11Cm0KBE/04D29dxn3f8QfxDsexYvNIZjoJPBqqZ7iMX +MhoWyw8ZF5Zs1mLIjFGVorePrm94N3MNPWM7x9M36bHUjx0vCZKFIhcGY1g+htE/ +QweaJzNVeA5z4qZmik41FbQyQSyHa3bOkTZu++/U6ghP+iDp5UDBjMTkVyqITUVN +gC+MR+da/I60irBVhue7younh4ovF+CrVDQJC06HZl6CAJJyA81SmRfi+dmKbbjZ +LF6rhz0norPjISJvkIqvdtM4VPBKI5wpgwCzpEqjuiKrAVujRT68zvBvJ4aVqb11 +k5QdJscAAwUH/jVJh0HbWAoiFTe+NvohfrA8vPcD0rtU3Y+siiqrabotnxJd2NuC +bxghJYGfNtnx0KDjFbCRKJVeTFok4UnuVYhXdH/c6i0/rCTNdeW2D6pmR4GfBozR +Pw/ARf+jONawGLyUj7uq13iquwMSE7VyNuF3ycL2OxXjgOWMjkH8c+zfHHpjaZ0R +QsetMq/iNBWraayKZnWUd+eQqNzE+NUo7w1jAu7oDpy+8a1eipxzK+O0HfU5LTiF +Z1Oe4Um0P2l3Xtx8nEgj4vSeoEkl2qunfGW00ZMMTCWabg0ZgxPzMfMeIcm6525A +Yn2qL+X/qBJTInAl7/hgPz2D1Yd7d5/RdWaISQQYEQIACQUCQsgiIgIbDAAKCRBI +6c1W/qZo25ZSAJ98WTrtl2HiX8ZqZq95v1+9cHtZPQCfZDoWQPybkNescLmXC7q5 +1kNTmEU= +=8QM5 +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELIIgoRBAC1onBpxKYgDvrgCaUWPY34947X3ogxGOfCN0p6Eqrx+2PUhm4n +vFvmczpMT4iDc0mUO+iwnwsEkXQI1eC99g8c0jnZAvzJZ5miAHL8hukMAMfDkYke +5aVvcPPc8uPDlItpszGmH0rM0V9TIt/i9QEXetpyNWhk4jj5qnohYhLeZwCgkOdO +RFAdNi4vfFPivvtAp2ffjU8D/R3x/UJCvkzi7i9rQHGo313xxmQu5BuqIjANBUij +8IE7LRPI/Qhg2hYy3sTJwImDi7VkS+fuvNVk0d6MTWplAXYU96bn12JaD21R9sKl +Fzcc+0iZI1wYA1PczisUkoTISE+dQFUsoGHfpDLhoBuesXQrhBavI8t8VPd+nkdt +J+oKA/9iRQ87FzxdYTkh2drrv69FZHc3Frsjw9nPcBq/voAvXH0MRilqyCg7HpW/ +T9naeOERksa+Rj4R57IF1l4e5oiiGJo9QmaKZcsCsXrREJCycrlEtMqXfSPy+bi5 +0yDZE/Qm1dwu13+OXOsRvkoNYjO8Mzo9K8wU12hMqN0a2bu6awAAn2F+iNBElfJS +8azqO/kEiIfpqu6/DQG0I0VsZ2FtYWwgMjA0OCA8dGVzdDIwNDhAZXhhbXBsZS5v +cmc+iF0EExECAB4FAkLIIgoCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQSOnN +Vv6maNvTwwCYkpcJmpl3aHCQdGomz7dFohDgjgCgiThZt2xTEi6GhBB1vuhk+f55 +n3+dAj0EQsgiIhAIAJI3Gb2Ehtz1taQ9AhPY4Avad2BsqD3S5X/R11Cm0KBE/04D +29dxn3f8QfxDsexYvNIZjoJPBqqZ7iMXMhoWyw8ZF5Zs1mLIjFGVorePrm94N3MN +PWM7x9M36bHUjx0vCZKFIhcGY1g+htE/QweaJzNVeA5z4qZmik41FbQyQSyHa3bO +kTZu++/U6ghP+iDp5UDBjMTkVyqITUVNgC+MR+da/I60irBVhue7younh4ovF+Cr +VDQJC06HZl6CAJJyA81SmRfi+dmKbbjZLF6rhz0norPjISJvkIqvdtM4VPBKI5wp +gwCzpEqjuiKrAVujRT68zvBvJ4aVqb11k5QdJscAAwUH/jVJh0HbWAoiFTe+Nvoh +frA8vPcD0rtU3Y+siiqrabotnxJd2NuCbxghJYGfNtnx0KDjFbCRKJVeTFok4Unu +VYhXdH/c6i0/rCTNdeW2D6pmR4GfBozRPw/ARf+jONawGLyUj7uq13iquwMSE7Vy +NuF3ycL2OxXjgOWMjkH8c+zfHHpjaZ0RQsetMq/iNBWraayKZnWUd+eQqNzE+NUo +7w1jAu7oDpy+8a1eipxzK+O0HfU5LTiFZ1Oe4Um0P2l3Xtx8nEgj4vSeoEkl2qun +fGW00ZMMTCWabg0ZgxPzMfMeIcm6525AYn2qL+X/qBJTInAl7/hgPz2D1Yd7d5/R +dWYAAVQKFPXbRaxbdArwRVXMzSD3qj/+VwwhwEDt8zmBGnlBfwVdkjQQrDUMmV1S +EwyISQQYEQIACQUCQsgiIgIbDAAKCRBI6c1W/qZo25ZSAJ4sgUfHTVsG/x3p3fcM +3b5R86qKEACggYKSwPWCs0YVRHOWqZY0pnHtLH8= +=3Dgk +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (3, 'elg4096', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=kRxT +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=Gjq6 +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (4, 'rsa2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQELBELIJbEBCADAIdtcoLAmQfl8pb73pPRuEYx8qW9klLfCGG5A4OUOi00JHNwP +ZaABe1PGzjoeXrgM1MTQZhoZu1Vdg+KDI6XAtiy9P6bLg7ntsXksD4wBoIKtQKc2 +55pdukxTiu+xeJJG2q8ZZPOp97CV9fbQ9vPCwgnuSsDCoQlibZikDVPAyVTvp7Jx +5rz8yXsl4sxvaeMZPqqFPtA/ENeQ3cpsyR1BQXSvoZpH1Fq0b8GcZTEdWWD/w6/K +MCRC8TmgEd+z3e8kIsCwFQ+TSHbCcxRWdgZE7gE31sJHHVkrZlXtLU8MPXWqslVz +R0cX+yC8j6bXI6/BqZ2SvRndJwuunRAr4um7AAYptB5SU0EgMjA0OCA8cnNhMjA0 +OEBleGFtcGxlLm9yZz6JATQEEwECAB4FAkLIJbECGwMGCwkIBwMCAxUCAwMWAgEC +HgECF4AACgkQnc+OnJvTHyQqHwf8DtzuAGmObfe3ggtn14x2wnU1Nigebe1K5liR +nrLuVlLBpdO6CWmMUzfKRvyZlx54GlA9uUQSjW+RlgejdOTQqesDrcTEukYd4yzw +bLZyM5Gb3lsE/FEmE7Dxw/0Utf59uACqzG8LACQn9J6sEgZWKxAupuYTHXd12lDP +D3dnU4uzKPhMcjnSN00pzjusP7C9NZd3OLkAx2vw/dmb4Q+/QxeZhVYYsAUuR2hv +9bgGWopumlOkt8Zu5YG6+CtTbJXprPI7pJ1jHbeE+q/29hWJQtS8Abx82AcOkzhv +S3NZKoJ/1DrGgoDAu1mGkM4KvLAxfDs/qQ9dZhtEmDbKPLTVEA== +=lR4n +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQOWBELIJbEBCADAIdtcoLAmQfl8pb73pPRuEYx8qW9klLfCGG5A4OUOi00JHNwP +ZaABe1PGzjoeXrgM1MTQZhoZu1Vdg+KDI6XAtiy9P6bLg7ntsXksD4wBoIKtQKc2 +55pdukxTiu+xeJJG2q8ZZPOp97CV9fbQ9vPCwgnuSsDCoQlibZikDVPAyVTvp7Jx +5rz8yXsl4sxvaeMZPqqFPtA/ENeQ3cpsyR1BQXSvoZpH1Fq0b8GcZTEdWWD/w6/K +MCRC8TmgEd+z3e8kIsCwFQ+TSHbCcxRWdgZE7gE31sJHHVkrZlXtLU8MPXWqslVz +R0cX+yC8j6bXI6/BqZ2SvRndJwuunRAr4um7AAYpAAf/QZsrrz0c7dgWwGqMIpw6 +fP+/lLa74+fa2CFRWtYowEiKsfDg/wN7Ua07036dNhPa8aZPsU6SRzm5PybKOURe +D9pNt0FxJkX0j5pCWfjSJgTbc1rCdqZ/oyBk/U6pQtf//zfw3PbDl7I8TC6GOt2w +5NgcXdsWHP7LAmPctOVUyzFsenevR0MFTHkMbmKI1HpFm8XN/e1Fl+qIAD+OagTF +5B32VvpoJtkh5nxnIuToNJsa9Iy7F9MM2CeFOyTMihMcjXKBBUaAYoF115irBvqu +7N/qWmzqLg8yxBZ56mh6meCF3+67VA2y7fL8rhw2QuqgLg1JFlKAVL+9crCSrn// +GQQA1kT7FytW6BNOffblFYZkrJer3icoRDqa/ljgH/yVaWoVT1igy0E9XzYO7MwP +2usj/resLy0NC1qCthk51cZ/wthooMl88e5Wb4l5FYwBEac7muSBTo4W8cAH1hFj +TWL6XAGvEzGX3Mt9pn8uYGlQLZAhJoNCAU2EOCbN1PchDvsEAOWNKYesuUVk8+sQ +St0NDNhd9BWtTWTHkCZb1dKC3JTfr9PqkTBLrWFbYjkOtvdPAW7FDaXXXZfdH1jH +WfwP3Q+I6sqgSaWpCS4dBAns3/RVtO7czVgyIwma04iIvJqderYrfvkUq95KfwP2 +V8wXkhrPPPxyrg5y3wQlpY2jb5RBBAC17SK1ms+DBtck4vpdjp3SJ32SbyC/DU30 +89Q12j74S7Zdu1qZlKnvy3kWPYX/hMuSzGZ+mLVJNFEqH2X01aFzppYz0hdI9PGB +9tTFEqZWQL9ZkXfjc79Cgnt12pNukRbtw0N/kyutOdIFHVT79wVAd+powqziXJsC +Kc+4xjwSCkZitB5SU0EgMjA0OCA8cnNhMjA0OEBleGFtcGxlLm9yZz6JATQEEwEC +AB4FAkLIJbECGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQnc+OnJvTHyQqHwf8 +DtzuAGmObfe3ggtn14x2wnU1Nigebe1K5liRnrLuVlLBpdO6CWmMUzfKRvyZlx54 +GlA9uUQSjW+RlgejdOTQqesDrcTEukYd4yzwbLZyM5Gb3lsE/FEmE7Dxw/0Utf59 +uACqzG8LACQn9J6sEgZWKxAupuYTHXd12lDPD3dnU4uzKPhMcjnSN00pzjusP7C9 +NZd3OLkAx2vw/dmb4Q+/QxeZhVYYsAUuR2hv9bgGWopumlOkt8Zu5YG6+CtTbJXp +rPI7pJ1jHbeE+q/29hWJQtS8Abx82AcOkzhvS3NZKoJ/1DrGgoDAu1mGkM4KvLAx +fDs/qQ9dZhtEmDbKPLTVEA== +=WKAv +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (5, 'psw-elg1024', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQLQfRWxnYW1hbCAx +MDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJCyCFIAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAniI9W2bC3CxARTpYrev7ihreDzFc +AJ9WYLQxDQAi5Ec9AQoodPkIagzZ4LkBDQRCyCFKEAQAh5SNbbJMAsJ+sQbcWEzd +ku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioymlDwraTKUAfuCZgNcg/0P +sxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlPiO0wt1lLX+SubktqbYxI ++h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSgMERiNzF0acZUYmc0e+/9 +6gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxsnKjUaw/qyoaFcNMzb4sF +k8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey9ifh8rZfu57UbdwdHa0v +iWc4DilhiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCfdPom+HlNVE9F +ig3hGY1Rb4NEk1gAn1u9IuQB+BgDP40YHHz6bKWS/x80 +=RWci +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQHpBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQP4HAwImKZ5q2QwT +D2DDAY/IQBjes7WgqZeacfLPDoB8ecD/KLoSCH6Z3etvbPHSOKiazxoJ962Ix74H +ZAE6ZbMTtl5dZW1ptB9FbGdhbWFsIDEwMjQgPHRlc3RAZXhhbXBsZS5vcmc+iF4E +ExECAB4FAkLIIUgCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQHCm8DRgXc2Q6 +2wCfXKegLIzoYi8cM57DCYXhn+MZB/MAn1D4zAi5uLQBJ8mJ9oQzbewgfAeinQFf +BELIIUoQBACHlI1tskwCwn6xBtxYTN2S7wB1gHnNjtDJ/0Q6+fSDf1vMA2HGaZvq +BtGVA3SKjKaUPCtpMpQB+4JmA1yD/Q+zEUZv2cNy+MhXyp1WmerU+7MwW4FuYYjr +B6Ds+PTV2U+I7TC3WUtf5K5uS2ptjEj6HfVzdENmrGP4oCDFHxg0YwADBgP7BCzY +d7Vnn6ng5KAwRGI3MXRpxlRiZzR77/3qB8vR+3cg/5JIWjqEQGuQpWFkqg9JJGvk +qk1oShuF3GycqNRrD+rKhoVw0zNviwWTzCrlSUKRH6Hva7qG/wW6V4JXxIlRPVTY +mO2VclHY97L2J+Hytl+7ntRt3B0drS+JZzgOKWH+BwMCJimeatkMEw9gRkFjt4Xa +9rX8awMBE5+vVcGKv/DNiCvJnlYvSdCj8VfuHsYFliiJo6u17NJon+K43e3yvDNk +f631VOVanGEz7TyqOkWQiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCe +IUWi3DXHZf6ivK7dDec22bGgoekAn0dTuPDvJ2Dfd0j0nyBWSuaxJnb/ +=SNvr +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (6, 'rsaenc2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQELBELr2m0BCADOrnknlnXI0EzRExf/TgoHvK7Xx/E0keWqV3KrOyC3/tY2KOrj +UVxaAX5pkFX9wdQObGPIJm06u6D16CH6CildX/vxG7YgvvKzK8JGAbwrXAfk7OIW +czO2zRaZGDynoK3mAxHRBReyTKtNv8rDQhuZs6AOozJNARdbyUO/yqUnqNNygWuT +4htFDEuLPIJwAbMSD0BvFW6YQaPdxzaAZm3EWVNbwDzjgbBUdBiUUwRdZIFUhsjJ +dirFdy5+uuZru6y6CNC1OERkJ7P8EyoFiZckAIE5gshVZzNuyLOZjc5DhWBvLbX4 +NZElAnfiv+4nA6y8wQLSIbmHA3nqJaBklj85AAYptCVSU0EgMjA0OCBFbmMgPHJz +YTIwNDhlbmNAZXhhbXBsZS5vcmc+iQE0BBMBAgAeBQJC69ptAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEMiZ6pNEGVVZHMkIAJtGHHZ9iM8Yq1rr0zl1L6SvlQP8 +JCaxHa31wH3PKqGtq2M+cpb2rXf7gAY/doHJPXggfVzkyFrysmQ1gPbDGYLyOutw ++IkhihEb5bWxQBNj+3zAFs1YX6v2HXWbSUSmyY1V9/+NTtKk03olDc/swd3lXzku +UOhcgfpBgIt3Q+MpT6M2+OIF7lVfSb1rWdpwTfGhZzW9szQOeoS4gPvxCCRyuabQ +RJ6DWH61F8fFIDJg1z+A/Obx4fqX6GOA69RzgZ3oukFBIXxNwV9PZNnAmHtZVYO8 +0g/oVYBbuvOYedffDBeQarhERZ5W2TnIE+nqY61YOLBqosliygdZTXULzNi5AQsE +QuvaugEIAOuCJZdkzORA6e1lr81Lnr4JzMsVBFA+X/yIkBbV6qX/A4nVSLAZKNPX +z1YIrMTu+1rMIiy10IWbA6zgMTpzPhJRfgePONgdnCYyK5Ksh5/C5ntzKwwGwxfK +lAXIxJurCHXTbEa+YvPdn76vJ3HsXOXVEL+fLb4U3l3Ng87YM202Lh1Ha2MeS2zE +FZcAoKbFqAAjDLEai64SoOFh0W3CsD1DL4zmfp+YZrUPHTtZadsi53i4KKW/ws9U +rHlolqYNhYze/uRLyfnUx9PN4r/GhEzauyDMV0smo91uB3aewPft+eCpmeWnu0PF +JVK4xyRmhIq2rVCw16a1pBJirvGM+y0ABimJAR8EGAECAAkFAkLr2roCGwwACgkQ +yJnqk0QZVVku1wgAg1bLSjPkhw+ldG5HzumpqR84+JKyozdJaJzefu2+1iqYE0B0 +WLz2PJVIiK41xiEkKhBvTOQYuXmtWqAWXptD91P5SoXoNJWLQO3TNwarANhHxkWg +w/TOUxQqoctlRUej5NDD+4eW5G9lcS1FEGuKDWtX096u80vO+TbyJjvx2eVM1k+X +dmeYsGOiNgDimCreJGYc14G7eY9jt24gw10n1sMAKI1qm6lcoHqZ9OOyla+wJdro +PYZGO7R8+1O9R22WrK6BYDT5j/1JwMZqbOESjNvDEVT0yOHClCHRN4CChbt6LhKh +CLUNdz/udIt0JAC6c/HdPLSW3HnmM3+iNj+Kug== +=pwU2 +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=UKh3 +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (7, 'rsaenc2048-psw', ' +same key with password +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.11 (GNU/Linux) + +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 +=QFm5 +-----END PGP PRIVATE KEY BLOCK----- +'); +-- elg1024 / aes128 +insert into encdata (id, data) values (1, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQEOA9k2z2S7c/RmEAQAgVWW0DeLrZ+1thWJGBPp2WRFL9HeNqqWHbKJCXJbz1Uy +faUY7yxVvG5Eutmo+JMiY3mg23/DgVVXHQZsTWpGvGM6djgUNGKUjZDbW6Nog7Mr +e78IywattCOmgUP9vIwwg3OVjuDCN/nVirGQFnXpJBc8DzWqDMWRWDy1M0ZsK7AD +/2JTosSFxUdpON0DKtIY3GLzmh6Nk3iV0g8VgJKUBT1rhCXuMDj3snm//EMm7hTY +PlnObq4mIhgz8NqprmhooxnU0Kapofb3P3wCHPpU14zxhXY8iKO/3JhBq2uFcx4X +uBMwkW4AdNxY/mzJZELteTL8Tr0s7PISk+owb4URpG3n0jsBc0CVULxrjh5Ejkdw +wCM195J6+KbQxOOFQ0b3uOVvv4dEgd/hRERCOq5EPaFhlHegyYJ7YO842vnSDA== +=PABx +-----END PGP MESSAGE----- +'); +-- elg2048 / blowfish +insert into encdata (id, data) values (2, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQIOAywibh/+XMfUEAf+OINhBngEsw4a/IJIeJvUgv1gTQzBwOdQEuc/runr4Oa8 +Skw/Bj0X/zgABVZLem1a35NHaNwaQaCFwMQ41YyWCu+jTdsiyX/Nw0w8LKKz0rNC +vVpG6YuV7Turtsf8a5lXy1K0SHkLlgxQ6c76GS4gtSl5+bsL2+5R1gSRJ9NXqCQP +OHRipEiYwBPqr5R21ZG0FXXNKGOGkj6jt/M/wh3WVtAhYuBI+HPKRfAEjd/Pu/eD +e1zYtkH1dKKFmp44+nF0tTI274xpuso7ShfKYrOK3saFWrl0DWiWteUinjSA1YBY +m7dG7NZ8PW+g1SZWhEoPjEEEHz3kWMvlKheMRDudnQf/dDyX6kZVIAQF/5B012hq +QyVewgTGysowFIDn01uIewoEA9cASw699jw9IoJp+k5WZXnU+INllBLzQxniQCSu +iEcr0x3fYqNtj9QBfbIqyRcY6HTWcmzyOUeGaSyX76j+tRAvtVtXpraFFFnaHB70 +YpXTjLkp8EBafzMghFaKDeXlr2TG/T7rbwcwWrFIwPqEAUKWN5m97Q3eyo8/ioMd +YoFD64J9ovSsgbuU5IpIGAsjxK+NKzg/2STH7zZFEVCtgcIXsTHTZfiwS98/+1H9 +p1DIDaXIcUFV2ztmcKxh9gt2sXRz1W+x6D8O0k3nanU5yGG4miLKaq18fbcA0BD1 ++NIzAfelq6nvvxYKcGcamBMgLo5JkZOBHvyr6RsAKIT5QYc0QTjysTk9l0Am3gYc +G2pAE+3k +=TBHV +-----END PGP MESSAGE----- +'); +-- elg4096 / aes256 +insert into encdata (id, data) values (3, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQQOA7aFBP0Sjh/5EA/+JCgncc8IZmmRjPStWnGf9tVJhgHTn+smIclibGzs0deS +SPSCitzpblwbUDvu964+/5e5Q1l7rRuNN+AgETlEd4eppv7Swn2ChdgOXxRwukcT +Nh3G+PTFvD4ayi7w1db3qvXIt0MwN4Alt436wJmK1oz2Ka9IcyO+wHWrDy1nSGSx +z5x7YEj+EZPgWc/YAvudqE8Jpzd/OT5zSHN09UFkIAk6NxisKaIstbEGFgpqtoDZ +1SJM84XAdL2IcaJ3YY7k/yzwlawhsakKd4GSd5vWmAwvyzzbSiBMfKsDE16ePLNU +ZBF7CzmlCBPZ7YrFAHLpXBXXkCQvzD2BEYOjse50ZEfJ036T7950Ozcdy1EQbGon +nyQ4Gh0PBpnMcBuiXOceWuYzhlzFOzDtlVKdNTxFRDcbEyW2jo9xQYvCCLnYy8EH +2M7S8jCtVYJBbn63a82ELv+3+kWYcsvBJv2ZVBh4ncrBu9o0P+OYS7ApoOU+j6p2 ++t0RXHksqXS1YiUwYF5KSw09EbYMgNZ9G04Px/PxLU6fSC9iDrGX7Xt3kOUP0mku +C518fPckT0zzRXqfFruJNRzDytW50KxkOQZzU1/Az1YlYN9QzWeU4EtLPb2fftZo +D0qH/ln+f9Op5t6sD2fcxZVECU1b/bFtZsxvwH406YL+UQ7hU/XnZrzVVzODal8P +/j1hg7v7BdJqu1DTp9nFWUuwMFcYAczuXn29IG183NZ7Ts4whDeYEhS8eNoLPX4j +txY12ILD/w/3Q4LoW/hPa6OdfEzsn0U5GLf1WiGmJE1H6ft2U/xUnerc/u0kt+FU +WAisArd4MuKtf7B5Vu/VF3kUdrR0hTniUKUivmC4o1jSId31Dufxj4aadVyldXAr +6TNBcdyragZjxEZ6hsBCYzA0Rd1a8atd6OaQoIEEfAzCu5Ks29pydHErStYGjWJ1 +KA5KPLVvjbHpDmRhlCcm8vgpYQsBYEB5gE9fx5yCTlsVhCB6y23h7hfdMqerDqkO +ZOPsO5h+tiHCdIrQ36sMjuINy1/K2rYcXd+Crh2iHcfidpU9fvDz2ihTRNQlhjuT +0cQZM5JhctEx4VXF4LDctRhit7Hn0iqsk604woQfJVvP8O673xSXT/kBY0A/v9C0 +3C4YoFNeSaKwbfZQ/4u1ZFPJxK2IIJa8UGpyAUewLMlzGVVagljybv/f4Z9ERAhy +huq5sMmw8UPsrJF2TUGHz5WSIwoh0J/qovoQI09I9sdEnFczDvRavMO2Mldy3E5i +exz9oewtel6GOmsZQSYWT/vJzbYMmvHNmNpVwwoKrLV6oI3kyQ80GHBwI1WlwHoK +2iRB0w8q4VVvJeYAz8ZIp380cqC3pfO0uZsrOx4g3k4X0jsB5y7rF5xXcZfnVbvG +DYKcOy60/OHMWVvpw6trAoA+iP+cVWPtrbRvLglTVTfYmi1ToZDDipkALBhndQ== +=L/M/ +-----END PGP MESSAGE----- +'); +-- rsaenc2048 / aes128 +insert into encdata (id, data) values (4, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQEMA/0CBsQJt0h1AQf+JyYnCiortj26P11zk28MKOGfWpWyAhuIgwbJXsdQ+e6r +pEyyqs9GC6gI7SNF6+J8B/gsMwvkAL4FHAQCvA4ZZ6eeXR1Of4YG22JQGmpWVWZg +DTyfhA2vkczuqfAD2tgUpMT6sdyGkQ/fnQ0lknlfHgC5GRx7aavOoAKtMqiZW5PR +yae/qR48mjX7Mb+mLvbagv9mHEgQSmHwFpaq2k456BbcZ23bvCmBnCvqV/90Ggfb +VP6gkSoFVsJ19RHsOhW1dk9ehbl51WB3zUOO5FZWwUTY9DJvKblRK/frF0+CXjE4 +HfcZXHSpSjx4haGGTsMvEJ85qFjZpr0eTGOdY5cFhNJAAVP8MZfji7OhPRAoOOIK +eRGOCkao12pvPyFTFnPd5vqmyBbdNpK4Q0hS82ljugMJvM0p3vJZVzW402Kz6iBL +GQ== +=XHkF +-----END PGP MESSAGE----- +'); +-- rsaenc2048 / aes128 (not from gnupg) +insert into encdata (id, data) values (5, ' +-----BEGIN PGP MESSAGE----- + +wcBMA/0CBsQJt0h1AQgAzxZ8j+OTeZ8IlLxfZ/mVd28/gUsCY+xigWBk/anZlK3T +p2tNU2idHzKdAttH2Hu/PWbZp4kwjl9spezYxMqCeBZqtfGED88Y+rqK0n/ul30A +7jjFHaw0XUOqFNlST1v6H2i7UXndnp+kcLfHPhnO5BIYWxB2CYBehItqtrn75eqr +C7trGzU/cr74efcWagbCDSNjiAV7GlEptlzmgVMmNikyI6w0ojEUx8lCLc/OsFz9 +pJUAX8xuwjxDVv+W7xk6c96grQiQlm+FLDYGiGNXoAzx3Wi/howu3uV40dXfY+jx +3WBrhEew5Pkpt1SsWoFnJWOfJ8GLd0ec8vfRCqAIVdLgAeS7NyawQYtd6wuVrEAj +5SMg4Thb4d+g45RksuGLHUUr4qO9tiXglODa4InhmJfgNuLk+RGz4LXjq8wepEmW +vRbgFOG54+Cf4C/gC+HkreDm5JKSKjvvw4B/jC6CDxq+JoziEe2Z1uEjCuEcr+Es +/eGzeOi36BejXPMHeKxXejj5qBBHKV0pHVhZSgffR0TtlXdB967Yl/5agV0R89hI +7Gw52emfnH4Z0Y4V0au2H0k1dR/2IxXdJEWSTG7Be1JHT59p9ei2gSEOrdBMIOjP +tbYYUlmmbvD49bHfThkDiC+oc9947LgQsk3kOOLbNHcjkbrjH8R5kjII4m/SEZA1 +g09T+338SzevBcVXh/cFrQ6/Et+lyyO2LJRUMs69g/HyzJOVWT2Iu8E0eS9MWevY +Qtrkrhrpkl3Y02qEp/j6M03Yu2t6ZF7dp51aJ5VhO2mmmtHaTnCyCc8Fcf72LmD8 +blH2nKZC9d6fi4YzSYMepZpMOFR65M80MCMiDUGnZBB8sEADu2/iVtqDUeG8mAA= +=PHJ1 +-----END PGP MESSAGE----- +'); +-- successful decrypt +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=1 and encdata.id=1; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=2; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=3 and encdata.id=3; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=6 and encdata.id=4; + pgp_pub_decrypt +----------------- + Secret message. +(1 row) + +-- wrong key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=1; +ERROR: Wrong key +-- sign-only key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=4 and encdata.id=1; +ERROR: No encryption key found +-- rsa: password-protected secret key, wrong password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), '123') +from keytbl, encdata where keytbl.id=7 and encdata.id=4; +ERROR: Wrong key or corrupt data +-- rsa: password-protected secret key, right password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool') +from keytbl, encdata where keytbl.id=7 and encdata.id=4; + pgp_pub_decrypt +----------------- + Secret message. +(1 row) + +-- password-protected secret key, no password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=5 and encdata.id=1; +ERROR: Need password for secret key +-- password-protected secret key, wrong password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'foo') +from keytbl, encdata where keytbl.id=5 and encdata.id=1; +ERROR: Wrong key or corrupt data +-- password-protected secret key, right password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool') +from keytbl, encdata where keytbl.id=5 and encdata.id=1; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +-- test for a short read from prefix_init +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=6 and encdata.id=5; +ERROR: Wrong key or corrupt data diff --git a/contrib/pgcrypto/expected/pgp-pubkey-decrypt_1.out b/contrib/pgcrypto/expected/pgp-pubkey-decrypt_1.out new file mode 100644 index 0000000..f41c6c9 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-decrypt_1.out @@ -0,0 +1,652 @@ +-- +-- PGP Public Key Encryption +-- +-- As most of the low-level stuff is tested in symmetric key +-- tests, here's only public-key specific tests +create table keytbl ( + id int4, + name text, + pubkey text, + seckey text +); +create table encdata ( + id int4, + data text +); +insert into keytbl (id, name, pubkey, seckey) +values (1, 'elg1024', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQLQfRWxnYW1hbCAx +MDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJCyCFIAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAniI9W2bC3CxARTpYrev7ihreDzFc +AJ9WYLQxDQAi5Ec9AQoodPkIagzZ4LkBDQRCyCFKEAQAh5SNbbJMAsJ+sQbcWEzd +ku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioymlDwraTKUAfuCZgNcg/0P +sxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlPiO0wt1lLX+SubktqbYxI ++h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSgMERiNzF0acZUYmc0e+/9 +6gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxsnKjUaw/qyoaFcNMzb4sF +k8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey9ifh8rZfu57UbdwdHa0v +iWc4DilhiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCfdPom+HlNVE9F +ig3hGY1Rb4NEk1gAn1u9IuQB+BgDP40YHHz6bKWS/x80 +=RWci +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQAAAnj4i4st+s+C6 +WKTIDcL1Iy0Saq8lCp60H0VsZ2FtYWwgMTAyNCA8dGVzdEBleGFtcGxlLm9yZz6I +XgQTEQIAHgUCQsghSAIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRAcKbwNGBdz +ZDrbAJ9cp6AsjOhiLxwznsMJheGf4xkH8wCfUPjMCLm4tAEnyYn2hDNt7CB8B6Kd +ATEEQsghShAEAIeUjW2yTALCfrEG3FhM3ZLvAHWAec2O0Mn/RDr59IN/W8wDYcZp +m+oG0ZUDdIqMppQ8K2kylAH7gmYDXIP9D7MRRm/Zw3L4yFfKnVaZ6tT7szBbgW5h +iOsHoOz49NXZT4jtMLdZS1/krm5Lam2MSPod9XN0Q2asY/igIMUfGDRjAAMGA/sE +LNh3tWefqeDkoDBEYjcxdGnGVGJnNHvv/eoHy9H7dyD/kkhaOoRAa5ClYWSqD0kk +a+SqTWhKG4XcbJyo1GsP6sqGhXDTM2+LBZPMKuVJQpEfoe9ruob/BbpXglfEiVE9 +VNiY7ZVyUdj3svYn4fK2X7ue1G3cHR2tL4lnOA4pYQAA9030E4u2ZKOfJBpUM+EM +m9VmsGjaQZV4teB0R/q3W8sRIYhJBBgRAgAJBQJCyCFKAhsMAAoJEBwpvA0YF3Nk +7a8AniFFotw1x2X+oryu3Q3nNtmxoKHpAJ9HU7jw7ydg33dI9J8gVkrmsSZ2/w== +=nvqq +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (2, 'elg2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIgoRBAC1onBpxKYgDvrgCaUWPY34947X3ogxGOfCN0p6Eqrx+2PUhm4n +vFvmczpMT4iDc0mUO+iwnwsEkXQI1eC99g8c0jnZAvzJZ5miAHL8hukMAMfDkYke +5aVvcPPc8uPDlItpszGmH0rM0V9TIt/i9QEXetpyNWhk4jj5qnohYhLeZwCgkOdO +RFAdNi4vfFPivvtAp2ffjU8D/R3x/UJCvkzi7i9rQHGo313xxmQu5BuqIjANBUij +8IE7LRPI/Qhg2hYy3sTJwImDi7VkS+fuvNVk0d6MTWplAXYU96bn12JaD21R9sKl +Fzcc+0iZI1wYA1PczisUkoTISE+dQFUsoGHfpDLhoBuesXQrhBavI8t8VPd+nkdt +J+oKA/9iRQ87FzxdYTkh2drrv69FZHc3Frsjw9nPcBq/voAvXH0MRilqyCg7HpW/ +T9naeOERksa+Rj4R57IF1l4e5oiiGJo9QmaKZcsCsXrREJCycrlEtMqXfSPy+bi5 +0yDZE/Qm1dwu13+OXOsRvkoNYjO8Mzo9K8wU12hMqN0a2bu6a7QjRWxnYW1hbCAy +MDQ4IDx0ZXN0MjA0OEBleGFtcGxlLm9yZz6IXgQTEQIAHgUCQsgiCgIbAwYLCQgH +AwIDFQIDAxYCAQIeAQIXgAAKCRBI6c1W/qZo29PDAKCG724enIxRog1j+aeCp/uq +or6mbwCePuKy2/1kD1FvnhkZ/R5fpm+pdm25Ag0EQsgiIhAIAJI3Gb2Ehtz1taQ9 +AhPY4Avad2BsqD3S5X/R11Cm0KBE/04D29dxn3f8QfxDsexYvNIZjoJPBqqZ7iMX +MhoWyw8ZF5Zs1mLIjFGVorePrm94N3MNPWM7x9M36bHUjx0vCZKFIhcGY1g+htE/ +QweaJzNVeA5z4qZmik41FbQyQSyHa3bOkTZu++/U6ghP+iDp5UDBjMTkVyqITUVN +gC+MR+da/I60irBVhue7younh4ovF+CrVDQJC06HZl6CAJJyA81SmRfi+dmKbbjZ +LF6rhz0norPjISJvkIqvdtM4VPBKI5wpgwCzpEqjuiKrAVujRT68zvBvJ4aVqb11 +k5QdJscAAwUH/jVJh0HbWAoiFTe+NvohfrA8vPcD0rtU3Y+siiqrabotnxJd2NuC +bxghJYGfNtnx0KDjFbCRKJVeTFok4UnuVYhXdH/c6i0/rCTNdeW2D6pmR4GfBozR +Pw/ARf+jONawGLyUj7uq13iquwMSE7VyNuF3ycL2OxXjgOWMjkH8c+zfHHpjaZ0R +QsetMq/iNBWraayKZnWUd+eQqNzE+NUo7w1jAu7oDpy+8a1eipxzK+O0HfU5LTiF +Z1Oe4Um0P2l3Xtx8nEgj4vSeoEkl2qunfGW00ZMMTCWabg0ZgxPzMfMeIcm6525A +Yn2qL+X/qBJTInAl7/hgPz2D1Yd7d5/RdWaISQQYEQIACQUCQsgiIgIbDAAKCRBI +6c1W/qZo25ZSAJ98WTrtl2HiX8ZqZq95v1+9cHtZPQCfZDoWQPybkNescLmXC7q5 +1kNTmEU= +=8QM5 +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELIIgoRBAC1onBpxKYgDvrgCaUWPY34947X3ogxGOfCN0p6Eqrx+2PUhm4n +vFvmczpMT4iDc0mUO+iwnwsEkXQI1eC99g8c0jnZAvzJZ5miAHL8hukMAMfDkYke +5aVvcPPc8uPDlItpszGmH0rM0V9TIt/i9QEXetpyNWhk4jj5qnohYhLeZwCgkOdO +RFAdNi4vfFPivvtAp2ffjU8D/R3x/UJCvkzi7i9rQHGo313xxmQu5BuqIjANBUij +8IE7LRPI/Qhg2hYy3sTJwImDi7VkS+fuvNVk0d6MTWplAXYU96bn12JaD21R9sKl +Fzcc+0iZI1wYA1PczisUkoTISE+dQFUsoGHfpDLhoBuesXQrhBavI8t8VPd+nkdt +J+oKA/9iRQ87FzxdYTkh2drrv69FZHc3Frsjw9nPcBq/voAvXH0MRilqyCg7HpW/ +T9naeOERksa+Rj4R57IF1l4e5oiiGJo9QmaKZcsCsXrREJCycrlEtMqXfSPy+bi5 +0yDZE/Qm1dwu13+OXOsRvkoNYjO8Mzo9K8wU12hMqN0a2bu6awAAn2F+iNBElfJS +8azqO/kEiIfpqu6/DQG0I0VsZ2FtYWwgMjA0OCA8dGVzdDIwNDhAZXhhbXBsZS5v +cmc+iF0EExECAB4FAkLIIgoCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQSOnN +Vv6maNvTwwCYkpcJmpl3aHCQdGomz7dFohDgjgCgiThZt2xTEi6GhBB1vuhk+f55 +n3+dAj0EQsgiIhAIAJI3Gb2Ehtz1taQ9AhPY4Avad2BsqD3S5X/R11Cm0KBE/04D +29dxn3f8QfxDsexYvNIZjoJPBqqZ7iMXMhoWyw8ZF5Zs1mLIjFGVorePrm94N3MN +PWM7x9M36bHUjx0vCZKFIhcGY1g+htE/QweaJzNVeA5z4qZmik41FbQyQSyHa3bO +kTZu++/U6ghP+iDp5UDBjMTkVyqITUVNgC+MR+da/I60irBVhue7younh4ovF+Cr +VDQJC06HZl6CAJJyA81SmRfi+dmKbbjZLF6rhz0norPjISJvkIqvdtM4VPBKI5wp +gwCzpEqjuiKrAVujRT68zvBvJ4aVqb11k5QdJscAAwUH/jVJh0HbWAoiFTe+Nvoh +frA8vPcD0rtU3Y+siiqrabotnxJd2NuCbxghJYGfNtnx0KDjFbCRKJVeTFok4Unu +VYhXdH/c6i0/rCTNdeW2D6pmR4GfBozRPw/ARf+jONawGLyUj7uq13iquwMSE7Vy +NuF3ycL2OxXjgOWMjkH8c+zfHHpjaZ0RQsetMq/iNBWraayKZnWUd+eQqNzE+NUo +7w1jAu7oDpy+8a1eipxzK+O0HfU5LTiFZ1Oe4Um0P2l3Xtx8nEgj4vSeoEkl2qun +fGW00ZMMTCWabg0ZgxPzMfMeIcm6525AYn2qL+X/qBJTInAl7/hgPz2D1Yd7d5/R +dWYAAVQKFPXbRaxbdArwRVXMzSD3qj/+VwwhwEDt8zmBGnlBfwVdkjQQrDUMmV1S +EwyISQQYEQIACQUCQsgiIgIbDAAKCRBI6c1W/qZo25ZSAJ4sgUfHTVsG/x3p3fcM +3b5R86qKEACggYKSwPWCs0YVRHOWqZY0pnHtLH8= +=3Dgk +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (3, 'elg4096', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=kRxT +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=Gjq6 +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (4, 'rsa2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQELBELIJbEBCADAIdtcoLAmQfl8pb73pPRuEYx8qW9klLfCGG5A4OUOi00JHNwP +ZaABe1PGzjoeXrgM1MTQZhoZu1Vdg+KDI6XAtiy9P6bLg7ntsXksD4wBoIKtQKc2 +55pdukxTiu+xeJJG2q8ZZPOp97CV9fbQ9vPCwgnuSsDCoQlibZikDVPAyVTvp7Jx +5rz8yXsl4sxvaeMZPqqFPtA/ENeQ3cpsyR1BQXSvoZpH1Fq0b8GcZTEdWWD/w6/K +MCRC8TmgEd+z3e8kIsCwFQ+TSHbCcxRWdgZE7gE31sJHHVkrZlXtLU8MPXWqslVz +R0cX+yC8j6bXI6/BqZ2SvRndJwuunRAr4um7AAYptB5SU0EgMjA0OCA8cnNhMjA0 +OEBleGFtcGxlLm9yZz6JATQEEwECAB4FAkLIJbECGwMGCwkIBwMCAxUCAwMWAgEC +HgECF4AACgkQnc+OnJvTHyQqHwf8DtzuAGmObfe3ggtn14x2wnU1Nigebe1K5liR +nrLuVlLBpdO6CWmMUzfKRvyZlx54GlA9uUQSjW+RlgejdOTQqesDrcTEukYd4yzw +bLZyM5Gb3lsE/FEmE7Dxw/0Utf59uACqzG8LACQn9J6sEgZWKxAupuYTHXd12lDP +D3dnU4uzKPhMcjnSN00pzjusP7C9NZd3OLkAx2vw/dmb4Q+/QxeZhVYYsAUuR2hv +9bgGWopumlOkt8Zu5YG6+CtTbJXprPI7pJ1jHbeE+q/29hWJQtS8Abx82AcOkzhv +S3NZKoJ/1DrGgoDAu1mGkM4KvLAxfDs/qQ9dZhtEmDbKPLTVEA== +=lR4n +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQOWBELIJbEBCADAIdtcoLAmQfl8pb73pPRuEYx8qW9klLfCGG5A4OUOi00JHNwP +ZaABe1PGzjoeXrgM1MTQZhoZu1Vdg+KDI6XAtiy9P6bLg7ntsXksD4wBoIKtQKc2 +55pdukxTiu+xeJJG2q8ZZPOp97CV9fbQ9vPCwgnuSsDCoQlibZikDVPAyVTvp7Jx +5rz8yXsl4sxvaeMZPqqFPtA/ENeQ3cpsyR1BQXSvoZpH1Fq0b8GcZTEdWWD/w6/K +MCRC8TmgEd+z3e8kIsCwFQ+TSHbCcxRWdgZE7gE31sJHHVkrZlXtLU8MPXWqslVz +R0cX+yC8j6bXI6/BqZ2SvRndJwuunRAr4um7AAYpAAf/QZsrrz0c7dgWwGqMIpw6 +fP+/lLa74+fa2CFRWtYowEiKsfDg/wN7Ua07036dNhPa8aZPsU6SRzm5PybKOURe +D9pNt0FxJkX0j5pCWfjSJgTbc1rCdqZ/oyBk/U6pQtf//zfw3PbDl7I8TC6GOt2w +5NgcXdsWHP7LAmPctOVUyzFsenevR0MFTHkMbmKI1HpFm8XN/e1Fl+qIAD+OagTF +5B32VvpoJtkh5nxnIuToNJsa9Iy7F9MM2CeFOyTMihMcjXKBBUaAYoF115irBvqu +7N/qWmzqLg8yxBZ56mh6meCF3+67VA2y7fL8rhw2QuqgLg1JFlKAVL+9crCSrn// +GQQA1kT7FytW6BNOffblFYZkrJer3icoRDqa/ljgH/yVaWoVT1igy0E9XzYO7MwP +2usj/resLy0NC1qCthk51cZ/wthooMl88e5Wb4l5FYwBEac7muSBTo4W8cAH1hFj +TWL6XAGvEzGX3Mt9pn8uYGlQLZAhJoNCAU2EOCbN1PchDvsEAOWNKYesuUVk8+sQ +St0NDNhd9BWtTWTHkCZb1dKC3JTfr9PqkTBLrWFbYjkOtvdPAW7FDaXXXZfdH1jH +WfwP3Q+I6sqgSaWpCS4dBAns3/RVtO7czVgyIwma04iIvJqderYrfvkUq95KfwP2 +V8wXkhrPPPxyrg5y3wQlpY2jb5RBBAC17SK1ms+DBtck4vpdjp3SJ32SbyC/DU30 +89Q12j74S7Zdu1qZlKnvy3kWPYX/hMuSzGZ+mLVJNFEqH2X01aFzppYz0hdI9PGB +9tTFEqZWQL9ZkXfjc79Cgnt12pNukRbtw0N/kyutOdIFHVT79wVAd+powqziXJsC +Kc+4xjwSCkZitB5SU0EgMjA0OCA8cnNhMjA0OEBleGFtcGxlLm9yZz6JATQEEwEC +AB4FAkLIJbECGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQnc+OnJvTHyQqHwf8 +DtzuAGmObfe3ggtn14x2wnU1Nigebe1K5liRnrLuVlLBpdO6CWmMUzfKRvyZlx54 +GlA9uUQSjW+RlgejdOTQqesDrcTEukYd4yzwbLZyM5Gb3lsE/FEmE7Dxw/0Utf59 +uACqzG8LACQn9J6sEgZWKxAupuYTHXd12lDPD3dnU4uzKPhMcjnSN00pzjusP7C9 +NZd3OLkAx2vw/dmb4Q+/QxeZhVYYsAUuR2hv9bgGWopumlOkt8Zu5YG6+CtTbJXp +rPI7pJ1jHbeE+q/29hWJQtS8Abx82AcOkzhvS3NZKoJ/1DrGgoDAu1mGkM4KvLAx +fDs/qQ9dZhtEmDbKPLTVEA== +=WKAv +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (5, 'psw-elg1024', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQLQfRWxnYW1hbCAx +MDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJCyCFIAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAniI9W2bC3CxARTpYrev7ihreDzFc +AJ9WYLQxDQAi5Ec9AQoodPkIagzZ4LkBDQRCyCFKEAQAh5SNbbJMAsJ+sQbcWEzd +ku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioymlDwraTKUAfuCZgNcg/0P +sxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlPiO0wt1lLX+SubktqbYxI ++h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSgMERiNzF0acZUYmc0e+/9 +6gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxsnKjUaw/qyoaFcNMzb4sF +k8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey9ifh8rZfu57UbdwdHa0v +iWc4DilhiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCfdPom+HlNVE9F +ig3hGY1Rb4NEk1gAn1u9IuQB+BgDP40YHHz6bKWS/x80 +=RWci +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQHpBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQP4HAwImKZ5q2QwT +D2DDAY/IQBjes7WgqZeacfLPDoB8ecD/KLoSCH6Z3etvbPHSOKiazxoJ962Ix74H +ZAE6ZbMTtl5dZW1ptB9FbGdhbWFsIDEwMjQgPHRlc3RAZXhhbXBsZS5vcmc+iF4E +ExECAB4FAkLIIUgCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQHCm8DRgXc2Q6 +2wCfXKegLIzoYi8cM57DCYXhn+MZB/MAn1D4zAi5uLQBJ8mJ9oQzbewgfAeinQFf +BELIIUoQBACHlI1tskwCwn6xBtxYTN2S7wB1gHnNjtDJ/0Q6+fSDf1vMA2HGaZvq +BtGVA3SKjKaUPCtpMpQB+4JmA1yD/Q+zEUZv2cNy+MhXyp1WmerU+7MwW4FuYYjr +B6Ds+PTV2U+I7TC3WUtf5K5uS2ptjEj6HfVzdENmrGP4oCDFHxg0YwADBgP7BCzY +d7Vnn6ng5KAwRGI3MXRpxlRiZzR77/3qB8vR+3cg/5JIWjqEQGuQpWFkqg9JJGvk +qk1oShuF3GycqNRrD+rKhoVw0zNviwWTzCrlSUKRH6Hva7qG/wW6V4JXxIlRPVTY +mO2VclHY97L2J+Hytl+7ntRt3B0drS+JZzgOKWH+BwMCJimeatkMEw9gRkFjt4Xa +9rX8awMBE5+vVcGKv/DNiCvJnlYvSdCj8VfuHsYFliiJo6u17NJon+K43e3yvDNk +f631VOVanGEz7TyqOkWQiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCe +IUWi3DXHZf6ivK7dDec22bGgoekAn0dTuPDvJ2Dfd0j0nyBWSuaxJnb/ +=SNvr +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (6, 'rsaenc2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQELBELr2m0BCADOrnknlnXI0EzRExf/TgoHvK7Xx/E0keWqV3KrOyC3/tY2KOrj +UVxaAX5pkFX9wdQObGPIJm06u6D16CH6CildX/vxG7YgvvKzK8JGAbwrXAfk7OIW +czO2zRaZGDynoK3mAxHRBReyTKtNv8rDQhuZs6AOozJNARdbyUO/yqUnqNNygWuT +4htFDEuLPIJwAbMSD0BvFW6YQaPdxzaAZm3EWVNbwDzjgbBUdBiUUwRdZIFUhsjJ +dirFdy5+uuZru6y6CNC1OERkJ7P8EyoFiZckAIE5gshVZzNuyLOZjc5DhWBvLbX4 +NZElAnfiv+4nA6y8wQLSIbmHA3nqJaBklj85AAYptCVSU0EgMjA0OCBFbmMgPHJz +YTIwNDhlbmNAZXhhbXBsZS5vcmc+iQE0BBMBAgAeBQJC69ptAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEMiZ6pNEGVVZHMkIAJtGHHZ9iM8Yq1rr0zl1L6SvlQP8 +JCaxHa31wH3PKqGtq2M+cpb2rXf7gAY/doHJPXggfVzkyFrysmQ1gPbDGYLyOutw ++IkhihEb5bWxQBNj+3zAFs1YX6v2HXWbSUSmyY1V9/+NTtKk03olDc/swd3lXzku +UOhcgfpBgIt3Q+MpT6M2+OIF7lVfSb1rWdpwTfGhZzW9szQOeoS4gPvxCCRyuabQ +RJ6DWH61F8fFIDJg1z+A/Obx4fqX6GOA69RzgZ3oukFBIXxNwV9PZNnAmHtZVYO8 +0g/oVYBbuvOYedffDBeQarhERZ5W2TnIE+nqY61YOLBqosliygdZTXULzNi5AQsE +QuvaugEIAOuCJZdkzORA6e1lr81Lnr4JzMsVBFA+X/yIkBbV6qX/A4nVSLAZKNPX +z1YIrMTu+1rMIiy10IWbA6zgMTpzPhJRfgePONgdnCYyK5Ksh5/C5ntzKwwGwxfK +lAXIxJurCHXTbEa+YvPdn76vJ3HsXOXVEL+fLb4U3l3Ng87YM202Lh1Ha2MeS2zE +FZcAoKbFqAAjDLEai64SoOFh0W3CsD1DL4zmfp+YZrUPHTtZadsi53i4KKW/ws9U +rHlolqYNhYze/uRLyfnUx9PN4r/GhEzauyDMV0smo91uB3aewPft+eCpmeWnu0PF +JVK4xyRmhIq2rVCw16a1pBJirvGM+y0ABimJAR8EGAECAAkFAkLr2roCGwwACgkQ +yJnqk0QZVVku1wgAg1bLSjPkhw+ldG5HzumpqR84+JKyozdJaJzefu2+1iqYE0B0 +WLz2PJVIiK41xiEkKhBvTOQYuXmtWqAWXptD91P5SoXoNJWLQO3TNwarANhHxkWg +w/TOUxQqoctlRUej5NDD+4eW5G9lcS1FEGuKDWtX096u80vO+TbyJjvx2eVM1k+X +dmeYsGOiNgDimCreJGYc14G7eY9jt24gw10n1sMAKI1qm6lcoHqZ9OOyla+wJdro +PYZGO7R8+1O9R22WrK6BYDT5j/1JwMZqbOESjNvDEVT0yOHClCHRN4CChbt6LhKh +CLUNdz/udIt0JAC6c/HdPLSW3HnmM3+iNj+Kug== +=pwU2 +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=UKh3 +-----END PGP PRIVATE KEY BLOCK----- +'); +insert into keytbl (id, name, pubkey, seckey) +values (7, 'rsaenc2048-psw', ' +same key with password +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.11 (GNU/Linux) + +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 +=QFm5 +-----END PGP PRIVATE KEY BLOCK----- +'); +-- elg1024 / aes128 +insert into encdata (id, data) values (1, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQEOA9k2z2S7c/RmEAQAgVWW0DeLrZ+1thWJGBPp2WRFL9HeNqqWHbKJCXJbz1Uy +faUY7yxVvG5Eutmo+JMiY3mg23/DgVVXHQZsTWpGvGM6djgUNGKUjZDbW6Nog7Mr +e78IywattCOmgUP9vIwwg3OVjuDCN/nVirGQFnXpJBc8DzWqDMWRWDy1M0ZsK7AD +/2JTosSFxUdpON0DKtIY3GLzmh6Nk3iV0g8VgJKUBT1rhCXuMDj3snm//EMm7hTY +PlnObq4mIhgz8NqprmhooxnU0Kapofb3P3wCHPpU14zxhXY8iKO/3JhBq2uFcx4X +uBMwkW4AdNxY/mzJZELteTL8Tr0s7PISk+owb4URpG3n0jsBc0CVULxrjh5Ejkdw +wCM195J6+KbQxOOFQ0b3uOVvv4dEgd/hRERCOq5EPaFhlHegyYJ7YO842vnSDA== +=PABx +-----END PGP MESSAGE----- +'); +-- elg2048 / blowfish +insert into encdata (id, data) values (2, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQIOAywibh/+XMfUEAf+OINhBngEsw4a/IJIeJvUgv1gTQzBwOdQEuc/runr4Oa8 +Skw/Bj0X/zgABVZLem1a35NHaNwaQaCFwMQ41YyWCu+jTdsiyX/Nw0w8LKKz0rNC +vVpG6YuV7Turtsf8a5lXy1K0SHkLlgxQ6c76GS4gtSl5+bsL2+5R1gSRJ9NXqCQP +OHRipEiYwBPqr5R21ZG0FXXNKGOGkj6jt/M/wh3WVtAhYuBI+HPKRfAEjd/Pu/eD +e1zYtkH1dKKFmp44+nF0tTI274xpuso7ShfKYrOK3saFWrl0DWiWteUinjSA1YBY +m7dG7NZ8PW+g1SZWhEoPjEEEHz3kWMvlKheMRDudnQf/dDyX6kZVIAQF/5B012hq +QyVewgTGysowFIDn01uIewoEA9cASw699jw9IoJp+k5WZXnU+INllBLzQxniQCSu +iEcr0x3fYqNtj9QBfbIqyRcY6HTWcmzyOUeGaSyX76j+tRAvtVtXpraFFFnaHB70 +YpXTjLkp8EBafzMghFaKDeXlr2TG/T7rbwcwWrFIwPqEAUKWN5m97Q3eyo8/ioMd +YoFD64J9ovSsgbuU5IpIGAsjxK+NKzg/2STH7zZFEVCtgcIXsTHTZfiwS98/+1H9 +p1DIDaXIcUFV2ztmcKxh9gt2sXRz1W+x6D8O0k3nanU5yGG4miLKaq18fbcA0BD1 ++NIzAfelq6nvvxYKcGcamBMgLo5JkZOBHvyr6RsAKIT5QYc0QTjysTk9l0Am3gYc +G2pAE+3k +=TBHV +-----END PGP MESSAGE----- +'); +-- elg4096 / aes256 +insert into encdata (id, data) values (3, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQQOA7aFBP0Sjh/5EA/+JCgncc8IZmmRjPStWnGf9tVJhgHTn+smIclibGzs0deS +SPSCitzpblwbUDvu964+/5e5Q1l7rRuNN+AgETlEd4eppv7Swn2ChdgOXxRwukcT +Nh3G+PTFvD4ayi7w1db3qvXIt0MwN4Alt436wJmK1oz2Ka9IcyO+wHWrDy1nSGSx +z5x7YEj+EZPgWc/YAvudqE8Jpzd/OT5zSHN09UFkIAk6NxisKaIstbEGFgpqtoDZ +1SJM84XAdL2IcaJ3YY7k/yzwlawhsakKd4GSd5vWmAwvyzzbSiBMfKsDE16ePLNU +ZBF7CzmlCBPZ7YrFAHLpXBXXkCQvzD2BEYOjse50ZEfJ036T7950Ozcdy1EQbGon +nyQ4Gh0PBpnMcBuiXOceWuYzhlzFOzDtlVKdNTxFRDcbEyW2jo9xQYvCCLnYy8EH +2M7S8jCtVYJBbn63a82ELv+3+kWYcsvBJv2ZVBh4ncrBu9o0P+OYS7ApoOU+j6p2 ++t0RXHksqXS1YiUwYF5KSw09EbYMgNZ9G04Px/PxLU6fSC9iDrGX7Xt3kOUP0mku +C518fPckT0zzRXqfFruJNRzDytW50KxkOQZzU1/Az1YlYN9QzWeU4EtLPb2fftZo +D0qH/ln+f9Op5t6sD2fcxZVECU1b/bFtZsxvwH406YL+UQ7hU/XnZrzVVzODal8P +/j1hg7v7BdJqu1DTp9nFWUuwMFcYAczuXn29IG183NZ7Ts4whDeYEhS8eNoLPX4j +txY12ILD/w/3Q4LoW/hPa6OdfEzsn0U5GLf1WiGmJE1H6ft2U/xUnerc/u0kt+FU +WAisArd4MuKtf7B5Vu/VF3kUdrR0hTniUKUivmC4o1jSId31Dufxj4aadVyldXAr +6TNBcdyragZjxEZ6hsBCYzA0Rd1a8atd6OaQoIEEfAzCu5Ks29pydHErStYGjWJ1 +KA5KPLVvjbHpDmRhlCcm8vgpYQsBYEB5gE9fx5yCTlsVhCB6y23h7hfdMqerDqkO +ZOPsO5h+tiHCdIrQ36sMjuINy1/K2rYcXd+Crh2iHcfidpU9fvDz2ihTRNQlhjuT +0cQZM5JhctEx4VXF4LDctRhit7Hn0iqsk604woQfJVvP8O673xSXT/kBY0A/v9C0 +3C4YoFNeSaKwbfZQ/4u1ZFPJxK2IIJa8UGpyAUewLMlzGVVagljybv/f4Z9ERAhy +huq5sMmw8UPsrJF2TUGHz5WSIwoh0J/qovoQI09I9sdEnFczDvRavMO2Mldy3E5i +exz9oewtel6GOmsZQSYWT/vJzbYMmvHNmNpVwwoKrLV6oI3kyQ80GHBwI1WlwHoK +2iRB0w8q4VVvJeYAz8ZIp380cqC3pfO0uZsrOx4g3k4X0jsB5y7rF5xXcZfnVbvG +DYKcOy60/OHMWVvpw6trAoA+iP+cVWPtrbRvLglTVTfYmi1ToZDDipkALBhndQ== +=L/M/ +-----END PGP MESSAGE----- +'); +-- rsaenc2048 / aes128 +insert into encdata (id, data) values (4, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQEMA/0CBsQJt0h1AQf+JyYnCiortj26P11zk28MKOGfWpWyAhuIgwbJXsdQ+e6r +pEyyqs9GC6gI7SNF6+J8B/gsMwvkAL4FHAQCvA4ZZ6eeXR1Of4YG22JQGmpWVWZg +DTyfhA2vkczuqfAD2tgUpMT6sdyGkQ/fnQ0lknlfHgC5GRx7aavOoAKtMqiZW5PR +yae/qR48mjX7Mb+mLvbagv9mHEgQSmHwFpaq2k456BbcZ23bvCmBnCvqV/90Ggfb +VP6gkSoFVsJ19RHsOhW1dk9ehbl51WB3zUOO5FZWwUTY9DJvKblRK/frF0+CXjE4 +HfcZXHSpSjx4haGGTsMvEJ85qFjZpr0eTGOdY5cFhNJAAVP8MZfji7OhPRAoOOIK +eRGOCkao12pvPyFTFnPd5vqmyBbdNpK4Q0hS82ljugMJvM0p3vJZVzW402Kz6iBL +GQ== +=XHkF +-----END PGP MESSAGE----- +'); +-- rsaenc2048 / aes128 (not from gnupg) +insert into encdata (id, data) values (5, ' +-----BEGIN PGP MESSAGE----- + +wcBMA/0CBsQJt0h1AQgAzxZ8j+OTeZ8IlLxfZ/mVd28/gUsCY+xigWBk/anZlK3T +p2tNU2idHzKdAttH2Hu/PWbZp4kwjl9spezYxMqCeBZqtfGED88Y+rqK0n/ul30A +7jjFHaw0XUOqFNlST1v6H2i7UXndnp+kcLfHPhnO5BIYWxB2CYBehItqtrn75eqr +C7trGzU/cr74efcWagbCDSNjiAV7GlEptlzmgVMmNikyI6w0ojEUx8lCLc/OsFz9 +pJUAX8xuwjxDVv+W7xk6c96grQiQlm+FLDYGiGNXoAzx3Wi/howu3uV40dXfY+jx +3WBrhEew5Pkpt1SsWoFnJWOfJ8GLd0ec8vfRCqAIVdLgAeS7NyawQYtd6wuVrEAj +5SMg4Thb4d+g45RksuGLHUUr4qO9tiXglODa4InhmJfgNuLk+RGz4LXjq8wepEmW +vRbgFOG54+Cf4C/gC+HkreDm5JKSKjvvw4B/jC6CDxq+JoziEe2Z1uEjCuEcr+Es +/eGzeOi36BejXPMHeKxXejj5qBBHKV0pHVhZSgffR0TtlXdB967Yl/5agV0R89hI +7Gw52emfnH4Z0Y4V0au2H0k1dR/2IxXdJEWSTG7Be1JHT59p9ei2gSEOrdBMIOjP +tbYYUlmmbvD49bHfThkDiC+oc9947LgQsk3kOOLbNHcjkbrjH8R5kjII4m/SEZA1 +g09T+338SzevBcVXh/cFrQ6/Et+lyyO2LJRUMs69g/HyzJOVWT2Iu8E0eS9MWevY +Qtrkrhrpkl3Y02qEp/j6M03Yu2t6ZF7dp51aJ5VhO2mmmtHaTnCyCc8Fcf72LmD8 +blH2nKZC9d6fi4YzSYMepZpMOFR65M80MCMiDUGnZBB8sEADu2/iVtqDUeG8mAA= +=PHJ1 +-----END PGP MESSAGE----- +'); +-- successful decrypt +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=1 and encdata.id=1; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=2; +ERROR: Wrong key or corrupt data +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=3 and encdata.id=3; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=6 and encdata.id=4; + pgp_pub_decrypt +----------------- + Secret message. +(1 row) + +-- wrong key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=1; +ERROR: Wrong key +-- sign-only key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=4 and encdata.id=1; +ERROR: No encryption key found +-- rsa: password-protected secret key, wrong password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), '123') +from keytbl, encdata where keytbl.id=7 and encdata.id=4; +ERROR: Wrong key or corrupt data +-- rsa: password-protected secret key, right password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool') +from keytbl, encdata where keytbl.id=7 and encdata.id=4; + pgp_pub_decrypt +----------------- + Secret message. +(1 row) + +-- password-protected secret key, no password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=5 and encdata.id=1; +ERROR: Need password for secret key +-- password-protected secret key, wrong password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'foo') +from keytbl, encdata where keytbl.id=5 and encdata.id=1; +ERROR: Wrong key or corrupt data +-- password-protected secret key, right password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool') +from keytbl, encdata where keytbl.id=5 and encdata.id=1; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +-- test for a short read from prefix_init +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=6 and encdata.id=5; +ERROR: Wrong key or corrupt data diff --git a/contrib/pgcrypto/expected/pgp-pubkey-encrypt.out b/contrib/pgcrypto/expected/pgp-pubkey-encrypt.out new file mode 100644 index 0000000..7f90554 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-encrypt.out @@ -0,0 +1,68 @@ +-- +-- PGP Public Key Encryption +-- +-- successful encrypt/decrypt +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=2; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=3; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=6; + pgp_pub_decrypt +----------------- + Secret msg +(1 row) + +-- try with rsa-sign only +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=4; +ERROR: No encryption key found +-- try with secret key +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(seckey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: Refusing to encrypt with secret key +-- does text-to-bytea works +select encode(pgp_pub_decrypt_bytea( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)), 'escape') +from keytbl where keytbl.id=1; + encode +------------ + Secret msg +(1 row) + +-- and bytea-to-text? +select pgp_pub_decrypt( + pgp_pub_encrypt_bytea('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: Not text data diff --git a/contrib/pgcrypto/expected/pgp-zlib-DISABLED.out b/contrib/pgcrypto/expected/pgp-zlib-DISABLED.out new file mode 100644 index 0000000..6f4eccd --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-zlib-DISABLED.out @@ -0,0 +1 @@ +-- zlib is disabled diff --git a/contrib/pgcrypto/expected/rijndael.out b/contrib/pgcrypto/expected/rijndael.out new file mode 100644 index 0000000..015ba44 --- /dev/null +++ b/contrib/pgcrypto/expected/rijndael.out @@ -0,0 +1,137 @@ +-- +-- AES cipher (aka Rijndael-128, -192, or -256) +-- +-- some standard Rijndael testvalues +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f', +'aes-ecb/pad:none'); + encrypt +------------------------------------ + \x69c4e0d86a7b0430d8cdb78070b4c55a +(1 row) + +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f1011121314151617', +'aes-ecb/pad:none'); + encrypt +------------------------------------ + \xdda97ca4864cdfe06eaf70a0ec0d7191 +(1 row) + +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', +'aes-ecb/pad:none'); + encrypt +------------------------------------ + \x8ea2b7ca516745bfeafc49904b496089 +(1 row) + +-- cbc +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', +'aes-cbc/pad:none'); + encrypt +------------------------------------ + \x8ea2b7ca516745bfeafc49904b496089 +(1 row) + +-- without padding, input not multiple of block size +SELECT encrypt( +'\x00112233445566778899aabbccddeeff00', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', +'aes-cbc/pad:none'); +ERROR: encrypt error: Encryption failed +-- key padding +SELECT encrypt( +'\x0011223344', +'\x000102030405', +'aes-cbc'); + encrypt +------------------------------------ + \x189a28932213f017b246678dbc28655f +(1 row) + +SELECT encrypt( +'\x0011223344', +'\x000102030405060708090a0b0c0d0e0f10111213', +'aes-cbc'); + encrypt +------------------------------------ + \x3b02279162d15580e069d3a71407a556 +(1 row) + +SELECT encrypt( +'\x0011223344', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b', +'aes-cbc'); + encrypt +------------------------------------ + \x4facb6a041d53e0a5a73289170901fe7 +(1 row) + +-- empty data +select encrypt('', 'foo', 'aes'); + encrypt +------------------------------------ + \xb48cc3338a2eb293b6007ef72c360d48 +(1 row) + +-- 10 bytes key +select encrypt('foo', '0123456789', 'aes'); + encrypt +------------------------------------ + \xf397f03d2819b7172b68d0706fda4693 +(1 row) + +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', 'aes'); + encrypt +------------------------------------ + \x5c9db77af02b4678117bcd8a71ae7f53 +(1 row) + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'aes'), '0123456', 'aes'), 'escape'); + encode +-------- + foo +(1 row) + +-- data not multiple of block size +select encode(decrypt(encrypt('foo', '0123456', 'aes') || '\x00'::bytea, '0123456', 'aes'), 'escape'); +ERROR: decrypt error: Decryption failed +-- bad padding +-- (The input value is the result of encrypt_iv('abcdefghijklmnopqrstuvwxyz', '0123456', 'abcd', 'aes') +-- with the 16th byte changed (s/db/eb/) to corrupt the padding of the last block.) +select encode(decrypt_iv('\xa21a9c15231465964e3396d32095e67eb52bab05f556a581621dee1b85385789', '0123456', 'abcd', 'aes'), 'escape'); +ERROR: decrypt_iv error: Decryption failed +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'aes'); + encrypt_iv +------------------------------------ + \x2c24cb7da91d6d5699801268b0f5adad +(1 row) + +select encode(decrypt_iv('\x2c24cb7da91d6d5699801268b0f5adad', '0123456', 'abcd', 'aes'), 'escape'); + encode +-------- + foo +(1 row) + +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'aes'); + encrypt +-------------------------------------------------------------------- + \xd9beb785dd5403ed02f66b755bb191b93ed93ca54930153f2c3b9ec7785056ad +(1 row) + +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes'), '0123456789', 'aes'), 'escape'); + encode +---------------------------- + Lets try a longer message. +(1 row) + diff --git a/contrib/pgcrypto/expected/sha1.out b/contrib/pgcrypto/expected/sha1.out new file mode 100644 index 0000000..b8eaed1 --- /dev/null +++ b/contrib/pgcrypto/expected/sha1.out @@ -0,0 +1,45 @@ +-- +-- SHA1 message digest +-- +SELECT digest('', 'sha1'); + digest +-------------------------------------------- + \xda39a3ee5e6b4b0d3255bfef95601890afd80709 +(1 row) + +SELECT digest('a', 'sha1'); + digest +-------------------------------------------- + \x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 +(1 row) + +SELECT digest('abc', 'sha1'); + digest +-------------------------------------------- + \xa9993e364706816aba3e25717850c26c9cd0d89d +(1 row) + +SELECT digest('message digest', 'sha1'); + digest +-------------------------------------------- + \xc12252ceda8be8994d5fa0290a47231c1d16aae3 +(1 row) + +SELECT digest('abcdefghijklmnopqrstuvwxyz', 'sha1'); + digest +-------------------------------------------- + \x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 +(1 row) + +SELECT digest('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'sha1'); + digest +-------------------------------------------- + \x761c457bf73b14d27e9e9265c46f4b4dda11f940 +(1 row) + +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha1'); + digest +-------------------------------------------- + \x50abf5706a150990a08b2c5ea40fa0e585554732 +(1 row) + diff --git a/contrib/pgcrypto/expected/sha2.out b/contrib/pgcrypto/expected/sha2.out new file mode 100644 index 0000000..6f67fe6 --- /dev/null +++ b/contrib/pgcrypto/expected/sha2.out @@ -0,0 +1,139 @@ +-- +-- SHA2 family +-- +-- SHA224 +SELECT digest('', 'sha224'); + digest +------------------------------------------------------------ + \xd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f +(1 row) + +SELECT digest('a', 'sha224'); + digest +------------------------------------------------------------ + \xabd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5 +(1 row) + +SELECT digest('abc', 'sha224'); + digest +------------------------------------------------------------ + \x23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 +(1 row) + +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha224'); + digest +------------------------------------------------------------ + \x75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 +(1 row) + +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha224'); + digest +------------------------------------------------------------ + \xb50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e +(1 row) + +-- SHA256 +SELECT digest('', 'sha256'); + digest +-------------------------------------------------------------------- + \xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +(1 row) + +SELECT digest('a', 'sha256'); + digest +-------------------------------------------------------------------- + \xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb +(1 row) + +SELECT digest('abc', 'sha256'); + digest +-------------------------------------------------------------------- + \xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad +(1 row) + +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha256'); + digest +-------------------------------------------------------------------- + \x248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 +(1 row) + +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha256'); + digest +-------------------------------------------------------------------- + \xf371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e +(1 row) + +-- SHA384 +SELECT digest('', 'sha384'); + digest +---------------------------------------------------------------------------------------------------- + \x38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b +(1 row) + +SELECT digest('a', 'sha384'); + digest +---------------------------------------------------------------------------------------------------- + \x54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31 +(1 row) + +SELECT digest('abc', 'sha384'); + digest +---------------------------------------------------------------------------------------------------- + \xcb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 +(1 row) + +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha384'); + digest +---------------------------------------------------------------------------------------------------- + \x3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b +(1 row) + +SELECT digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha384'); + digest +---------------------------------------------------------------------------------------------------- + \x09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039 +(1 row) + +SELECT digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha384'); + digest +---------------------------------------------------------------------------------------------------- + \x3d208973ab3508dbbd7e2c2862ba290ad3010e4978c198dc4d8fd014e582823a89e16f9b2a7bbc1ac938e2d199e8bea4 +(1 row) + +-- SHA512 +SELECT digest('', 'sha512'); + digest +------------------------------------------------------------------------------------------------------------------------------------ + \xcf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e +(1 row) + +SELECT digest('a', 'sha512'); + digest +------------------------------------------------------------------------------------------------------------------------------------ + \x1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75 +(1 row) + +SELECT digest('abc', 'sha512'); + digest +------------------------------------------------------------------------------------------------------------------------------------ + \xddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f +(1 row) + +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha512'); + digest +------------------------------------------------------------------------------------------------------------------------------------ + \x204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 +(1 row) + +SELECT digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha512'); + digest +------------------------------------------------------------------------------------------------------------------------------------ + \x8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909 +(1 row) + +SELECT digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha512'); + digest +------------------------------------------------------------------------------------------------------------------------------------ + \x930d0cefcb30ff1133b6898121f1cf3d27578afcafe8677c5257cf069911f75d8f5831b56ebfda67b278e66dff8b84fe2b2870f742a580d8edb41987232850c9 +(1 row) + diff --git a/contrib/pgcrypto/mbuf.c b/contrib/pgcrypto/mbuf.c new file mode 100644 index 0000000..bc668a0 --- /dev/null +++ b/contrib/pgcrypto/mbuf.c @@ -0,0 +1,560 @@ +/* + * mbuf.c + * Memory buffer operations. + * + * 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/mbuf.c + */ + +#include "postgres.h" + +#include "mbuf.h" +#include "px.h" + +#define STEP (16*1024) + +struct MBuf +{ + uint8 *data; + uint8 *data_end; + uint8 *read_pos; + uint8 *buf_end; + bool no_write; + bool own_data; +}; + +int +mbuf_avail(MBuf *mbuf) +{ + return mbuf->data_end - mbuf->read_pos; +} + +int +mbuf_size(MBuf *mbuf) +{ + return mbuf->data_end - mbuf->data; +} + +int +mbuf_tell(MBuf *mbuf) +{ + return mbuf->read_pos - mbuf->data; +} + +int +mbuf_free(MBuf *mbuf) +{ + if (mbuf->own_data) + { + px_memset(mbuf->data, 0, mbuf->buf_end - mbuf->data); + pfree(mbuf->data); + } + pfree(mbuf); + return 0; +} + +static void +prepare_room(MBuf *mbuf, int block_len) +{ + uint8 *newbuf; + unsigned newlen; + + if (mbuf->data_end + block_len <= mbuf->buf_end) + return; + + newlen = (mbuf->buf_end - mbuf->data) + + ((block_len + STEP + STEP - 1) & -STEP); + + newbuf = repalloc(mbuf->data, newlen); + + mbuf->buf_end = newbuf + newlen; + mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data); + mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data); + mbuf->data = newbuf; +} + +int +mbuf_append(MBuf *dst, const uint8 *buf, int len) +{ + if (dst->no_write) + { + px_debug("mbuf_append: no_write"); + return PXE_BUG; + } + + prepare_room(dst, len); + + memcpy(dst->data_end, buf, len); + dst->data_end += len; + + return 0; +} + +MBuf * +mbuf_create(int len) +{ + MBuf *mbuf; + + if (!len) + len = 8192; + + mbuf = palloc(sizeof *mbuf); + mbuf->data = palloc(len); + mbuf->buf_end = mbuf->data + len; + mbuf->data_end = mbuf->data; + mbuf->read_pos = mbuf->data; + + mbuf->no_write = false; + mbuf->own_data = true; + + return mbuf; +} + +MBuf * +mbuf_create_from_data(uint8 *data, int len) +{ + MBuf *mbuf; + + mbuf = palloc(sizeof *mbuf); + mbuf->data = (uint8 *) data; + mbuf->buf_end = mbuf->data + len; + mbuf->data_end = mbuf->data + len; + mbuf->read_pos = mbuf->data; + + mbuf->no_write = true; + mbuf->own_data = false; + + return mbuf; +} + + +int +mbuf_grab(MBuf *mbuf, int len, uint8 **data_p) +{ + if (len > mbuf_avail(mbuf)) + len = mbuf_avail(mbuf); + + mbuf->no_write = true; + + *data_p = mbuf->read_pos; + mbuf->read_pos += len; + return len; +} + +int +mbuf_rewind(MBuf *mbuf) +{ + mbuf->read_pos = mbuf->data; + return 0; +} + +int +mbuf_steal_data(MBuf *mbuf, uint8 **data_p) +{ + int len = mbuf_size(mbuf); + + mbuf->no_write = true; + mbuf->own_data = false; + + *data_p = mbuf->data; + + mbuf->data = mbuf->data_end = mbuf->read_pos = mbuf->buf_end = NULL; + + return len; +} + +/* + * PullFilter + */ + +struct PullFilter +{ + PullFilter *src; + const PullFilterOps *op; + int buflen; + uint8 *buf; + int pos; + void *priv; +}; + +int +pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src) +{ + PullFilter *pf; + void *priv; + int res; + + if (op->init != NULL) + { + res = op->init(&priv, init_arg, src); + if (res < 0) + return res; + } + else + { + priv = init_arg; + res = 0; + } + + pf = palloc0(sizeof(*pf)); + pf->buflen = res; + pf->op = op; + pf->priv = priv; + pf->src = src; + if (pf->buflen > 0) + { + pf->buf = palloc(pf->buflen); + pf->pos = 0; + } + else + { + pf->buf = NULL; + pf->pos = 0; + } + *pf_p = pf; + return 0; +} + +void +pullf_free(PullFilter *pf) +{ + if (pf->op->free) + pf->op->free(pf->priv); + + if (pf->buf) + { + px_memset(pf->buf, 0, pf->buflen); + pfree(pf->buf); + } + + px_memset(pf, 0, sizeof(*pf)); + pfree(pf); +} + +/* may return less data than asked, 0 means eof */ +int +pullf_read(PullFilter *pf, int len, uint8 **data_p) +{ + int res; + + if (pf->op->pull) + { + if (pf->buflen && len > pf->buflen) + len = pf->buflen; + res = pf->op->pull(pf->priv, pf->src, len, data_p, + pf->buf, pf->buflen); + } + else + res = pullf_read(pf->src, len, data_p); + return res; +} + +int +pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf) +{ + int res, + total; + uint8 *tmp; + + res = pullf_read(pf, len, data_p); + if (res <= 0 || res == len) + return res; + + /* read was shorter, use tmpbuf */ + memcpy(tmpbuf, *data_p, res); + *data_p = tmpbuf; + len -= res; + total = res; + + while (len > 0) + { + res = pullf_read(pf, len, &tmp); + if (res < 0) + { + /* so the caller must clear only on success */ + px_memset(tmpbuf, 0, total); + return res; + } + if (res == 0) + break; + memcpy(tmpbuf + total, tmp, res); + total += res; + len -= res; + } + return total; +} + +/* + * caller wants exactly len bytes and don't bother with references + */ +int +pullf_read_fixed(PullFilter *src, int len, uint8 *dst) +{ + int res; + uint8 *p; + + res = pullf_read_max(src, len, &p, dst); + if (res < 0) + return res; + if (res != len) + { + px_debug("pullf_read_fixed: need=%d got=%d", len, res); + return PXE_PGP_CORRUPT_DATA; + } + if (p != dst) + memcpy(dst, p, len); + return 0; +} + +/* + * read from MBuf + */ +static int +pull_from_mbuf(void *arg, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + MBuf *mbuf = arg; + + return mbuf_grab(mbuf, len, data_p); +} + +static const struct PullFilterOps mbuf_reader = { + NULL, pull_from_mbuf, NULL +}; + +int +pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src) +{ + return pullf_create(mp_p, &mbuf_reader, src, NULL); +} + + +/* + * PushFilter + */ + +struct PushFilter +{ + PushFilter *next; + const PushFilterOps *op; + int block_size; + uint8 *buf; + int pos; + void *priv; +}; + +int +pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next) +{ + PushFilter *mp; + void *priv; + int res; + + if (op->init != NULL) + { + res = op->init(next, init_arg, &priv); + if (res < 0) + return res; + } + else + { + priv = init_arg; + res = 0; + } + + mp = palloc0(sizeof(*mp)); + mp->block_size = res; + mp->op = op; + mp->priv = priv; + mp->next = next; + if (mp->block_size > 0) + { + mp->buf = palloc(mp->block_size); + mp->pos = 0; + } + else + { + mp->buf = NULL; + mp->pos = 0; + } + *mp_p = mp; + return 0; +} + +void +pushf_free(PushFilter *mp) +{ + if (mp->op->free) + mp->op->free(mp->priv); + + if (mp->buf) + { + px_memset(mp->buf, 0, mp->block_size); + pfree(mp->buf); + } + + px_memset(mp, 0, sizeof(*mp)); + pfree(mp); +} + +void +pushf_free_all(PushFilter *mp) +{ + PushFilter *tmp; + + while (mp) + { + tmp = mp->next; + pushf_free(mp); + mp = tmp; + } +} + +static int +wrap_process(PushFilter *mp, const uint8 *data, int len) +{ + int res; + + if (mp->op->push != NULL) + res = mp->op->push(mp->next, mp->priv, data, len); + else + res = pushf_write(mp->next, data, len); + if (res > 0) + return PXE_BUG; + return res; +} + +/* consumes all data, returns len on success */ +int +pushf_write(PushFilter *mp, const uint8 *data, int len) +{ + int need, + res; + + /* + * no buffering + */ + if (mp->block_size <= 0) + return wrap_process(mp, data, len); + + /* + * try to empty buffer + */ + need = mp->block_size - mp->pos; + if (need > 0) + { + if (len < need) + { + memcpy(mp->buf + mp->pos, data, len); + mp->pos += len; + return 0; + } + memcpy(mp->buf + mp->pos, data, need); + len -= need; + data += need; + } + + /* + * buffer full, process + */ + res = wrap_process(mp, mp->buf, mp->block_size); + if (res < 0) + return res; + mp->pos = 0; + + /* + * now process directly from data + */ + while (len > 0) + { + if (len > mp->block_size) + { + res = wrap_process(mp, data, mp->block_size); + if (res < 0) + return res; + data += mp->block_size; + len -= mp->block_size; + } + else + { + memcpy(mp->buf, data, len); + mp->pos += len; + break; + } + } + return 0; +} + +int +pushf_flush(PushFilter *mp) +{ + int res; + + while (mp) + { + if (mp->block_size > 0) + { + res = wrap_process(mp, mp->buf, mp->pos); + if (res < 0) + return res; + } + + if (mp->op->flush) + { + res = mp->op->flush(mp->next, mp->priv); + if (res < 0) + return res; + } + + mp = mp->next; + } + return 0; +} + + +/* + * write to MBuf + */ +static int +push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len) +{ + int res = 0; + MBuf *mbuf = arg; + + if (len > 0) + res = mbuf_append(mbuf, data, len); + return res < 0 ? res : 0; +} + +static const struct PushFilterOps mbuf_filter = { + NULL, push_into_mbuf, NULL, NULL +}; + +int +pushf_create_mbuf_writer(PushFilter **res, MBuf *dst) +{ + return pushf_create(res, &mbuf_filter, dst, NULL); +} diff --git a/contrib/pgcrypto/mbuf.h b/contrib/pgcrypto/mbuf.h new file mode 100644 index 0000000..e6d754e --- /dev/null +++ b/contrib/pgcrypto/mbuf.h @@ -0,0 +1,124 @@ +/* + * mbuf.h + * Memory buffer operations. + * + * 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/mbuf.h + */ + +#ifndef __PX_MBUF_H +#define __PX_MBUF_H + +typedef struct MBuf MBuf; +typedef struct PushFilter PushFilter; +typedef struct PullFilter PullFilter; +typedef struct PushFilterOps PushFilterOps; +typedef struct PullFilterOps PullFilterOps; + +struct PushFilterOps +{ + /* + * should return needed buffer size, 0- no buffering, <0 on error if NULL, + * no buffering, and priv=init_arg + */ + int (*init) (PushFilter *next, void *init_arg, void **priv_p); + + /* + * send data to next. should consume all? if null, it will be simply + * copied (in-place) returns 0 on error + */ + int (*push) (PushFilter *next, void *priv, + const uint8 *src, int len); + int (*flush) (PushFilter *next, void *priv); + void (*free) (void *priv); +}; + +struct PullFilterOps +{ + /* + * should return needed buffer size, 0- no buffering, <0 on error if NULL, + * no buffering, and priv=init_arg + */ + int (*init) (void **priv_p, void *init_arg, PullFilter *src); + + /* + * request data from src, put result ptr to data_p can use ptr from src or + * use buf as work area if NULL in-place copy + */ + int (*pull) (void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen); + void (*free) (void *priv); +}; + +/* + * Memory buffer + */ +MBuf *mbuf_create(int len); +MBuf *mbuf_create_from_data(uint8 *data, int len); +int mbuf_tell(MBuf *mbuf); +int mbuf_avail(MBuf *mbuf); +int mbuf_size(MBuf *mbuf); +int mbuf_grab(MBuf *mbuf, int len, uint8 **data_p); +int mbuf_steal_data(MBuf *mbuf, uint8 **data_p); +int mbuf_append(MBuf *dst, const uint8 *buf, int cnt); +int mbuf_rewind(MBuf *mbuf); +int mbuf_free(MBuf *mbuf); + +/* + * Push filter + */ +int pushf_create(PushFilter **res, const PushFilterOps *ops, void *init_arg, + PushFilter *next); +int pushf_write(PushFilter *mp, const uint8 *data, int len); +void pushf_free_all(PushFilter *mp); +void pushf_free(PushFilter *mp); +int pushf_flush(PushFilter *mp); + +int pushf_create_mbuf_writer(PushFilter **mp_p, MBuf *mbuf); + +/* + * Pull filter + */ +int pullf_create(PullFilter **res, const PullFilterOps *ops, + void *init_arg, PullFilter *src); +int pullf_read(PullFilter *mp, int len, uint8 **data_p); +int pullf_read_max(PullFilter *mp, int len, + uint8 **data_p, uint8 *tmpbuf); +void pullf_free(PullFilter *mp); +int pullf_read_fixed(PullFilter *src, int len, uint8 *dst); + +int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf); + +#define GETBYTE(pf, dst) \ + do { \ + uint8 __b; \ + int __res = pullf_read_fixed(pf, 1, &__b); \ + if (__res < 0) \ + return __res; \ + (dst) = __b; \ + } while (0) + +#endif /* __PX_MBUF_H */ diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c new file mode 100644 index 0000000..cf31551 --- /dev/null +++ b/contrib/pgcrypto/openssl.c @@ -0,0 +1,829 @@ +/* + * openssl.c + * Wrapper for OpenSSL library. + * + * Copyright (c) 2001 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/openssl.c + */ + +#include "postgres.h" + +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/rand.h> + +#include "px.h" +#include "utils/memutils.h" +#include "utils/resowner.h" + +/* + * Max lengths we might want to handle. + */ +#define MAX_KEY (512/8) +#define MAX_IV (128/8) + +/* + * Hashes + */ + +/* + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. + */ +typedef struct OSSLDigest +{ + const EVP_MD *algo; + EVP_MD_CTX *ctx; + + ResourceOwner owner; + struct OSSLDigest *next; + struct OSSLDigest *prev; +} OSSLDigest; + +static OSSLDigest *open_digests = NULL; +static bool digest_resowner_callback_registered = false; + +static void +free_openssl_digest(OSSLDigest *digest) +{ + EVP_MD_CTX_destroy(digest->ctx); + if (digest->prev) + digest->prev->next = digest->next; + else + open_digests = digest->next; + if (digest->next) + digest->next->prev = digest->prev; + pfree(digest); +} + +/* + * Close any open OpenSSL handles on abort. + */ +static void +digest_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) +{ + OSSLDigest *curr; + OSSLDigest *next; + + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; + + next = open_digests; + while (next) + { + curr = next; + next = curr->next; + + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr); + free_openssl_digest(curr); + } + } +} + +static unsigned +digest_result_size(PX_MD *h) +{ + OSSLDigest *digest = (OSSLDigest *) h->p.ptr; + int result = EVP_MD_CTX_size(digest->ctx); + + if (result < 0) + elog(ERROR, "EVP_MD_CTX_size() failed"); + + return result; +} + +static unsigned +digest_block_size(PX_MD *h) +{ + OSSLDigest *digest = (OSSLDigest *) h->p.ptr; + int result = EVP_MD_CTX_block_size(digest->ctx); + + if (result < 0) + elog(ERROR, "EVP_MD_CTX_block_size() failed"); + + return result; +} + +static void +digest_reset(PX_MD *h) +{ + OSSLDigest *digest = (OSSLDigest *) h->p.ptr; + + if (!EVP_DigestInit_ex(digest->ctx, digest->algo, NULL)) + elog(ERROR, "EVP_DigestInit_ex() failed"); +} + +static void +digest_update(PX_MD *h, const uint8 *data, unsigned dlen) +{ + OSSLDigest *digest = (OSSLDigest *) h->p.ptr; + + if (!EVP_DigestUpdate(digest->ctx, data, dlen)) + elog(ERROR, "EVP_DigestUpdate() failed"); +} + +static void +digest_finish(PX_MD *h, uint8 *dst) +{ + OSSLDigest *digest = (OSSLDigest *) h->p.ptr; + + if (!EVP_DigestFinal_ex(digest->ctx, dst, NULL)) + elog(ERROR, "EVP_DigestFinal_ex() failed"); +} + +static void +digest_free(PX_MD *h) +{ + OSSLDigest *digest = (OSSLDigest *) h->p.ptr; + + free_openssl_digest(digest); + pfree(h); +} + +static int px_openssl_initialized = 0; + +/* PUBLIC functions */ + +int +px_find_digest(const char *name, PX_MD **res) +{ + const EVP_MD *md; + EVP_MD_CTX *ctx; + PX_MD *h; + OSSLDigest *digest; + + if (!px_openssl_initialized) + { + px_openssl_initialized = 1; + OpenSSL_add_all_algorithms(); + } + + if (!digest_resowner_callback_registered) + { + RegisterResourceReleaseCallback(digest_free_callback, NULL); + digest_resowner_callback_registered = true; + } + + md = EVP_get_digestbyname(name); + if (md == NULL) + return PXE_NO_HASH; + + /* + * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest)); + + ctx = EVP_MD_CTX_create(); + if (!ctx) + { + pfree(digest); + return PXE_CIPHER_INIT; + } + if (EVP_DigestInit_ex(ctx, md, NULL) == 0) + { + EVP_MD_CTX_destroy(ctx); + pfree(digest); + return PXE_CIPHER_INIT; + } + + digest->algo = md; + digest->ctx = ctx; + digest->owner = CurrentResourceOwner; + digest->next = open_digests; + digest->prev = NULL; + open_digests = digest; + + /* The PX_MD object is allocated in the current memory context. */ + h = palloc(sizeof(*h)); + h->result_size = digest_result_size; + h->block_size = digest_block_size; + h->reset = digest_reset; + h->update = digest_update; + h->finish = digest_finish; + h->free = digest_free; + h->p.ptr = (void *) digest; + + *res = h; + return 0; +} + +/* + * Ciphers + * + * We use OpenSSL's EVP* family of functions for these. + */ + +/* + * prototype for the EVP functions that return an algorithm, e.g. + * EVP_aes_128_cbc(). + */ +typedef const EVP_CIPHER *(*ossl_EVP_cipher_func) (void); + +/* + * ossl_cipher contains the static information about each cipher. + */ +struct ossl_cipher +{ + int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv); + ossl_EVP_cipher_func cipher_func; + int block_size; + int max_key_size; +}; + +/* + * OSSLCipher contains the state for using a cipher. A separate OSSLCipher + * object is allocated in each px_find_cipher() call. + * + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. + */ +typedef struct OSSLCipher +{ + EVP_CIPHER_CTX *evp_ctx; + const EVP_CIPHER *evp_ciph; + uint8 key[MAX_KEY]; + uint8 iv[MAX_IV]; + unsigned klen; + unsigned init; + const struct ossl_cipher *ciph; + + ResourceOwner owner; + struct OSSLCipher *next; + struct OSSLCipher *prev; +} OSSLCipher; + +static OSSLCipher *open_ciphers = NULL; +static bool cipher_resowner_callback_registered = false; + +static void +free_openssl_cipher(OSSLCipher *od) +{ + EVP_CIPHER_CTX_free(od->evp_ctx); + if (od->prev) + od->prev->next = od->next; + else + open_ciphers = od->next; + if (od->next) + od->next->prev = od->prev; + pfree(od); +} + +/* + * Close any open OpenSSL cipher handles on abort. + */ +static void +cipher_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) +{ + OSSLCipher *curr; + OSSLCipher *next; + + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; + + next = open_ciphers; + while (next) + { + curr = next; + next = curr->next; + + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr); + free_openssl_cipher(curr); + } + } +} + +/* Common routines for all algorithms */ + +static unsigned +gen_ossl_block_size(PX_Cipher *c) +{ + OSSLCipher *od = (OSSLCipher *) c->ptr; + + return od->ciph->block_size; +} + +static unsigned +gen_ossl_key_size(PX_Cipher *c) +{ + OSSLCipher *od = (OSSLCipher *) c->ptr; + + return od->ciph->max_key_size; +} + +static unsigned +gen_ossl_iv_size(PX_Cipher *c) +{ + unsigned ivlen; + OSSLCipher *od = (OSSLCipher *) c->ptr; + + ivlen = od->ciph->block_size; + return ivlen; +} + +static void +gen_ossl_free(PX_Cipher *c) +{ + OSSLCipher *od = (OSSLCipher *) c->ptr; + + free_openssl_cipher(od); + pfree(c); +} + +static int +gen_ossl_decrypt(PX_Cipher *c, int padding, const uint8 *data, unsigned dlen, + uint8 *res, unsigned *rlen) +{ + OSSLCipher *od = c->ptr; + int outlen, + outlen2; + + if (!od->init) + { + if (!EVP_DecryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, padding)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen)) + return PXE_CIPHER_INIT; + if (!EVP_DecryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv)) + return PXE_CIPHER_INIT; + od->init = true; + } + + if (!EVP_DecryptUpdate(od->evp_ctx, res, &outlen, data, dlen)) + return PXE_DECRYPT_FAILED; + if (!EVP_DecryptFinal_ex(od->evp_ctx, res + outlen, &outlen2)) + return PXE_DECRYPT_FAILED; + *rlen = outlen + outlen2; + + return 0; +} + +static int +gen_ossl_encrypt(PX_Cipher *c, int padding, const uint8 *data, unsigned dlen, + uint8 *res, unsigned *rlen) +{ + OSSLCipher *od = c->ptr; + int outlen, + outlen2; + + if (!od->init) + { + if (!EVP_EncryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_padding(od->evp_ctx, padding)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen)) + return PXE_CIPHER_INIT; + if (!EVP_EncryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv)) + return PXE_CIPHER_INIT; + od->init = true; + } + + if (!EVP_EncryptUpdate(od->evp_ctx, res, &outlen, data, dlen)) + return PXE_ENCRYPT_FAILED; + if (!EVP_EncryptFinal_ex(od->evp_ctx, res + outlen, &outlen2)) + return PXE_ENCRYPT_FAILED; + *rlen = outlen + outlen2; + + return 0; +} + +/* Blowfish */ + +/* + * Check if strong crypto is supported. Some OpenSSL installations + * support only short keys and unfortunately BF_set_key does not return any + * error value. This function tests if is possible to use strong key. + */ +static int +bf_check_supported_key_len(void) +{ + static const uint8 key[56] = { + 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, + 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x55, 0x66, 0x77, 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, + 0x3b, 0x2f, 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76, + 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + static const uint8 data[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; + static const uint8 res[8] = {0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53}; + uint8 out[8]; + EVP_CIPHER_CTX *evp_ctx; + int outlen; + int status = 0; + + /* encrypt with 448bits key and verify output */ + evp_ctx = EVP_CIPHER_CTX_new(); + if (!evp_ctx) + return 0; + if (!EVP_EncryptInit_ex(evp_ctx, EVP_bf_ecb(), NULL, NULL, NULL)) + goto leave; + if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, 56)) + goto leave; + if (!EVP_EncryptInit_ex(evp_ctx, NULL, NULL, key, NULL)) + goto leave; + + if (!EVP_EncryptUpdate(evp_ctx, out, &outlen, data, 8)) + goto leave; + + if (memcmp(out, res, 8) != 0) + goto leave; /* Output does not match -> strong cipher is + * not supported */ + status = 1; + +leave: + EVP_CIPHER_CTX_free(evp_ctx); + return status; +} + +static int +bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); + static int bf_is_strong = -1; + + /* + * Test if key len is supported. BF_set_key silently cut large keys and it + * could be a problem when user transfer crypted data from one server to + * another. + */ + + if (bf_is_strong == -1) + bf_is_strong = bf_check_supported_key_len(); + + if (!bf_is_strong && klen > 16) + return PXE_KEY_TOO_BIG; + + /* Key len is supported. We can use it. */ + od->klen = klen; + memcpy(od->key, key, klen); + + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); + return 0; +} + +/* DES */ + +static int +ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); + + od->klen = 8; + memset(od->key, 0, 8); + memcpy(od->key, key, klen > 8 ? 8 : klen); + + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); + return 0; +} + +/* DES3 */ + +static int +ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); + + od->klen = 24; + memset(od->key, 0, 24); + memcpy(od->key, key, klen > 24 ? 24 : klen); + + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); + return 0; +} + +/* CAST5 */ + +static int +ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); + + od->klen = klen; + memcpy(od->key, key, klen); + + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); + return 0; +} + +/* AES */ + +static int +ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); + + if (klen <= 128 / 8) + od->klen = 128 / 8; + else if (klen <= 192 / 8) + od->klen = 192 / 8; + else if (klen <= 256 / 8) + od->klen = 256 / 8; + else + return PXE_KEY_TOO_BIG; + + memcpy(od->key, key, klen); + + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); + + return 0; +} + +static int +ossl_aes_ecb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + int err; + + err = ossl_aes_init(c, key, klen, iv); + if (err) + return err; + + switch (od->klen) + { + case 128 / 8: + od->evp_ciph = EVP_aes_128_ecb(); + break; + case 192 / 8: + od->evp_ciph = EVP_aes_192_ecb(); + break; + case 256 / 8: + od->evp_ciph = EVP_aes_256_ecb(); + break; + default: + /* shouldn't happen */ + err = PXE_CIPHER_INIT; + break; + } + + return err; +} + +static int +ossl_aes_cbc_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) +{ + OSSLCipher *od = c->ptr; + int err; + + err = ossl_aes_init(c, key, klen, iv); + if (err) + return err; + + switch (od->klen) + { + case 128 / 8: + od->evp_ciph = EVP_aes_128_cbc(); + break; + case 192 / 8: + od->evp_ciph = EVP_aes_192_cbc(); + break; + case 256 / 8: + od->evp_ciph = EVP_aes_256_cbc(); + break; + default: + /* shouldn't happen */ + err = PXE_CIPHER_INIT; + break; + } + + return err; +} + +/* + * aliases + */ + +static PX_Alias ossl_aliases[] = { + {"bf", "bf-cbc"}, + {"blowfish", "bf-cbc"}, + {"blowfish-cbc", "bf-cbc"}, + {"blowfish-ecb", "bf-ecb"}, + {"blowfish-cfb", "bf-cfb"}, + {"des", "des-cbc"}, + {"3des", "des3-cbc"}, + {"3des-ecb", "des3-ecb"}, + {"3des-cbc", "des3-cbc"}, + {"cast5", "cast5-cbc"}, + {"aes", "aes-cbc"}, + {"rijndael", "aes-cbc"}, + {"rijndael-cbc", "aes-cbc"}, + {"rijndael-ecb", "aes-ecb"}, + {NULL} +}; + +static const struct ossl_cipher ossl_bf_cbc = { + bf_init, + EVP_bf_cbc, + 64 / 8, 448 / 8 +}; + +static const struct ossl_cipher ossl_bf_ecb = { + bf_init, + EVP_bf_ecb, + 64 / 8, 448 / 8 +}; + +static const struct ossl_cipher ossl_bf_cfb = { + bf_init, + EVP_bf_cfb, + 64 / 8, 448 / 8 +}; + +static const struct ossl_cipher ossl_des_ecb = { + ossl_des_init, + EVP_des_ecb, + 64 / 8, 64 / 8 +}; + +static const struct ossl_cipher ossl_des_cbc = { + ossl_des_init, + EVP_des_cbc, + 64 / 8, 64 / 8 +}; + +static const struct ossl_cipher ossl_des3_ecb = { + ossl_des3_init, + EVP_des_ede3_ecb, + 64 / 8, 192 / 8 +}; + +static const struct ossl_cipher ossl_des3_cbc = { + ossl_des3_init, + EVP_des_ede3_cbc, + 64 / 8, 192 / 8 +}; + +static const struct ossl_cipher ossl_cast_ecb = { + ossl_cast_init, + EVP_cast5_ecb, + 64 / 8, 128 / 8 +}; + +static const struct ossl_cipher ossl_cast_cbc = { + ossl_cast_init, + EVP_cast5_cbc, + 64 / 8, 128 / 8 +}; + +static const struct ossl_cipher ossl_aes_ecb = { + ossl_aes_ecb_init, + NULL, /* EVP_aes_XXX_ecb(), determined in init + * function */ + 128 / 8, 256 / 8 +}; + +static const struct ossl_cipher ossl_aes_cbc = { + ossl_aes_cbc_init, + NULL, /* EVP_aes_XXX_cbc(), determined in init + * function */ + 128 / 8, 256 / 8 +}; + +/* + * Special handlers + */ +struct ossl_cipher_lookup +{ + const char *name; + const struct ossl_cipher *ciph; +}; + +static const struct ossl_cipher_lookup ossl_cipher_types[] = { + {"bf-cbc", &ossl_bf_cbc}, + {"bf-ecb", &ossl_bf_ecb}, + {"bf-cfb", &ossl_bf_cfb}, + {"des-ecb", &ossl_des_ecb}, + {"des-cbc", &ossl_des_cbc}, + {"des3-ecb", &ossl_des3_ecb}, + {"des3-cbc", &ossl_des3_cbc}, + {"cast5-ecb", &ossl_cast_ecb}, + {"cast5-cbc", &ossl_cast_cbc}, + {"aes-ecb", &ossl_aes_ecb}, + {"aes-cbc", &ossl_aes_cbc}, + {NULL} +}; + +/* PUBLIC functions */ + +int +px_find_cipher(const char *name, PX_Cipher **res) +{ + const struct ossl_cipher_lookup *i; + PX_Cipher *c = NULL; + EVP_CIPHER_CTX *ctx; + OSSLCipher *od; + + name = px_resolve_alias(ossl_aliases, name); + for (i = ossl_cipher_types; i->name; i++) + if (strcmp(i->name, name) == 0) + break; + if (i->name == NULL) + return PXE_NO_CIPHER; + + if (!cipher_resowner_callback_registered) + { + RegisterResourceReleaseCallback(cipher_free_callback, NULL); + cipher_resowner_callback_registered = true; + } + + /* + * Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + od = MemoryContextAllocZero(TopMemoryContext, sizeof(*od)); + od->ciph = i->ciph; + + /* Allocate an EVP_CIPHER_CTX object. */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + pfree(od); + return PXE_CIPHER_INIT; + } + + od->evp_ctx = ctx; + od->owner = CurrentResourceOwner; + od->next = open_ciphers; + od->prev = NULL; + open_ciphers = od; + + if (i->ciph->cipher_func) + od->evp_ciph = i->ciph->cipher_func(); + + /* The PX_Cipher is allocated in current memory context */ + c = palloc(sizeof(*c)); + c->block_size = gen_ossl_block_size; + c->key_size = gen_ossl_key_size; + c->iv_size = gen_ossl_iv_size; + c->free = gen_ossl_free; + c->init = od->ciph->init; + c->encrypt = gen_ossl_encrypt; + c->decrypt = gen_ossl_decrypt; + c->ptr = od; + + *res = c; + return 0; +} diff --git a/contrib/pgcrypto/pgcrypto--1.0--1.1.sql b/contrib/pgcrypto/pgcrypto--1.0--1.1.sql new file mode 100644 index 0000000..42e0c7f --- /dev/null +++ b/contrib/pgcrypto/pgcrypto--1.0--1.1.sql @@ -0,0 +1,9 @@ +/* contrib/pgcrypto/pgcrypto--1.0--1.1.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.1'" to load this file. \quit + +CREATE FUNCTION gen_random_uuid() +RETURNS uuid +AS 'MODULE_PATHNAME', 'pg_random_uuid' +LANGUAGE C VOLATILE; diff --git a/contrib/pgcrypto/pgcrypto--1.1--1.2.sql b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql new file mode 100644 index 0000000..753e169 --- /dev/null +++ b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql @@ -0,0 +1,14 @@ +/* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit + +CREATE FUNCTION armor(bytea, text[], text[]) +RETURNS text +AS 'MODULE_PATHNAME', 'pg_armor' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION pgp_armor_headers(text, key OUT text, value OUT text) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'pgp_armor_headers' +LANGUAGE C IMMUTABLE STRICT; diff --git a/contrib/pgcrypto/pgcrypto--1.2--1.3.sql b/contrib/pgcrypto/pgcrypto--1.2--1.3.sql new file mode 100644 index 0000000..525a037 --- /dev/null +++ b/contrib/pgcrypto/pgcrypto--1.2--1.3.sql @@ -0,0 +1,41 @@ +/* contrib/pgcrypto/pgcrypto--1.2--1.3.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.3'" to load this file. \quit + +ALTER FUNCTION digest(text, text) PARALLEL SAFE; +ALTER FUNCTION digest(bytea, text) PARALLEL SAFE; +ALTER FUNCTION hmac(text, text, text) PARALLEL SAFE; +ALTER FUNCTION hmac(bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION crypt(text, text) PARALLEL SAFE; +ALTER FUNCTION gen_salt(text) PARALLEL SAFE; +ALTER FUNCTION gen_salt(text, int4) PARALLEL SAFE; +ALTER FUNCTION encrypt(bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION decrypt(bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION encrypt_iv(bytea, bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION decrypt_iv(bytea, bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION gen_random_bytes(int4) PARALLEL SAFE; +ALTER FUNCTION gen_random_uuid() PARALLEL SAFE; +ALTER FUNCTION pgp_sym_encrypt(text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_encrypt_bytea(bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_encrypt(text, text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_encrypt_bytea(bytea, text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_decrypt(bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_decrypt_bytea(bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_decrypt(bytea, text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_sym_decrypt_bytea(bytea, text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_encrypt(text, bytea) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_encrypt_bytea(bytea, bytea) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_encrypt(text, bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_decrypt(bytea, bytea) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_decrypt_bytea(bytea, bytea) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_decrypt(bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_decrypt(bytea, bytea, text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text) PARALLEL SAFE; +ALTER FUNCTION pgp_key_id(bytea) PARALLEL SAFE; +ALTER FUNCTION armor(bytea) PARALLEL SAFE; +ALTER FUNCTION armor(bytea, text[], text[]) PARALLEL SAFE; +ALTER FUNCTION dearmor(text) PARALLEL SAFE; +ALTER FUNCTION pgp_armor_headers(text) PARALLEL SAFE; diff --git a/contrib/pgcrypto/pgcrypto--1.3.sql b/contrib/pgcrypto/pgcrypto--1.3.sql new file mode 100644 index 0000000..c2628ca --- /dev/null +++ b/contrib/pgcrypto/pgcrypto--1.3.sql @@ -0,0 +1,217 @@ +/* contrib/pgcrypto/pgcrypto--1.3.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit + +CREATE FUNCTION digest(text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_digest' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION digest(bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_digest' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION hmac(text, text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_hmac' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION hmac(bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_hmac' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION crypt(text, text) +RETURNS text +AS 'MODULE_PATHNAME', 'pg_crypt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION gen_salt(text) +RETURNS text +AS 'MODULE_PATHNAME', 'pg_gen_salt' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE FUNCTION gen_salt(text, int4) +RETURNS text +AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE FUNCTION encrypt(bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_encrypt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION decrypt(bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_decrypt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_encrypt_iv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_decrypt_iv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION gen_random_bytes(int4) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_random_bytes' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE FUNCTION gen_random_uuid() +RETURNS uuid +AS 'MODULE_PATHNAME', 'pg_random_uuid' +LANGUAGE C VOLATILE PARALLEL SAFE; + +-- +-- pgp_sym_encrypt(data, key) +-- +CREATE FUNCTION pgp_sym_encrypt(text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text' +LANGUAGE C STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- pgp_sym_encrypt(data, key, args) +-- +CREATE FUNCTION pgp_sym_encrypt(text, text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text' +LANGUAGE C STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- pgp_sym_decrypt(data, key) +-- +CREATE FUNCTION pgp_sym_decrypt(bytea, text) +RETURNS text +AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- pgp_sym_decrypt(data, key, args) +-- +CREATE FUNCTION pgp_sym_decrypt(bytea, text, text) +RETURNS text +AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- pgp_pub_encrypt(data, key) +-- +CREATE FUNCTION pgp_pub_encrypt(text, bytea) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text' +LANGUAGE C STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- pgp_pub_encrypt(data, key, args) +-- +CREATE FUNCTION pgp_pub_encrypt(text, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text' +LANGUAGE C STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea' +LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- pgp_pub_decrypt(data, key) +-- +CREATE FUNCTION pgp_pub_decrypt(bytea, bytea) +RETURNS text +AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- pgp_pub_decrypt(data, key, psw) +-- +CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text) +RETURNS text +AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- pgp_pub_decrypt(data, key, psw, arg) +-- +CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text) +RETURNS text +AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- PGP key ID +-- +CREATE FUNCTION pgp_key_id(bytea) +RETURNS text +AS 'MODULE_PATHNAME', 'pgp_key_id_w' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- pgp armor +-- +CREATE FUNCTION armor(bytea) +RETURNS text +AS 'MODULE_PATHNAME', 'pg_armor' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION armor(bytea, text[], text[]) +RETURNS text +AS 'MODULE_PATHNAME', 'pg_armor' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION dearmor(text) +RETURNS bytea +AS 'MODULE_PATHNAME', 'pg_dearmor' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION pgp_armor_headers(text, key OUT text, value OUT text) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'pgp_armor_headers' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c new file mode 100644 index 0000000..f0ac625 --- /dev/null +++ b/contrib/pgcrypto/pgcrypto.c @@ -0,0 +1,475 @@ +/* + * pgcrypto.c + * Various cryptographic stuff for PostgreSQL. + * + * Copyright (c) 2001 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/pgcrypto.c + */ + +#include "postgres.h" + +#include <ctype.h> + +#include "parser/scansup.h" +#include "pgcrypto.h" +#include "px-crypt.h" +#include "px.h" +#include "utils/builtins.h" +#include "utils/uuid.h" + +PG_MODULE_MAGIC; + +/* private stuff */ + +typedef int (*PFN) (const char *name, void **res); +static void *find_provider(text *name, PFN pf, const char *desc, int silent); + +/* SQL function: hash(bytea, text) returns bytea */ +PG_FUNCTION_INFO_V1(pg_digest); + +Datum +pg_digest(PG_FUNCTION_ARGS) +{ + bytea *arg; + text *name; + unsigned len, + hlen; + PX_MD *md; + bytea *res; + + name = PG_GETARG_TEXT_PP(1); + + /* will give error if fails */ + md = find_provider(name, (PFN) px_find_digest, "Digest", 0); + + hlen = px_md_result_size(md); + + res = (text *) palloc(hlen + VARHDRSZ); + SET_VARSIZE(res, hlen + VARHDRSZ); + + arg = PG_GETARG_BYTEA_PP(0); + len = VARSIZE_ANY_EXHDR(arg); + + px_md_update(md, (uint8 *) VARDATA_ANY(arg), len); + px_md_finish(md, (uint8 *) VARDATA(res)); + px_md_free(md); + + PG_FREE_IF_COPY(arg, 0); + PG_FREE_IF_COPY(name, 1); + + PG_RETURN_BYTEA_P(res); +} + +/* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */ +PG_FUNCTION_INFO_V1(pg_hmac); + +Datum +pg_hmac(PG_FUNCTION_ARGS) +{ + bytea *arg; + bytea *key; + text *name; + unsigned len, + hlen, + klen; + PX_HMAC *h; + bytea *res; + + name = PG_GETARG_TEXT_PP(2); + + /* will give error if fails */ + h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0); + + hlen = px_hmac_result_size(h); + + res = (text *) palloc(hlen + VARHDRSZ); + SET_VARSIZE(res, hlen + VARHDRSZ); + + arg = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + len = VARSIZE_ANY_EXHDR(arg); + klen = VARSIZE_ANY_EXHDR(key); + + px_hmac_init(h, (uint8 *) VARDATA_ANY(key), klen); + px_hmac_update(h, (uint8 *) VARDATA_ANY(arg), len); + px_hmac_finish(h, (uint8 *) VARDATA(res)); + px_hmac_free(h); + + PG_FREE_IF_COPY(arg, 0); + PG_FREE_IF_COPY(key, 1); + PG_FREE_IF_COPY(name, 2); + + PG_RETURN_BYTEA_P(res); +} + + +/* SQL function: pg_gen_salt(text) returns text */ +PG_FUNCTION_INFO_V1(pg_gen_salt); + +Datum +pg_gen_salt(PG_FUNCTION_ARGS) +{ + text *arg0 = PG_GETARG_TEXT_PP(0); + int len; + char buf[PX_MAX_SALT_LEN + 1]; + + text_to_cstring_buffer(arg0, buf, sizeof(buf)); + len = px_gen_salt(buf, buf, 0); + if (len < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("gen_salt: %s", px_strerror(len)))); + + PG_FREE_IF_COPY(arg0, 0); + + PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len)); +} + +/* SQL function: pg_gen_salt(text, int4) returns text */ +PG_FUNCTION_INFO_V1(pg_gen_salt_rounds); + +Datum +pg_gen_salt_rounds(PG_FUNCTION_ARGS) +{ + text *arg0 = PG_GETARG_TEXT_PP(0); + int rounds = PG_GETARG_INT32(1); + int len; + char buf[PX_MAX_SALT_LEN + 1]; + + text_to_cstring_buffer(arg0, buf, sizeof(buf)); + len = px_gen_salt(buf, buf, rounds); + if (len < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("gen_salt: %s", px_strerror(len)))); + + PG_FREE_IF_COPY(arg0, 0); + + PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len)); +} + +/* SQL function: pg_crypt(psw:text, salt:text) returns text */ +PG_FUNCTION_INFO_V1(pg_crypt); + +Datum +pg_crypt(PG_FUNCTION_ARGS) +{ + text *arg0 = PG_GETARG_TEXT_PP(0); + text *arg1 = PG_GETARG_TEXT_PP(1); + char *buf0, + *buf1, + *cres, + *resbuf; + text *res; + + buf0 = text_to_cstring(arg0); + buf1 = text_to_cstring(arg1); + + resbuf = palloc0(PX_MAX_CRYPT); + + cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT); + + pfree(buf0); + pfree(buf1); + + if (cres == NULL) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("crypt(3) returned NULL"))); + + res = cstring_to_text(cres); + + pfree(resbuf); + + PG_FREE_IF_COPY(arg0, 0); + PG_FREE_IF_COPY(arg1, 1); + + PG_RETURN_TEXT_P(res); +} + +/* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */ +PG_FUNCTION_INFO_V1(pg_encrypt); + +Datum +pg_encrypt(PG_FUNCTION_ARGS) +{ + int err; + bytea *data, + *key, + *res; + text *type; + PX_Combo *c; + unsigned dlen, + klen, + rlen; + + type = PG_GETARG_TEXT_PP(2); + c = find_provider(type, (PFN) px_find_combo, "Cipher", 0); + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + dlen = VARSIZE_ANY_EXHDR(data); + klen = VARSIZE_ANY_EXHDR(key); + + rlen = px_combo_encrypt_len(c, dlen); + res = palloc(VARHDRSZ + rlen); + + err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0); + if (!err) + err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen, + (uint8 *) VARDATA(res), &rlen); + px_combo_free(c); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + PG_FREE_IF_COPY(type, 2); + + if (err) + { + pfree(res); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("encrypt error: %s", px_strerror(err)))); + } + + SET_VARSIZE(res, VARHDRSZ + rlen); + PG_RETURN_BYTEA_P(res); +} + +/* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */ +PG_FUNCTION_INFO_V1(pg_decrypt); + +Datum +pg_decrypt(PG_FUNCTION_ARGS) +{ + int err; + bytea *data, + *key, + *res; + text *type; + PX_Combo *c; + unsigned dlen, + klen, + rlen; + + type = PG_GETARG_TEXT_PP(2); + c = find_provider(type, (PFN) px_find_combo, "Cipher", 0); + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + dlen = VARSIZE_ANY_EXHDR(data); + klen = VARSIZE_ANY_EXHDR(key); + + rlen = px_combo_decrypt_len(c, dlen); + res = palloc(VARHDRSZ + rlen); + + err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0); + if (!err) + err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen, + (uint8 *) VARDATA(res), &rlen); + + px_combo_free(c); + + if (err) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("decrypt error: %s", px_strerror(err)))); + + SET_VARSIZE(res, VARHDRSZ + rlen); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + PG_FREE_IF_COPY(type, 2); + + PG_RETURN_BYTEA_P(res); +} + +/* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */ +PG_FUNCTION_INFO_V1(pg_encrypt_iv); + +Datum +pg_encrypt_iv(PG_FUNCTION_ARGS) +{ + int err; + bytea *data, + *key, + *iv, + *res; + text *type; + PX_Combo *c; + unsigned dlen, + klen, + ivlen, + rlen; + + type = PG_GETARG_TEXT_PP(3); + c = find_provider(type, (PFN) px_find_combo, "Cipher", 0); + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + iv = PG_GETARG_BYTEA_PP(2); + dlen = VARSIZE_ANY_EXHDR(data); + klen = VARSIZE_ANY_EXHDR(key); + ivlen = VARSIZE_ANY_EXHDR(iv); + + rlen = px_combo_encrypt_len(c, dlen); + res = palloc(VARHDRSZ + rlen); + + err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, + (uint8 *) VARDATA_ANY(iv), ivlen); + if (!err) + err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen, + (uint8 *) VARDATA(res), &rlen); + + px_combo_free(c); + + if (err) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("encrypt_iv error: %s", px_strerror(err)))); + + SET_VARSIZE(res, VARHDRSZ + rlen); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + PG_FREE_IF_COPY(iv, 2); + PG_FREE_IF_COPY(type, 3); + + PG_RETURN_BYTEA_P(res); +} + +/* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */ +PG_FUNCTION_INFO_V1(pg_decrypt_iv); + +Datum +pg_decrypt_iv(PG_FUNCTION_ARGS) +{ + int err; + bytea *data, + *key, + *iv, + *res; + text *type; + PX_Combo *c; + unsigned dlen, + klen, + rlen, + ivlen; + + type = PG_GETARG_TEXT_PP(3); + c = find_provider(type, (PFN) px_find_combo, "Cipher", 0); + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + iv = PG_GETARG_BYTEA_PP(2); + dlen = VARSIZE_ANY_EXHDR(data); + klen = VARSIZE_ANY_EXHDR(key); + ivlen = VARSIZE_ANY_EXHDR(iv); + + rlen = px_combo_decrypt_len(c, dlen); + res = palloc(VARHDRSZ + rlen); + + err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, + (uint8 *) VARDATA_ANY(iv), ivlen); + if (!err) + err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen, + (uint8 *) VARDATA(res), &rlen); + + px_combo_free(c); + + if (err) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("decrypt_iv error: %s", px_strerror(err)))); + + SET_VARSIZE(res, VARHDRSZ + rlen); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + PG_FREE_IF_COPY(iv, 2); + PG_FREE_IF_COPY(type, 3); + + PG_RETURN_BYTEA_P(res); +} + +/* SQL function: pg_random_bytes(int4) returns bytea */ +PG_FUNCTION_INFO_V1(pg_random_bytes); + +Datum +pg_random_bytes(PG_FUNCTION_ARGS) +{ + int len = PG_GETARG_INT32(0); + bytea *res; + + if (len < 1 || len > 1024) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("Length not in range"))); + + res = palloc(VARHDRSZ + len); + SET_VARSIZE(res, VARHDRSZ + len); + + /* generate result */ + if (!pg_strong_random(VARDATA(res), len)) + px_THROW_ERROR(PXE_NO_RANDOM); + + PG_RETURN_BYTEA_P(res); +} + +/* SQL function: gen_random_uuid() returns uuid */ +PG_FUNCTION_INFO_V1(pg_random_uuid); + +Datum +pg_random_uuid(PG_FUNCTION_ARGS) +{ + /* redirect to built-in function */ + return gen_random_uuid(fcinfo); +} + +static void * +find_provider(text *name, + PFN provider_lookup, + const char *desc, int silent) +{ + void *res; + char *buf; + int err; + + buf = downcase_truncate_identifier(VARDATA_ANY(name), + VARSIZE_ANY_EXHDR(name), + false); + + err = provider_lookup(buf, &res); + + if (err && !silent) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot use \"%s\": %s", buf, px_strerror(err)))); + + pfree(buf); + + return err ? NULL : res; +} diff --git a/contrib/pgcrypto/pgcrypto.control b/contrib/pgcrypto/pgcrypto.control new file mode 100644 index 0000000..d2151d3 --- /dev/null +++ b/contrib/pgcrypto/pgcrypto.control @@ -0,0 +1,6 @@ +# pgcrypto extension +comment = 'cryptographic functions' +default_version = '1.3' +module_pathname = '$libdir/pgcrypto' +relocatable = true +trusted = true diff --git a/contrib/pgcrypto/pgcrypto.h b/contrib/pgcrypto/pgcrypto.h new file mode 100644 index 0000000..65a1ed3 --- /dev/null +++ b/contrib/pgcrypto/pgcrypto.h @@ -0,0 +1,37 @@ +/* + * pgcrypto.h + * Header file for pgcrypto. + * + * Copyright (c) 2000 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/pgcrypto.h + */ + +#ifndef _PG_CRYPTO_H +#define _PG_CRYPTO_H + +#include "fmgr.h" + +#endif diff --git a/contrib/pgcrypto/pgp-armor.c b/contrib/pgcrypto/pgp-armor.c new file mode 100644 index 0000000..679779a --- /dev/null +++ b/contrib/pgcrypto/pgp-armor.c @@ -0,0 +1,488 @@ +/* + * 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 "pgp.h" +#include "px.h" + +/* + * BASE64 - duplicated :( + */ + +static const unsigned char _base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int +pg_base64_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 +pg_base64_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 +pg_base64_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 +pg_base64_dec_len(unsigned srclen) +{ + return (srclen * 3) >> 2; +} + +/* + * PGP armor + */ + +static const char *armor_header = "-----BEGIN PGP MESSAGE-----\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; +} + +void +pgp_armor_encode(const uint8 *src, unsigned len, StringInfo dst, + int num_headers, char **keys, char **values) +{ + int n; + int res; + unsigned b64len; + unsigned crc = crc24(src, len); + + appendStringInfoString(dst, armor_header); + + for (n = 0; n < num_headers; n++) + appendStringInfo(dst, "%s: %s\n", keys[n], values[n]); + appendStringInfoChar(dst, '\n'); + + /* make sure we have enough room to pg_base64_encode() */ + b64len = pg_base64_enc_len(len); + enlargeStringInfo(dst, (int) b64len); + + res = pg_base64_encode(src, len, (uint8 *) dst->data + dst->len); + if (res > b64len) + elog(FATAL, "overflow - encode estimate too small"); + dst->len += res; + + if (*(dst->data + dst->len - 1) != '\n') + appendStringInfoChar(dst, '\n'); + + appendStringInfoChar(dst, '='); + appendStringInfoChar(dst, _base64[(crc >> 18) & 0x3f]); + appendStringInfoChar(dst, _base64[(crc >> 12) & 0x3f]); + appendStringInfoChar(dst, _base64[(crc >> 6) & 0x3f]); + appendStringInfoChar(dst, _base64[crc & 0x3f]); + + appendStringInfoString(dst, armor_footer); +} + +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, int len, StringInfo 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 blen; + 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 (pg_base64_decode(p + 1, 4, buf) != 3) + goto out; + crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2]; + + /* decode data */ + blen = (int) pg_base64_dec_len(len); + enlargeStringInfo(dst, blen); + res = pg_base64_decode(base64_start, base64_end - base64_start, (uint8 *) dst->data); + if (res > blen) + elog(FATAL, "overflow - decode estimate too small"); + if (res >= 0) + { + if (crc24((uint8 *) dst->data, res) == crc) + dst->len += res; + else + res = PXE_PGP_CORRUPT_ARMOR; + } +out: + return res; +} + +/* + * Extracts all armor headers from an ASCII-armored input. + * + * Returns 0 on success, or PXE_* error code on error. On success, the + * number of headers and their keys and values are returned in *nheaders, + * *nkeys and *nvalues. + */ +int +pgp_extract_armor_headers(const uint8 *src, unsigned len, + int *nheaders, char ***keys, char ***values) +{ + const uint8 *data_end = src + len; + const uint8 *p; + const uint8 *base64_start; + const uint8 *armor_start; + const uint8 *armor_end; + Size armor_len; + char *line; + char *nextline; + char *eol, + *colon; + int hlen; + char *buf; + int hdrlines; + int n; + + /* armor start */ + hlen = find_header(src, data_end, &armor_start, 0); + if (hlen <= 0) + return PXE_PGP_CORRUPT_ARMOR; + armor_start += hlen; + + /* armor end */ + hlen = find_header(armor_start, data_end, &armor_end, 1); + if (hlen <= 0) + return PXE_PGP_CORRUPT_ARMOR; + + /* Count the number of armor header lines. */ + hdrlines = 0; + p = armor_start; + while (p < armor_end && *p != '\n' && *p != '\r') + { + p = memchr(p, '\n', armor_end - p); + if (!p) + return PXE_PGP_CORRUPT_ARMOR; + + /* step to start of next line */ + p++; + hdrlines++; + } + base64_start = p; + + /* + * Make a modifiable copy of the part of the input that contains the + * headers. The returned key/value pointers will point inside the buffer. + */ + armor_len = base64_start - armor_start; + buf = palloc(armor_len + 1); + memcpy(buf, armor_start, armor_len); + buf[armor_len] = '\0'; + + /* Allocate return arrays */ + *keys = (char **) palloc(hdrlines * sizeof(char *)); + *values = (char **) palloc(hdrlines * sizeof(char *)); + + /* + * Split the header lines at newlines and ": " separators, and collect + * pointers to the keys and values in the return arrays. + */ + n = 0; + line = buf; + for (;;) + { + /* find end of line */ + eol = strchr(line, '\n'); + if (!eol) + break; + nextline = eol + 1; + /* if the line ends in CR + LF, strip the CR */ + if (eol > line && *(eol - 1) == '\r') + eol--; + *eol = '\0'; + + /* find colon+space separating the key and value */ + colon = strstr(line, ": "); + if (!colon) + return PXE_PGP_CORRUPT_ARMOR; + *colon = '\0'; + + /* shouldn't happen, we counted the number of lines beforehand */ + if (n >= hdrlines) + elog(ERROR, "unexpected number of armor header lines"); + + (*keys)[n] = line; + (*values)[n] = colon + 2; + n++; + + /* step to start of next line */ + line = nextline; + } + + if (n != hdrlines) + elog(ERROR, "unexpected number of armor header lines"); + + *nheaders = n; + return 0; +} diff --git a/contrib/pgcrypto/pgp-cfb.c b/contrib/pgcrypto/pgp-cfb.c new file mode 100644 index 0000000..de41e82 --- /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 "pgp.h" +#include "px.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 = palloc0(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); + px_memset(ctx, 0, sizeof(*ctx)); + pfree(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) + { + unsigned rlen; + + px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, ctx->fre, &rlen); + 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); +} diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c new file mode 100644 index 0000000..086bec3 --- /dev/null +++ b/contrib/pgcrypto/pgp-compress.c @@ -0,0 +1,346 @@ +/* + * 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 "pgp.h" +#include "px.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 palloc(n_items * item_len); +} + +static void +z_free(void *priv, void *addr) +{ + pfree(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 = palloc0(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) + { + pfree(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 + */ + st->stream.next_in = unconstify(uint8 *, data); + st->stream.avail_in = len; + while (st->stream.avail_in > 0) + { + st->stream.next_out = st->buf; + st->stream.avail_out = st->buf_len; + res = deflate(&st->stream, Z_NO_FLUSH); + 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; + } + } + + 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); + px_memset(st, 0, sizeof(*st)); + pfree(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 = palloc0(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) + { + pfree(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) + { + uint8 *tmp; + + /* + * A stream must be terminated by a normal packet. If the last stream + * packet in the source stream is a full packet, a normal empty packet + * must follow. Since the underlying packet reader doesn't know that + * the compressed stream has been ended, we need to consume the + * terminating packet here. This read does not harm even if the + * stream has already ended. + */ + res = pullf_read(src, 1, &tmp); + + if (res < 0) + return res; + else if (res > 0) + { + px_debug("decompress_read: extra bytes after end of stream"); + return PXE_PGP_CORRUPT_DATA; + } + dec->eof = 1; + } + goto restart; +} + +static void +decompress_free(void *priv) +{ + struct DecomprData *dec = priv; + + inflateEnd(&dec->stream); + px_memset(dec, 0, sizeof(*dec)); + pfree(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_LIBZ */ + +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 diff --git a/contrib/pgcrypto/pgp-decrypt.c b/contrib/pgcrypto/pgp-decrypt.c new file mode 100644 index 0000000..d12dcad --- /dev/null +++ b/contrib/pgcrypto/pgp-decrypt.c @@ -0,0 +1,1212 @@ +/* + * 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 "mbuf.h" +#include "pgp.h" +#include "px.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 don't 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); + + while (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; + + px_memset(pkt, 0, sizeof(*pkt)); + pfree(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 = palloc(sizeof(*pkt)); + + pkt->type = pkttype; + pkt->len = len; + res = pullf_create(pf_p, &pktreader_filter, pkt, src); + if (res < 0) + pfree(pkt); + return res; +} + +/* + * Prefix check filter + * https://tools.ietf.org/html/rfc4880#section-5.7 + * https://tools.ietf.org/html/rfc4880#section-5.13 + */ + +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"); + px_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"); + /* report error in pgp_decrypt() */ + ctx->corrupt_prefix = 1; + } + px_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) +{ + int res; + uint8 hash[20]; + uint8 tmpbuf[20]; + uint8 *data; + + /* should not happen */ + if (ctx->use_mdcbuf_filter) + return PXE_BUG; + + /* It's SHA1 */ + if (len != 20) + return PXE_PGP_CORRUPT_DATA; + + /* mdc_read should not call px_md_update */ + ctx->in_mdc_pkt = 1; + + /* read data */ + res = pullf_read_max(src, len, &data, tmpbuf); + if (res < 0) + return res; + if (res == 0) + { + px_debug("no mdc"); + return PXE_PGP_CORRUPT_DATA; + } + + /* 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, 20); + px_memset(hash, 0, 20); + px_memset(tmpbuf, 0, sizeof(tmpbuf)); + if (res != 0) + { + px_debug("mdc_finish: mdc failed"); + return PXE_PGP_CORRUPT_DATA; + } + ctx->mdc_checked = 1; + return 0; +} + +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 || ctx->in_mdc_pkt) + return pullf_read(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_DATA_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 = palloc0(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); + px_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; + px_memset(st, 0, sizeof(*st)); + pfree(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_count = s2k_decode_count(ctx->s2k.iter); + 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); + } + + px_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; + } + px_memset(tmpbuf, 0, sizeof(tmpbuf)); + 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; + } + px_memset(tmpbuf, 0, 4); + + /* + * If called from an SQL function that returns text, pgp_decrypt() rejects + * inputs not self-identifying as text. + */ + if (ctx->text_mode) + if (type != 't' && type != 'u') + { + px_debug("parse_literal_data: data type=%c", type); + ctx->unexpected_binary = true; + } + + 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; + uint8 *discard_buf; + + 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"); + /* report error in pgp_decrypt() */ + ctx->unsupported_compr = 1; + + /* + * Discard the compressed data, allowing it to first affect any + * MDC digest computation. + */ + while (1) + { + res = pullf_read(pkt, 32 * 1024, &discard_buf); + if (res <= 0) + break; + } + + 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; + + 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 SYMENCRYPTED_DATA_MDC packet 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; + } + + res = mdc_finish(ctx, pkt, len); + 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; +} + +/* + * expect to be at packet end, any data is error + */ +int +pgp_expect_packet_end(PullFilter *pkt) +{ + int res; + uint8 *tmp; + + 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; +} + +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; + + /* + * Report a failure of the prefix_init() "quick check" now, rather than + * upon detection, to hinder timing attacks. pgcrypto is not generally + * secure against timing attacks, but this helps. + */ + if (!got_data || ctx->corrupt_prefix) + return PXE_PGP_CORRUPT_DATA; + + /* + * Code interpreting purportedly-decrypted data prior to this stage shall + * report no error other than PXE_PGP_CORRUPT_DATA. (PXE_BUG is okay so + * long as it remains unreachable.) This ensures that an attacker able to + * choose a ciphertext and receive a corresponding decryption error + * message cannot use that oracle to gather clues about the decryption + * key. See "An Attack on CFB Mode Encryption As Used By OpenPGP" by + * Serge Mister and Robert Zuccherato. + * + * A problematic value in the first octet of a Literal Data or Compressed + * Data packet may indicate a simple user error, such as the need to call + * pgp_sym_decrypt_bytea instead of pgp_sym_decrypt. Occasionally, + * though, it is the first symptom of the encryption key not matching the + * decryption key. When this was the only problem encountered, report a + * specific error to guide the user; otherwise, we will have reported + * PXE_PGP_CORRUPT_DATA before now. A key mismatch makes the other errors + * into red herrings, and this avoids leaking clues to attackers. + */ + if (ctx->unsupported_compr) + return PXE_PGP_UNSUPPORTED_COMPR; + if (ctx->unexpected_binary) + return PXE_PGP_NOT_TEXT; + + return res; +} diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c new file mode 100644 index 0000000..f7467c9 --- /dev/null +++ b/contrib/pgcrypto/pgp-encrypt.c @@ -0,0 +1,704 @@ +/* + * 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 "pgp.h" +#include "px.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); + px_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 = palloc0(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; + + if (st->ciph) + pgp_cfb_free(st->ciph); + px_memset(st, 0, sizeof(*st)); + pfree(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 = palloc(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; + + px_memset(st, 0, sizeof(*st)); + pfree(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); + if (!pg_strong_random(prefix, bs)) + return PXE_NO_RANDOM; + + prefix[bs + 0] = prefix[bs - 2]; + prefix[bs + 1] = prefix[bs - 1]; + + res = pushf_write(dst, prefix, bs + 2); + px_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); + + px_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, ctx->s2k_count); + 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) +{ + if (ctx->use_sess_key || ctx->pub_key) + { + ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo); + if (!pg_strong_random(ctx->sess_key, ctx->sess_key_len)) + return PXE_NO_RANDOM; + } + 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 sym_key + */ + 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; +} diff --git a/contrib/pgcrypto/pgp-info.c b/contrib/pgcrypto/pgp-info.c new file mode 100644 index 0000000..83dc604 --- /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 "mbuf.h" +#include "pgp.h" +#include "px.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++; + /* fall through */ + 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; +} diff --git a/contrib/pgcrypto/pgp-mpi-openssl.c b/contrib/pgcrypto/pgp-mpi-openssl.c new file mode 100644 index 0000000..75e4c8b --- /dev/null +++ b/contrib/pgcrypto/pgp-mpi-openssl.c @@ -0,0 +1,284 @@ +/* + * 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 "pgp.h" +#include "px.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 component 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 + * algorithm hovers 10-70 bits above gpg values. And for + * larger p, it uses gpg's algorithm. + * + * 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; +} diff --git a/contrib/pgcrypto/pgp-mpi.c b/contrib/pgcrypto/pgp-mpi.c new file mode 100644 index 0000000..03be279 --- /dev/null +++ b/contrib/pgcrypto/pgp-mpi.c @@ -0,0 +1,142 @@ +/* + * pgp-mpi.c + * OpenPGP MPI helper 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.c + */ +#include "postgres.h" + +#include "pgp.h" +#include "px.h" + +int +pgp_mpi_alloc(int bits, PGP_MPI **mpi) +{ + PGP_MPI *n; + int len = (bits + 7) / 8; + + if (bits < 0 || bits > 0xFFFF) + { + px_debug("pgp_mpi_alloc: unreasonable request: bits=%d", bits); + return PXE_PGP_CORRUPT_DATA; + } + n = palloc(sizeof(*n) + len); + n->bits = bits; + n->bytes = len; + n->data = (uint8 *) (n) + sizeof(*n); + *mpi = n; + return 0; +} + +int +pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi) +{ + int res; + PGP_MPI *n; + + res = pgp_mpi_alloc(bits, &n); + if (res < 0) + return res; + memcpy(n->data, data, n->bytes); + *mpi = n; + return 0; +} + +int +pgp_mpi_free(PGP_MPI *mpi) +{ + if (mpi == NULL) + return 0; + px_memset(mpi, 0, sizeof(*mpi) + mpi->bytes); + pfree(mpi); + return 0; +} + +int +pgp_mpi_read(PullFilter *src, PGP_MPI **mpi) +{ + int res; + uint8 hdr[2]; + int bits; + PGP_MPI *n; + + res = pullf_read_fixed(src, 2, hdr); + if (res < 0) + return res; + bits = ((unsigned) hdr[0] << 8) + hdr[1]; + + res = pgp_mpi_alloc(bits, &n); + if (res < 0) + return res; + + res = pullf_read_fixed(src, n->bytes, n->data); + if (res < 0) + pgp_mpi_free(n); + else + *mpi = n; + return res; +} + +int +pgp_mpi_write(PushFilter *dst, PGP_MPI *n) +{ + int res; + uint8 buf[2]; + + buf[0] = n->bits >> 8; + buf[1] = n->bits & 0xFF; + res = pushf_write(dst, buf, 2); + if (res >= 0) + res = pushf_write(dst, n->data, n->bytes); + return res; +} + +int +pgp_mpi_hash(PX_MD *md, PGP_MPI *n) +{ + uint8 buf[2]; + + buf[0] = n->bits >> 8; + buf[1] = n->bits & 0xFF; + px_md_update(md, buf, 2); + px_md_update(md, n->data, n->bytes); + + return 0; +} + +unsigned +pgp_mpi_cksum(unsigned cksum, PGP_MPI *n) +{ + int i; + + cksum += n->bits >> 8; + cksum += n->bits & 0xFF; + for (i = 0; i < n->bytes; i++) + cksum += n->data[i]; + + return cksum & 0xFFFF; +} diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c new file mode 100644 index 0000000..0536bfb --- /dev/null +++ b/contrib/pgcrypto/pgp-pgsql.c @@ -0,0 +1,1006 @@ +/* + * pgp-pgsql.c + * PostgreSQL wrappers for pgp. + * + * 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-pgsql.c + */ + +#include "postgres.h" + +#include "catalog/pg_type.h" +#include "common/string.h" +#include "funcapi.h" +#include "lib/stringinfo.h" +#include "mb/pg_wchar.h" +#include "mbuf.h" +#include "pgp.h" +#include "px.h" +#include "utils/array.h" +#include "utils/builtins.h" + +/* + * public functions + */ +PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea); +PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text); +PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea); +PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text); + +PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea); +PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text); +PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea); +PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text); + +PG_FUNCTION_INFO_V1(pgp_key_id_w); + +PG_FUNCTION_INFO_V1(pg_armor); +PG_FUNCTION_INFO_V1(pg_dearmor); +PG_FUNCTION_INFO_V1(pgp_armor_headers); + +/* + * returns src in case of no conversion or error + */ +static text * +convert_charset(text *src, int cset_from, int cset_to) +{ + int src_len = VARSIZE_ANY_EXHDR(src); + unsigned char *dst; + unsigned char *csrc = (unsigned char *) VARDATA_ANY(src); + text *res; + + dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to); + if (dst == csrc) + return src; + + res = cstring_to_text((char *) dst); + pfree(dst); + return res; +} + +static text * +convert_from_utf8(text *src) +{ + return convert_charset(src, PG_UTF8, GetDatabaseEncoding()); +} + +static text * +convert_to_utf8(text *src) +{ + return convert_charset(src, GetDatabaseEncoding(), PG_UTF8); +} + +static void +clear_and_pfree(text *p) +{ + px_memset(p, 0, VARSIZE_ANY(p)); + pfree(p); +} + +/* + * expect-* arguments storage + */ +struct debug_expect +{ + int debug; + int expect; + int cipher_algo; + int s2k_mode; + int s2k_count; + int s2k_cipher_algo; + int s2k_digest_algo; + int compress_algo; + int use_sess_key; + int disable_mdc; + int unicode_mode; +}; + +static void +fill_expect(struct debug_expect *ex, int text_mode) +{ + ex->debug = 0; + ex->expect = 0; + ex->cipher_algo = -1; + ex->s2k_mode = -1; + ex->s2k_count = -1; + ex->s2k_cipher_algo = -1; + ex->s2k_digest_algo = -1; + ex->compress_algo = -1; + ex->use_sess_key = -1; + ex->disable_mdc = -1; + ex->unicode_mode = -1; +} + +#define EX_MSG(arg) \ + ereport(NOTICE, (errmsg( \ + "pgp_decrypt: unexpected %s: expected %d got %d", \ + CppAsString(arg), ex->arg, ctx->arg))) + +#define EX_CHECK(arg) do { \ + if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \ + } while (0) + +static void +check_expect(PGP_Context *ctx, struct debug_expect *ex) +{ + EX_CHECK(cipher_algo); + EX_CHECK(s2k_mode); + EX_CHECK(s2k_count); + EX_CHECK(s2k_digest_algo); + EX_CHECK(use_sess_key); + if (ctx->use_sess_key) + EX_CHECK(s2k_cipher_algo); + EX_CHECK(disable_mdc); + EX_CHECK(compress_algo); + EX_CHECK(unicode_mode); +} + +static void +show_debug(const char *msg) +{ + ereport(NOTICE, (errmsg("dbg: %s", msg))); +} + +static int +set_arg(PGP_Context *ctx, char *key, char *val, + struct debug_expect *ex) +{ + int res = 0; + + if (strcmp(key, "cipher-algo") == 0) + res = pgp_set_cipher_algo(ctx, val); + else if (strcmp(key, "disable-mdc") == 0) + res = pgp_disable_mdc(ctx, atoi(val)); + else if (strcmp(key, "sess-key") == 0) + res = pgp_set_sess_key(ctx, atoi(val)); + else if (strcmp(key, "s2k-mode") == 0) + res = pgp_set_s2k_mode(ctx, atoi(val)); + else if (strcmp(key, "s2k-count") == 0) + res = pgp_set_s2k_count(ctx, atoi(val)); + else if (strcmp(key, "s2k-digest-algo") == 0) + res = pgp_set_s2k_digest_algo(ctx, val); + else if (strcmp(key, "s2k-cipher-algo") == 0) + res = pgp_set_s2k_cipher_algo(ctx, val); + else if (strcmp(key, "compress-algo") == 0) + res = pgp_set_compress_algo(ctx, atoi(val)); + else if (strcmp(key, "compress-level") == 0) + res = pgp_set_compress_level(ctx, atoi(val)); + else if (strcmp(key, "convert-crlf") == 0) + res = pgp_set_convert_crlf(ctx, atoi(val)); + else if (strcmp(key, "unicode-mode") == 0) + res = pgp_set_unicode_mode(ctx, atoi(val)); + + /* + * The remaining options are for debugging/testing and are therefore not + * documented in the user-facing docs. + */ + else if (ex != NULL && strcmp(key, "debug") == 0) + ex->debug = atoi(val); + else if (ex != NULL && strcmp(key, "expect-cipher-algo") == 0) + { + ex->expect = 1; + ex->cipher_algo = pgp_get_cipher_code(val); + } + else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0) + { + ex->expect = 1; + ex->disable_mdc = atoi(val); + } + else if (ex != NULL && strcmp(key, "expect-sess-key") == 0) + { + ex->expect = 1; + ex->use_sess_key = atoi(val); + } + else if (ex != NULL && strcmp(key, "expect-s2k-mode") == 0) + { + ex->expect = 1; + ex->s2k_mode = atoi(val); + } + else if (ex != NULL && strcmp(key, "expect-s2k-count") == 0) + { + ex->expect = 1; + ex->s2k_count = atoi(val); + } + else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0) + { + ex->expect = 1; + ex->s2k_digest_algo = pgp_get_digest_code(val); + } + else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo") == 0) + { + ex->expect = 1; + ex->s2k_cipher_algo = pgp_get_cipher_code(val); + } + else if (ex != NULL && strcmp(key, "expect-compress-algo") == 0) + { + ex->expect = 1; + ex->compress_algo = atoi(val); + } + else if (ex != NULL && strcmp(key, "expect-unicode-mode") == 0) + { + ex->expect = 1; + ex->unicode_mode = atoi(val); + } + else + res = PXE_ARGUMENT_ERROR; + + return res; +} + +/* + * Find next word. Handle ',' and '=' as words. Skip whitespace. + * Put word info into res_p, res_len. + * Returns ptr to next word. + */ +static char * +getword(char *p, char **res_p, int *res_len) +{ + /* whitespace at start */ + while (*p && (*p == ' ' || *p == '\t' || *p == '\n')) + p++; + + /* word data */ + *res_p = p; + if (*p == '=' || *p == ',') + p++; + else + while (*p && !(*p == ' ' || *p == '\t' || *p == '\n' + || *p == '=' || *p == ',')) + p++; + + /* word end */ + *res_len = p - *res_p; + + /* whitespace at end */ + while (*p && (*p == ' ' || *p == '\t' || *p == '\n')) + p++; + + return p; +} + +/* + * Convert to lowercase asciiz string. + */ +static char * +downcase_convert(const uint8 *s, int len) +{ + int c, + i; + char *res = palloc(len + 1); + + for (i = 0; i < len; i++) + { + c = s[i]; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + res[i] = c; + } + res[len] = 0; + return res; +} + +static int +parse_args(PGP_Context *ctx, uint8 *args, int arg_len, + struct debug_expect *ex) +{ + char *str = downcase_convert(args, arg_len); + char *key, + *val; + int key_len, + val_len; + int res = 0; + char *p = str; + + while (*p) + { + res = PXE_ARGUMENT_ERROR; + p = getword(p, &key, &key_len); + if (*p++ != '=') + break; + p = getword(p, &val, &val_len); + if (*p == '\0') + ; + else if (*p++ != ',') + break; + + if (*key == 0 || *val == 0 || val_len == 0) + break; + + key[key_len] = 0; + val[val_len] = 0; + + res = set_arg(ctx, key, val, ex); + if (res < 0) + break; + } + pfree(str); + return res; +} + +static MBuf * +create_mbuf_from_vardata(text *data) +{ + return mbuf_create_from_data((uint8 *) VARDATA_ANY(data), + VARSIZE_ANY_EXHDR(data)); +} + +static void +init_work(PGP_Context **ctx_p, int is_text, + text *args, struct debug_expect *ex) +{ + int err = pgp_init(ctx_p); + + fill_expect(ex, is_text); + + if (err == 0 && args != NULL) + err = parse_args(*ctx_p, (uint8 *) VARDATA_ANY(args), + VARSIZE_ANY_EXHDR(args), ex); + + if (err) + px_THROW_ERROR(err); + + if (ex->debug) + px_set_debug_handler(show_debug); + + pgp_set_text_mode(*ctx_p, is_text); +} + +static bytea * +encrypt_internal(int is_pubenc, int is_text, + text *data, text *key, text *args) +{ + MBuf *src, + *dst; + uint8 tmp[VARHDRSZ]; + uint8 *restmp; + bytea *res; + int res_len; + PGP_Context *ctx; + int err; + struct debug_expect ex; + text *tmp_data = NULL; + + init_work(&ctx, is_text, args, &ex); + + if (is_text && pgp_get_unicode_mode(ctx)) + { + tmp_data = convert_to_utf8(data); + if (tmp_data == data) + tmp_data = NULL; + else + data = tmp_data; + } + + src = create_mbuf_from_vardata(data); + dst = mbuf_create(VARSIZE_ANY(data) + 128); + + /* + * reserve room for header + */ + mbuf_append(dst, tmp, VARHDRSZ); + + /* + * set key + */ + if (is_pubenc) + { + MBuf *kbuf = create_mbuf_from_vardata(key); + + err = pgp_set_pubkey(ctx, kbuf, + NULL, 0, 0); + mbuf_free(kbuf); + } + else + err = pgp_set_symkey(ctx, (uint8 *) VARDATA_ANY(key), + VARSIZE_ANY_EXHDR(key)); + + /* + * encrypt + */ + if (err >= 0) + err = pgp_encrypt(ctx, src, dst); + + /* + * check for error + */ + if (err) + { + if (ex.debug) + px_set_debug_handler(NULL); + if (tmp_data) + clear_and_pfree(tmp_data); + pgp_free(ctx); + mbuf_free(src); + mbuf_free(dst); + px_THROW_ERROR(err); + } + + /* res_len includes VARHDRSZ */ + res_len = mbuf_steal_data(dst, &restmp); + res = (bytea *) restmp; + SET_VARSIZE(res, res_len); + + if (tmp_data) + clear_and_pfree(tmp_data); + pgp_free(ctx); + mbuf_free(src); + mbuf_free(dst); + + px_set_debug_handler(NULL); + + return res; +} + +static bytea * +decrypt_internal(int is_pubenc, int need_text, text *data, + text *key, text *keypsw, text *args) +{ + int err; + MBuf *src = NULL, + *dst = NULL; + uint8 tmp[VARHDRSZ]; + uint8 *restmp; + bytea *res; + int res_len; + PGP_Context *ctx = NULL; + struct debug_expect ex; + int got_unicode = 0; + + + init_work(&ctx, need_text, args, &ex); + + src = mbuf_create_from_data((uint8 *) VARDATA_ANY(data), + VARSIZE_ANY_EXHDR(data)); + dst = mbuf_create(VARSIZE_ANY(data) + 2048); + + /* + * reserve room for header + */ + mbuf_append(dst, tmp, VARHDRSZ); + + /* + * set key + */ + if (is_pubenc) + { + uint8 *psw = NULL; + int psw_len = 0; + MBuf *kbuf; + + if (keypsw) + { + psw = (uint8 *) VARDATA_ANY(keypsw); + psw_len = VARSIZE_ANY_EXHDR(keypsw); + } + kbuf = create_mbuf_from_vardata(key); + err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1); + mbuf_free(kbuf); + } + else + err = pgp_set_symkey(ctx, (uint8 *) VARDATA_ANY(key), + VARSIZE_ANY_EXHDR(key)); + + /* decrypt */ + if (err >= 0) + { + err = pgp_decrypt(ctx, src, dst); + + if (ex.expect) + check_expect(ctx, &ex); + + /* remember the setting */ + got_unicode = pgp_get_unicode_mode(ctx); + } + + mbuf_free(src); + pgp_free(ctx); + + if (err) + { + px_set_debug_handler(NULL); + mbuf_free(dst); + px_THROW_ERROR(err); + } + + res_len = mbuf_steal_data(dst, &restmp); + mbuf_free(dst); + + /* res_len includes VARHDRSZ */ + res = (bytea *) restmp; + SET_VARSIZE(res, res_len); + + if (need_text && got_unicode) + { + text *utf = convert_from_utf8(res); + + if (utf != res) + { + clear_and_pfree(res); + res = utf; + } + } + px_set_debug_handler(NULL); + + return res; +} + +/* + * Wrappers for symmetric-key functions + */ +Datum +pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_PP(2); + + res = encrypt_internal(0, 0, data, key, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(arg, 2); + PG_RETURN_TEXT_P(res); +} + +Datum +pgp_sym_encrypt_text(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_PP(2); + + res = encrypt_internal(0, 1, data, key, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(arg, 2); + PG_RETURN_TEXT_P(res); +} + + +Datum +pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_PP(2); + + res = decrypt_internal(0, 0, data, key, NULL, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(arg, 2); + PG_RETURN_TEXT_P(res); +} + +Datum +pgp_sym_decrypt_text(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_PP(2); + + res = decrypt_internal(0, 1, data, key, NULL, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(arg, 2); + PG_RETURN_TEXT_P(res); +} + +/* + * Wrappers for public-key functions + */ + +Datum +pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_PP(2); + + res = encrypt_internal(1, 0, data, key, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(arg, 2); + PG_RETURN_TEXT_P(res); +} + +Datum +pgp_pub_encrypt_text(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_PP(2); + + res = encrypt_internal(1, 1, data, key, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(arg, 2); + PG_RETURN_TEXT_P(res); +} + + +Datum +pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *psw = NULL, + *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + psw = PG_GETARG_BYTEA_PP(2); + if (PG_NARGS() > 3) + arg = PG_GETARG_BYTEA_PP(3); + + res = decrypt_internal(1, 0, data, key, psw, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(psw, 2); + if (PG_NARGS() > 3) + PG_FREE_IF_COPY(arg, 3); + PG_RETURN_TEXT_P(res); +} + +Datum +pgp_pub_decrypt_text(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *psw = NULL, + *arg = NULL; + text *res; + + data = PG_GETARG_BYTEA_PP(0); + key = PG_GETARG_BYTEA_PP(1); + if (PG_NARGS() > 2) + psw = PG_GETARG_BYTEA_PP(2); + if (PG_NARGS() > 3) + arg = PG_GETARG_BYTEA_PP(3); + + res = decrypt_internal(1, 1, data, key, psw, arg); + + PG_FREE_IF_COPY(data, 0); + PG_FREE_IF_COPY(key, 1); + if (PG_NARGS() > 2) + PG_FREE_IF_COPY(psw, 2); + if (PG_NARGS() > 3) + PG_FREE_IF_COPY(arg, 3); + PG_RETURN_TEXT_P(res); +} + + +/* + * Wrappers for PGP ascii armor + */ + +/* + * Helper function for pg_armor. Converts arrays of keys and values into + * plain C arrays, and checks that they don't contain invalid characters. + */ +static int +parse_key_value_arrays(ArrayType *key_array, ArrayType *val_array, + char ***p_keys, char ***p_values) +{ + int nkdims = ARR_NDIM(key_array); + int nvdims = ARR_NDIM(val_array); + char **keys, + **values; + Datum *key_datums, + *val_datums; + bool *key_nulls, + *val_nulls; + int key_count, + val_count; + int i; + + if (nkdims > 1 || nkdims != nvdims) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("wrong number of array subscripts"))); + if (nkdims == 0) + return 0; + + deconstruct_array(key_array, + TEXTOID, -1, false, TYPALIGN_INT, + &key_datums, &key_nulls, &key_count); + + deconstruct_array(val_array, + TEXTOID, -1, false, TYPALIGN_INT, + &val_datums, &val_nulls, &val_count); + + if (key_count != val_count) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("mismatched array dimensions"))); + + keys = (char **) palloc(sizeof(char *) * key_count); + values = (char **) palloc(sizeof(char *) * val_count); + + for (i = 0; i < key_count; i++) + { + char *v; + + /* Check that the key doesn't contain anything funny */ + if (key_nulls[i]) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("null value not allowed for header key"))); + + v = TextDatumGetCString(key_datums[i]); + + if (!pg_is_ascii(v)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("header key must not contain non-ASCII characters"))); + if (strstr(v, ": ")) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("header key must not contain \": \""))); + if (strchr(v, '\n')) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("header key must not contain newlines"))); + keys[i] = v; + + /* And the same for the value */ + if (val_nulls[i]) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("null value not allowed for header value"))); + + v = TextDatumGetCString(val_datums[i]); + + if (!pg_is_ascii(v)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("header value must not contain non-ASCII characters"))); + if (strchr(v, '\n')) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("header value must not contain newlines"))); + + values[i] = v; + } + + *p_keys = keys; + *p_values = values; + return key_count; +} + +Datum +pg_armor(PG_FUNCTION_ARGS) +{ + bytea *data; + text *res; + int data_len; + StringInfoData buf; + int num_headers; + char **keys = NULL, + **values = NULL; + + data = PG_GETARG_BYTEA_PP(0); + data_len = VARSIZE_ANY_EXHDR(data); + if (PG_NARGS() == 3) + { + num_headers = parse_key_value_arrays(PG_GETARG_ARRAYTYPE_P(1), + PG_GETARG_ARRAYTYPE_P(2), + &keys, &values); + } + else if (PG_NARGS() == 1) + num_headers = 0; + else + elog(ERROR, "unexpected number of arguments %d", PG_NARGS()); + + initStringInfo(&buf); + + pgp_armor_encode((uint8 *) VARDATA_ANY(data), data_len, &buf, + num_headers, keys, values); + + res = palloc(VARHDRSZ + buf.len); + SET_VARSIZE(res, VARHDRSZ + buf.len); + memcpy(VARDATA(res), buf.data, buf.len); + pfree(buf.data); + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} + +Datum +pg_dearmor(PG_FUNCTION_ARGS) +{ + text *data; + bytea *res; + int data_len; + int ret; + StringInfoData buf; + + data = PG_GETARG_TEXT_PP(0); + data_len = VARSIZE_ANY_EXHDR(data); + + initStringInfo(&buf); + + ret = pgp_armor_decode((uint8 *) VARDATA_ANY(data), data_len, &buf); + if (ret < 0) + px_THROW_ERROR(ret); + res = palloc(VARHDRSZ + buf.len); + SET_VARSIZE(res, VARHDRSZ + buf.len); + memcpy(VARDATA(res), buf.data, buf.len); + pfree(buf.data); + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} + +/* cross-call state for pgp_armor_headers */ +typedef struct +{ + int nheaders; + char **keys; + char **values; +} pgp_armor_headers_state; + +Datum +pgp_armor_headers(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + pgp_armor_headers_state *state; + char *utf8key; + char *utf8val; + HeapTuple tuple; + TupleDesc tupdesc; + AttInMetadata *attinmeta; + + if (SRF_IS_FIRSTCALL()) + { + text *data = PG_GETARG_TEXT_PP(0); + int res; + MemoryContext oldcontext; + + funcctx = SRF_FIRSTCALL_INIT(); + + /* we need the state allocated in the multi call context */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + attinmeta = TupleDescGetAttInMetadata(tupdesc); + funcctx->attinmeta = attinmeta; + + state = (pgp_armor_headers_state *) palloc(sizeof(pgp_armor_headers_state)); + + res = pgp_extract_armor_headers((uint8 *) VARDATA_ANY(data), + VARSIZE_ANY_EXHDR(data), + &state->nheaders, &state->keys, + &state->values); + if (res < 0) + px_THROW_ERROR(res); + + MemoryContextSwitchTo(oldcontext); + funcctx->user_fctx = state; + } + + funcctx = SRF_PERCALL_SETUP(); + state = (pgp_armor_headers_state *) funcctx->user_fctx; + + if (funcctx->call_cntr >= state->nheaders) + SRF_RETURN_DONE(funcctx); + else + { + char *values[2]; + + /* we assume that the keys (and values) are in UTF-8. */ + utf8key = state->keys[funcctx->call_cntr]; + utf8val = state->values[funcctx->call_cntr]; + + values[0] = pg_any_to_server(utf8key, strlen(utf8key), PG_UTF8); + values[1] = pg_any_to_server(utf8val, strlen(utf8val), PG_UTF8); + + /* build a tuple */ + tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } +} + + + +/* + * Wrappers for PGP key id + */ + +Datum +pgp_key_id_w(PG_FUNCTION_ARGS) +{ + bytea *data; + text *res; + int res_len; + MBuf *buf; + + data = PG_GETARG_BYTEA_PP(0); + buf = create_mbuf_from_vardata(data); + res = palloc(VARHDRSZ + 17); + + res_len = pgp_get_keyid(buf, VARDATA(res)); + mbuf_free(buf); + if (res_len < 0) + px_THROW_ERROR(res_len); + SET_VARSIZE(res, VARHDRSZ + res_len); + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} diff --git a/contrib/pgcrypto/pgp-pubdec.c b/contrib/pgcrypto/pgp-pubdec.c new file mode 100644 index 0000000..a0a5738 --- /dev/null +++ b/contrib/pgcrypto/pgp-pubdec.c @@ -0,0 +1,235 @@ +/* + * pgp-pubdec.c + * Decrypt public-key encrypted session key. + * + * 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-pubdec.c + */ +#include "postgres.h" + +#include "pgp.h" +#include "px.h" + +/* + * padded msg = 02 || PS || 00 || M + * PS - pad bytes + * M - msg + */ +static uint8 * +check_eme_pkcs1_v15(uint8 *data, int len) +{ + uint8 *data_end = data + len; + uint8 *p = data; + int rnd = 0; + + if (len < 1 + 8 + 1) + return NULL; + + if (*p++ != 2) + return NULL; + + while (p < data_end && *p) + { + p++; + rnd++; + } + + if (p == data_end) + return NULL; + if (*p != 0) + return NULL; + if (rnd < 8) + return NULL; + return p + 1; +} + +/* + * secret message: 1 byte algo, sesskey, 2 byte cksum + * ignore algo in cksum + */ +static int +control_cksum(uint8 *msg, int msglen) +{ + int i; + unsigned my_cksum, + got_cksum; + + if (msglen < 3) + return PXE_PGP_WRONG_KEY; + + my_cksum = 0; + for (i = 1; i < msglen - 2; i++) + my_cksum += msg[i]; + my_cksum &= 0xFFFF; + got_cksum = ((unsigned) (msg[msglen - 2]) << 8) + msg[msglen - 1]; + if (my_cksum != got_cksum) + { + px_debug("pubenc cksum failed"); + return PXE_PGP_WRONG_KEY; + } + return 0; +} + +static int +decrypt_elgamal(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p) +{ + int res; + PGP_MPI *c1 = NULL; + PGP_MPI *c2 = NULL; + + if (pk->algo != PGP_PUB_ELG_ENCRYPT) + return PXE_PGP_WRONG_KEY; + + /* read elgamal encrypted data */ + res = pgp_mpi_read(pkt, &c1); + if (res < 0) + goto out; + res = pgp_mpi_read(pkt, &c2); + if (res < 0) + goto out; + + /* decrypt */ + res = pgp_elgamal_decrypt(pk, c1, c2, m_p); + +out: + pgp_mpi_free(c1); + pgp_mpi_free(c2); + return res; +} + +static int +decrypt_rsa(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p) +{ + int res; + PGP_MPI *c; + + if (pk->algo != PGP_PUB_RSA_ENCRYPT + && pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN) + return PXE_PGP_WRONG_KEY; + + /* read rsa encrypted data */ + res = pgp_mpi_read(pkt, &c); + if (res < 0) + return res; + + /* decrypt */ + res = pgp_rsa_decrypt(pk, c, m_p); + + pgp_mpi_free(c); + return res; +} + +/* key id is missing - user is expected to try all keys */ +static const uint8 + any_key[] = {0, 0, 0, 0, 0, 0, 0, 0}; + +int +pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt) +{ + int ver; + int algo; + int res; + uint8 key_id[8]; + PGP_PubKey *pk; + uint8 *msg; + int msglen; + PGP_MPI *m; + + pk = ctx->pub_key; + if (pk == NULL) + { + px_debug("no pubkey?"); + return PXE_BUG; + } + + GETBYTE(pkt, ver); + if (ver != 3) + { + px_debug("unknown pubenc_sesskey pkt ver=%d", ver); + return PXE_PGP_CORRUPT_DATA; + } + + /* + * check if keyid's match - user-friendly msg + */ + res = pullf_read_fixed(pkt, 8, key_id); + if (res < 0) + return res; + if (memcmp(key_id, any_key, 8) != 0 + && memcmp(key_id, pk->key_id, 8) != 0) + { + px_debug("key_id's does not match"); + return PXE_PGP_WRONG_KEY; + } + + /* + * Decrypt + */ + GETBYTE(pkt, algo); + switch (algo) + { + case PGP_PUB_ELG_ENCRYPT: + res = decrypt_elgamal(pk, pkt, &m); + break; + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + res = decrypt_rsa(pk, pkt, &m); + break; + default: + res = PXE_PGP_UNKNOWN_PUBALGO; + } + if (res < 0) + return res; + + /* + * extract message + */ + msg = check_eme_pkcs1_v15(m->data, m->bytes); + if (msg == NULL) + { + px_debug("check_eme_pkcs1_v15 failed"); + res = PXE_PGP_WRONG_KEY; + goto out; + } + msglen = m->bytes - (msg - m->data); + + res = control_cksum(msg, msglen); + if (res < 0) + goto out; + + /* + * got sesskey + */ + ctx->cipher_algo = *msg; + ctx->sess_key_len = msglen - 3; + memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len); + +out: + pgp_mpi_free(m); + if (res < 0) + return res; + return pgp_expect_packet_end(pkt); +} diff --git a/contrib/pgcrypto/pgp-pubenc.c b/contrib/pgcrypto/pgp-pubenc.c new file mode 100644 index 0000000..c254a37 --- /dev/null +++ b/contrib/pgcrypto/pgp-pubenc.c @@ -0,0 +1,244 @@ +/* + * pgp-pubenc.c + * Encrypt session key with public key. + * + * 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-pubenc.c + */ +#include "postgres.h" + +#include "pgp.h" +#include "px.h" + +/* + * padded msg: 02 || non-zero pad bytes || 00 || msg + */ +static int +pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p) +{ + uint8 *buf, + *p; + int pad_len = res_len - 2 - data_len; + + if (pad_len < 8) + return PXE_BUG; + + buf = palloc(res_len); + buf[0] = 0x02; + + if (!pg_strong_random(buf + 1, pad_len)) + { + pfree(buf); + return PXE_NO_RANDOM; + } + + /* pad must not contain zero bytes */ + p = buf + 1; + while (p < buf + 1 + pad_len) + { + if (*p == 0) + { + if (!pg_strong_random(p, 1)) + { + px_memset(buf, 0, res_len); + pfree(buf); + return PXE_NO_RANDOM; + } + } + if (*p != 0) + p++; + } + + buf[pad_len + 1] = 0; + memcpy(buf + pad_len + 2, data, data_len); + *res_p = buf; + + return 0; +} + +static int +create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes) +{ + uint8 *secmsg; + int res, + i; + unsigned cksum = 0; + int klen = ctx->sess_key_len; + uint8 *padded = NULL; + PGP_MPI *m = NULL; + + /* calc checksum */ + for (i = 0; i < klen; i++) + cksum += ctx->sess_key[i]; + + /* + * create "secret message" + */ + secmsg = palloc(klen + 3); + secmsg[0] = ctx->cipher_algo; + memcpy(secmsg + 1, ctx->sess_key, klen); + secmsg[klen + 1] = (cksum >> 8) & 0xFF; + secmsg[klen + 2] = cksum & 0xFF; + + /* + * now create a large integer of it + */ + res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded); + if (res >= 0) + { + /* first byte will be 0x02 */ + int full_bits = full_bytes * 8 - 6; + + res = pgp_mpi_create(padded, full_bits, &m); + } + + if (padded) + { + px_memset(padded, 0, full_bytes); + pfree(padded); + } + px_memset(secmsg, 0, klen + 3); + pfree(secmsg); + + if (res >= 0) + *msg_p = m; + + return res; +} + +static int +encrypt_and_write_elgamal(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt) +{ + int res; + PGP_MPI *m = NULL, + *c1 = NULL, + *c2 = NULL; + + /* create padded msg */ + res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1); + if (res < 0) + goto err; + + /* encrypt it */ + res = pgp_elgamal_encrypt(pk, m, &c1, &c2); + if (res < 0) + goto err; + + /* write out */ + res = pgp_mpi_write(pkt, c1); + if (res < 0) + goto err; + res = pgp_mpi_write(pkt, c2); + +err: + pgp_mpi_free(m); + pgp_mpi_free(c1); + pgp_mpi_free(c2); + return res; +} + +static int +encrypt_and_write_rsa(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt) +{ + int res; + PGP_MPI *m = NULL, + *c = NULL; + + /* create padded msg */ + res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1); + if (res < 0) + goto err; + + /* encrypt it */ + res = pgp_rsa_encrypt(pk, m, &c); + if (res < 0) + goto err; + + /* write out */ + res = pgp_mpi_write(pkt, c); + +err: + pgp_mpi_free(m); + pgp_mpi_free(c); + return res; +} + +int +pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst) +{ + int res; + PGP_PubKey *pk = ctx->pub_key; + uint8 ver = 3; + PushFilter *pkt = NULL; + uint8 algo; + + if (pk == NULL) + { + px_debug("no pubkey?\n"); + return PXE_BUG; + } + + algo = pk->algo; + + /* + * now write packet + */ + res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt); + if (res < 0) + goto err; + res = pushf_write(pkt, &ver, 1); + if (res < 0) + goto err; + res = pushf_write(pkt, pk->key_id, 8); + if (res < 0) + goto err; + res = pushf_write(pkt, &algo, 1); + if (res < 0) + goto err; + + switch (algo) + { + case PGP_PUB_ELG_ENCRYPT: + res = encrypt_and_write_elgamal(ctx, pk, pkt); + break; + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + res = encrypt_and_write_rsa(ctx, pk, pkt); + break; + } + if (res < 0) + goto err; + + /* + * done, signal packet end + */ + res = pushf_flush(pkt); +err: + if (pkt) + pushf_free(pkt); + + return res; +} diff --git a/contrib/pgcrypto/pgp-pubkey.c b/contrib/pgcrypto/pgp-pubkey.c new file mode 100644 index 0000000..9a6561c --- /dev/null +++ b/contrib/pgcrypto/pgp-pubkey.c @@ -0,0 +1,583 @@ +/* + * pgp-pubkey.c + * Read public or secret key. + * + * 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-pubkey.c + */ +#include "postgres.h" + +#include "mbuf.h" +#include "pgp.h" +#include "px.h" + +int +pgp_key_alloc(PGP_PubKey **pk_p) +{ + PGP_PubKey *pk; + + pk = palloc0(sizeof(*pk)); + *pk_p = pk; + return 0; +} + +void +pgp_key_free(PGP_PubKey *pk) +{ + if (pk == NULL) + return; + + switch (pk->algo) + { + case PGP_PUB_ELG_ENCRYPT: + pgp_mpi_free(pk->pub.elg.p); + pgp_mpi_free(pk->pub.elg.g); + pgp_mpi_free(pk->pub.elg.y); + pgp_mpi_free(pk->sec.elg.x); + break; + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + pgp_mpi_free(pk->pub.rsa.n); + pgp_mpi_free(pk->pub.rsa.e); + pgp_mpi_free(pk->sec.rsa.d); + pgp_mpi_free(pk->sec.rsa.p); + pgp_mpi_free(pk->sec.rsa.q); + pgp_mpi_free(pk->sec.rsa.u); + break; + case PGP_PUB_DSA_SIGN: + pgp_mpi_free(pk->pub.dsa.p); + pgp_mpi_free(pk->pub.dsa.q); + pgp_mpi_free(pk->pub.dsa.g); + pgp_mpi_free(pk->pub.dsa.y); + pgp_mpi_free(pk->sec.dsa.x); + break; + } + px_memset(pk, 0, sizeof(*pk)); + pfree(pk); +} + +static int +calc_key_id(PGP_PubKey *pk) +{ + int res; + PX_MD *md; + int len; + uint8 hdr[3]; + uint8 hash[20]; + + res = pgp_load_digest(PGP_DIGEST_SHA1, &md); + if (res < 0) + return res; + + len = 1 + 4 + 1; + switch (pk->algo) + { + case PGP_PUB_ELG_ENCRYPT: + len += 2 + pk->pub.elg.p->bytes; + len += 2 + pk->pub.elg.g->bytes; + len += 2 + pk->pub.elg.y->bytes; + break; + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + len += 2 + pk->pub.rsa.n->bytes; + len += 2 + pk->pub.rsa.e->bytes; + break; + case PGP_PUB_DSA_SIGN: + len += 2 + pk->pub.dsa.p->bytes; + len += 2 + pk->pub.dsa.q->bytes; + len += 2 + pk->pub.dsa.g->bytes; + len += 2 + pk->pub.dsa.y->bytes; + break; + } + + hdr[0] = 0x99; + hdr[1] = len >> 8; + hdr[2] = len & 0xFF; + px_md_update(md, hdr, 3); + + px_md_update(md, &pk->ver, 1); + px_md_update(md, pk->time, 4); + px_md_update(md, &pk->algo, 1); + + switch (pk->algo) + { + case PGP_PUB_ELG_ENCRYPT: + pgp_mpi_hash(md, pk->pub.elg.p); + pgp_mpi_hash(md, pk->pub.elg.g); + pgp_mpi_hash(md, pk->pub.elg.y); + break; + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + pgp_mpi_hash(md, pk->pub.rsa.n); + pgp_mpi_hash(md, pk->pub.rsa.e); + break; + case PGP_PUB_DSA_SIGN: + pgp_mpi_hash(md, pk->pub.dsa.p); + pgp_mpi_hash(md, pk->pub.dsa.q); + pgp_mpi_hash(md, pk->pub.dsa.g); + pgp_mpi_hash(md, pk->pub.dsa.y); + break; + } + + px_md_finish(md, hash); + px_md_free(md); + + memcpy(pk->key_id, hash + 12, 8); + px_memset(hash, 0, 20); + + return 0; +} + +int +_pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p) +{ + int res; + PGP_PubKey *pk; + + res = pgp_key_alloc(&pk); + if (res < 0) + return res; + + /* get version */ + GETBYTE(pkt, pk->ver); + if (pk->ver != 4) + { + res = PXE_PGP_NOT_V4_KEYPKT; + goto out; + } + + /* read time */ + res = pullf_read_fixed(pkt, 4, pk->time); + if (res < 0) + goto out; + + /* pubkey algorithm */ + GETBYTE(pkt, pk->algo); + + switch (pk->algo) + { + case PGP_PUB_DSA_SIGN: + res = pgp_mpi_read(pkt, &pk->pub.dsa.p); + if (res < 0) + break; + res = pgp_mpi_read(pkt, &pk->pub.dsa.q); + if (res < 0) + break; + res = pgp_mpi_read(pkt, &pk->pub.dsa.g); + if (res < 0) + break; + res = pgp_mpi_read(pkt, &pk->pub.dsa.y); + if (res < 0) + break; + + res = calc_key_id(pk); + break; + + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + res = pgp_mpi_read(pkt, &pk->pub.rsa.n); + if (res < 0) + break; + res = pgp_mpi_read(pkt, &pk->pub.rsa.e); + if (res < 0) + break; + + res = calc_key_id(pk); + + if (pk->algo != PGP_PUB_RSA_SIGN) + pk->can_encrypt = 1; + break; + + case PGP_PUB_ELG_ENCRYPT: + res = pgp_mpi_read(pkt, &pk->pub.elg.p); + if (res < 0) + break; + res = pgp_mpi_read(pkt, &pk->pub.elg.g); + if (res < 0) + break; + res = pgp_mpi_read(pkt, &pk->pub.elg.y); + if (res < 0) + break; + + res = calc_key_id(pk); + + pk->can_encrypt = 1; + break; + + default: + px_debug("unknown public algo: %d", pk->algo); + res = PXE_PGP_UNKNOWN_PUBALGO; + } + +out: + if (res < 0) + pgp_key_free(pk); + else + *pk_p = pk; + + return res; +} + +#define HIDE_CLEAR 0 +#define HIDE_CKSUM 255 +#define HIDE_SHA1 254 + +static int +check_key_sha1(PullFilter *src, PGP_PubKey *pk) +{ + int res; + uint8 got_sha1[20]; + uint8 my_sha1[20]; + PX_MD *md; + + res = pullf_read_fixed(src, 20, got_sha1); + if (res < 0) + return res; + + res = pgp_load_digest(PGP_DIGEST_SHA1, &md); + if (res < 0) + goto err; + switch (pk->algo) + { + case PGP_PUB_ELG_ENCRYPT: + pgp_mpi_hash(md, pk->sec.elg.x); + break; + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + pgp_mpi_hash(md, pk->sec.rsa.d); + pgp_mpi_hash(md, pk->sec.rsa.p); + pgp_mpi_hash(md, pk->sec.rsa.q); + pgp_mpi_hash(md, pk->sec.rsa.u); + break; + case PGP_PUB_DSA_SIGN: + pgp_mpi_hash(md, pk->sec.dsa.x); + break; + } + px_md_finish(md, my_sha1); + px_md_free(md); + + if (memcmp(my_sha1, got_sha1, 20) != 0) + { + px_debug("key sha1 check failed"); + res = PXE_PGP_KEYPKT_CORRUPT; + } +err: + px_memset(got_sha1, 0, 20); + px_memset(my_sha1, 0, 20); + return res; +} + +static int +check_key_cksum(PullFilter *src, PGP_PubKey *pk) +{ + int res; + unsigned got_cksum, + my_cksum = 0; + uint8 buf[2]; + + res = pullf_read_fixed(src, 2, buf); + if (res < 0) + return res; + + got_cksum = ((unsigned) buf[0] << 8) + buf[1]; + switch (pk->algo) + { + case PGP_PUB_ELG_ENCRYPT: + my_cksum = pgp_mpi_cksum(0, pk->sec.elg.x); + break; + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + my_cksum = pgp_mpi_cksum(0, pk->sec.rsa.d); + my_cksum = pgp_mpi_cksum(my_cksum, pk->sec.rsa.p); + my_cksum = pgp_mpi_cksum(my_cksum, pk->sec.rsa.q); + my_cksum = pgp_mpi_cksum(my_cksum, pk->sec.rsa.u); + break; + case PGP_PUB_DSA_SIGN: + my_cksum = pgp_mpi_cksum(0, pk->sec.dsa.x); + break; + } + if (my_cksum != got_cksum) + { + px_debug("key cksum check failed"); + return PXE_PGP_KEYPKT_CORRUPT; + } + return 0; +} + +static int +process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p, + const uint8 *key, int key_len) +{ + int res; + int hide_type; + int cipher_algo; + int bs; + uint8 iv[512]; + PullFilter *pf_decrypt = NULL, + *pf_key; + PGP_CFB *cfb = NULL; + PGP_S2K s2k; + PGP_PubKey *pk; + + /* first read public key part */ + res = _pgp_read_public_key(pkt, &pk); + if (res < 0) + return res; + + /* + * is secret key encrypted? + */ + GETBYTE(pkt, hide_type); + if (hide_type == HIDE_SHA1 || hide_type == HIDE_CKSUM) + { + if (key == NULL) + return PXE_PGP_NEED_SECRET_PSW; + GETBYTE(pkt, cipher_algo); + res = pgp_s2k_read(pkt, &s2k); + if (res < 0) + return res; + + res = pgp_s2k_process(&s2k, cipher_algo, key, key_len); + if (res < 0) + return res; + + bs = pgp_get_cipher_block_size(cipher_algo); + if (bs == 0) + { + px_debug("unknown cipher algo=%d", cipher_algo); + return PXE_PGP_UNSUPPORTED_CIPHER; + } + res = pullf_read_fixed(pkt, bs, iv); + if (res < 0) + return res; + + /* + * create decrypt filter + */ + res = pgp_cfb_create(&cfb, cipher_algo, s2k.key, s2k.key_len, 0, iv); + if (res < 0) + return res; + res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt); + if (res < 0) + return res; + pf_key = pf_decrypt; + } + else if (hide_type == HIDE_CLEAR) + { + pf_key = pkt; + } + else + { + px_debug("unknown hide type"); + return PXE_PGP_KEYPKT_CORRUPT; + } + + /* read secret key */ + switch (pk->algo) + { + case PGP_PUB_RSA_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_ENCRYPT_SIGN: + res = pgp_mpi_read(pf_key, &pk->sec.rsa.d); + if (res < 0) + break; + res = pgp_mpi_read(pf_key, &pk->sec.rsa.p); + if (res < 0) + break; + res = pgp_mpi_read(pf_key, &pk->sec.rsa.q); + if (res < 0) + break; + res = pgp_mpi_read(pf_key, &pk->sec.rsa.u); + if (res < 0) + break; + break; + case PGP_PUB_ELG_ENCRYPT: + res = pgp_mpi_read(pf_key, &pk->sec.elg.x); + break; + case PGP_PUB_DSA_SIGN: + res = pgp_mpi_read(pf_key, &pk->sec.dsa.x); + break; + default: + px_debug("unknown public algo: %d", pk->algo); + res = PXE_PGP_KEYPKT_CORRUPT; + } + /* read checksum / sha1 */ + if (res >= 0) + { + if (hide_type == HIDE_SHA1) + res = check_key_sha1(pf_key, pk); + else + res = check_key_cksum(pf_key, pk); + } + if (res >= 0) + res = pgp_expect_packet_end(pf_key); + + if (pf_decrypt) + pullf_free(pf_decrypt); + if (cfb) + pgp_cfb_free(cfb); + + if (res < 0) + pgp_key_free(pk); + else + *pk_p = pk; + + return res; +} + +static int +internal_read_key(PullFilter *src, PGP_PubKey **pk_p, + const uint8 *psw, int psw_len, int pubtype) +{ + PullFilter *pkt = NULL; + int res; + uint8 tag; + int len; + PGP_PubKey *enc_key = NULL; + PGP_PubKey *pk = NULL; + int got_main_key = 0; + + /* + * Search for encryption key. + * + * Error out on anything fancy. + */ + 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_PUBLIC_KEY: + case PGP_PKT_SECRET_KEY: + if (got_main_key) + { + res = PXE_PGP_MULTIPLE_KEYS; + break; + } + got_main_key = 1; + res = pgp_skip_packet(pkt); + break; + + case PGP_PKT_PUBLIC_SUBKEY: + if (pubtype != 0) + res = PXE_PGP_EXPECT_SECRET_KEY; + else + res = _pgp_read_public_key(pkt, &pk); + break; + + case PGP_PKT_SECRET_SUBKEY: + if (pubtype != 1) + res = PXE_PGP_EXPECT_PUBLIC_KEY; + else + res = process_secret_key(pkt, &pk, psw, psw_len); + break; + + 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: + px_debug("unknown/unexpected packet: %d", tag); + res = PXE_PGP_UNEXPECTED_PKT; + } + pullf_free(pkt); + pkt = NULL; + + if (pk != NULL) + { + if (res >= 0 && pk->can_encrypt) + { + if (enc_key == NULL) + { + enc_key = pk; + pk = NULL; + } + else + res = PXE_PGP_MULTIPLE_SUBKEYS; + } + + if (pk) + pgp_key_free(pk); + pk = NULL; + } + + if (res < 0) + break; + } + + if (pkt) + pullf_free(pkt); + + if (res < 0) + { + if (enc_key) + pgp_key_free(enc_key); + return res; + } + + if (!enc_key) + res = PXE_PGP_NO_USABLE_KEY; + else + *pk_p = enc_key; + return res; +} + +int +pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt, + const uint8 *key, int key_len, int pubtype) +{ + int res; + PullFilter *src; + PGP_PubKey *pk = NULL; + + res = pullf_create_mbuf_reader(&src, keypkt); + if (res < 0) + return res; + + res = internal_read_key(src, &pk, key, key_len, pubtype); + pullf_free(src); + + if (res >= 0) + ctx->pub_key = pk; + + return res < 0 ? res : 0; +} diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c new file mode 100644 index 0000000..81ca1f0 --- /dev/null +++ b/contrib/pgcrypto/pgp-s2k.c @@ -0,0 +1,308 @@ +/* + * pgp-s2k.c + * OpenPGP string2key 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-s2k.c + */ + +#include "postgres.h" + +#include "pgp.h" +#include "px.h" + +static int +calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key, + unsigned key_len) +{ + unsigned md_rlen; + uint8 buf[PGP_MAX_DIGEST]; + unsigned preload; + unsigned remain; + uint8 *dst = s2k->key; + + md_rlen = px_md_result_size(md); + + remain = s2k->key_len; + preload = 0; + while (remain > 0) + { + px_md_reset(md); + + if (preload) + { + memset(buf, 0, preload); + px_md_update(md, buf, preload); + } + preload++; + + px_md_update(md, key, key_len); + px_md_finish(md, buf); + + if (remain > md_rlen) + { + memcpy(dst, buf, md_rlen); + dst += md_rlen; + remain -= md_rlen; + } + else + { + memcpy(dst, buf, remain); + remain = 0; + } + } + px_memset(buf, 0, sizeof(buf)); + return 0; +} + +static int +calc_s2k_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned key_len) +{ + unsigned md_rlen; + uint8 buf[PGP_MAX_DIGEST]; + unsigned preload = 0; + uint8 *dst; + unsigned remain; + + md_rlen = px_md_result_size(md); + + dst = s2k->key; + remain = s2k->key_len; + while (remain > 0) + { + px_md_reset(md); + + if (preload > 0) + { + memset(buf, 0, preload); + px_md_update(md, buf, preload); + } + preload++; + + px_md_update(md, s2k->salt, PGP_S2K_SALT); + px_md_update(md, key, key_len); + px_md_finish(md, buf); + + if (remain > md_rlen) + { + memcpy(dst, buf, md_rlen); + remain -= md_rlen; + dst += md_rlen; + } + else + { + memcpy(dst, buf, remain); + remain = 0; + } + } + px_memset(buf, 0, sizeof(buf)); + return 0; +} + +static int +calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, + unsigned key_len) +{ + unsigned md_rlen; + uint8 buf[PGP_MAX_DIGEST]; + uint8 *dst; + unsigned preload = 0; + unsigned remain, + c, + curcnt, + count; + + count = s2k_decode_count(s2k->iter); + + md_rlen = px_md_result_size(md); + + remain = s2k->key_len; + dst = s2k->key; + while (remain > 0) + { + px_md_reset(md); + + if (preload) + { + memset(buf, 0, preload); + px_md_update(md, buf, preload); + } + preload++; + + px_md_update(md, s2k->salt, PGP_S2K_SALT); + px_md_update(md, key, key_len); + curcnt = PGP_S2K_SALT + key_len; + + while (curcnt < count) + { + if (curcnt + PGP_S2K_SALT < count) + c = PGP_S2K_SALT; + else + c = count - curcnt; + px_md_update(md, s2k->salt, c); + curcnt += c; + + if (curcnt + key_len < count) + c = key_len; + else if (curcnt < count) + c = count - curcnt; + else + break; + px_md_update(md, key, c); + curcnt += c; + } + px_md_finish(md, buf); + + if (remain > md_rlen) + { + memcpy(dst, buf, md_rlen); + remain -= md_rlen; + dst += md_rlen; + } + else + { + memcpy(dst, buf, remain); + remain = 0; + } + } + px_memset(buf, 0, sizeof(buf)); + return 0; +} + +/* + * Decide PGP_S2K_ISALTED iteration count (in OpenPGP one-byte representation) + * + * Too small: weak + * Too big: slow + * gpg defaults to 96 => 65536 iters + * + * For our default (count=-1) we let it float a bit: 96 + 32 => between 65536 + * and 262144 iterations. + * + * Otherwise, find the smallest number which provides at least the specified + * iteration count. + */ +static uint8 +decide_s2k_iter(unsigned rand_byte, int count) +{ + int iter; + + if (count == -1) + return 96 + (rand_byte & 0x1F); + /* this is a bit brute-force, but should be quick enough */ + for (iter = 0; iter <= 255; iter++) + if (s2k_decode_count(iter) >= count) + return iter; + return 255; +} + +int +pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count) +{ + int res = 0; + uint8 tmp; + + s2k->mode = mode; + s2k->digest_algo = digest_algo; + + switch (s2k->mode) + { + case PGP_S2K_SIMPLE: + break; + case PGP_S2K_SALTED: + if (!pg_strong_random(s2k->salt, PGP_S2K_SALT)) + return PXE_NO_RANDOM; + break; + case PGP_S2K_ISALTED: + if (!pg_strong_random(s2k->salt, PGP_S2K_SALT)) + return PXE_NO_RANDOM; + if (!pg_strong_random(&tmp, 1)) + return PXE_NO_RANDOM; + s2k->iter = decide_s2k_iter(tmp, count); + break; + default: + res = PXE_PGP_BAD_S2K_MODE; + } + return res; +} + +int +pgp_s2k_read(PullFilter *src, PGP_S2K *s2k) +{ + int res = 0; + + GETBYTE(src, s2k->mode); + GETBYTE(src, s2k->digest_algo); + switch (s2k->mode) + { + case 0: + break; + case 1: + res = pullf_read_fixed(src, 8, s2k->salt); + break; + case 3: + res = pullf_read_fixed(src, 8, s2k->salt); + if (res < 0) + break; + GETBYTE(src, s2k->iter); + break; + default: + res = PXE_PGP_BAD_S2K_MODE; + } + return res; +} + +int +pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len) +{ + int res; + PX_MD *md; + + s2k->key_len = pgp_get_cipher_key_size(cipher); + if (s2k->key_len <= 0) + return PXE_PGP_UNSUPPORTED_CIPHER; + + res = pgp_load_digest(s2k->digest_algo, &md); + if (res < 0) + return res; + + switch (s2k->mode) + { + case 0: + res = calc_s2k_simple(s2k, md, key, key_len); + break; + case 1: + res = calc_s2k_salted(s2k, md, key, key_len); + break; + case 3: + res = calc_s2k_iter_salted(s2k, md, key, key_len); + break; + default: + res = PXE_PGP_BAD_S2K_MODE; + } + px_md_free(md); + return res; +} diff --git a/contrib/pgcrypto/pgp.c b/contrib/pgcrypto/pgp.c new file mode 100644 index 0000000..3e9c2fe --- /dev/null +++ b/contrib/pgcrypto/pgp.c @@ -0,0 +1,370 @@ +/* + * pgp.c + * Various utility stuff. + * + * 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.c + */ + +#include "postgres.h" + +#include "pgp.h" +#include "px.h" + +/* + * Defaults. + */ +static int def_cipher_algo = PGP_SYM_AES_128; +static int def_s2k_cipher_algo = -1; +static int def_s2k_mode = PGP_S2K_ISALTED; +static int def_s2k_count = -1; +static int def_s2k_digest_algo = PGP_DIGEST_SHA1; +static int def_compress_algo = PGP_COMPR_NONE; +static int def_compress_level = 6; +static int def_disable_mdc = 0; +static int def_use_sess_key = 0; +static int def_text_mode = 0; +static int def_unicode_mode = 0; +static int def_convert_crlf = 0; + +struct digest_info +{ + const char *name; + int code; +}; + +struct cipher_info +{ + const char *name; + int code; + const char *int_name; + int key_len; + int block_len; +}; + +static const struct digest_info digest_list[] = { + {"md5", PGP_DIGEST_MD5}, + {"sha1", PGP_DIGEST_SHA1}, + {"sha-1", PGP_DIGEST_SHA1}, + {"ripemd160", PGP_DIGEST_RIPEMD160}, + {"sha256", PGP_DIGEST_SHA256}, + {"sha384", PGP_DIGEST_SHA384}, + {"sha512", PGP_DIGEST_SHA512}, + {NULL, 0} +}; + +static const struct cipher_info cipher_list[] = { + {"3des", PGP_SYM_DES3, "3des-ecb", 192 / 8, 64 / 8}, + {"cast5", PGP_SYM_CAST5, "cast5-ecb", 128 / 8, 64 / 8}, + {"bf", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8}, + {"blowfish", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8}, + {"aes", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8}, + {"aes128", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8}, + {"aes192", PGP_SYM_AES_192, "aes-ecb", 192 / 8, 128 / 8}, + {"aes256", PGP_SYM_AES_256, "aes-ecb", 256 / 8, 128 / 8}, + {"twofish", PGP_SYM_TWOFISH, "twofish-ecb", 256 / 8, 128 / 8}, + {NULL, 0, NULL} +}; + +static const struct cipher_info * +get_cipher_info(int code) +{ + const struct cipher_info *i; + + for (i = cipher_list; i->name; i++) + if (i->code == code) + return i; + return NULL; +} + +int +pgp_get_digest_code(const char *name) +{ + const struct digest_info *i; + + for (i = digest_list; i->name; i++) + if (pg_strcasecmp(i->name, name) == 0) + return i->code; + return PXE_PGP_UNSUPPORTED_HASH; +} + +int +pgp_get_cipher_code(const char *name) +{ + const struct cipher_info *i; + + for (i = cipher_list; i->name; i++) + if (pg_strcasecmp(i->name, name) == 0) + return i->code; + return PXE_PGP_UNSUPPORTED_CIPHER; +} + +const char * +pgp_get_digest_name(int code) +{ + const struct digest_info *i; + + for (i = digest_list; i->name; i++) + if (i->code == code) + return i->name; + return NULL; +} + +const char * +pgp_get_cipher_name(int code) +{ + const struct cipher_info *i = get_cipher_info(code); + + if (i != NULL) + return i->name; + return NULL; +} + +int +pgp_get_cipher_key_size(int code) +{ + const struct cipher_info *i = get_cipher_info(code); + + if (i != NULL) + return i->key_len; + return 0; +} + +int +pgp_get_cipher_block_size(int code) +{ + const struct cipher_info *i = get_cipher_info(code); + + if (i != NULL) + return i->block_len; + return 0; +} + +int +pgp_load_cipher(int code, PX_Cipher **res) +{ + int err; + const struct cipher_info *i = get_cipher_info(code); + + if (i == NULL) + return PXE_PGP_CORRUPT_DATA; + + err = px_find_cipher(i->int_name, res); + if (err == 0) + return 0; + + return PXE_PGP_UNSUPPORTED_CIPHER; +} + +int +pgp_load_digest(int code, PX_MD **res) +{ + int err; + const char *name = pgp_get_digest_name(code); + + if (name == NULL) + return PXE_PGP_CORRUPT_DATA; + + err = px_find_digest(name, res); + if (err == 0) + return 0; + + return PXE_PGP_UNSUPPORTED_HASH; +} + +int +pgp_init(PGP_Context **ctx_p) +{ + PGP_Context *ctx; + + ctx = palloc0(sizeof *ctx); + + ctx->cipher_algo = def_cipher_algo; + ctx->s2k_cipher_algo = def_s2k_cipher_algo; + ctx->s2k_mode = def_s2k_mode; + ctx->s2k_count = def_s2k_count; + ctx->s2k_digest_algo = def_s2k_digest_algo; + ctx->compress_algo = def_compress_algo; + ctx->compress_level = def_compress_level; + ctx->disable_mdc = def_disable_mdc; + ctx->use_sess_key = def_use_sess_key; + ctx->unicode_mode = def_unicode_mode; + ctx->convert_crlf = def_convert_crlf; + ctx->text_mode = def_text_mode; + + *ctx_p = ctx; + return 0; +} + +int +pgp_free(PGP_Context *ctx) +{ + if (ctx->pub_key) + pgp_key_free(ctx->pub_key); + px_memset(ctx, 0, sizeof *ctx); + pfree(ctx); + return 0; +} + +int +pgp_disable_mdc(PGP_Context *ctx, int disable) +{ + ctx->disable_mdc = disable ? 1 : 0; + return 0; +} + +int +pgp_set_sess_key(PGP_Context *ctx, int use) +{ + ctx->use_sess_key = use ? 1 : 0; + return 0; +} + +int +pgp_set_convert_crlf(PGP_Context *ctx, int doit) +{ + ctx->convert_crlf = doit ? 1 : 0; + return 0; +} + +int +pgp_set_s2k_mode(PGP_Context *ctx, int mode) +{ + int err = PXE_OK; + + switch (mode) + { + case PGP_S2K_SIMPLE: + case PGP_S2K_SALTED: + case PGP_S2K_ISALTED: + ctx->s2k_mode = mode; + break; + default: + err = PXE_ARGUMENT_ERROR; + break; + } + return err; +} + +int +pgp_set_s2k_count(PGP_Context *ctx, int count) +{ + if (ctx->s2k_mode == PGP_S2K_ISALTED && count >= 1024 && count <= 65011712) + { + ctx->s2k_count = count; + return PXE_OK; + } + return PXE_ARGUMENT_ERROR; +} + +int +pgp_set_compress_algo(PGP_Context *ctx, int algo) +{ + switch (algo) + { + case PGP_COMPR_NONE: + case PGP_COMPR_ZIP: + case PGP_COMPR_ZLIB: + case PGP_COMPR_BZIP2: + ctx->compress_algo = algo; + return 0; + } + return PXE_ARGUMENT_ERROR; +} + +int +pgp_set_compress_level(PGP_Context *ctx, int level) +{ + if (level >= 0 && level <= 9) + { + ctx->compress_level = level; + return 0; + } + return PXE_ARGUMENT_ERROR; +} + +int +pgp_set_text_mode(PGP_Context *ctx, int mode) +{ + ctx->text_mode = mode; + return 0; +} + +int +pgp_set_cipher_algo(PGP_Context *ctx, const char *name) +{ + int code = pgp_get_cipher_code(name); + + if (code < 0) + return code; + ctx->cipher_algo = code; + return 0; +} + +int +pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name) +{ + int code = pgp_get_cipher_code(name); + + if (code < 0) + return code; + ctx->s2k_cipher_algo = code; + return 0; +} + +int +pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name) +{ + int code = pgp_get_digest_code(name); + + if (code < 0) + return code; + ctx->s2k_digest_algo = code; + return 0; +} + +int +pgp_get_unicode_mode(PGP_Context *ctx) +{ + return ctx->unicode_mode; +} + +int +pgp_set_unicode_mode(PGP_Context *ctx, int mode) +{ + ctx->unicode_mode = mode ? 1 : 0; + return 0; +} + +int +pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int len) +{ + if (key == NULL || len < 1) + return PXE_ARGUMENT_ERROR; + ctx->sym_key = key; + ctx->sym_key_len = len; + return 0; +} diff --git a/contrib/pgcrypto/pgp.h b/contrib/pgcrypto/pgp.h new file mode 100644 index 0000000..f338523 --- /dev/null +++ b/contrib/pgcrypto/pgp.h @@ -0,0 +1,327 @@ +/* + * pgp.h + * OpenPGP implementation. + * + * 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.h + */ + +#include "lib/stringinfo.h" + +#include "mbuf.h" +#include "px.h" + +enum PGP_S2K_TYPE +{ + PGP_S2K_SIMPLE = 0, + PGP_S2K_SALTED = 1, + PGP_S2K_ISALTED = 3 +}; + +enum PGP_PKT_TYPE +{ + PGP_PKT_RESERVED = 0, + PGP_PKT_PUBENCRYPTED_SESSKEY = 1, + PGP_PKT_SIGNATURE = 2, + PGP_PKT_SYMENCRYPTED_SESSKEY = 3, + PGP_PKT_SECRET_KEY = 5, + PGP_PKT_PUBLIC_KEY = 6, + PGP_PKT_SECRET_SUBKEY = 7, + PGP_PKT_COMPRESSED_DATA = 8, + PGP_PKT_SYMENCRYPTED_DATA = 9, + PGP_PKT_MARKER = 10, + PGP_PKT_LITERAL_DATA = 11, + PGP_PKT_TRUST = 12, + PGP_PKT_USER_ID = 13, + PGP_PKT_PUBLIC_SUBKEY = 14, + PGP_PKT_USER_ATTR = 17, + PGP_PKT_SYMENCRYPTED_DATA_MDC = 18, + PGP_PKT_MDC = 19, + PGP_PKT_PRIV_61 = 61 /* occurs in gpg secring */ +}; + +enum PGP_PUB_ALGO_TYPE +{ + PGP_PUB_RSA_ENCRYPT_SIGN = 1, + PGP_PUB_RSA_ENCRYPT = 2, + PGP_PUB_RSA_SIGN = 3, + PGP_PUB_ELG_ENCRYPT = 16, + PGP_PUB_DSA_SIGN = 17 +}; + +enum PGP_SYMENC_TYPE +{ + PGP_SYM_PLAIN = 0, /* ?? */ + PGP_SYM_IDEA = 1, /* obsolete, PGP 2.6 compat */ + PGP_SYM_DES3 = 2, /* must */ + PGP_SYM_CAST5 = 3, /* should */ + PGP_SYM_BLOWFISH = 4, + PGP_SYM_SAFER_SK128 = 5, /* obsolete */ + PGP_SYM_DES_SK = 6, /* obsolete */ + PGP_SYM_AES_128 = 7, /* should */ + PGP_SYM_AES_192 = 8, + PGP_SYM_AES_256 = 9, + PGP_SYM_TWOFISH = 10 +}; + +enum PGP_COMPR_TYPE +{ + PGP_COMPR_NONE = 0, /* must */ + PGP_COMPR_ZIP = 1, /* should */ + PGP_COMPR_ZLIB = 2, + PGP_COMPR_BZIP2 = 3 +}; + +enum PGP_DIGEST_TYPE +{ + PGP_DIGEST_MD5 = 1, /* should, deprecated */ + PGP_DIGEST_SHA1 = 2, /* must */ + PGP_DIGEST_RIPEMD160 = 3, + PGP_DIGEST_XSHA = 4, /* obsolete */ + PGP_DIGEST_MD2 = 5, /* obsolete */ + PGP_DIGEST_TIGER192 = 6, /* obsolete */ + PGP_DIGEST_HAVAL5_160 = 7, /* obsolete */ + PGP_DIGEST_SHA256 = 8, + PGP_DIGEST_SHA384 = 9, + PGP_DIGEST_SHA512 = 10 +}; + +#define PGP_MAX_KEY (256/8) +#define PGP_MAX_BLOCK (256/8) +#define PGP_MAX_DIGEST (512/8) +#define PGP_S2K_SALT 8 + +typedef struct PGP_MPI PGP_MPI; +typedef struct PGP_PubKey PGP_PubKey; +typedef struct PGP_Context PGP_Context; +typedef struct PGP_S2K PGP_S2K; + +struct PGP_S2K +{ + uint8 mode; + uint8 digest_algo; + uint8 salt[8]; + uint8 iter; /* encoded (one-octet) count */ + /* calculated: */ + uint8 key[PGP_MAX_KEY]; + uint8 key_len; +}; + + +struct PGP_Context +{ + /* + * parameters + */ + PGP_S2K s2k; + int s2k_mode; + int s2k_count; /* 4-byte decoded count */ + int s2k_digest_algo; + int s2k_cipher_algo; + int cipher_algo; + int compress_algo; + int compress_level; + int disable_mdc; + int use_sess_key; + int text_mode; + int convert_crlf; + int unicode_mode; + + /* + * internal variables + */ + int mdc_checked; + int corrupt_prefix; /* prefix failed RFC 4880 "quick check" */ + int unsupported_compr; /* has bzip2 compression */ + int unexpected_binary; /* binary data seen in text_mode */ + int in_mdc_pkt; + int use_mdcbuf_filter; + PX_MD *mdc_ctx; + + PGP_PubKey *pub_key; /* ctx owns it */ + const uint8 *sym_key; /* ctx does not own it */ + int sym_key_len; + + /* + * read or generated data + */ + uint8 sess_key[PGP_MAX_KEY]; + unsigned sess_key_len; +}; + +/* from RFC 4880 3.7.1.3 */ +#define s2k_decode_count(cval) \ + (((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6)) + +struct PGP_MPI +{ + uint8 *data; + int bits; + int bytes; +}; + +struct PGP_PubKey +{ + uint8 ver; + uint8 time[4]; + uint8 algo; + + /* public part */ + union + { + struct + { + PGP_MPI *p; + PGP_MPI *g; + PGP_MPI *y; + } elg; + struct + { + PGP_MPI *n; + PGP_MPI *e; + } rsa; + struct + { + PGP_MPI *p; + PGP_MPI *q; + PGP_MPI *g; + PGP_MPI *y; + } dsa; + } pub; + + /* secret part */ + union + { + struct + { + PGP_MPI *x; + } elg; + struct + { + PGP_MPI *d; + PGP_MPI *p; + PGP_MPI *q; + PGP_MPI *u; + } rsa; + struct + { + PGP_MPI *x; + } dsa; + } sec; + + uint8 key_id[8]; + int can_encrypt; +}; + +int pgp_init(PGP_Context **ctx); +int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst); +int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst); +int pgp_free(PGP_Context *ctx); + +int pgp_get_digest_code(const char *name); +int pgp_get_cipher_code(const char *name); +const char *pgp_get_digest_name(int code); +const char *pgp_get_cipher_name(int code); + +int pgp_set_cipher_algo(PGP_Context *ctx, const char *name); +int pgp_set_s2k_mode(PGP_Context *ctx, int type); +int pgp_set_s2k_count(PGP_Context *ctx, int count); +int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name); +int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name); +int pgp_set_convert_crlf(PGP_Context *ctx, int doit); +int pgp_disable_mdc(PGP_Context *ctx, int disable); +int pgp_set_sess_key(PGP_Context *ctx, int use); +int pgp_set_compress_algo(PGP_Context *ctx, int algo); +int pgp_set_compress_level(PGP_Context *ctx, int level); +int pgp_set_text_mode(PGP_Context *ctx, int mode); +int pgp_set_unicode_mode(PGP_Context *ctx, int mode); +int pgp_get_unicode_mode(PGP_Context *ctx); + +int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen); +int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt, + const uint8 *key, int klen, int pubtype); + +int pgp_get_keyid(MBuf *pgp_data, char *dst); + +/* internal functions */ + +int pgp_load_digest(int c, PX_MD **res); +int pgp_load_cipher(int c, PX_Cipher **res); +int pgp_get_cipher_key_size(int c); +int pgp_get_cipher_block_size(int c); + +int pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count); +int pgp_s2k_read(PullFilter *src, PGP_S2K *s2k); +int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen); + +typedef struct PGP_CFB PGP_CFB; +int pgp_cfb_create(PGP_CFB **ctx_p, int algo, + const uint8 *key, int key_len, int resync, uint8 *iv); +void pgp_cfb_free(PGP_CFB *ctx); +int pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst); +int pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst); + +void pgp_armor_encode(const uint8 *src, unsigned len, StringInfo dst, + int num_headers, char **keys, char **values); +int pgp_armor_decode(const uint8 *src, int len, StringInfo dst); +int pgp_extract_armor_headers(const uint8 *src, unsigned len, + int *nheaders, char ***keys, char ***values); + +int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst); +int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src); + +int pgp_key_alloc(PGP_PubKey **pk_p); +void pgp_key_free(PGP_PubKey *pk); +int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p); + +int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt); +int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len, + int pkttype, PGP_Context *ctx); +int pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, + int allow_ctx); + +int pgp_skip_packet(PullFilter *pkt); +int pgp_expect_packet_end(PullFilter *pkt); + +int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst); +int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p); + +int pgp_mpi_alloc(int bits, PGP_MPI **mpi); +int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi); +int pgp_mpi_free(PGP_MPI *mpi); +int pgp_mpi_read(PullFilter *src, PGP_MPI **mpi); +int pgp_mpi_write(PushFilter *dst, PGP_MPI *n); +int pgp_mpi_hash(PX_MD *md, PGP_MPI *n); +unsigned pgp_mpi_cksum(unsigned cksum, PGP_MPI *n); + +int pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *m, + PGP_MPI **c1, PGP_MPI **c2); +int pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *c1, PGP_MPI *c2, + PGP_MPI **m); +int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c); +int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m); + +extern struct PullFilterOps pgp_decrypt_filter; diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c new file mode 100644 index 0000000..0913ff2 --- /dev/null +++ b/contrib/pgcrypto/px-crypt.c @@ -0,0 +1,164 @@ +/* + * px-crypt.c + * Wrapper for various crypt algorithms. + * + * Copyright (c) 2001 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/px-crypt.c + */ + +#include "postgres.h" + +#include "px-crypt.h" +#include "px.h" + +static char * +run_crypt_des(const char *psw, const char *salt, + char *buf, unsigned len) +{ + char *res; + + res = px_crypt_des(psw, salt); + if (res == NULL || strlen(res) > len - 1) + return NULL; + strcpy(buf, res); + return buf; +} + +static char * +run_crypt_md5(const char *psw, const char *salt, + char *buf, unsigned len) +{ + char *res; + + res = px_crypt_md5(psw, salt, buf, len); + return res; +} + +static char * +run_crypt_bf(const char *psw, const char *salt, + char *buf, unsigned len) +{ + char *res; + + res = _crypt_blowfish_rn(psw, salt, buf, len); + return res; +} + +struct px_crypt_algo +{ + char *id; + unsigned id_len; + char *(*crypt) (const char *psw, const char *salt, + char *buf, unsigned len); +}; + +static const struct px_crypt_algo + px_crypt_list[] = { + {"$2a$", 4, run_crypt_bf}, + {"$2x$", 4, run_crypt_bf}, + {"$2$", 3, NULL}, /* N/A */ + {"$1$", 3, run_crypt_md5}, + {"_", 1, run_crypt_des}, + {"", 0, run_crypt_des}, + {NULL, 0, NULL} +}; + +char * +px_crypt(const char *psw, const char *salt, char *buf, unsigned len) +{ + const struct px_crypt_algo *c; + + for (c = px_crypt_list; c->id; c++) + { + if (!c->id_len) + break; + if (strncmp(salt, c->id, c->id_len) == 0) + break; + } + + if (c->crypt == NULL) + return NULL; + + return c->crypt(psw, salt, buf, len); +} + +/* + * salt generators + */ + +struct generator +{ + char *name; + char *(*gen) (unsigned long count, const char *input, int size, + char *output, int output_size); + int input_len; + int def_rounds; + int min_rounds; + int max_rounds; +}; + +static struct generator gen_list[] = { + {"des", _crypt_gensalt_traditional_rn, 2, 0, 0, 0}, + {"md5", _crypt_gensalt_md5_rn, 6, 0, 0, 0}, + {"xdes", _crypt_gensalt_extended_rn, 3, PX_XDES_ROUNDS, 1, 0xFFFFFF}, + {"bf", _crypt_gensalt_blowfish_rn, 16, PX_BF_ROUNDS, 4, 31}, + {NULL, NULL, 0, 0, 0, 0} +}; + +int +px_gen_salt(const char *salt_type, char *buf, int rounds) +{ + struct generator *g; + char *p; + char rbuf[16]; + + for (g = gen_list; g->name; g++) + if (pg_strcasecmp(g->name, salt_type) == 0) + break; + + if (g->name == NULL) + return PXE_UNKNOWN_SALT_ALGO; + + if (g->def_rounds) + { + if (rounds == 0) + rounds = g->def_rounds; + + if (rounds < g->min_rounds || rounds > g->max_rounds) + return PXE_BAD_SALT_ROUNDS; + } + + if (!pg_strong_random(rbuf, g->input_len)) + return PXE_NO_RANDOM; + + p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN); + px_memset(rbuf, 0, sizeof(rbuf)); + + if (p == NULL) + return PXE_BAD_SALT_ROUNDS; + + return strlen(p); +} diff --git a/contrib/pgcrypto/px-crypt.h b/contrib/pgcrypto/px-crypt.h new file mode 100644 index 0000000..08001a8 --- /dev/null +++ b/contrib/pgcrypto/px-crypt.h @@ -0,0 +1,82 @@ +/* + * px-crypt.h + * Header file for px_crypt(). + * + * Copyright (c) 2001 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/px-crypt.h + */ + +#ifndef _PX_CRYPT_H +#define _PX_CRYPT_H + +/* max room for result */ +#define PX_MAX_CRYPT 128 + +/* max salt returned by gen_salt() */ +#define PX_MAX_SALT_LEN 128 + +/* default rounds for xdes salt */ +/* NetBSD bin/passwd/local_passwd.c has (29 * 25)*/ +#define PX_XDES_ROUNDS (29 * 25) + +/* default for blowfish salt */ +#define PX_BF_ROUNDS 6 + +/* + * main interface + */ +char *px_crypt(const char *psw, const char *salt, char *buf, unsigned buflen); +int px_gen_salt(const char *salt_type, char *dst, int rounds); + +/* + * internal functions + */ + +/* crypt-gensalt.c */ +char *_crypt_gensalt_traditional_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_extended_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_md5_rn(unsigned long count, + const char *input, int size, char *output, int output_size); +char *_crypt_gensalt_blowfish_rn(unsigned long count, + const char *input, int size, char *output, int output_size); + +/* disable 'extended DES crypt' */ +/* #define DISABLE_XDES */ + +/* crypt-blowfish.c */ +char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size); + +/* crypt-des.c */ +char *px_crypt_des(const char *key, const char *setting); + +/* crypt-md5.c */ +char *px_crypt_md5(const char *pw, const char *salt, + char *dst, unsigned dstlen); + +#endif /* _PX_CRYPT_H */ diff --git a/contrib/pgcrypto/px-hmac.c b/contrib/pgcrypto/px-hmac.c new file mode 100644 index 0000000..99174d2 --- /dev/null +++ b/contrib/pgcrypto/px-hmac.c @@ -0,0 +1,176 @@ +/* + * px-hmac.c + * HMAC implementation. + * + * Copyright (c) 2001 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/px-hmac.c + */ + +#include "postgres.h" + +#include "px.h" + +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5C + +static unsigned +hmac_result_size(PX_HMAC *h) +{ + return px_md_result_size(h->md); +} + +static unsigned +hmac_block_size(PX_HMAC *h) +{ + return px_md_block_size(h->md); +} + +static void +hmac_init(PX_HMAC *h, const uint8 *key, unsigned klen) +{ + unsigned bs, + i; + uint8 *keybuf; + PX_MD *md = h->md; + + bs = px_md_block_size(md); + keybuf = palloc0(bs); + + if (klen > bs) + { + px_md_update(md, key, klen); + px_md_finish(md, keybuf); + px_md_reset(md); + } + else + memcpy(keybuf, key, klen); + + for (i = 0; i < bs; i++) + { + h->p.ipad[i] = keybuf[i] ^ HMAC_IPAD; + h->p.opad[i] = keybuf[i] ^ HMAC_OPAD; + } + + px_memset(keybuf, 0, bs); + pfree(keybuf); + + px_md_update(md, h->p.ipad, bs); +} + +static void +hmac_reset(PX_HMAC *h) +{ + PX_MD *md = h->md; + unsigned bs = px_md_block_size(md); + + px_md_reset(md); + px_md_update(md, h->p.ipad, bs); +} + +static void +hmac_update(PX_HMAC *h, const uint8 *data, unsigned dlen) +{ + px_md_update(h->md, data, dlen); +} + +static void +hmac_finish(PX_HMAC *h, uint8 *dst) +{ + PX_MD *md = h->md; + unsigned bs, + hlen; + uint8 *buf; + + bs = px_md_block_size(md); + hlen = px_md_result_size(md); + + buf = palloc(hlen); + + px_md_finish(md, buf); + + px_md_reset(md); + px_md_update(md, h->p.opad, bs); + px_md_update(md, buf, hlen); + px_md_finish(md, dst); + + px_memset(buf, 0, hlen); + pfree(buf); +} + +static void +hmac_free(PX_HMAC *h) +{ + unsigned bs; + + bs = px_md_block_size(h->md); + px_md_free(h->md); + + px_memset(h->p.ipad, 0, bs); + px_memset(h->p.opad, 0, bs); + pfree(h->p.ipad); + pfree(h->p.opad); + pfree(h); +} + + +/* PUBLIC FUNCTIONS */ + +int +px_find_hmac(const char *name, PX_HMAC **res) +{ + int err; + PX_MD *md; + PX_HMAC *h; + unsigned bs; + + err = px_find_digest(name, &md); + if (err) + return err; + + bs = px_md_block_size(md); + if (bs < 2) + { + px_md_free(md); + return PXE_HASH_UNUSABLE_FOR_HMAC; + } + + h = palloc(sizeof(*h)); + h->p.ipad = palloc(bs); + h->p.opad = palloc(bs); + h->md = md; + + h->result_size = hmac_result_size; + h->block_size = hmac_block_size; + h->reset = hmac_reset; + h->update = hmac_update; + h->finish = hmac_finish; + h->free = hmac_free; + h->init = hmac_init; + + *res = h; + + return 0; +} diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c new file mode 100644 index 0000000..3b098c6 --- /dev/null +++ b/contrib/pgcrypto/px.c @@ -0,0 +1,341 @@ +/* + * px.c + * Various cryptographic stuff for PostgreSQL. + * + * Copyright (c) 2001 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/px.c + */ + +#include "postgres.h" + +#include "px.h" + +struct error_desc +{ + int err; + const char *desc; +}; + +static const struct error_desc px_err_list[] = { + {PXE_OK, "Everything ok"}, + {PXE_NO_HASH, "No such hash algorithm"}, + {PXE_NO_CIPHER, "No such cipher algorithm"}, + {PXE_BAD_OPTION, "Unknown option"}, + {PXE_BAD_FORMAT, "Badly formatted type"}, + {PXE_KEY_TOO_BIG, "Key was too big"}, + {PXE_CIPHER_INIT, "Cipher cannot be initialized"}, + {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"}, + {PXE_BUG, "pgcrypto bug"}, + {PXE_ARGUMENT_ERROR, "Illegal argument to function"}, + {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"}, + {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"}, + {PXE_NO_RANDOM, "Failed to generate strong random bits"}, + {PXE_DECRYPT_FAILED, "Decryption failed"}, + {PXE_ENCRYPT_FAILED, "Encryption failed"}, + {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_MATH_FAILED, "Math operation failed"}, + {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"}, + {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"}, + {PXE_PGP_WRONG_KEY, "Wrong 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 encryption key found"}, + {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"}, + + {0, NULL}, +}; + +/* + * Call ereport(ERROR, ...), with an error code and message corresponding to + * the PXE_* error code given as argument. + * + * This is similar to px_strerror(err), but for some errors, we fill in the + * error code and detail fields more appropriately. + */ +void +px_THROW_ERROR(int err) +{ + if (err == PXE_NO_RANDOM) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not generate a random number"))); + } + else + { + /* For other errors, use the message from the above list. */ + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("%s", px_strerror(err)))); + } +} + +const char * +px_strerror(int err) +{ + const struct error_desc *e; + + for (e = px_err_list; e->desc; e++) + if (e->err == err) + return e->desc; + return "Bad error code"; +} + +/* memset that must not be optimized away */ +void +px_memset(void *ptr, int c, size_t len) +{ + memset(ptr, c, len); +} + +const char * +px_resolve_alias(const PX_Alias *list, const char *name) +{ + while (list->name) + { + if (pg_strcasecmp(list->alias, name) == 0) + return list->name; + list++; + } + 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) + */ + +static unsigned +combo_encrypt_len(PX_Combo *cx, unsigned dlen) +{ + return dlen + 512; +} + +static unsigned +combo_decrypt_len(PX_Combo *cx, unsigned dlen) +{ + return dlen; +} + +static int +combo_init(PX_Combo *cx, const uint8 *key, unsigned klen, + const uint8 *iv, unsigned ivlen) +{ + int err; + unsigned ks, + ivs; + PX_Cipher *c = cx->cipher; + uint8 *ivbuf = NULL; + uint8 *keybuf; + + ks = px_cipher_key_size(c); + + ivs = px_cipher_iv_size(c); + if (ivs > 0) + { + ivbuf = palloc0(ivs); + if (ivlen > ivs) + memcpy(ivbuf, iv, ivs); + else if (ivlen > 0) + memcpy(ivbuf, iv, ivlen); + } + + if (klen > ks) + klen = ks; + keybuf = palloc0(ks); + memset(keybuf, 0, ks); + memcpy(keybuf, key, klen); + + err = px_cipher_init(c, keybuf, klen, ivbuf); + + if (ivbuf) + pfree(ivbuf); + pfree(keybuf); + + return err; +} + +static int +combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen, + uint8 *res, unsigned *rlen) +{ + return px_cipher_encrypt(cx->cipher, cx->padding, data, dlen, res, rlen); +} + +static int +combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen, + uint8 *res, unsigned *rlen) +{ + return px_cipher_decrypt(cx->cipher, cx->padding, data, dlen, res, rlen); +} + +static void +combo_free(PX_Combo *cx) +{ + if (cx->cipher) + px_cipher_free(cx->cipher); + px_memset(cx, 0, sizeof(*cx)); + pfree(cx); +} + +/* PARSER */ + +static int +parse_cipher_name(char *full, char **cipher, char **pad) +{ + char *p, + *p2, + *q; + + *cipher = full; + *pad = NULL; + + p = strchr(full, '/'); + if (p != NULL) + *p++ = 0; + while (p != NULL) + { + if ((q = strchr(p, '/')) != NULL) + *q++ = 0; + + if (!*p) + { + p = q; + continue; + } + p2 = strchr(p, ':'); + if (p2 != NULL) + { + *p2++ = 0; + if (strcmp(p, "pad") == 0) + *pad = p2; + else + return PXE_BAD_OPTION; + } + else + return PXE_BAD_FORMAT; + + p = q; + } + return 0; +} + +/* provider */ + +int +px_find_combo(const char *name, PX_Combo **res) +{ + int err; + char *buf, + *s_cipher, + *s_pad; + + PX_Combo *cx; + + cx = palloc0(sizeof(*cx)); + buf = pstrdup(name); + + err = parse_cipher_name(buf, &s_cipher, &s_pad); + if (err) + { + pfree(buf); + pfree(cx); + return err; + } + + err = px_find_cipher(s_cipher, &cx->cipher); + if (err) + goto err1; + + if (s_pad != NULL) + { + if (strcmp(s_pad, "pkcs") == 0) + cx->padding = 1; + else if (strcmp(s_pad, "none") == 0) + cx->padding = 0; + else + goto err1; + } + else + cx->padding = 1; + + cx->init = combo_init; + cx->encrypt = combo_encrypt; + cx->decrypt = combo_decrypt; + cx->encrypt_len = combo_encrypt_len; + cx->decrypt_len = combo_decrypt_len; + cx->free = combo_free; + + pfree(buf); + + *res = cx; + + return 0; + +err1: + if (cx->cipher) + px_cipher_free(cx->cipher); + pfree(cx); + pfree(buf); + return PXE_NO_CIPHER; +} diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h new file mode 100644 index 0000000..4ef40f3 --- /dev/null +++ b/contrib/pgcrypto/px.h @@ -0,0 +1,228 @@ +/* + * px.h + * Header file for pgcrypto. + * + * Copyright (c) 2001 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/px.h + */ + +#ifndef __PX_H +#define __PX_H + +#include <sys/param.h> + +/* keep debug messages? */ +#define PX_DEBUG + +/* max salt returned */ +#define PX_MAX_SALT_LEN 128 + +/* + * PX error codes + */ +#define PXE_OK 0 +/* -1 is unused */ +#define PXE_NO_HASH -2 +#define PXE_NO_CIPHER -3 +/* -4 is unused */ +#define PXE_BAD_OPTION -5 +#define PXE_BAD_FORMAT -6 +#define PXE_KEY_TOO_BIG -7 +#define PXE_CIPHER_INIT -8 +#define PXE_HASH_UNUSABLE_FOR_HMAC -9 +/* -10 is unused */ +/* -11 is unused */ +#define PXE_BUG -12 +#define PXE_ARGUMENT_ERROR -13 +#define PXE_UNKNOWN_SALT_ALGO -14 +#define PXE_BAD_SALT_ROUNDS -15 +/* -16 is unused */ +#define PXE_NO_RANDOM -17 +#define PXE_DECRYPT_FAILED -18 +#define PXE_ENCRYPT_FAILED -19 + +#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 +/* -108 is unused */ +#define PXE_PGP_MATH_FAILED -109 +#define PXE_PGP_SHORT_ELGAMAL_KEY -110 +/* -111 is unused */ +#define PXE_PGP_UNKNOWN_PUBALGO -112 +#define PXE_PGP_WRONG_KEY -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; +typedef struct px_cipher PX_Cipher; +typedef struct px_combo PX_Combo; + +struct px_digest +{ + unsigned (*result_size) (PX_MD *h); + unsigned (*block_size) (PX_MD *h); + void (*reset) (PX_MD *h); + void (*update) (PX_MD *h, const uint8 *data, unsigned dlen); + void (*finish) (PX_MD *h, uint8 *dst); + void (*free) (PX_MD *h); + /* private */ + union + { + unsigned code; + void *ptr; + } p; +}; + +struct px_alias +{ + char *alias; + char *name; +}; + +struct px_hmac +{ + unsigned (*result_size) (PX_HMAC *h); + unsigned (*block_size) (PX_HMAC *h); + void (*reset) (PX_HMAC *h); + void (*update) (PX_HMAC *h, const uint8 *data, unsigned dlen); + void (*finish) (PX_HMAC *h, uint8 *dst); + void (*free) (PX_HMAC *h); + void (*init) (PX_HMAC *h, const uint8 *key, unsigned klen); + + PX_MD *md; + /* private */ + struct + { + uint8 *ipad; + uint8 *opad; + } p; +}; + +struct px_cipher +{ + unsigned (*block_size) (PX_Cipher *c); + unsigned (*key_size) (PX_Cipher *c); /* max key len */ + unsigned (*iv_size) (PX_Cipher *c); + + int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv); + int (*encrypt) (PX_Cipher *c, int padding, const uint8 *data, unsigned dlen, uint8 *res, unsigned *rlen); + int (*decrypt) (PX_Cipher *c, int padding, const uint8 *data, unsigned dlen, uint8 *res, unsigned *rlen); + void (*free) (PX_Cipher *c); + /* private */ + void *ptr; + int pstat; /* mcrypt uses it */ +}; + +struct px_combo +{ + int (*init) (PX_Combo *cx, const uint8 *key, unsigned klen, + const uint8 *iv, unsigned ivlen); + int (*encrypt) (PX_Combo *cx, const uint8 *data, unsigned dlen, + uint8 *res, unsigned *rlen); + int (*decrypt) (PX_Combo *cx, const uint8 *data, unsigned dlen, + uint8 *res, unsigned *rlen); + unsigned (*encrypt_len) (PX_Combo *cx, unsigned dlen); + unsigned (*decrypt_len) (PX_Combo *cx, unsigned dlen); + void (*free) (PX_Combo *cx); + + PX_Cipher *cipher; + unsigned padding; +}; + +int px_find_digest(const char *name, PX_MD **res); +int px_find_hmac(const char *name, PX_HMAC **res); +int px_find_cipher(const char *name, PX_Cipher **res); +int px_find_combo(const char *name, PX_Combo **res); + +void px_THROW_ERROR(int err) pg_attribute_noreturn(); +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 *)); + +void px_memset(void *ptr, int c, size_t len); + +#ifdef PX_DEBUG +void px_debug(const char *fmt,...) pg_attribute_printf(1, 2); +#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) +#define px_md_update(md, data, dlen) (md)->update(md, data, dlen) +#define px_md_finish(md, buf) (md)->finish(md, buf) +#define px_md_free(md) (md)->free(md) + +#define px_hmac_result_size(hmac) (hmac)->result_size(hmac) +#define px_hmac_block_size(hmac) (hmac)->block_size(hmac) +#define px_hmac_reset(hmac) (hmac)->reset(hmac) +#define px_hmac_init(hmac, key, klen) (hmac)->init(hmac, key, klen) +#define px_hmac_update(hmac, data, dlen) (hmac)->update(hmac, data, dlen) +#define px_hmac_finish(hmac, buf) (hmac)->finish(hmac, buf) +#define px_hmac_free(hmac) (hmac)->free(hmac) + + +#define px_cipher_key_size(c) (c)->key_size(c) +#define px_cipher_block_size(c) (c)->block_size(c) +#define px_cipher_iv_size(c) (c)->iv_size(c) +#define px_cipher_init(c, k, klen, iv) (c)->init(c, k, klen, iv) +#define px_cipher_encrypt(c, padding, data, dlen, res, rlen) \ + (c)->encrypt(c, padding, data, dlen, res, rlen) +#define px_cipher_decrypt(c, padding, data, dlen, res, rlen) \ + (c)->decrypt(c, padding, data, dlen, res, rlen) +#define px_cipher_free(c) (c)->free(c) + + +#define px_combo_encrypt_len(c, dlen) (c)->encrypt_len(c, dlen) +#define px_combo_decrypt_len(c, dlen) (c)->decrypt_len(c, dlen) +#define px_combo_init(c, key, klen, iv, ivlen) \ + (c)->init(c, key, klen, iv, ivlen) +#define px_combo_encrypt(c, data, dlen, res, rlen) \ + (c)->encrypt(c, data, dlen, res, rlen) +#define px_combo_decrypt(c, data, dlen, res, rlen) \ + (c)->decrypt(c, data, dlen, res, rlen) +#define px_combo_free(c) (c)->free(c) + +#endif /* __PX_H */ diff --git a/contrib/pgcrypto/sql/3des.sql b/contrib/pgcrypto/sql/3des.sql new file mode 100644 index 0000000..1b71a10 --- /dev/null +++ b/contrib/pgcrypto/sql/3des.sql @@ -0,0 +1,25 @@ +-- +-- 3DES cipher +-- + +-- test vector from somewhere +SELECT encrypt('\x8000000000000000', + '\x010101010101010101010101010101010101010101010101', + '3des-ecb/pad:none'); + +select encrypt('', 'foo', '3des'); +-- 10 bytes key +select encrypt('foo', '0123456789', '3des'); +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', '3des'); + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', '3des'), '0123456', '3des'), 'escape'); + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', '3des'); +select encode(decrypt_iv('\x50735067b073bb93', '0123456', 'abcd', '3des'), 'escape'); + +-- long message +select encrypt('Lets try a longer message.', '0123456789012345678901', '3des'); +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789012345678901', '3des'), '0123456789012345678901', '3des'), 'escape'); diff --git a/contrib/pgcrypto/sql/blowfish.sql b/contrib/pgcrypto/sql/blowfish.sql new file mode 100644 index 0000000..c212cf2 --- /dev/null +++ b/contrib/pgcrypto/sql/blowfish.sql @@ -0,0 +1,53 @@ +-- +-- Blowfish cipher +-- + +-- some standard Blowfish testvalues +SELECT encrypt('\x0000000000000000', '\x0000000000000000', 'bf-ecb/pad:none'); +SELECT encrypt('\xffffffffffffffff', '\xffffffffffffffff', 'bf-ecb/pad:none'); +SELECT encrypt('\x1000000000000001', '\x3000000000000000', 'bf-ecb/pad:none'); +SELECT encrypt('\x1111111111111111', '\x1111111111111111', 'bf-ecb/pad:none'); +SELECT encrypt('\x0123456789abcdef', '\xfedcba9876543210', 'bf-ecb/pad:none'); +SELECT encrypt('\x01a1d6d039776742', '\xfedcba9876543210', 'bf-ecb/pad:none'); +SELECT encrypt('\xffffffffffffffff', '\x0000000000000000', 'bf-ecb/pad:none'); + +-- setkey +SELECT encrypt('\xfedcba9876543210', '\xf0e1d2c3b4a5968778695a4b3c2d1e0f', 'bf-ecb/pad:none'); + +-- with padding +SELECT encrypt('\x01234567890123456789', '\x33443344334433443344334433443344', 'bf-ecb'); + +-- cbc + +-- 28 bytes key +SELECT encrypt('\x6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5', + '\x37363534333231204e6f77206973207468652074696d6520666f7220', + 'bf-cbc'); + +-- 29 bytes key +SELECT encrypt('\x6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc', + '\x37363534333231204e6f77206973207468652074696d6520666f722000', + 'bf-cbc'); + +-- blowfish-448 +SELECT encrypt('\xfedcba9876543210', + '\xf0e1d2c3b4a5968778695a4b3c2d1e0f001122334455667704689104c2fd3b2f584023641aba61761f1f1f1f0e0e0e0effffffffffffffff', + 'bf-ecb/pad:none'); + +-- empty data +select encrypt('', 'foo', 'bf'); +-- 10 bytes key +select encrypt('foo', '0123456789', 'bf'); +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', 'bf'); + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'bf'), '0123456', 'bf'), 'escape'); + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'bf'); +select encode(decrypt_iv('\x95c7e89322525d59', '0123456', 'abcd', 'bf'), 'escape'); + +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'bf'); +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'bf'), '0123456789', 'bf'), 'escape'); diff --git a/contrib/pgcrypto/sql/cast5.sql b/contrib/pgcrypto/sql/cast5.sql new file mode 100644 index 0000000..b3089b2 --- /dev/null +++ b/contrib/pgcrypto/sql/cast5.sql @@ -0,0 +1,32 @@ +-- +-- Cast5 cipher +-- + +-- test vectors from RFC2144 + +-- 128 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x0123456712345678234567893456789A', 'cast5-ecb/pad:none'); + +-- 80 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x01234567123456782345', 'cast5-ecb/pad:none'); + +-- 40 bit key +SELECT encrypt('\x0123456789ABCDEF', '\x0123456712', 'cast5-ecb/pad:none'); + +-- cbc + +-- empty data +select encrypt('', 'foo', 'cast5'); +-- 10 bytes key +select encrypt('foo', '0123456789', 'cast5'); + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'cast5'), '0123456', 'cast5'), 'escape'); + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'cast5'); +select encode(decrypt_iv('\x384a970695ce016a', '0123456', 'abcd', 'cast5'), 'escape'); + +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'cast5'); +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'cast5'), '0123456789', 'cast5'), 'escape'); diff --git a/contrib/pgcrypto/sql/crypt-blowfish.sql b/contrib/pgcrypto/sql/crypt-blowfish.sql new file mode 100644 index 0000000..3b5a681 --- /dev/null +++ b/contrib/pgcrypto/sql/crypt-blowfish.sql @@ -0,0 +1,26 @@ +-- +-- crypt() and gen_salt(): bcrypt +-- + +SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); + +SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); + +-- error, salt too short: +SELECT crypt('foox', '$2a$'); + +-- error, first digit of count in salt invalid +SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O'); + +-- error, count in salt too small +SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O'); + +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); + +UPDATE ctest SET salt = gen_salt('bf', 8); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/sql/crypt-des.sql b/contrib/pgcrypto/sql/crypt-des.sql new file mode 100644 index 0000000..a85ec1e --- /dev/null +++ b/contrib/pgcrypto/sql/crypt-des.sql @@ -0,0 +1,21 @@ +-- +-- crypt() and gen_salt(): crypt-des +-- + +SELECT crypt('', 'NB'); + +SELECT crypt('foox', 'NB'); + +-- We are supposed to pass in a 2-character salt. +-- error since salt is too short: +SELECT crypt('password', 'a'); + +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); + +UPDATE ctest SET salt = gen_salt('des'); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/sql/crypt-md5.sql b/contrib/pgcrypto/sql/crypt-md5.sql new file mode 100644 index 0000000..ba7befb --- /dev/null +++ b/contrib/pgcrypto/sql/crypt-md5.sql @@ -0,0 +1,17 @@ +-- +-- crypt() and gen_salt(): md5 +-- + +SELECT crypt('', '$1$Szzz0yzz'); + +SELECT crypt('foox', '$1$Szzz0yzz'); + +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); + +UPDATE ctest SET salt = gen_salt('md5'); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/sql/crypt-xdes.sql b/contrib/pgcrypto/sql/crypt-xdes.sql new file mode 100644 index 0000000..8171cd8 --- /dev/null +++ b/contrib/pgcrypto/sql/crypt-xdes.sql @@ -0,0 +1,33 @@ +-- +-- crypt() and gen_salt(): extended des +-- + +SELECT crypt('', '_J9..j2zz'); + +SELECT crypt('foox', '_J9..j2zz'); + +-- check XDES handling of keys longer than 8 chars +SELECT crypt('longlongpassword', '_J9..j2zz'); + +-- error, salt too short +SELECT crypt('foox', '_J9..BWH'); + +-- error, count specified in the second argument is 0 +SELECT crypt('password', '_........'); + +-- error, count will wind up still being 0 due to invalid encoding +-- of the count: only chars ``./0-9A-Za-z' are valid +SELECT crypt('password', '_..!!!!!!'); + +-- count should be non-zero here, will work +SELECT crypt('password', '_/!!!!!!!'); + +CREATE TABLE ctest (data text, res text, salt text); +INSERT INTO ctest VALUES ('password', '', ''); + +UPDATE ctest SET salt = gen_salt('xdes', 1001); +UPDATE ctest SET res = crypt(data, salt); +SELECT res = crypt(data, res) AS "worked" +FROM ctest; + +DROP TABLE ctest; diff --git a/contrib/pgcrypto/sql/des.sql b/contrib/pgcrypto/sql/des.sql new file mode 100644 index 0000000..08c77a4 --- /dev/null +++ b/contrib/pgcrypto/sql/des.sql @@ -0,0 +1,24 @@ +-- +-- DES cipher +-- + +-- no official test vectors atm + +-- from blowfish.sql +SELECT encrypt('\x0123456789abcdef', '\xfedcba9876543210', 'des-ecb/pad:none'); + +-- empty data +select encrypt('', 'foo', 'des'); +-- 8 bytes key +select encrypt('foo', '01234589', 'des'); + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'des'), '0123456', 'des'), 'escape'); + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'des'); +select encode(decrypt_iv('\x50735067b073bb93', '0123456', 'abcd', 'des'), 'escape'); + +-- long message +select encrypt('Lets try a longer message.', '01234567', 'des'); +select encode(decrypt(encrypt('Lets try a longer message.', '01234567', 'des'), '01234567', 'des'), 'escape'); diff --git a/contrib/pgcrypto/sql/hmac-md5.sql b/contrib/pgcrypto/sql/hmac-md5.sql new file mode 100644 index 0000000..981ed09 --- /dev/null +++ b/contrib/pgcrypto/sql/hmac-md5.sql @@ -0,0 +1,44 @@ +-- +-- HMAC-MD5 +-- + +SELECT hmac( +'Hi There', +'\x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'::bytea, +'md5'); + +-- 2 +SELECT hmac( +'Jefe', +'what do ya want for nothing?', +'md5'); + +-- 3 +SELECT hmac( +'\xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'::bytea, +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'md5'); + +-- 4 +SELECT hmac( +'\xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'::bytea, +'\x0102030405060708090a0b0c0d0e0f10111213141516171819'::bytea, +'md5'); + +-- 5 +SELECT hmac( +'Test With Truncation', +'\x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'::bytea, +'md5'); + +-- 6 +SELECT hmac( +'Test Using Larger Than Block-Size Key - Hash Key First', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'md5'); + +-- 7 +SELECT hmac( +'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'md5'); diff --git a/contrib/pgcrypto/sql/hmac-sha1.sql b/contrib/pgcrypto/sql/hmac-sha1.sql new file mode 100644 index 0000000..f9a7b71 --- /dev/null +++ b/contrib/pgcrypto/sql/hmac-sha1.sql @@ -0,0 +1,44 @@ +-- +-- HMAC-SHA1 +-- + +SELECT hmac( +'Hi There', +'\x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'::bytea, +'sha1'); + +-- 2 +SELECT hmac( +'Jefe', +'what do ya want for nothing?', +'sha1'); + +-- 3 +SELECT hmac( +'\xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'::bytea, +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'sha1'); + +-- 4 +SELECT hmac( +'\xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'::bytea, +'\x0102030405060708090a0b0c0d0e0f10111213141516171819'::bytea, +'sha1'); + +-- 5 +SELECT hmac( +'Test With Truncation', +'\x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'::bytea, +'sha1'); + +-- 6 +SELECT hmac( +'Test Using Larger Than Block-Size Key - Hash Key First', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'sha1'); + +-- 7 +SELECT hmac( +'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data', +'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea, +'sha1'); diff --git a/contrib/pgcrypto/sql/init.sql b/contrib/pgcrypto/sql/init.sql new file mode 100644 index 0000000..6388187 --- /dev/null +++ b/contrib/pgcrypto/sql/init.sql @@ -0,0 +1,11 @@ +-- +-- init pgcrypto +-- + +CREATE EXTENSION pgcrypto; + +-- check error handling +select gen_salt('foo'); +select digest('foo', 'foo'); +select hmac('foo', 'foo', 'foo'); +select encrypt('foo', 'foo', 'foo'); diff --git a/contrib/pgcrypto/sql/md5.sql b/contrib/pgcrypto/sql/md5.sql new file mode 100644 index 0000000..0403613 --- /dev/null +++ b/contrib/pgcrypto/sql/md5.sql @@ -0,0 +1,11 @@ +-- +-- MD5 message digest +-- + +SELECT digest('', 'md5'); +SELECT digest('a', 'md5'); +SELECT digest('abc', 'md5'); +SELECT digest('message digest', 'md5'); +SELECT digest('abcdefghijklmnopqrstuvwxyz', 'md5'); +SELECT digest('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'md5'); +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'md5'); diff --git a/contrib/pgcrypto/sql/pgp-armor.sql b/contrib/pgcrypto/sql/pgp-armor.sql new file mode 100644 index 0000000..736b542 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-armor.sql @@ -0,0 +1,214 @@ +-- +-- PGP Armor +-- + +select armor(''); +select armor('test'); +select encode(dearmor(armor('')), 'escape'); +select encode(dearmor(armor('zooka')), 'escape'); + +select armor('0123456789abcdef0123456789abcdef0123456789abcdef +0123456789abcdef0123456789abcdef0123456789abcdef'); + +-- lots formatting +select encode(dearmor(' a pgp msg: + +-----BEGIN PGP MESSAGE----- +Comment: Some junk + +em9va2E= + + =D5cR + +-----END PGP MESSAGE-----'), 'escape'); + +-- lots messages +select encode(dearmor(' +wrong packet: + -----BEGIN PGP MESSAGE----- + + d3Jvbmc= + =vCYP + -----END PGP MESSAGE----- + +right packet: +-----BEGIN PGP MESSAGE----- + +cmlnaHQ= +=nbpj +-----END PGP MESSAGE----- + +use only first packet +-----BEGIN PGP MESSAGE----- + +d3Jvbmc= +=vCYP +-----END PGP MESSAGE----- +'), 'escape'); + +-- bad crc +select dearmor(' +-----BEGIN PGP MESSAGE----- + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- corrupt (no space after the colon) +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +foo: + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- corrupt (no empty line) +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- no headers +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- header with empty value +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +foo: + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- simple +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +fookey: foovalue +barkey: barvalue + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- insane keys, part 1 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +insane:key : + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- insane keys, part 2 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +insane:key : text value here + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- long value +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +long: this value is more than 76 characters long, but it should still parse correctly as that''s permitted by RFC 4880 + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- long value, split up +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +long: this value is more than 76 characters long, but it should still +long: parse correctly as that''s permitted by RFC 4880 + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- long value, split up, part 2 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +long: this value is more than +long: 76 characters long, but it should still +long: parse correctly as that''s permitted by RFC 4880 + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +-- long value, split up, part 3 +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +emptykey: +long: this value is more than +emptykey: +long: 76 characters long, but it should still +emptykey: +long: parse correctly as that''s permitted by RFC 4880 +emptykey: + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); + +select * from pgp_armor_headers(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.blowfish.sha1.mdc.s2k3.z0 + +jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS +yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE= +=JcP+ +-----END PGP MESSAGE----- +'); + +-- test CR+LF line endings +select * from pgp_armor_headers(replace(' +-----BEGIN PGP MESSAGE----- +fookey: foovalue +barkey: barvalue + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +', E'\n', E'\r\n')); + +-- test header generation +select armor('zooka', array['foo'], array['bar']); +select armor('zooka', array['Version', 'Comment'], array['Created by pgcrypto', 'PostgreSQL, the world''s most advanced open source database']); +select * from pgp_armor_headers( + armor('zooka', array['Version', 'Comment'], + array['Created by pgcrypto', 'PostgreSQL, the world''s most advanced open source database'])); + +-- error/corner cases +select armor('', array['foo'], array['too', 'many']); +select armor('', array['too', 'many'], array['foo']); +select armor('', array[['']], array['foo']); +select armor('', array['foo'], array[['']]); +select armor('', array[null], array['foo']); +select armor('', array['foo'], array[null]); +select armor('', '[0:0]={"foo"}', array['foo']); +select armor('', array['foo'], '[0:0]={"foo"}'); +select armor('', array[E'embedded\nnewline'], array['foo']); +select armor('', array['foo'], array[E'embedded\nnewline']); +select armor('', array['embedded: colon+space'], array['foo']); diff --git a/contrib/pgcrypto/sql/pgp-compression.sql b/contrib/pgcrypto/sql/pgp-compression.sql new file mode 100644 index 0000000..87c59c6 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-compression.sql @@ -0,0 +1,51 @@ +-- +-- PGP compression support +-- + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0ECQMCsci6AdHnELlh0kQB4jFcVwHMJg0Bulop7m3Mi36s15TAhBo0AnzIrRFrdLVCkKohsS6+ +DMcmR53SXfLoDJOv/M8uKj3QSq7oWNIp95pxfA== +=tbSn +-----END PGP MESSAGE----- +'), 'key', 'expect-compress-algo=1'); + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=0'), + 'key', 'expect-compress-algo=0'); + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=1'), + 'key', 'expect-compress-algo=1'); + +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', 'compress-algo=2'), + 'key', 'expect-compress-algo=2'); + +-- level=0 should turn compression off +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret message', 'key', + 'compress-algo=2, compress-level=0'), + 'key', 'expect-compress-algo=0'); + +-- check corner case involving an input string of 16kB, as per bug #16476. +SELECT setseed(0); +WITH random_string AS +( + -- This generates a random string of 16366 bytes. This is chosen + -- as random so that it does not get compressed, and the decompression + -- would work on a string with the same length as the origin, making the + -- test behavior more predictible. lpad() ensures that the generated + -- hexadecimal value is completed by extra zero characters if random() + -- has generated a value strictly lower than 16. + SELECT string_agg(decode(lpad(to_hex((random()*256)::int), 2, '0'), 'hex'), '') as bytes + FROM generate_series(0, 16365) +) +SELECT bytes = + pgp_sym_decrypt_bytea( + pgp_sym_encrypt_bytea(bytes, 'key', + 'compress-algo=1,compress-level=1'), + 'key', 'expect-compress-algo=1') + AS is_same + FROM random_string; diff --git a/contrib/pgcrypto/sql/pgp-decrypt.sql b/contrib/pgcrypto/sql/pgp-decrypt.sql new file mode 100644 index 0000000..49a0267 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-decrypt.sql @@ -0,0 +1,309 @@ +-- +-- pgp decrypt tests +-- + +-- Checking ciphers +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.blowfish.sha1.mdc.s2k3.z0 + +jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS +yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE= +=JcP+ +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCci97v0Q6Z0Zg0kQBsVf5Oe3iC+FBzUmuMV9KxmAyOMyjCc/5i8f1Eest +UTAsG35A1vYs02VARKzGz6xI2UHwFUirP+brPBg3Ee7muOx8pA== +=XtrP +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCI7YQpWqp3D1g0kQBCjB7GlX7+SQeXNleXeXQ78ZAPNliquGDq9u378zI +5FPTqAhIB2/2fjY8QEIs1ai00qphjX2NitxV/3Wn+6dufB4Q4g== +=rCZt +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMC4f/5djqCC1Rg0kQBTHEPsD+Sw7biBsM2er3vKyGPAQkuTBGKC5ie7hT/ +lceMfQdbAg6oTFyJpk/wH18GzRDphCofg0X8uLgkAKMrpcmgog== +=fB6S +-----END PGP MESSAGE----- +'), 'foobar'); + +-- Checking MDC modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.nomdc.s2k3.z0 + +jA0EBwMCnv07rlXqWctgyS2Dm2JfOKCRL4sLSLJUC8RS2cH7cIhKSuLitOtyquB+ +u9YkgfJfsuRJmgQ9tmo= +=60ui +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEeP3idNjQ1Bg0kQBf4G0wX+2QNzLh2YNwYkQgQkfYhn/hLXjV4nK9nsE +8Ex1Dsdt5UPvOz8W8VKQRS6loOfOe+yyXil8W3IYFwUpdDUi+Q== +=moGf +-----END PGP MESSAGE----- +'), 'foobar'); + +-- Checking hashes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.md5.mdc.s2k3.z0 + +jA0EBwMClrXXtOXetohg0kQBn0Kl1ymevQZRHkdoYRHgzCwSQEiss7zYff2UNzgO +KyRrHf7zEBuZiZ2AG34jNVMOLToj1jJUg5zTSdecUzQVCykWTA== +=NyLk +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCApbdlrURoWJg0kQBzHM/E0o7djY82bNuspjxjAcPFrrtp0uvDdMQ4z2m +/PM8jhgI5vxFYfNQjLl8y3fHYIomk9YflN9K/Q13iq8A8sjeTw== +=FxbQ +-----END PGP MESSAGE----- +'), 'foobar'); + +-- Checking S2K modes +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k0.z0 + +jAQEBwAC0kQBKTaLAKE3xzps+QIZowqRNb2eAdzBw2LxEW2YD5PgNlbhJdGg+dvw +Ah9GXjGS1TVALzTImJbz1uHUZRfhJlFbc5yGQw== +=YvkV +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k1.z0 + +jAwEBwEC/QTByBLI3b/SRAHPxKzI6SZBo5lAEOD+EsvKQWO4adL9tDY+++Iqy1xK +4IaWXVKEj9R2Lr2xntWWMGZtcKtjD2lFFRXXd9dZp1ZThNDz +=dbXm +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCEq4Su3ZqNEJg0kQB4QG5jBTKF0i04xtH+avzmLhstBNRxvV3nsmB3cwl +z+9ZaA/XdSx5ZiFnMym8P6r8uY9rLjjNptvvRHlxIReF+p9MNg== +=VJKg +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k0.z0 + +jAQECAAC0kQBBDnQWkgsx9YFaqDfWmpsiyAJ6y2xG/sBvap1dySYEMuZ+wJTXQ9E +Cr3i2M7TgVZ0M4jp4QL0adG1lpN5iK7aQeOwMw== +=cg+i +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k1.z0 + +jAwECAECruOfyNDFiTnSRAEVoGXm4A9UZKkWljdzjEO/iaE7mIraltIpQMkiqCh9 +7h8uZ2u9uRBOv222fZodGvc6bvq/4R4hAa/6qSHtm8mdmvGt +=aHmC +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes192.sha1.mdc.s2k3.z0 + +jA0ECAMCjFn6SRi3SONg0kQBqtSHPaD0m7rXfDAhCWU/ypAsI93GuHGRyM99cvMv +q6eF6859ZVnli3BFSDSk3a4e/pXhglxmDYCfjAXkozKNYLo6yw== +=K0LS +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k0.z0 + +jAQECQAC0kQB4L1eMbani07XF2ZYiXNK9LW3v8w41oUPl7dStmrJPQFwsdxmrDHu +rQr3WbdKdY9ufjOE5+mXI+EFkSPrF9rL9NCq6w== +=RGts +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k1.z0 + +jAwECQECKHhrou7ZOIXSRAHWIVP+xjVQcjAVBTt+qh9SNzYe248xFTwozkwev3mO ++KVJW0qhk0An+Y2KF99/bYFl9cL5D3Tl43fC8fXGl3x3m7pR +=SUrU +-----END PGP MESSAGE----- +'), 'foobar'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes256.sha1.mdc.s2k3.z0 + +jA0ECQMCjc8lwZu8Fz1g0kQBkEzjImi21liep5jj+3dAJ2aZFfUkohi8b3n9z+7+ +4+NRzL7cMW2RLAFnJbiqXDlRHMwleeuLN1up2WIxsxtYYuaBjA== +=XZrG +-----END PGP MESSAGE----- +'), 'foobar'); + +-- Checking longer passwords +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCx6dBiuqrYNRg0kQBEo63AvA1SCslxP7ayanLf1H0/hlk2nONVhTwVEWi +tTGup1mMz6Cfh1uDRErUuXpx9A0gdMu7zX0o5XjrL7WGDAZdSw== +=XKKG +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCBDvYuS990iFg0kQBW31UK5OiCjWf5x6KJ8qNNT2HZWQCjCBZMU0XsOC6 +CMxFKadf144H/vpoV9GA0f22keQgCl0EsTE4V4lweVOPTKCMJg== +=gWDh +-----END PGP MESSAGE----- +'), '0123456789abcdefghij2jk4h5g2j54khg23h54g2kh54g2khj54g23hj54'); + +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCqXbFafC+ofVg0kQBejyiPqH0QMERVGfmPOjtAxvyG5KDIJPYojTgVSDt +FwsDabdQUz5O7bgNSnxfmyw1OifGF+W2bIn/8W+0rDf8u3+O+Q== +=OxOF +-----END PGP MESSAGE----- +'), 'x'); + +-- Checking various data +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat1.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCGJ+SpuOysINg0kQBJfSjzsW0x4OVcAyr17O7FBvMTwIGeGcJd99oTQU8 +Xtx3kDqnhUq9Z1fS3qPbi5iNP2A9NxOBxPWz2JzxhydANlgbxg== +=W/ik +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat2.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCvdpDvidNzMxg0jUBvj8eS2+1t/9/zgemxvhtc0fvdKGGbjH7dleaTJRB +SaV9L04ky1qECNDx3XjnoKLC+H7IOQ== +=Fxen +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: dat3.aes.sha1.mdc.s2k3.z0 + +jA0EBwMCxQvxJZ3G/HRg0lgBeYmTa7/uDAjPyFwSX4CYBgpZWVn/JS8JzILrcWF8 +gFnkUKIE0PSaYFp+Yi1VlRfUtRQ/X/LYNGa7tWZS+4VQajz2Xtz4vUeAEiYFYPXk +73Hb8m1yRhQK +=ivrD +-----END PGP MESSAGE----- +'), '0123456789abcdefghij'), 'sha1'); + +-- Checking CRLF +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=0'), 'sha1'); + +select digest(pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- +Comment: crlf mess + +ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms +a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs +=mBP9 +-----END PGP MESSAGE----- +'), 'key', 'convert-crlf=1'), 'sha1'); + +-- check BUG #11905, problem with messages 6 less than a power of 2. +select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',65530); + + +-- Negative tests + +-- Decryption with a certain incorrect key yields an apparent Literal Data +-- packet reporting its content to be binary data. Ciphertext source: +-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave +-- rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV +VsxxqLSPzNLAeIspJk5G +=mSd/ +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); + +-- Routine text/binary mismatch. +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1'); + +-- Decryption with a certain incorrect key yields an apparent BZip2-compressed +-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key') +-- until the random prefix gave rise to that property. +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP +GXsd65oYJZp3Khz0qfyn +=Nmpq +-----END PGP MESSAGE----- +'), 'wrong-key', 'debug=1'); + +-- Routine use of BZip2 compression. Ciphertext source: +-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \ +-- --personal-cipher-preferences aes --no-emit-version --batch \ +-- --symmetric --passphrase key --armor +select pgp_sym_decrypt(dearmor(' +-----BEGIN PGP MESSAGE----- + +jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe +QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R +UCAAw2JRIISttRHMfDpDuZJpvYo= +=AZ9M +-----END PGP MESSAGE----- +'), 'key', 'debug=1'); diff --git a/contrib/pgcrypto/sql/pgp-encrypt.sql b/contrib/pgcrypto/sql/pgp-encrypt.sql new file mode 100644 index 0000000..ed8b177 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-encrypt.sql @@ -0,0 +1,104 @@ +-- +-- PGP encrypt +-- + +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), 'key'); + +-- check whether the defaults are ok +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), + 'key', 'expect-cipher-algo=aes128, + expect-disable-mdc=0, + expect-sess-key=0, + expect-s2k-mode=3, + expect-s2k-digest-algo=sha1, + expect-compress-algo=0 + '); + +-- maybe the expect- stuff simply does not work +select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), + 'key', 'expect-cipher-algo=bf, + expect-disable-mdc=1, + expect-sess-key=1, + expect-s2k-mode=0, + expect-s2k-digest-algo=md5, + expect-compress-algo=1 + '); + +-- bytea as text +select pgp_sym_decrypt(pgp_sym_encrypt_bytea('Binary', 'baz'), 'baz'); + +-- text as bytea +select encode(pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'), 'escape'); + + +-- algorithm change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'), + 'key', 'expect-cipher-algo=bf'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes'), + 'key', 'expect-cipher-algo=aes128'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'), + 'key', 'expect-cipher-algo=aes192'); + +-- s2k change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=0'), + 'key', 'expect-s2k-mode=0'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=1'), + 'key', 'expect-s2k-mode=1'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'), + 'key', 'expect-s2k-mode=3'); + +-- s2k count change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'), + 'key', 'expect-s2k-count=1024'); +-- s2k_count rounds up +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'), + 'key', 'expect-s2k-count=65000000'); + +-- s2k digest change +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), + 'key', 'expect-s2k-digest-algo=md5'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'), + 'key', 'expect-s2k-digest-algo=sha1'); + +-- sess key +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=0'), + 'key', 'expect-sess-key=0'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1'), + 'key', 'expect-sess-key=1'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=bf'), + 'key', 'expect-sess-key=1, expect-cipher-algo=bf'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes192'), + 'key', 'expect-sess-key=1, expect-cipher-algo=aes192'); +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes256'), + 'key', 'expect-sess-key=1, expect-cipher-algo=aes256'); + +-- no mdc +select pgp_sym_decrypt( + pgp_sym_encrypt('Secret.', 'key', 'disable-mdc=1'), + 'key', 'expect-disable-mdc=1'); + +-- crlf +select pgp_sym_decrypt_bytea( + pgp_sym_encrypt(E'1\n2\n3\r\n', 'key', 'convert-crlf=1'), + 'key'); + +-- conversion should be lossless +select digest(pgp_sym_decrypt( + pgp_sym_encrypt(E'\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'), + 'key', 'convert-crlf=1'), 'sha1') as result, + digest(E'\r\n0\n1\r\r\n\n2\r', 'sha1') as expect; diff --git a/contrib/pgcrypto/sql/pgp-info.sql b/contrib/pgcrypto/sql/pgp-info.sql new file mode 100644 index 0000000..8e1d72a --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-info.sql @@ -0,0 +1,22 @@ +-- +-- PGP info functions +-- + +-- pgp_key_id + +select pgp_key_id(dearmor(pubkey)) from keytbl where id=1; +select pgp_key_id(dearmor(pubkey)) from keytbl where id=2; +select pgp_key_id(dearmor(pubkey)) from keytbl where id=3; +select pgp_key_id(dearmor(pubkey)) from keytbl where id=4; -- should fail +select pgp_key_id(dearmor(pubkey)) from keytbl where id=5; +select pgp_key_id(dearmor(pubkey)) from keytbl where id=6; + +select pgp_key_id(dearmor(seckey)) from keytbl where id=1; +select pgp_key_id(dearmor(seckey)) from keytbl where id=2; +select pgp_key_id(dearmor(seckey)) from keytbl where id=3; +select pgp_key_id(dearmor(seckey)) from keytbl where id=4; -- should fail +select pgp_key_id(dearmor(seckey)) from keytbl where id=5; +select pgp_key_id(dearmor(seckey)) from keytbl where id=6; + +select pgp_key_id(dearmor(data)) as data_key_id +from encdata order by id; diff --git a/contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql b/contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql new file mode 100644 index 0000000..3f2bae9 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql @@ -0,0 +1,647 @@ +-- +-- PGP Public Key Encryption +-- + +-- As most of the low-level stuff is tested in symmetric key +-- tests, here's only public-key specific tests + +create table keytbl ( + id int4, + name text, + pubkey text, + seckey text +); +create table encdata ( + id int4, + data text +); + +insert into keytbl (id, name, pubkey, seckey) +values (1, 'elg1024', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQLQfRWxnYW1hbCAx +MDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJCyCFIAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAniI9W2bC3CxARTpYrev7ihreDzFc +AJ9WYLQxDQAi5Ec9AQoodPkIagzZ4LkBDQRCyCFKEAQAh5SNbbJMAsJ+sQbcWEzd +ku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioymlDwraTKUAfuCZgNcg/0P +sxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlPiO0wt1lLX+SubktqbYxI ++h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSgMERiNzF0acZUYmc0e+/9 +6gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxsnKjUaw/qyoaFcNMzb4sF +k8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey9ifh8rZfu57UbdwdHa0v +iWc4DilhiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCfdPom+HlNVE9F +ig3hGY1Rb4NEk1gAn1u9IuQB+BgDP40YHHz6bKWS/x80 +=RWci +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQAAAnj4i4st+s+C6 +WKTIDcL1Iy0Saq8lCp60H0VsZ2FtYWwgMTAyNCA8dGVzdEBleGFtcGxlLm9yZz6I +XgQTEQIAHgUCQsghSAIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRAcKbwNGBdz +ZDrbAJ9cp6AsjOhiLxwznsMJheGf4xkH8wCfUPjMCLm4tAEnyYn2hDNt7CB8B6Kd +ATEEQsghShAEAIeUjW2yTALCfrEG3FhM3ZLvAHWAec2O0Mn/RDr59IN/W8wDYcZp +m+oG0ZUDdIqMppQ8K2kylAH7gmYDXIP9D7MRRm/Zw3L4yFfKnVaZ6tT7szBbgW5h +iOsHoOz49NXZT4jtMLdZS1/krm5Lam2MSPod9XN0Q2asY/igIMUfGDRjAAMGA/sE +LNh3tWefqeDkoDBEYjcxdGnGVGJnNHvv/eoHy9H7dyD/kkhaOoRAa5ClYWSqD0kk +a+SqTWhKG4XcbJyo1GsP6sqGhXDTM2+LBZPMKuVJQpEfoe9ruob/BbpXglfEiVE9 +VNiY7ZVyUdj3svYn4fK2X7ue1G3cHR2tL4lnOA4pYQAA9030E4u2ZKOfJBpUM+EM +m9VmsGjaQZV4teB0R/q3W8sRIYhJBBgRAgAJBQJCyCFKAhsMAAoJEBwpvA0YF3Nk +7a8AniFFotw1x2X+oryu3Q3nNtmxoKHpAJ9HU7jw7ydg33dI9J8gVkrmsSZ2/w== +=nvqq +-----END PGP PRIVATE KEY BLOCK----- +'); + +insert into keytbl (id, name, pubkey, seckey) +values (2, 'elg2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIgoRBAC1onBpxKYgDvrgCaUWPY34947X3ogxGOfCN0p6Eqrx+2PUhm4n +vFvmczpMT4iDc0mUO+iwnwsEkXQI1eC99g8c0jnZAvzJZ5miAHL8hukMAMfDkYke +5aVvcPPc8uPDlItpszGmH0rM0V9TIt/i9QEXetpyNWhk4jj5qnohYhLeZwCgkOdO +RFAdNi4vfFPivvtAp2ffjU8D/R3x/UJCvkzi7i9rQHGo313xxmQu5BuqIjANBUij +8IE7LRPI/Qhg2hYy3sTJwImDi7VkS+fuvNVk0d6MTWplAXYU96bn12JaD21R9sKl +Fzcc+0iZI1wYA1PczisUkoTISE+dQFUsoGHfpDLhoBuesXQrhBavI8t8VPd+nkdt +J+oKA/9iRQ87FzxdYTkh2drrv69FZHc3Frsjw9nPcBq/voAvXH0MRilqyCg7HpW/ +T9naeOERksa+Rj4R57IF1l4e5oiiGJo9QmaKZcsCsXrREJCycrlEtMqXfSPy+bi5 +0yDZE/Qm1dwu13+OXOsRvkoNYjO8Mzo9K8wU12hMqN0a2bu6a7QjRWxnYW1hbCAy +MDQ4IDx0ZXN0MjA0OEBleGFtcGxlLm9yZz6IXgQTEQIAHgUCQsgiCgIbAwYLCQgH +AwIDFQIDAxYCAQIeAQIXgAAKCRBI6c1W/qZo29PDAKCG724enIxRog1j+aeCp/uq +or6mbwCePuKy2/1kD1FvnhkZ/R5fpm+pdm25Ag0EQsgiIhAIAJI3Gb2Ehtz1taQ9 +AhPY4Avad2BsqD3S5X/R11Cm0KBE/04D29dxn3f8QfxDsexYvNIZjoJPBqqZ7iMX +MhoWyw8ZF5Zs1mLIjFGVorePrm94N3MNPWM7x9M36bHUjx0vCZKFIhcGY1g+htE/ +QweaJzNVeA5z4qZmik41FbQyQSyHa3bOkTZu++/U6ghP+iDp5UDBjMTkVyqITUVN +gC+MR+da/I60irBVhue7younh4ovF+CrVDQJC06HZl6CAJJyA81SmRfi+dmKbbjZ +LF6rhz0norPjISJvkIqvdtM4VPBKI5wpgwCzpEqjuiKrAVujRT68zvBvJ4aVqb11 +k5QdJscAAwUH/jVJh0HbWAoiFTe+NvohfrA8vPcD0rtU3Y+siiqrabotnxJd2NuC +bxghJYGfNtnx0KDjFbCRKJVeTFok4UnuVYhXdH/c6i0/rCTNdeW2D6pmR4GfBozR +Pw/ARf+jONawGLyUj7uq13iquwMSE7VyNuF3ycL2OxXjgOWMjkH8c+zfHHpjaZ0R +QsetMq/iNBWraayKZnWUd+eQqNzE+NUo7w1jAu7oDpy+8a1eipxzK+O0HfU5LTiF +Z1Oe4Um0P2l3Xtx8nEgj4vSeoEkl2qunfGW00ZMMTCWabg0ZgxPzMfMeIcm6525A +Yn2qL+X/qBJTInAl7/hgPz2D1Yd7d5/RdWaISQQYEQIACQUCQsgiIgIbDAAKCRBI +6c1W/qZo25ZSAJ98WTrtl2HiX8ZqZq95v1+9cHtZPQCfZDoWQPybkNescLmXC7q5 +1kNTmEU= +=8QM5 +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELIIgoRBAC1onBpxKYgDvrgCaUWPY34947X3ogxGOfCN0p6Eqrx+2PUhm4n +vFvmczpMT4iDc0mUO+iwnwsEkXQI1eC99g8c0jnZAvzJZ5miAHL8hukMAMfDkYke +5aVvcPPc8uPDlItpszGmH0rM0V9TIt/i9QEXetpyNWhk4jj5qnohYhLeZwCgkOdO +RFAdNi4vfFPivvtAp2ffjU8D/R3x/UJCvkzi7i9rQHGo313xxmQu5BuqIjANBUij +8IE7LRPI/Qhg2hYy3sTJwImDi7VkS+fuvNVk0d6MTWplAXYU96bn12JaD21R9sKl +Fzcc+0iZI1wYA1PczisUkoTISE+dQFUsoGHfpDLhoBuesXQrhBavI8t8VPd+nkdt +J+oKA/9iRQ87FzxdYTkh2drrv69FZHc3Frsjw9nPcBq/voAvXH0MRilqyCg7HpW/ +T9naeOERksa+Rj4R57IF1l4e5oiiGJo9QmaKZcsCsXrREJCycrlEtMqXfSPy+bi5 +0yDZE/Qm1dwu13+OXOsRvkoNYjO8Mzo9K8wU12hMqN0a2bu6awAAn2F+iNBElfJS +8azqO/kEiIfpqu6/DQG0I0VsZ2FtYWwgMjA0OCA8dGVzdDIwNDhAZXhhbXBsZS5v +cmc+iF0EExECAB4FAkLIIgoCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQSOnN +Vv6maNvTwwCYkpcJmpl3aHCQdGomz7dFohDgjgCgiThZt2xTEi6GhBB1vuhk+f55 +n3+dAj0EQsgiIhAIAJI3Gb2Ehtz1taQ9AhPY4Avad2BsqD3S5X/R11Cm0KBE/04D +29dxn3f8QfxDsexYvNIZjoJPBqqZ7iMXMhoWyw8ZF5Zs1mLIjFGVorePrm94N3MN +PWM7x9M36bHUjx0vCZKFIhcGY1g+htE/QweaJzNVeA5z4qZmik41FbQyQSyHa3bO +kTZu++/U6ghP+iDp5UDBjMTkVyqITUVNgC+MR+da/I60irBVhue7younh4ovF+Cr +VDQJC06HZl6CAJJyA81SmRfi+dmKbbjZLF6rhz0norPjISJvkIqvdtM4VPBKI5wp +gwCzpEqjuiKrAVujRT68zvBvJ4aVqb11k5QdJscAAwUH/jVJh0HbWAoiFTe+Nvoh +frA8vPcD0rtU3Y+siiqrabotnxJd2NuCbxghJYGfNtnx0KDjFbCRKJVeTFok4Unu +VYhXdH/c6i0/rCTNdeW2D6pmR4GfBozRPw/ARf+jONawGLyUj7uq13iquwMSE7Vy +NuF3ycL2OxXjgOWMjkH8c+zfHHpjaZ0RQsetMq/iNBWraayKZnWUd+eQqNzE+NUo +7w1jAu7oDpy+8a1eipxzK+O0HfU5LTiFZ1Oe4Um0P2l3Xtx8nEgj4vSeoEkl2qun +fGW00ZMMTCWabg0ZgxPzMfMeIcm6525AYn2qL+X/qBJTInAl7/hgPz2D1Yd7d5/R +dWYAAVQKFPXbRaxbdArwRVXMzSD3qj/+VwwhwEDt8zmBGnlBfwVdkjQQrDUMmV1S +EwyISQQYEQIACQUCQsgiIgIbDAAKCRBI6c1W/qZo25ZSAJ4sgUfHTVsG/x3p3fcM +3b5R86qKEACggYKSwPWCs0YVRHOWqZY0pnHtLH8= +=3Dgk +-----END PGP PRIVATE KEY BLOCK----- +'); + +insert into keytbl (id, name, pubkey, seckey) +values (3, 'elg4096', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=kRxT +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=Gjq6 +-----END PGP PRIVATE KEY BLOCK----- +'); + +insert into keytbl (id, name, pubkey, seckey) +values (4, 'rsa2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQELBELIJbEBCADAIdtcoLAmQfl8pb73pPRuEYx8qW9klLfCGG5A4OUOi00JHNwP +ZaABe1PGzjoeXrgM1MTQZhoZu1Vdg+KDI6XAtiy9P6bLg7ntsXksD4wBoIKtQKc2 +55pdukxTiu+xeJJG2q8ZZPOp97CV9fbQ9vPCwgnuSsDCoQlibZikDVPAyVTvp7Jx +5rz8yXsl4sxvaeMZPqqFPtA/ENeQ3cpsyR1BQXSvoZpH1Fq0b8GcZTEdWWD/w6/K +MCRC8TmgEd+z3e8kIsCwFQ+TSHbCcxRWdgZE7gE31sJHHVkrZlXtLU8MPXWqslVz +R0cX+yC8j6bXI6/BqZ2SvRndJwuunRAr4um7AAYptB5SU0EgMjA0OCA8cnNhMjA0 +OEBleGFtcGxlLm9yZz6JATQEEwECAB4FAkLIJbECGwMGCwkIBwMCAxUCAwMWAgEC +HgECF4AACgkQnc+OnJvTHyQqHwf8DtzuAGmObfe3ggtn14x2wnU1Nigebe1K5liR +nrLuVlLBpdO6CWmMUzfKRvyZlx54GlA9uUQSjW+RlgejdOTQqesDrcTEukYd4yzw +bLZyM5Gb3lsE/FEmE7Dxw/0Utf59uACqzG8LACQn9J6sEgZWKxAupuYTHXd12lDP +D3dnU4uzKPhMcjnSN00pzjusP7C9NZd3OLkAx2vw/dmb4Q+/QxeZhVYYsAUuR2hv +9bgGWopumlOkt8Zu5YG6+CtTbJXprPI7pJ1jHbeE+q/29hWJQtS8Abx82AcOkzhv +S3NZKoJ/1DrGgoDAu1mGkM4KvLAxfDs/qQ9dZhtEmDbKPLTVEA== +=lR4n +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQOWBELIJbEBCADAIdtcoLAmQfl8pb73pPRuEYx8qW9klLfCGG5A4OUOi00JHNwP +ZaABe1PGzjoeXrgM1MTQZhoZu1Vdg+KDI6XAtiy9P6bLg7ntsXksD4wBoIKtQKc2 +55pdukxTiu+xeJJG2q8ZZPOp97CV9fbQ9vPCwgnuSsDCoQlibZikDVPAyVTvp7Jx +5rz8yXsl4sxvaeMZPqqFPtA/ENeQ3cpsyR1BQXSvoZpH1Fq0b8GcZTEdWWD/w6/K +MCRC8TmgEd+z3e8kIsCwFQ+TSHbCcxRWdgZE7gE31sJHHVkrZlXtLU8MPXWqslVz +R0cX+yC8j6bXI6/BqZ2SvRndJwuunRAr4um7AAYpAAf/QZsrrz0c7dgWwGqMIpw6 +fP+/lLa74+fa2CFRWtYowEiKsfDg/wN7Ua07036dNhPa8aZPsU6SRzm5PybKOURe +D9pNt0FxJkX0j5pCWfjSJgTbc1rCdqZ/oyBk/U6pQtf//zfw3PbDl7I8TC6GOt2w +5NgcXdsWHP7LAmPctOVUyzFsenevR0MFTHkMbmKI1HpFm8XN/e1Fl+qIAD+OagTF +5B32VvpoJtkh5nxnIuToNJsa9Iy7F9MM2CeFOyTMihMcjXKBBUaAYoF115irBvqu +7N/qWmzqLg8yxBZ56mh6meCF3+67VA2y7fL8rhw2QuqgLg1JFlKAVL+9crCSrn// +GQQA1kT7FytW6BNOffblFYZkrJer3icoRDqa/ljgH/yVaWoVT1igy0E9XzYO7MwP +2usj/resLy0NC1qCthk51cZ/wthooMl88e5Wb4l5FYwBEac7muSBTo4W8cAH1hFj +TWL6XAGvEzGX3Mt9pn8uYGlQLZAhJoNCAU2EOCbN1PchDvsEAOWNKYesuUVk8+sQ +St0NDNhd9BWtTWTHkCZb1dKC3JTfr9PqkTBLrWFbYjkOtvdPAW7FDaXXXZfdH1jH +WfwP3Q+I6sqgSaWpCS4dBAns3/RVtO7czVgyIwma04iIvJqderYrfvkUq95KfwP2 +V8wXkhrPPPxyrg5y3wQlpY2jb5RBBAC17SK1ms+DBtck4vpdjp3SJ32SbyC/DU30 +89Q12j74S7Zdu1qZlKnvy3kWPYX/hMuSzGZ+mLVJNFEqH2X01aFzppYz0hdI9PGB +9tTFEqZWQL9ZkXfjc79Cgnt12pNukRbtw0N/kyutOdIFHVT79wVAd+powqziXJsC +Kc+4xjwSCkZitB5SU0EgMjA0OCA8cnNhMjA0OEBleGFtcGxlLm9yZz6JATQEEwEC +AB4FAkLIJbECGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQnc+OnJvTHyQqHwf8 +DtzuAGmObfe3ggtn14x2wnU1Nigebe1K5liRnrLuVlLBpdO6CWmMUzfKRvyZlx54 +GlA9uUQSjW+RlgejdOTQqesDrcTEukYd4yzwbLZyM5Gb3lsE/FEmE7Dxw/0Utf59 +uACqzG8LACQn9J6sEgZWKxAupuYTHXd12lDPD3dnU4uzKPhMcjnSN00pzjusP7C9 +NZd3OLkAx2vw/dmb4Q+/QxeZhVYYsAUuR2hv9bgGWopumlOkt8Zu5YG6+CtTbJXp +rPI7pJ1jHbeE+q/29hWJQtS8Abx82AcOkzhvS3NZKoJ/1DrGgoDAu1mGkM4KvLAx +fDs/qQ9dZhtEmDbKPLTVEA== +=WKAv +-----END PGP PRIVATE KEY BLOCK----- +'); + +insert into keytbl (id, name, pubkey, seckey) +values (5, 'psw-elg1024', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQGiBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQLQfRWxnYW1hbCAx +MDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJCyCFIAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAniI9W2bC3CxARTpYrev7ihreDzFc +AJ9WYLQxDQAi5Ec9AQoodPkIagzZ4LkBDQRCyCFKEAQAh5SNbbJMAsJ+sQbcWEzd +ku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioymlDwraTKUAfuCZgNcg/0P +sxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlPiO0wt1lLX+SubktqbYxI ++h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSgMERiNzF0acZUYmc0e+/9 +6gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxsnKjUaw/qyoaFcNMzb4sF +k8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey9ifh8rZfu57UbdwdHa0v +iWc4DilhiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCfdPom+HlNVE9F +ig3hGY1Rb4NEk1gAn1u9IuQB+BgDP40YHHz6bKWS/x80 +=RWci +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQHpBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +tGPBX7OMuaX5eGZ84LFUGvaP0k7anfmXcDkCO3P9GgL+ro/dS2Ps/vChQPZqHaxE +xpKDUt47B7DGdRJrC8DRnIR4wbSyQA6ma3S1yFqC5pJhSs+mqf9eExOjiwCgntth +klRxIYw352ZX9Ov9oht/p/ED/1Xi4PS+tkXVvyIw5aZfa61bT6XvDkoPI0Aj3GE5 +YmCHJlKA/IhEr8QJOLV++5VEv4l6KQ1/DFoJzoNdr1AGJukgTc6X/WcQRzfQtUic +PHQme5oAWoHa6bVQZOwvbJh3mOXDq/Tk/KF22go8maM44vMn4bvv+SBbslviYLiL +jZJ1A/9JXF1esNq+X9HehJyqHHU7LEEf/ck6zC7o2erM3/LZlZuLNPD2cv3oL3Nv +saEgcTSZl+8XmO8pLmzjKIb+hi70qVx3t2IhMqbb4B/dMY1Ck62gPBKa81/Wwi7v +IsEBQLEtyBmGmI64YpzoRNFeaaF9JY+sAKqROqe6dLjJ7vebQP4HAwImKZ5q2QwT +D2DDAY/IQBjes7WgqZeacfLPDoB8ecD/KLoSCH6Z3etvbPHSOKiazxoJ962Ix74H +ZAE6ZbMTtl5dZW1ptB9FbGdhbWFsIDEwMjQgPHRlc3RAZXhhbXBsZS5vcmc+iF4E +ExECAB4FAkLIIUgCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQHCm8DRgXc2Q6 +2wCfXKegLIzoYi8cM57DCYXhn+MZB/MAn1D4zAi5uLQBJ8mJ9oQzbewgfAeinQFf +BELIIUoQBACHlI1tskwCwn6xBtxYTN2S7wB1gHnNjtDJ/0Q6+fSDf1vMA2HGaZvq +BtGVA3SKjKaUPCtpMpQB+4JmA1yD/Q+zEUZv2cNy+MhXyp1WmerU+7MwW4FuYYjr +B6Ds+PTV2U+I7TC3WUtf5K5uS2ptjEj6HfVzdENmrGP4oCDFHxg0YwADBgP7BCzY +d7Vnn6ng5KAwRGI3MXRpxlRiZzR77/3qB8vR+3cg/5JIWjqEQGuQpWFkqg9JJGvk +qk1oShuF3GycqNRrD+rKhoVw0zNviwWTzCrlSUKRH6Hva7qG/wW6V4JXxIlRPVTY +mO2VclHY97L2J+Hytl+7ntRt3B0drS+JZzgOKWH+BwMCJimeatkMEw9gRkFjt4Xa +9rX8awMBE5+vVcGKv/DNiCvJnlYvSdCj8VfuHsYFliiJo6u17NJon+K43e3yvDNk +f631VOVanGEz7TyqOkWQiEkEGBECAAkFAkLIIUoCGwwACgkQHCm8DRgXc2TtrwCe +IUWi3DXHZf6ivK7dDec22bGgoekAn0dTuPDvJ2Dfd0j0nyBWSuaxJnb/ +=SNvr +-----END PGP PRIVATE KEY BLOCK----- +'); + +insert into keytbl (id, name, pubkey, seckey) +values (6, 'rsaenc2048', ' +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +mQELBELr2m0BCADOrnknlnXI0EzRExf/TgoHvK7Xx/E0keWqV3KrOyC3/tY2KOrj +UVxaAX5pkFX9wdQObGPIJm06u6D16CH6CildX/vxG7YgvvKzK8JGAbwrXAfk7OIW +czO2zRaZGDynoK3mAxHRBReyTKtNv8rDQhuZs6AOozJNARdbyUO/yqUnqNNygWuT +4htFDEuLPIJwAbMSD0BvFW6YQaPdxzaAZm3EWVNbwDzjgbBUdBiUUwRdZIFUhsjJ +dirFdy5+uuZru6y6CNC1OERkJ7P8EyoFiZckAIE5gshVZzNuyLOZjc5DhWBvLbX4 +NZElAnfiv+4nA6y8wQLSIbmHA3nqJaBklj85AAYptCVSU0EgMjA0OCBFbmMgPHJz +YTIwNDhlbmNAZXhhbXBsZS5vcmc+iQE0BBMBAgAeBQJC69ptAhsDBgsJCAcDAgMV +AgMDFgIBAh4BAheAAAoJEMiZ6pNEGVVZHMkIAJtGHHZ9iM8Yq1rr0zl1L6SvlQP8 +JCaxHa31wH3PKqGtq2M+cpb2rXf7gAY/doHJPXggfVzkyFrysmQ1gPbDGYLyOutw ++IkhihEb5bWxQBNj+3zAFs1YX6v2HXWbSUSmyY1V9/+NTtKk03olDc/swd3lXzku +UOhcgfpBgIt3Q+MpT6M2+OIF7lVfSb1rWdpwTfGhZzW9szQOeoS4gPvxCCRyuabQ +RJ6DWH61F8fFIDJg1z+A/Obx4fqX6GOA69RzgZ3oukFBIXxNwV9PZNnAmHtZVYO8 +0g/oVYBbuvOYedffDBeQarhERZ5W2TnIE+nqY61YOLBqosliygdZTXULzNi5AQsE +QuvaugEIAOuCJZdkzORA6e1lr81Lnr4JzMsVBFA+X/yIkBbV6qX/A4nVSLAZKNPX +z1YIrMTu+1rMIiy10IWbA6zgMTpzPhJRfgePONgdnCYyK5Ksh5/C5ntzKwwGwxfK +lAXIxJurCHXTbEa+YvPdn76vJ3HsXOXVEL+fLb4U3l3Ng87YM202Lh1Ha2MeS2zE +FZcAoKbFqAAjDLEai64SoOFh0W3CsD1DL4zmfp+YZrUPHTtZadsi53i4KKW/ws9U +rHlolqYNhYze/uRLyfnUx9PN4r/GhEzauyDMV0smo91uB3aewPft+eCpmeWnu0PF +JVK4xyRmhIq2rVCw16a1pBJirvGM+y0ABimJAR8EGAECAAkFAkLr2roCGwwACgkQ +yJnqk0QZVVku1wgAg1bLSjPkhw+ldG5HzumpqR84+JKyozdJaJzefu2+1iqYE0B0 +WLz2PJVIiK41xiEkKhBvTOQYuXmtWqAWXptD91P5SoXoNJWLQO3TNwarANhHxkWg +w/TOUxQqoctlRUej5NDD+4eW5G9lcS1FEGuKDWtX096u80vO+TbyJjvx2eVM1k+X +dmeYsGOiNgDimCreJGYc14G7eY9jt24gw10n1sMAKI1qm6lcoHqZ9OOyla+wJdro +PYZGO7R8+1O9R22WrK6BYDT5j/1JwMZqbOESjNvDEVT0yOHClCHRN4CChbt6LhKh +CLUNdz/udIt0JAC6c/HdPLSW3HnmM3+iNj+Kug== +=pwU2 +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=UKh3 +-----END PGP PRIVATE KEY BLOCK----- +'); + +insert into keytbl (id, name, pubkey, seckey) +values (7, 'rsaenc2048-psw', ' +same key with password +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.11 (GNU/Linux) + +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 +=QFm5 +-----END PGP PRIVATE KEY BLOCK----- +'); + + +-- elg1024 / aes128 +insert into encdata (id, data) values (1, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQEOA9k2z2S7c/RmEAQAgVWW0DeLrZ+1thWJGBPp2WRFL9HeNqqWHbKJCXJbz1Uy +faUY7yxVvG5Eutmo+JMiY3mg23/DgVVXHQZsTWpGvGM6djgUNGKUjZDbW6Nog7Mr +e78IywattCOmgUP9vIwwg3OVjuDCN/nVirGQFnXpJBc8DzWqDMWRWDy1M0ZsK7AD +/2JTosSFxUdpON0DKtIY3GLzmh6Nk3iV0g8VgJKUBT1rhCXuMDj3snm//EMm7hTY +PlnObq4mIhgz8NqprmhooxnU0Kapofb3P3wCHPpU14zxhXY8iKO/3JhBq2uFcx4X +uBMwkW4AdNxY/mzJZELteTL8Tr0s7PISk+owb4URpG3n0jsBc0CVULxrjh5Ejkdw +wCM195J6+KbQxOOFQ0b3uOVvv4dEgd/hRERCOq5EPaFhlHegyYJ7YO842vnSDA== +=PABx +-----END PGP MESSAGE----- +'); + +-- elg2048 / blowfish +insert into encdata (id, data) values (2, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQIOAywibh/+XMfUEAf+OINhBngEsw4a/IJIeJvUgv1gTQzBwOdQEuc/runr4Oa8 +Skw/Bj0X/zgABVZLem1a35NHaNwaQaCFwMQ41YyWCu+jTdsiyX/Nw0w8LKKz0rNC +vVpG6YuV7Turtsf8a5lXy1K0SHkLlgxQ6c76GS4gtSl5+bsL2+5R1gSRJ9NXqCQP +OHRipEiYwBPqr5R21ZG0FXXNKGOGkj6jt/M/wh3WVtAhYuBI+HPKRfAEjd/Pu/eD +e1zYtkH1dKKFmp44+nF0tTI274xpuso7ShfKYrOK3saFWrl0DWiWteUinjSA1YBY +m7dG7NZ8PW+g1SZWhEoPjEEEHz3kWMvlKheMRDudnQf/dDyX6kZVIAQF/5B012hq +QyVewgTGysowFIDn01uIewoEA9cASw699jw9IoJp+k5WZXnU+INllBLzQxniQCSu +iEcr0x3fYqNtj9QBfbIqyRcY6HTWcmzyOUeGaSyX76j+tRAvtVtXpraFFFnaHB70 +YpXTjLkp8EBafzMghFaKDeXlr2TG/T7rbwcwWrFIwPqEAUKWN5m97Q3eyo8/ioMd +YoFD64J9ovSsgbuU5IpIGAsjxK+NKzg/2STH7zZFEVCtgcIXsTHTZfiwS98/+1H9 +p1DIDaXIcUFV2ztmcKxh9gt2sXRz1W+x6D8O0k3nanU5yGG4miLKaq18fbcA0BD1 ++NIzAfelq6nvvxYKcGcamBMgLo5JkZOBHvyr6RsAKIT5QYc0QTjysTk9l0Am3gYc +G2pAE+3k +=TBHV +-----END PGP MESSAGE----- +'); + +-- elg4096 / aes256 +insert into encdata (id, data) values (3, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQQOA7aFBP0Sjh/5EA/+JCgncc8IZmmRjPStWnGf9tVJhgHTn+smIclibGzs0deS +SPSCitzpblwbUDvu964+/5e5Q1l7rRuNN+AgETlEd4eppv7Swn2ChdgOXxRwukcT +Nh3G+PTFvD4ayi7w1db3qvXIt0MwN4Alt436wJmK1oz2Ka9IcyO+wHWrDy1nSGSx +z5x7YEj+EZPgWc/YAvudqE8Jpzd/OT5zSHN09UFkIAk6NxisKaIstbEGFgpqtoDZ +1SJM84XAdL2IcaJ3YY7k/yzwlawhsakKd4GSd5vWmAwvyzzbSiBMfKsDE16ePLNU +ZBF7CzmlCBPZ7YrFAHLpXBXXkCQvzD2BEYOjse50ZEfJ036T7950Ozcdy1EQbGon +nyQ4Gh0PBpnMcBuiXOceWuYzhlzFOzDtlVKdNTxFRDcbEyW2jo9xQYvCCLnYy8EH +2M7S8jCtVYJBbn63a82ELv+3+kWYcsvBJv2ZVBh4ncrBu9o0P+OYS7ApoOU+j6p2 ++t0RXHksqXS1YiUwYF5KSw09EbYMgNZ9G04Px/PxLU6fSC9iDrGX7Xt3kOUP0mku +C518fPckT0zzRXqfFruJNRzDytW50KxkOQZzU1/Az1YlYN9QzWeU4EtLPb2fftZo +D0qH/ln+f9Op5t6sD2fcxZVECU1b/bFtZsxvwH406YL+UQ7hU/XnZrzVVzODal8P +/j1hg7v7BdJqu1DTp9nFWUuwMFcYAczuXn29IG183NZ7Ts4whDeYEhS8eNoLPX4j +txY12ILD/w/3Q4LoW/hPa6OdfEzsn0U5GLf1WiGmJE1H6ft2U/xUnerc/u0kt+FU +WAisArd4MuKtf7B5Vu/VF3kUdrR0hTniUKUivmC4o1jSId31Dufxj4aadVyldXAr +6TNBcdyragZjxEZ6hsBCYzA0Rd1a8atd6OaQoIEEfAzCu5Ks29pydHErStYGjWJ1 +KA5KPLVvjbHpDmRhlCcm8vgpYQsBYEB5gE9fx5yCTlsVhCB6y23h7hfdMqerDqkO +ZOPsO5h+tiHCdIrQ36sMjuINy1/K2rYcXd+Crh2iHcfidpU9fvDz2ihTRNQlhjuT +0cQZM5JhctEx4VXF4LDctRhit7Hn0iqsk604woQfJVvP8O673xSXT/kBY0A/v9C0 +3C4YoFNeSaKwbfZQ/4u1ZFPJxK2IIJa8UGpyAUewLMlzGVVagljybv/f4Z9ERAhy +huq5sMmw8UPsrJF2TUGHz5WSIwoh0J/qovoQI09I9sdEnFczDvRavMO2Mldy3E5i +exz9oewtel6GOmsZQSYWT/vJzbYMmvHNmNpVwwoKrLV6oI3kyQ80GHBwI1WlwHoK +2iRB0w8q4VVvJeYAz8ZIp380cqC3pfO0uZsrOx4g3k4X0jsB5y7rF5xXcZfnVbvG +DYKcOy60/OHMWVvpw6trAoA+iP+cVWPtrbRvLglTVTfYmi1ToZDDipkALBhndQ== +=L/M/ +-----END PGP MESSAGE----- +'); + +-- rsaenc2048 / aes128 +insert into encdata (id, data) values (4, ' +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.1 (GNU/Linux) + +hQEMA/0CBsQJt0h1AQf+JyYnCiortj26P11zk28MKOGfWpWyAhuIgwbJXsdQ+e6r +pEyyqs9GC6gI7SNF6+J8B/gsMwvkAL4FHAQCvA4ZZ6eeXR1Of4YG22JQGmpWVWZg +DTyfhA2vkczuqfAD2tgUpMT6sdyGkQ/fnQ0lknlfHgC5GRx7aavOoAKtMqiZW5PR +yae/qR48mjX7Mb+mLvbagv9mHEgQSmHwFpaq2k456BbcZ23bvCmBnCvqV/90Ggfb +VP6gkSoFVsJ19RHsOhW1dk9ehbl51WB3zUOO5FZWwUTY9DJvKblRK/frF0+CXjE4 +HfcZXHSpSjx4haGGTsMvEJ85qFjZpr0eTGOdY5cFhNJAAVP8MZfji7OhPRAoOOIK +eRGOCkao12pvPyFTFnPd5vqmyBbdNpK4Q0hS82ljugMJvM0p3vJZVzW402Kz6iBL +GQ== +=XHkF +-----END PGP MESSAGE----- +'); + +-- rsaenc2048 / aes128 (not from gnupg) +insert into encdata (id, data) values (5, ' +-----BEGIN PGP MESSAGE----- + +wcBMA/0CBsQJt0h1AQgAzxZ8j+OTeZ8IlLxfZ/mVd28/gUsCY+xigWBk/anZlK3T +p2tNU2idHzKdAttH2Hu/PWbZp4kwjl9spezYxMqCeBZqtfGED88Y+rqK0n/ul30A +7jjFHaw0XUOqFNlST1v6H2i7UXndnp+kcLfHPhnO5BIYWxB2CYBehItqtrn75eqr +C7trGzU/cr74efcWagbCDSNjiAV7GlEptlzmgVMmNikyI6w0ojEUx8lCLc/OsFz9 +pJUAX8xuwjxDVv+W7xk6c96grQiQlm+FLDYGiGNXoAzx3Wi/howu3uV40dXfY+jx +3WBrhEew5Pkpt1SsWoFnJWOfJ8GLd0ec8vfRCqAIVdLgAeS7NyawQYtd6wuVrEAj +5SMg4Thb4d+g45RksuGLHUUr4qO9tiXglODa4InhmJfgNuLk+RGz4LXjq8wepEmW +vRbgFOG54+Cf4C/gC+HkreDm5JKSKjvvw4B/jC6CDxq+JoziEe2Z1uEjCuEcr+Es +/eGzeOi36BejXPMHeKxXejj5qBBHKV0pHVhZSgffR0TtlXdB967Yl/5agV0R89hI +7Gw52emfnH4Z0Y4V0au2H0k1dR/2IxXdJEWSTG7Be1JHT59p9ei2gSEOrdBMIOjP +tbYYUlmmbvD49bHfThkDiC+oc9947LgQsk3kOOLbNHcjkbrjH8R5kjII4m/SEZA1 +g09T+338SzevBcVXh/cFrQ6/Et+lyyO2LJRUMs69g/HyzJOVWT2Iu8E0eS9MWevY +Qtrkrhrpkl3Y02qEp/j6M03Yu2t6ZF7dp51aJ5VhO2mmmtHaTnCyCc8Fcf72LmD8 +blH2nKZC9d6fi4YzSYMepZpMOFR65M80MCMiDUGnZBB8sEADu2/iVtqDUeG8mAA= +=PHJ1 +-----END PGP MESSAGE----- +'); + +-- successful decrypt +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=1 and encdata.id=1; + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=2; + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=3 and encdata.id=3; + +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=6 and encdata.id=4; + +-- wrong key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=1; + +-- sign-only key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=4 and encdata.id=1; + +-- rsa: password-protected secret key, wrong password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), '123') +from keytbl, encdata where keytbl.id=7 and encdata.id=4; + +-- rsa: password-protected secret key, right password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool') +from keytbl, encdata where keytbl.id=7 and encdata.id=4; + +-- password-protected secret key, no password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=5 and encdata.id=1; + +-- password-protected secret key, wrong password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'foo') +from keytbl, encdata where keytbl.id=5 and encdata.id=1; + +-- password-protected secret key, right password +select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool') +from keytbl, encdata where keytbl.id=5 and encdata.id=1; + +-- test for a short read from prefix_init +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=6 and encdata.id=5; diff --git a/contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql b/contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql new file mode 100644 index 0000000..c9edbc6 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql @@ -0,0 +1,48 @@ +-- +-- PGP Public Key Encryption +-- + +-- successful encrypt/decrypt +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; + +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=2; + +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=3; + +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=6; + +-- try with rsa-sign only +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=4; + +-- try with secret key +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(seckey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; + +-- does text-to-bytea works +select encode(pgp_pub_decrypt_bytea( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)), 'escape') +from keytbl where keytbl.id=1; + +-- and bytea-to-text? +select pgp_pub_decrypt( + pgp_pub_encrypt_bytea('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; diff --git a/contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql b/contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql new file mode 100644 index 0000000..6f4eccd --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql @@ -0,0 +1 @@ +-- zlib is disabled diff --git a/contrib/pgcrypto/sql/rijndael.sql b/contrib/pgcrypto/sql/rijndael.sql new file mode 100644 index 0000000..a276641 --- /dev/null +++ b/contrib/pgcrypto/sql/rijndael.sql @@ -0,0 +1,72 @@ +-- +-- AES cipher (aka Rijndael-128, -192, or -256) +-- + +-- some standard Rijndael testvalues +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f', +'aes-ecb/pad:none'); + +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f1011121314151617', +'aes-ecb/pad:none'); + +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', +'aes-ecb/pad:none'); + +-- cbc +SELECT encrypt( +'\x00112233445566778899aabbccddeeff', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', +'aes-cbc/pad:none'); + +-- without padding, input not multiple of block size +SELECT encrypt( +'\x00112233445566778899aabbccddeeff00', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', +'aes-cbc/pad:none'); + +-- key padding + +SELECT encrypt( +'\x0011223344', +'\x000102030405', +'aes-cbc'); + +SELECT encrypt( +'\x0011223344', +'\x000102030405060708090a0b0c0d0e0f10111213', +'aes-cbc'); + +SELECT encrypt( +'\x0011223344', +'\x000102030405060708090a0b0c0d0e0f101112131415161718191a1b', +'aes-cbc'); + +-- empty data +select encrypt('', 'foo', 'aes'); +-- 10 bytes key +select encrypt('foo', '0123456789', 'aes'); +-- 22 bytes key +select encrypt('foo', '0123456789012345678901', 'aes'); + +-- decrypt +select encode(decrypt(encrypt('foo', '0123456', 'aes'), '0123456', 'aes'), 'escape'); +-- data not multiple of block size +select encode(decrypt(encrypt('foo', '0123456', 'aes') || '\x00'::bytea, '0123456', 'aes'), 'escape'); +-- bad padding +-- (The input value is the result of encrypt_iv('abcdefghijklmnopqrstuvwxyz', '0123456', 'abcd', 'aes') +-- with the 16th byte changed (s/db/eb/) to corrupt the padding of the last block.) +select encode(decrypt_iv('\xa21a9c15231465964e3396d32095e67eb52bab05f556a581621dee1b85385789', '0123456', 'abcd', 'aes'), 'escape'); + +-- iv +select encrypt_iv('foo', '0123456', 'abcd', 'aes'); +select encode(decrypt_iv('\x2c24cb7da91d6d5699801268b0f5adad', '0123456', 'abcd', 'aes'), 'escape'); + +-- long message +select encrypt('Lets try a longer message.', '0123456789', 'aes'); +select encode(decrypt(encrypt('Lets try a longer message.', '0123456789', 'aes'), '0123456789', 'aes'), 'escape'); diff --git a/contrib/pgcrypto/sql/sha1.sql b/contrib/pgcrypto/sql/sha1.sql new file mode 100644 index 0000000..6d1f24e --- /dev/null +++ b/contrib/pgcrypto/sql/sha1.sql @@ -0,0 +1,11 @@ +-- +-- SHA1 message digest +-- + +SELECT digest('', 'sha1'); +SELECT digest('a', 'sha1'); +SELECT digest('abc', 'sha1'); +SELECT digest('message digest', 'sha1'); +SELECT digest('abcdefghijklmnopqrstuvwxyz', 'sha1'); +SELECT digest('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'sha1'); +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha1'); diff --git a/contrib/pgcrypto/sql/sha2.sql b/contrib/pgcrypto/sql/sha2.sql new file mode 100644 index 0000000..3aafd35 --- /dev/null +++ b/contrib/pgcrypto/sql/sha2.sql @@ -0,0 +1,33 @@ +-- +-- SHA2 family +-- + +-- SHA224 +SELECT digest('', 'sha224'); +SELECT digest('a', 'sha224'); +SELECT digest('abc', 'sha224'); +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha224'); +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha224'); + +-- SHA256 +SELECT digest('', 'sha256'); +SELECT digest('a', 'sha256'); +SELECT digest('abc', 'sha256'); +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha256'); +SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha256'); + +-- SHA384 +SELECT digest('', 'sha384'); +SELECT digest('a', 'sha384'); +SELECT digest('abc', 'sha384'); +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha384'); +SELECT digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha384'); +SELECT digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha384'); + +-- SHA512 +SELECT digest('', 'sha512'); +SELECT digest('a', 'sha512'); +SELECT digest('abc', 'sha512'); +SELECT digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha512'); +SELECT digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha512'); +SELECT digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha512'); |