From e94dd6ab9100961511e3407fea9e5b191dec7165 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sun, 10 Jul 2005 13:46:29 +0000 Subject: [PATCH] Add missing pgcrypto files from previous commit. --- contrib/pgcrypto/expected/pgp-armor.out | 102 ++ contrib/pgcrypto/expected/pgp-compression.out | 50 + contrib/pgcrypto/expected/pgp-decrypt.out | 366 ++++++ .../expected/pgp-encrypt-DISABLED.out | 1 + contrib/pgcrypto/expected/pgp-encrypt.out | 189 +++ contrib/pgcrypto/expected/pgp-info.out | 65 + .../pgcrypto/expected/pgp-pubkey-DISABLED.out | 1 + .../pgcrypto/expected/pgp-pubkey-decrypt.out | 441 +++++++ .../pgcrypto/expected/pgp-pubkey-encrypt.out | 59 + .../pgcrypto/expected/pgp-zlib-DISABLED.out | 1 + contrib/pgcrypto/expected/sha2.out | 108 ++ contrib/pgcrypto/fortuna.c | 365 ++++++ contrib/pgcrypto/fortuna.h | 45 + contrib/pgcrypto/mbuf.c | 556 ++++++++ contrib/pgcrypto/mbuf.h | 121 ++ contrib/pgcrypto/pgp-armor.c | 383 ++++++ contrib/pgcrypto/pgp-cfb.c | 257 ++++ contrib/pgcrypto/pgp-compress.c | 322 +++++ contrib/pgcrypto/pgp-decrypt.c | 1156 +++++++++++++++++ contrib/pgcrypto/pgp-encrypt.c | 698 ++++++++++ contrib/pgcrypto/pgp-info.c | 213 +++ contrib/pgcrypto/pgp-mpi-internal.c | 50 + contrib/pgcrypto/pgp-mpi-openssl.c | 197 +++ contrib/pgcrypto/pgp-mpi.c | 134 ++ contrib/pgcrypto/pgp-pgsql.c | 901 +++++++++++++ contrib/pgcrypto/pgp-pubdec.c | 193 +++ contrib/pgcrypto/pgp-pubenc.c | 230 ++++ contrib/pgcrypto/pgp-pubkey.c | 448 +++++++ contrib/pgcrypto/pgp-s2k.c | 299 +++++ contrib/pgcrypto/pgp.c | 351 +++++ contrib/pgcrypto/pgp.h | 273 ++++ contrib/pgcrypto/sha2.c | 895 +++++++++++++ contrib/pgcrypto/sha2.h | 80 ++ contrib/pgcrypto/sql/pgp-armor.sql | 56 + contrib/pgcrypto/sql/pgp-compression.sql | 31 + contrib/pgcrypto/sql/pgp-decrypt.sql | 266 ++++ contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql | 3 + contrib/pgcrypto/sql/pgp-encrypt.sql | 96 ++ contrib/pgcrypto/sql/pgp-info.sql | 21 + contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql | 3 + contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql | 437 +++++++ contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql | 45 + contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql | 3 + contrib/pgcrypto/sql/sha2.sql | 28 + 44 files changed, 10539 insertions(+) create mode 100644 contrib/pgcrypto/expected/pgp-armor.out create mode 100644 contrib/pgcrypto/expected/pgp-compression.out create mode 100644 contrib/pgcrypto/expected/pgp-decrypt.out create mode 100644 contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out create mode 100644 contrib/pgcrypto/expected/pgp-encrypt.out create mode 100644 contrib/pgcrypto/expected/pgp-info.out create mode 100644 contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out create mode 100644 contrib/pgcrypto/expected/pgp-pubkey-decrypt.out create mode 100644 contrib/pgcrypto/expected/pgp-pubkey-encrypt.out create mode 100644 contrib/pgcrypto/expected/pgp-zlib-DISABLED.out create mode 100644 contrib/pgcrypto/expected/sha2.out create mode 100644 contrib/pgcrypto/fortuna.c create mode 100644 contrib/pgcrypto/fortuna.h create mode 100644 contrib/pgcrypto/mbuf.c create mode 100644 contrib/pgcrypto/mbuf.h create mode 100644 contrib/pgcrypto/pgp-armor.c create mode 100644 contrib/pgcrypto/pgp-cfb.c create mode 100644 contrib/pgcrypto/pgp-compress.c create mode 100644 contrib/pgcrypto/pgp-decrypt.c create mode 100644 contrib/pgcrypto/pgp-encrypt.c create mode 100644 contrib/pgcrypto/pgp-info.c create mode 100644 contrib/pgcrypto/pgp-mpi-internal.c create mode 100644 contrib/pgcrypto/pgp-mpi-openssl.c create mode 100644 contrib/pgcrypto/pgp-mpi.c create mode 100644 contrib/pgcrypto/pgp-pgsql.c create mode 100644 contrib/pgcrypto/pgp-pubdec.c create mode 100644 contrib/pgcrypto/pgp-pubenc.c create mode 100644 contrib/pgcrypto/pgp-pubkey.c create mode 100644 contrib/pgcrypto/pgp-s2k.c create mode 100644 contrib/pgcrypto/pgp.c create mode 100644 contrib/pgcrypto/pgp.h create mode 100644 contrib/pgcrypto/sha2.c create mode 100644 contrib/pgcrypto/sha2.h create mode 100644 contrib/pgcrypto/sql/pgp-armor.sql create mode 100644 contrib/pgcrypto/sql/pgp-compression.sql create mode 100644 contrib/pgcrypto/sql/pgp-decrypt.sql create mode 100644 contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql create mode 100644 contrib/pgcrypto/sql/pgp-encrypt.sql create mode 100644 contrib/pgcrypto/sql/pgp-info.sql create mode 100644 contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql create mode 100644 contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql create mode 100644 contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql create mode 100644 contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql create mode 100644 contrib/pgcrypto/sql/sha2.sql diff --git a/contrib/pgcrypto/expected/pgp-armor.out b/contrib/pgcrypto/expected/pgp-armor.out new file mode 100644 index 0000000000..ba7d426237 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-armor.out @@ -0,0 +1,102 @@ +-- +-- 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 dearmor(armor('')); + dearmor +--------- + +(1 row) + +select dearmor(armor('zooka')); + dearmor +--------- + zooka +(1 row) + +select armor('0123456789abcdef0123456789abcdef0123456789abcdef +0123456789abcdef0123456789abcdef0123456789abcdef'); + armor +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + -----BEGIN PGP MESSAGE----- + +MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmCjAxMjM0NTY3 +ODlhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmMDEyMzQ1Njc4OWFiY2RlZg== +=JFw5 +-----END PGP MESSAGE----- + +(1 row) + +-- lots formatting +select dearmor(' a pgp msg: + +-----BEGIN PGP MESSAGE----- +Comment: Some junk + +em9va2E= + + =D5cR + +-----END PGP MESSAGE-----'); + dearmor +--------- + zooka +(1 row) + +-- lots messages +select 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----- +'); + dearmor +--------- + right +(1 row) + +-- bad crc +select dearmor(' +-----BEGIN PGP MESSAGE----- + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); +ERROR: dearmor: Corrupt ascii-armor diff --git a/contrib/pgcrypto/expected/pgp-compression.out b/contrib/pgcrypto/expected/pgp-compression.out new file mode 100644 index 0000000000..32b350b8fe --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-compression.out @@ -0,0 +1,50 @@ +-- +-- 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) + diff --git a/contrib/pgcrypto/expected/pgp-decrypt.out b/contrib/pgcrypto/expected/pgp-decrypt.out new file mode 100644 index 0000000000..8ecb56f009 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-decrypt.out @@ -0,0 +1,366 @@ +-- +-- pgp_descrypt 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 encode(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'), 'hex'); + encode +------------------------------------------ + 0225e3ede6f2587b076d021a189ff60aad67e066 +(1 row) + +-- expected: 0225e3ede6f2587b076d021a189ff60aad67e066 +select encode(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'), 'hex'); + encode +------------------------------------------ + da39a3ee5e6b4b0d3255bfef95601890afd80709 +(1 row) + +-- expected: da39a3ee5e6b4b0d3255bfef95601890afd80709 +select encode(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'), 'hex'); + encode +------------------------------------------ + 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c +(1 row) + +-- expected: 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c +-- Checking CRLF +select encode(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'), 'hex'); + encode +------------------------------------------ + 9353062be7720f1446d30b9e75573a4833886784 +(1 row) + +-- expected: 9353062be7720f1446d30b9e75573a4833886784 +select encode(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'), 'hex'); + encode +------------------------------------------ + 7efefcab38467f7484d6fa43dc86cf5281bd78e2 +(1 row) + +-- expected: 7efefcab38467f7484d6fa43dc86cf5281bd78e2 diff --git a/contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out b/contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out new file mode 100644 index 0000000000..4122300d97 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out @@ -0,0 +1 @@ +-- no random source diff --git a/contrib/pgcrypto/expected/pgp-encrypt.out b/contrib/pgcrypto/expected/pgp-encrypt.out new file mode 100644 index 0000000000..b04bae5720 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-encrypt.out @@ -0,0 +1,189 @@ +-- +-- 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: pgp_decrypt error: Not text data +-- text as bytea +select pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'); + pgp_sym_decrypt_bytea +----------------------- + 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 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 encode(pgp_sym_decrypt_bytea( + pgp_sym_encrypt('1\n2\n3\r\n', 'key', 'convert-crlf=1'), + 'key'), 'hex'); + encode +---------------------- + 310d0a320d0a330d0d0a +(1 row) + +-- conversion should be lossless +select encode(digest(pgp_sym_decrypt( + pgp_sym_encrypt('\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'), + 'key', 'convert-crlf=1'), 'sha1'), 'hex') as result, + encode(digest('\r\n0\n1\r\r\n\n2\r', 'sha1'), 'hex') as expect; + result | expect +------------------------------------------+------------------------------------------ + 47bde5d88d6ef8770572b9cbb4278b402aa69966 | 47bde5d88d6ef8770572b9cbb4278b402aa69966 +(1 row) + diff --git a/contrib/pgcrypto/expected/pgp-info.out b/contrib/pgcrypto/expected/pgp-info.out new file mode 100644 index 0000000000..300d41adcd --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-info.out @@ -0,0 +1,65 @@ +-- +-- 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 usable key found (expecting Elgamal key) +select pgp_key_id(dearmor(pubkey)) from keytbl where id=5; + pgp_key_id +------------------ + D936CF64BB73F466 +(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 usable key found (expecting Elgamal key) +select pgp_key_id(dearmor(seckey)) from keytbl where id=5; + pgp_key_id +------------------ + D936CF64BB73F466 +(1 row) + +select pgp_key_id(dearmor(data)) as data_key_id +from encdata order by id; + data_key_id +------------------ + D936CF64BB73F466 + 2C226E1FFE5CC7D4 + B68504FD128E1FF9 +(3 rows) + diff --git a/contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out b/contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out new file mode 100644 index 0000000000..d35c0971ba --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out @@ -0,0 +1 @@ +-- no bignum support diff --git a/contrib/pgcrypto/expected/pgp-pubkey-decrypt.out b/contrib/pgcrypto/expected/pgp-pubkey-decrypt.out new file mode 100644 index 0000000000..28881ad347 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-decrypt.out @@ -0,0 +1,441 @@ +-- +-- 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) + +mQGiBELII7wRBACFuaAvb11cIvjJK9LkZr4cYuYhLWh3DJdojNNnLNiym5OEksvY +05cw8OgqKtPzICU7o/mHXTWhzJYUt3i50/AeYygI8Q0uATS6RnDAKNlES1EMoHKz +2a5iFbYs4bm4IwlkvYd8uWjcu+U0YLbxir39u+anIc6eT+q3WiH/q3zDRwCgkT98 +cnIG8iO8PdwDSP8G4Lt6TYED/R45GvCzJ4onQALLE92KkLUz8aFWSl05r84kczEN +SxiP9Ss6m465RmwWHfwYAu4b+c4GeNyU8fIU2EM8cezchC+edEi3xu1s+pCV0Dk4 +18DGC8WKCICO30vBynuNmYg7W/7Zd4wtjss454fMW7+idVDNM701mmXBtI1nsBtG +7Z4tA/9FxjFbJK9jh24RewfjHpLYqcfCo2SsUjOwsnMZ5yg2yv9KyVVQhRqwmrqt +q8MRyjGmfoD9PPdCgvqgzy0hHvAHUtTm2zUczGTG+0g4hNIklxC/Mv6J4KE+NWTh +uB4acqofHyaw2WnKOuRUsoDi6rG5AyjNMyAK/vVcEGj7J1tk27QjRWxnYW1hbCA0 +MDk2IDx0ZXN0NDA5NkBleGFtcGxlLm9yZz6IXgQTEQIAHgUCQsgjvAIbAwYLCQgH +AwIDFQIDAxYCAQIeAQIXgAAKCRBj+HX2P2d0oAEDAJ9lI+CNmb42z3+a6TnVusM6 +FI7oLwCfUwA1zEcRdsT3nIkoYh0iKxFSDFW5BA0EQsgkdhAQAJQbLXlgcJ/jq+Xh +Eujb77/eeftFJObNIRYD9fmJ7HFIXbUcknEpbs+cRH/nrj5dGSY3OT3jCXOUtvec +sCoX/CpZWL0oqDjAiZtNSFiulw5Gav4gHYkWKgKdSo+2rkavEPqKIVHvMeXaJtGT +d7v/AmL/P8T7gls93o5WFBOLtPbDvWqaKRy2U5TAhl1laiM0vGALRVjvSCgnGw9g +FpSnXbO3AfenUSjDzZujfGLHtU44ixHSS/D4DepiF3YaYLsN4CBqZRv6FbMZD5W3 +DnJY4kS1kH0MzdcF19TlcZ3itTCcGIt1tMKf84mccPoqdMzH7vumBGTeFEly5Afp +9berJcirqh2fzlunN0GS02z6SGWnjTbDlkNDxuxPSBbpcpNyD3jpYAUqSwRsZ/+5 +zkzcbGtDmvy9sJ5lAXkxGoIoQ1tEVX/LOHnh2NQHK8ourVOnr7MS0nozssITZJ5E +XqtHiREjiYEuPyZiVZKJHLWuYYaF+n40znnz3sJuXFRreHhHbbvRdlYUU5mJV+XZ +BLgKuS33NdpGeMIngnCc/9IQ6OZb6ixc94kbkd3w2PVr8CbKlu/IHTjWOO2mAo+D ++OydlYl23FiM3KOyMP1HcEOJMB/nwkMtrvd+522Lu9n77ktKfot9IPrQDIQTyXjR +3pCOFtCOBnk2tJHMPoG9jn9ah/LHAAMHEACDZ5I/MHGfmiKg2hrmqBu2J2j/deC8 +CpwcyDH1ovQ0gHvb9ESa+CVRU2Wdy2CD7Q9SmtMverB5eneL418iPVRcQdwRmQ2y +IH4udlBa6ce9HTUCaecAZ4/tYBnaC0Av/9l9tz14eYcwRMDpB+bnkhgF+PZ1KAfD +9wcY2aHbtsf3lZBc5h4owPJkxpe/BNzuJxW3q4VpSbLsZhwnCZ2wg7DRwP44wFIk +00ptmoBY59gsU6I40XtzrF8JDr0cA57xND5RY21Z8lnnYRE1Tc8h5REps9ZIxW3/ +yl91404bPLqxczpUHQAMSTAmBaStPYX1nS51uofOhLs5SKPCUmxfGKIOhsD0oLUn +78DnkONVGeXzBibSwwtbgfMzee4G8wSUfJ7w8WXz1TyanaGLnJ+DuKASSOrFoBCD +HEDuWZWgSL74NOQupFRk0gxOPmqU94Y8HziQWma/cETbmD83q8rxN+GM2oBxQkQG +xcbqMTHE7aVhV3tymbSWVaYhww3oIwsZS9oUIi1DnPEowS6CpVRrwdvLjLJnJzzV +O3AFPn9eZ1Q7R1tNx+zZ4OOfhvI/OlRJ3HBx2L53embkbdY9gFYCCdTjPyjKoDIx +kALgCajjCYMNUsAKNSd6mMCQ8TtvukSzkZS1RGKP27ohsdnzIVsiEAbxDMMcI4k1 +ul0LExUTCXSjeIhJBBgRAgAJBQJCyCR2AhsMAAoJEGP4dfY/Z3Sg19sAn0NDS8pb +qrMpQAxSb7zRTmcXEFd9AJ435H0ttP/NhLHXC9ezgbCMmpXMOQ== +=kRxT +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELII7wRBACFuaAvb11cIvjJK9LkZr4cYuYhLWh3DJdojNNnLNiym5OEksvY +05cw8OgqKtPzICU7o/mHXTWhzJYUt3i50/AeYygI8Q0uATS6RnDAKNlES1EMoHKz +2a5iFbYs4bm4IwlkvYd8uWjcu+U0YLbxir39u+anIc6eT+q3WiH/q3zDRwCgkT98 +cnIG8iO8PdwDSP8G4Lt6TYED/R45GvCzJ4onQALLE92KkLUz8aFWSl05r84kczEN +SxiP9Ss6m465RmwWHfwYAu4b+c4GeNyU8fIU2EM8cezchC+edEi3xu1s+pCV0Dk4 +18DGC8WKCICO30vBynuNmYg7W/7Zd4wtjss454fMW7+idVDNM701mmXBtI1nsBtG +7Z4tA/9FxjFbJK9jh24RewfjHpLYqcfCo2SsUjOwsnMZ5yg2yv9KyVVQhRqwmrqt +q8MRyjGmfoD9PPdCgvqgzy0hHvAHUtTm2zUczGTG+0g4hNIklxC/Mv6J4KE+NWTh +uB4acqofHyaw2WnKOuRUsoDi6rG5AyjNMyAK/vVcEGj7J1tk2wAAoJCUNy6awTkw +XfbLbpqh0fvDst7jDLa0I0VsZ2FtYWwgNDA5NiA8dGVzdDQwOTZAZXhhbXBsZS5v +cmc+iF4EExECAB4FAkLII7wCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQY/h1 +9j9ndKABAwCeNEOVK87EzXYbtxYBsnjrUI948NIAn2+f3BXiBFDV5NvqPwIZ0m77 +Fwy4nQRMBELIJHYQEACUGy15YHCf46vl4RLo2++/3nn7RSTmzSEWA/X5iexxSF21 +HJJxKW7PnER/564+XRkmNzk94wlzlLb3nLAqF/wqWVi9KKg4wImbTUhYrpcORmr+ +IB2JFioCnUqPtq5GrxD6iiFR7zHl2ibRk3e7/wJi/z/E+4JbPd6OVhQTi7T2w71q +mikctlOUwIZdZWojNLxgC0VY70goJxsPYBaUp12ztwH3p1Eow82bo3xix7VOOIsR +0kvw+A3qYhd2GmC7DeAgamUb+hWzGQ+Vtw5yWOJEtZB9DM3XBdfU5XGd4rUwnBiL +dbTCn/OJnHD6KnTMx+77pgRk3hRJcuQH6fW3qyXIq6odn85bpzdBktNs+khlp402 +w5ZDQ8bsT0gW6XKTcg946WAFKksEbGf/uc5M3GxrQ5r8vbCeZQF5MRqCKENbRFV/ +yzh54djUByvKLq1Tp6+zEtJ6M7LCE2SeRF6rR4kRI4mBLj8mYlWSiRy1rmGGhfp+ +NM55897CblxUa3h4R2270XZWFFOZiVfl2QS4Crkt9zXaRnjCJ4JwnP/SEOjmW+os +XPeJG5Hd8Nj1a/AmypbvyB041jjtpgKPg/jsnZWJdtxYjNyjsjD9R3BDiTAf58JD +La73fudti7vZ++5LSn6LfSD60AyEE8l40d6QjhbQjgZ5NrSRzD6BvY5/WofyxwAD +BxAAg2eSPzBxn5oioNoa5qgbtido/3XgvAqcHMgx9aL0NIB72/REmvglUVNlnctg +g+0PUprTL3qweXp3i+NfIj1UXEHcEZkNsiB+LnZQWunHvR01AmnnAGeP7WAZ2gtA +L//Zfbc9eHmHMETA6Qfm55IYBfj2dSgHw/cHGNmh27bH95WQXOYeKMDyZMaXvwTc +7icVt6uFaUmy7GYcJwmdsIOw0cD+OMBSJNNKbZqAWOfYLFOiONF7c6xfCQ69HAOe +8TQ+UWNtWfJZ52ERNU3PIeURKbPWSMVt/8pfdeNOGzy6sXM6VB0ADEkwJgWkrT2F +9Z0udbqHzoS7OUijwlJsXxiiDobA9KC1J+/A55DjVRnl8wYm0sMLW4HzM3nuBvME +lHye8PFl89U8mp2hi5yfg7igEkjqxaAQgxxA7lmVoEi++DTkLqRUZNIMTj5qlPeG +PB84kFpmv3BE25g/N6vK8TfhjNqAcUJEBsXG6jExxO2lYVd7cpm0llWmIcMN6CML +GUvaFCItQ5zxKMEugqVUa8Hby4yyZyc81TtwBT5/XmdUO0dbTcfs2eDjn4byPzpU +Sdxwcdi+d3pm5G3WPYBWAgnU4z8oyqAyMZAC4Amo4wmDDVLACjUnepjAkPE7b7pE +s5GUtURij9u6IbHZ8yFbIhAG8QzDHCOJNbpdCxMVEwl0o3gAAckBdfKuasiNUn5G +L5XRnSvaOFzftr8zteOlZChCSNvzH5k+i1j7RJbWq06OeKRywPzjfjgM2MvRzI43 +ICeISQQYEQIACQUCQsgkdgIbDAAKCRBj+HX2P2d0oNfbAJ9+G3SeXrk+dWwo9EGi +hqMi2GVTsgCfeoQJPsc8FLYUgfymc/3xqAVLUtg= +=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) + +lQHhBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +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+sAKqROqe6dLjJ7vebQP4DAwL3TCgrYdj6 ++GAnoSqGa87twi8a6QRRYIlEx3ddUCDCjzkJmRfF+LFtvX3OtWWK0+Syi3kj2IK9 +YT7pF7QfRWxnYW1hbCAxMDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJC +yCFIAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAn1ynoCyM +6GIvHDOewwmF4Z/jGQfzAJ9Q+MwIubi0ASfJifaEM23sIHwHop0BVwRCyCFKEAQA +h5SNbbJMAsJ+sQbcWEzdku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioym +lDwraTKUAfuCZgNcg/0PsxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlP +iO0wt1lLX+SubktqbYxI+h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSg +MERiNzF0acZUYmc0e+/96gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxs +nKjUaw/qyoaFcNMzb4sFk8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey +9ifh8rZfu57UbdwdHa0viWc4Dilh/gMDAvdMKCth2Pr4YCCPsELdgJuzhGfDNRSg +nKMRWBWHSJRk6JmCjM1iJQNHc4mMhR8gvi2TeqYLOhYjcF7nr/LA+JvLV+adj/mI +SQQYEQIACQUCQsghSgIbDAAKCRAcKbwNGBdzZO2vAJ4hRaLcNcdl/qK8rt0N5zbZ +saCh6QCfR1O48O8nYN93SPSfIFZK5rEmdv8= +=Y6Qv +-----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----- +'); +-- 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) + +-- wrong key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=2 and encdata.id=1; +ERROR: pgp_decrypt error: Data is not encrypted with this key +-- sign-only key +select pgp_pub_decrypt(dearmor(data), dearmor(seckey)) +from keytbl, encdata where keytbl.id=4 and encdata.id=1; +ERROR: pgp_decrypt error: No usable key found (expecting Elgamal key) +-- 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: pgp_decrypt 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: pgp_decrypt error: 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) + diff --git a/contrib/pgcrypto/expected/pgp-pubkey-encrypt.out b/contrib/pgcrypto/expected/pgp-pubkey-encrypt.out new file mode 100644 index 0000000000..a7b1c027ee --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-pubkey-encrypt.out @@ -0,0 +1,59 @@ +-- +-- 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) + +-- 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: pgp_encrypt error: No usable key found (expecting Elgamal key) +-- try with secret key +select pgp_pub_decrypt( + pgp_pub_encrypt('Secret msg', dearmor(seckey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; +ERROR: pgp_encrypt error: Refusing to encrypt with secret key +-- does text-to-bytea works +select pgp_pub_decrypt_bytea( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +from keytbl where keytbl.id=1; + pgp_pub_decrypt_bytea +----------------------- + 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: pgp_decrypt 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 0000000000..6f4eccd457 --- /dev/null +++ b/contrib/pgcrypto/expected/pgp-zlib-DISABLED.out @@ -0,0 +1 @@ +-- zlib is disabled diff --git a/contrib/pgcrypto/expected/sha2.out b/contrib/pgcrypto/expected/sha2.out new file mode 100644 index 0000000000..20bdf0ed81 --- /dev/null +++ b/contrib/pgcrypto/expected/sha2.out @@ -0,0 +1,108 @@ +-- +-- SHA2 family +-- +-- SHA256 +SELECT encode(digest('', 'sha256'), 'hex'); + encode +------------------------------------------------------------------ + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +(1 row) + +SELECT encode(digest('a', 'sha256'), 'hex'); + encode +------------------------------------------------------------------ + ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb +(1 row) + +SELECT encode(digest('abc', 'sha256'), 'hex'); + encode +------------------------------------------------------------------ + ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad +(1 row) + +SELECT encode(digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha256'), 'hex'); + encode +------------------------------------------------------------------ + 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 +(1 row) + +SELECT encode(digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha256'), 'hex'); + encode +------------------------------------------------------------------ + f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e +(1 row) + +-- SHA384 +SELECT encode(digest('', 'sha384'), 'hex'); + encode +-------------------------------------------------------------------------------------------------- + 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b +(1 row) + +SELECT encode(digest('a', 'sha384'), 'hex'); + encode +-------------------------------------------------------------------------------------------------- + 54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31 +(1 row) + +SELECT encode(digest('abc', 'sha384'), 'hex'); + encode +-------------------------------------------------------------------------------------------------- + cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 +(1 row) + +SELECT encode(digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha384'), 'hex'); + encode +-------------------------------------------------------------------------------------------------- + 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b +(1 row) + +SELECT encode(digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha384'), 'hex'); + encode +-------------------------------------------------------------------------------------------------- + 09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039 +(1 row) + +SELECT encode(digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha384'), 'hex'); + encode +-------------------------------------------------------------------------------------------------- + 3d208973ab3508dbbd7e2c2862ba290ad3010e4978c198dc4d8fd014e582823a89e16f9b2a7bbc1ac938e2d199e8bea4 +(1 row) + +-- SHA512 +SELECT encode(digest('', 'sha512'), 'hex'); + encode +---------------------------------------------------------------------------------------------------------------------------------- + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e +(1 row) + +SELECT encode(digest('a', 'sha512'), 'hex'); + encode +---------------------------------------------------------------------------------------------------------------------------------- + 1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75 +(1 row) + +SELECT encode(digest('abc', 'sha512'), 'hex'); + encode +---------------------------------------------------------------------------------------------------------------------------------- + ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f +(1 row) + +SELECT encode(digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha512'), 'hex'); + encode +---------------------------------------------------------------------------------------------------------------------------------- + 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 +(1 row) + +SELECT encode(digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha512'), 'hex'); + encode +---------------------------------------------------------------------------------------------------------------------------------- + 8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909 +(1 row) + +SELECT encode(digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha512'), 'hex'); + encode +---------------------------------------------------------------------------------------------------------------------------------- + 930d0cefcb30ff1133b6898121f1cf3d27578afcafe8677c5257cf069911f75d8f5831b56ebfda67b278e66dff8b84fe2b2870f742a580d8edb41987232850c9 +(1 row) + diff --git a/contrib/pgcrypto/fortuna.c b/contrib/pgcrypto/fortuna.c new file mode 100644 index 0000000000..ff02a9773e --- /dev/null +++ b/contrib/pgcrypto/fortuna.c @@ -0,0 +1,365 @@ +/* + * fortuna.c + * Fortuna-like PRNG. + * + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.1 2005/07/10 13:46:27 momjian Exp $ + */ + +#include +#include +#include + +#include "rijndael.h" +#include "sha2.h" + +#include "fortuna.h" + + +/* + * Why Fortuna-like: There does not seem to be any definitive reference + * on Fortuna in the net. Instead this implementation is based on + * following references: + * + * http://en.wikipedia.org/wiki/Fortuna_(PRNG) + * - Wikipedia article + * http://jlcooke.ca/random/ + * - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux. + */ + +/* + * There is some confusion about whether and how to carry forward + * the state of the pools. Seems like original Fortuna does not + * do it, resetting hash after each request. I guess expecting + * feeding to happen more often that requesting. This is absolutely + * unsuitable for pgcrypto, as nothing asynchronous happens here. + * + * J.L. Cooke fixed this by feeding previous hash to new re-initialized + * hash context. + * + * Fortuna predecessor Yarrow requires ability to query intermediate + * 'final result' from hash, without affecting it. + * + * This implementation uses the Yarrow method - asking intermediate + * results, but continuing with old state. + */ + + +/* + * Algorithm parameters + */ + +/* + * How many pools. + * + * Original Fortuna uses 32 pools, that means 32'th pool is + * used not earlier than in 13th year. This is a waste in + * pgcrypto, as we have very low-frequancy seeding. Here + * is preferable to have all entropy usable in reasonable time. + * + * With 23 pools, 23th pool is used after 9 days which seems + * more sane. + * + * In our case the minimal cycle time would be bit longer + * than the system-randomness feeding frequency. + */ +#define NUM_POOLS 23 + +/* in microseconds */ +#define RESEED_INTERVAL 100000 /* 0.1 sec */ + +/* for one big request, reseed after this many bytes */ +#define RESEED_BYTES (1024*1024) + + +/* + * Algorithm constants + */ + +/* max sources */ +#define MAX_SOURCES 8 + +/* Both cipher key size and hash result size */ +#define BLOCK 32 + +/* cipher block size */ +#define CIPH_BLOCK 16 + +/* for internal wrappers */ +#define MD_CTX SHA256_CTX +#define CIPH_CTX rijndael_ctx + +struct fortuna_state { + uint8 counter[CIPH_BLOCK]; + uint8 result[CIPH_BLOCK]; + uint8 key[BLOCK]; + MD_CTX pool[NUM_POOLS]; + CIPH_CTX ciph; + unsigned source_pos[MAX_SOURCES]; + unsigned reseed_count; + struct timeval last_reseed_time; +}; +typedef struct fortuna_state FState; + + +/* + * Use our own wrappers here. + * - Need to get intermediate result from digest, without affecting it. + * - Need re-set key on a cipher context. + * - Algorithms are guaranteed to exist. + * - No memory allocations. + */ + +static void ciph_init(CIPH_CTX *ctx, const uint8 *key, int klen) +{ + rijndael_set_key(ctx, (const uint32 *)key, klen, 1); +} + +static void ciph_encrypt(CIPH_CTX *ctx, const uint8 *in, uint8 *out) +{ + rijndael_encrypt(ctx, (const uint32 *)in, (uint32 *)out); +} + +static void md_init(MD_CTX *ctx) +{ + SHA256_Init(ctx); +} + +static void md_update(MD_CTX *ctx, const uint8 *data, int len) +{ + SHA256_Update(ctx, data, len); +} + +static void md_result(MD_CTX *ctx, uint8 *dst) +{ + SHA256_CTX tmp; + memcpy(&tmp, ctx, sizeof(*ctx)); + SHA256_Final(dst, &tmp); + memset(&tmp, 0, sizeof(tmp)); +} + + +/* + * initialize state + */ +static void init_state(FState *st) +{ + int i; + memset(st, 0, sizeof(*st)); + for (i = 0; i < NUM_POOLS; i++) + md_init(&st->pool[i]); +} + +/* + * Must not reseed more ofter than RESEED_PER_SEC + * times per second. + */ +static int too_often(FState *st) +{ + int ok; + struct timeval tv; + struct timeval *last = &st->last_reseed_time; + + gettimeofday(&tv, NULL); + + ok = 0; + if (tv.tv_sec != last->tv_sec) + ok = 1; + else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) + ok = 1; + + memcpy(last, &tv, sizeof(tv)); + memset(&tv, 0, sizeof(tv)); + + return ok; +} + +/* + * generate new key from all the pools + */ +static void reseed(FState *st) +{ + unsigned k; + unsigned n; + MD_CTX key_md; + uint8 buf[BLOCK]; + + /* check frequency */ + if (too_often(st)) + return; + + /* + * Both #0 and #1 reseed would use only pool 0. + * Just skip #0 then. + */ + n = ++st->reseed_count; + + /* + * The goal: use k-th pool only 1/(2^k) of the time. + */ + md_init(&key_md); + for (k = 0; k < NUM_POOLS; k++) { + md_result(&st->pool[k], buf); + md_update(&key_md, buf, BLOCK); + + if (n & 1 || !n) + break; + n >>= 1; + } + + /* add old key into mix too */ + md_update(&key_md, st->key, BLOCK); + + /* now we have new key */ + md_result(&key_md, st->key); + + /* use new key */ + ciph_init(&st->ciph, st->key, BLOCK); + + memset(&key_md, 0, sizeof(key_md)); + memset(buf, 0, BLOCK); + n = k = 0; +} + +/* + * update pools + */ +static void add_entropy(FState *st, unsigned src_id, const uint8 *data, unsigned len) +{ + unsigned pos; + uint8 hash[BLOCK]; + MD_CTX md; + + /* just in case there's a bug somewhere */ + if (src_id >= MAX_SOURCES) + src_id = USER_ENTROPY; + + /* hash given data */ + md_init(&md); + md_update(&md, data, len); + md_result(&md, hash); + + /* update pools round-robin manner */ + pos = st->source_pos[src_id]; + md_update( &st->pool[pos], hash, BLOCK); + + if (++pos >= NUM_POOLS) + pos = 0; + st->source_pos[src_id] = pos; + + memset(hash, 0, BLOCK); + memset(&md, 0, sizeof(md)); +} + +/* + * Endianess does not matter. + * It just needs to change without repeating. + */ +static void inc_counter(FState *st) +{ + uint32 *val = (uint32*)st->counter; + if (++val[0]) + return; + if (++val[1]) + return; + if (++val[2]) + return; + ++val[3]; +} + +static void extract_data(FState *st, unsigned count, uint8 *dst) +{ + unsigned n; + unsigned block_nr = 0; + + /* + * Every request should be with different key, + * if possible. + */ + reseed(st); + + /* + * If the reseed didn't happen, don't use the old data + * rather encrypt again. + */ + + while (count > 0) { + /* must not give out too many bytes with one key */ + if (block_nr > (RESEED_BYTES / CIPH_BLOCK)) + { + reseed(st); + block_nr = 0; + } + + /* produce bytes */ + ciph_encrypt(&st->ciph, st->counter, st->result); + block_nr++; + + /* prepare for next time */ + inc_counter(st); + + /* copy result */ + if (count > CIPH_BLOCK) + n = CIPH_BLOCK; + else + n = count; + memcpy(dst, st->result, n); + dst += n; + count -= n; + } +} + +/* + * public interface + */ + +static FState main_state; +static int init_done = 0; + +void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len) +{ + if (!init_done) + { + init_state(&main_state); + init_done = 1; + } + if (!data || !len) + return; + add_entropy(&main_state, src_id, data, len); +} + +void fortuna_get_bytes(unsigned len, uint8 *dst) +{ + if (!init_done) + { + init_state(&main_state); + init_done = 1; + } + if (!dst || !len) + return; + extract_data(&main_state, len, dst); +} + diff --git a/contrib/pgcrypto/fortuna.h b/contrib/pgcrypto/fortuna.h new file mode 100644 index 0000000000..b576eb981d --- /dev/null +++ b/contrib/pgcrypto/fortuna.h @@ -0,0 +1,45 @@ +/* + * fortuna.c + * Fortuna PRNG. + * + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.h,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#ifndef __FORTUNA_H +#define __FORTUNA_H + +/* + * Event source ID's + */ +#define SYSTEM_ENTROPY 0 +#define USER_ENTROPY 1 + +void fortuna_get_bytes(unsigned len, uint8 *dst); +void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len); + +#endif + diff --git a/contrib/pgcrypto/mbuf.c b/contrib/pgcrypto/mbuf.c new file mode 100644 index 0000000000..eb5dff9265 --- /dev/null +++ b/contrib/pgcrypto/mbuf.c @@ -0,0 +1,556 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/mbuf.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include + +#include "px.h" +#include "mbuf.h" + +#define STEP (16*1024) + +struct MBuf +{ + uint8 *data; + uint8 *data_end; + uint8 *read_pos; + uint8 *buf_end; + int no_write:1; + int own_data:1; +}; + +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) + { + memset(mbuf->data, 0, mbuf->buf_end - mbuf->data); + px_free(mbuf->data); + } + px_free(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 = px_realloc(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; + + return; +} + +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 = px_alloc(sizeof *mbuf); + mbuf->data = px_alloc(len); + mbuf->buf_end = mbuf->data + len; + mbuf->data_end = mbuf->data; + mbuf->read_pos = mbuf->data; + + mbuf->no_write = 0; + mbuf->own_data = 1; + + return mbuf; +} + +MBuf * +mbuf_create_from_data(const uint8 *data, int len) +{ + MBuf *mbuf; + + mbuf = px_alloc(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 = 1; + mbuf->own_data = 0; + + return mbuf; +} + + +int +mbuf_grab(MBuf * mbuf, int len, uint8 **data_p) +{ + if (len > mbuf_avail(mbuf)) + len = mbuf_avail(mbuf); + + mbuf->no_write = 1; + + *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 = 1; + mbuf->own_data = 0; + + *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 = px_alloc(sizeof(*pf)); + memset(pf, 0, sizeof(*pf)); + pf->buflen = res; + pf->op = op; + pf->priv = priv; + pf->src = src; + if (pf->buflen > 0) + { + pf->buf = px_alloc(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) + { + memset(pf->buf, 0, pf->buflen); + px_free(pf->buf); + } + + memset(pf, 0, sizeof(*pf)); + px_free(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 */ + memset(tmpbuf, 0, total); + return res; + } + if (res == 0) + break; + memcpy(tmpbuf + total, tmp, res); + total += res; + } + return total; +} + +/* + * caller wants exatly len bytes and dont 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_MBUF_SHORT_READ; + } + 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 = px_alloc(sizeof(*mp)); + memset(mp, 0, sizeof(*mp)); + mp->block_size = res; + mp->op = op; + mp->priv = priv; + mp->next = next; + if (mp->block_size > 0) + { + mp->buf = px_alloc(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) + { + memset(mp->buf, 0, mp->block_size); + px_free(mp->buf); + } + + memset(mp, 0, sizeof(*mp)); + px_free(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 0000000000..6042a4fc2e --- /dev/null +++ b/contrib/pgcrypto/mbuf.h @@ -0,0 +1,121 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/mbuf.h,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#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(const 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/pgp-armor.c b/contrib/pgcrypto/pgp-armor.c new file mode 100644 index 0000000000..20f443f22e --- /dev/null +++ b/contrib/pgcrypto/pgp-armor.c @@ -0,0 +1,383 @@ +/* + * pgp-armor.c + * PGP ascii-armor. + * + * Copyright (c) 2005 Marko Kreen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-armor.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include + +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +/* + * BASE64 - duplicated :( + */ + +static const unsigned char _base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int +b64_encode(const uint8 *src, unsigned len, uint8 *dst) +{ + uint8 *p, + *lend = dst + 76; + const uint8 *s, + *end = src + len; + int pos = 2; + unsigned long buf = 0; + + s = src; + p = dst; + + while (s < end) + { + buf |= *s << (pos << 3); + pos--; + s++; + + /* + * write it out + */ + if (pos < 0) + { + *p++ = _base64[(buf >> 18) & 0x3f]; + *p++ = _base64[(buf >> 12) & 0x3f]; + *p++ = _base64[(buf >> 6) & 0x3f]; + *p++ = _base64[buf & 0x3f]; + + pos = 2; + buf = 0; + } + if (p >= lend) + { + *p++ = '\n'; + lend = p + 76; + } + } + if (pos != 2) + { + *p++ = _base64[(buf >> 18) & 0x3f]; + *p++ = _base64[(buf >> 12) & 0x3f]; + *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '='; + *p++ = '='; + } + + return p - dst; +} + +/* probably should use lookup table */ +static int +b64_decode(const uint8 *src, unsigned len, uint8 *dst) +{ + const uint8 *srcend = src + len, + *s = src; + uint8 *p = dst; + char c; + unsigned b = 0; + unsigned long buf = 0; + int pos = 0, + end = 0; + + while (s < srcend) + { + c = *s++; + if (c >= 'A' && c <= 'Z') + b = c - 'A'; + else if (c >= 'a' && c <= 'z') + b = c - 'a' + 26; + else if (c >= '0' && c <= '9') + b = c - '0' + 52; + else if (c == '+') + b = 62; + else if (c == '/') + b = 63; + else if (c == '=') + { + /* + * end sequence + */ + if (!end) + { + if (pos == 2) + end = 1; + else if (pos == 3) + end = 2; + else + return PXE_PGP_CORRUPT_ARMOR; + } + b = 0; + } + else if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + continue; + else + return PXE_PGP_CORRUPT_ARMOR; + + /* + * add it to buffer + */ + buf = (buf << 6) + b; + pos++; + if (pos == 4) + { + *p++ = (buf >> 16) & 255; + if (end == 0 || end > 1) + *p++ = (buf >> 8) & 255; + if (end == 0 || end > 2) + *p++ = buf & 255; + buf = 0; + pos = 0; + } + } + + if (pos != 0) + return PXE_PGP_CORRUPT_ARMOR; + return p - dst; +} + +static unsigned +b64_enc_len(unsigned srclen) +{ + /* + * 3 bytes will be converted to 4, linefeed after 76 chars + */ + return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4); +} + +static unsigned +b64_dec_len(unsigned srclen) +{ + return (srclen * 3) >> 2; +} + +/* + * PGP armor + */ + +static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n\n"; +static const char *armor_footer = "\n-----END PGP MESSAGE-----\n"; + +/* CRC24 implementation from rfc2440 */ +#define CRC24_INIT 0x00b704ceL +#define CRC24_POLY 0x01864cfbL +static long +crc24(const uint8 *data, unsigned len) +{ + unsigned crc = CRC24_INIT; + int i; + + while (len--) + { + crc ^= (*data++) << 16; + for (i = 0; i < 8; i++) + { + crc <<= 1; + if (crc & 0x1000000) + crc ^= CRC24_POLY; + } + } + return crc & 0xffffffL; +} + +int +pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst) +{ + int n; + uint8 *pos = dst; + unsigned crc = crc24(src, len); + + n = strlen(armor_header); + memcpy(pos, armor_header, n); + pos += n; + + n = b64_encode(src, len, pos); + pos += n; + + if (*(pos - 1) != '\n') + *pos++ = '\n'; + + *pos++ = '='; + pos[3] = _base64[crc & 0x3f]; + crc >>= 6; + pos[2] = _base64[crc & 0x3f]; + crc >>= 6; + pos[1] = _base64[crc & 0x3f]; + crc >>= 6; + pos[0] = _base64[crc & 0x3f]; + pos += 4; + + n = strlen(armor_footer); + memcpy(pos, armor_footer, n); + pos += n; + + return pos - dst; +} + +static const uint8 * +find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen) +{ + const uint8 *p = data; + if (!strlen) + return NULL; + if (data_end - data < strlen) + return NULL; + while (p < data_end) { + p = memchr(p, str[0], data_end - p); + if (p == NULL) + return NULL; + if (p + strlen > data_end) + return NULL; + if (memcmp(p, str, strlen) == 0) + return p; + p++; + } + return NULL; +} + +static int +find_header(const uint8 *data, const uint8 *datend, + const uint8 **start_p, int is_end) +{ + const uint8 *p = data; + static const char *start_sep = "-----BEGIN"; + static const char *end_sep = "-----END"; + const char *sep = is_end ? end_sep : start_sep; + + /* find header line */ + while (1) + { + p = find_str(p, datend, sep, strlen(sep)); + if (p == NULL) + return PXE_PGP_CORRUPT_ARMOR; + /* it must start at beginning of line */ + if (p == data || *(p - 1) == '\n') + break; + p += strlen(sep); + } + *start_p = p; + p += strlen(sep); + + /* check if header text ok */ + for (; p < datend && *p != '-'; p++) + { + /* various junk can be there, but definitely not line-feed */ + if (*p >= ' ') + continue; + return PXE_PGP_CORRUPT_ARMOR; + } + if (datend - p < 5 || memcmp(p, sep, 5) != 0) + return PXE_PGP_CORRUPT_ARMOR; + p += 5; + + /* check if at end of line */ + if (p < datend) + { + if (*p != '\n' && *p != '\r') + return PXE_PGP_CORRUPT_ARMOR; + if (*p == '\r') + p++; + if (p < datend && *p == '\n') + p++; + } + return p - *start_p; +} + +int +pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst) +{ + const uint8 *p = src; + const uint8 *data_end = src + len; + long crc; + const uint8 *base64_start, *armor_end; + const uint8 *base64_end = NULL; + uint8 buf[4]; + int hlen; + int res = PXE_PGP_CORRUPT_ARMOR; + + /* armor start */ + hlen = find_header(src, data_end, &p, 0); + if (hlen <= 0) + goto out; + p += hlen; + + /* armor end */ + hlen = find_header(p, data_end, &armor_end, 1); + if (hlen <= 0) + goto out; + + /* skip comments - find empty line */ + while (p < armor_end && *p != '\n' && *p != '\r') + { + p = memchr(p, '\n', armor_end - p); + if (!p) + goto out; + + /* step to start of next line */ + p++; + } + base64_start = p; + + /* find crc pos */ + for (p = armor_end; p >= base64_start; p--) + if (*p == '=') + { + base64_end = p - 1; + break; + } + if (base64_end == NULL) + goto out; + + /* decode crc */ + if (b64_decode(p + 1, 4, buf) != 3) + goto out; + crc = (((long)buf[0]) << 16) + (((long)buf[1]) << 8) + (long)buf[2]; + + /* decode data */ + res = b64_decode(base64_start, base64_end - base64_start, dst); + + /* check crc */ + if (res >= 0 && crc24(dst, res) != crc) + res = PXE_PGP_CORRUPT_ARMOR; +out: + return res; +} + +unsigned +pgp_armor_enc_len(unsigned len) +{ + return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16; +} + +unsigned +pgp_armor_dec_len(unsigned len) +{ + return b64_dec_len(len); +} + diff --git a/contrib/pgcrypto/pgp-cfb.c b/contrib/pgcrypto/pgp-cfb.c new file mode 100644 index 0000000000..52f37228c7 --- /dev/null +++ b/contrib/pgcrypto/pgp-cfb.c @@ -0,0 +1,257 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-cfb.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include +#include "mbuf.h" +#include "px.h" +#include "pgp.h" + +typedef int (*mix_data_t)(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst); + +struct PGP_CFB +{ + PX_Cipher *ciph; + int block_size; + int pos; + int block_no; + int resync; + uint8 fr[PGP_MAX_BLOCK]; + uint8 fre[PGP_MAX_BLOCK]; + uint8 encbuf[PGP_MAX_BLOCK]; +}; + +int +pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len, + int resync, uint8 *iv) +{ + int res; + PX_Cipher *ciph; + PGP_CFB *ctx; + + res = pgp_load_cipher(algo, &ciph); + if (res < 0) + return res; + + res = px_cipher_init(ciph, key, key_len, NULL); + if (res < 0) + { + px_cipher_free(ciph); + return res; + } + + ctx = px_alloc(sizeof(*ctx)); + memset(ctx, 0, sizeof(*ctx)); + ctx->ciph = ciph; + ctx->block_size = px_cipher_block_size(ciph); + ctx->resync = resync; + + if (iv) + memcpy(ctx->fr, iv, ctx->block_size); + + *ctx_p = ctx; + return 0; +} + +void +pgp_cfb_free(PGP_CFB *ctx) +{ + px_cipher_free(ctx->ciph); + memset(ctx, 0, sizeof(*ctx)); + px_free(ctx); +} + +/* + * Data processing for normal CFB. (PGP_PKT_SYMENCRYPTED_DATA_MDC) + */ +static int +mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst) +{ + int i; + for (i = ctx->pos; i < ctx->pos + len; i++) + *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++); + ctx->pos += len; + return len; +} + +static int +mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst) +{ + int i; + for (i = ctx->pos; i < ctx->pos + len; i++) + { + ctx->encbuf[i] = *data++; + *dst++ = ctx->fre[i] ^ ctx->encbuf[i]; + } + ctx->pos += len; + return len; +} + +/* + * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA) + * + * The goal is to hide the horror from the rest of the code, + * thus its all concentrated here. + */ +static int +mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst) +{ + int i,n; + /* block #2 is 2 bytes long */ + if (ctx->block_no == 2) + { + n = 2 - ctx->pos; + if (len < n) + n = len; + for (i = ctx->pos; i < ctx->pos + n; i++) + *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++); + + ctx->pos += n; + len -= n; + + if (ctx->pos == 2) + { + memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2); + memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2); + ctx->pos = 0; + return n; + } + } + for (i = ctx->pos; i < ctx->pos + len; i++) + *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++); + ctx->pos += len; + return len; +} + +static int +mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst) +{ + int i,n; + /* block #2 is 2 bytes long */ + if (ctx->block_no == 2) + { + n = 2 - ctx->pos; + if (len < n) + n = len; + for (i = ctx->pos; i < ctx->pos + n; i++) + { + ctx->encbuf[i] = *data++; + *dst++ = ctx->fre[i] ^ ctx->encbuf[i]; + } + ctx->pos += n; + len -= n; + + if (ctx->pos == 2) + { + memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2); + memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2); + ctx->pos = 0; + return n; + } + } + for (i = ctx->pos; i < ctx->pos + len; i++) + { + ctx->encbuf[i] = *data++; + *dst++ = ctx->fre[i] ^ ctx->encbuf[i]; + } + ctx->pos += len; + return len; +} + +/* + * common code for both encrypt and decrypt. + */ +static int +cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst, + mix_data_t mix_data) +{ + int n; + int res; + + while (len > 0 && ctx->pos > 0) + { + n = ctx->block_size - ctx->pos; + if (len < n) + n = len; + + n = mix_data(ctx, data, n, dst); + data += n; + dst += n; + len -= n; + + if (ctx->pos == ctx->block_size) + { + memcpy(ctx->fr, ctx->encbuf, ctx->block_size); + ctx->pos = 0; + } + } + + while (len > 0) + { + px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, ctx->fre); + if (ctx->block_no < 5) + ctx->block_no++; + + n = ctx->block_size; + if (len < n) + n = len; + + res = mix_data(ctx, data, n, dst); + data += res; + dst += res; + len -= res; + + if (ctx->pos == ctx->block_size) + { + memcpy(ctx->fr, ctx->encbuf, ctx->block_size); + ctx->pos = 0; + } + } + return 0; +} + +/* + * public interface + */ + +int +pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst) +{ + mix_data_t mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal; + return cfb_process(ctx, data, len, dst, mix); +} + +int +pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst) +{ + mix_data_t mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal; + return cfb_process(ctx, data, len, dst, mix); +} + diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c new file mode 100644 index 0000000000..4faf0e4e1a --- /dev/null +++ b/contrib/pgcrypto/pgp-compress.c @@ -0,0 +1,322 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-compress.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include + +#include "mbuf.h" +#include "px.h" +#include "pgp.h" + + +/* + * Compressed pkt writer + */ + +#ifndef DISABLE_ZLIB + +#include +#define ZIP_OUT_BUF 8192 +#define ZIP_IN_BLOCK 8192 + +struct ZipStat +{ + uint8 type; + int buf_len; + int hdr_done; + z_stream stream; + uint8 buf[ZIP_OUT_BUF]; +}; + +static void * +z_alloc(void *priv, unsigned n_items, unsigned item_len) +{ + return px_alloc(n_items * item_len); +} + +static void +z_free(void *priv, void *addr) +{ + px_free(addr); +} + +static int +compress_init(PushFilter * next, void *init_arg, void **priv_p) +{ + int res; + struct ZipStat *st; + PGP_Context *ctx = init_arg; + uint8 type = ctx->compress_algo; + + if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP) + return PXE_PGP_UNSUPPORTED_COMPR; + + /* + * init + */ + st = px_alloc(sizeof(*st)); + memset(st, 0, sizeof(*st)); + st->buf_len = ZIP_OUT_BUF; + st->stream.zalloc = z_alloc; + st->stream.zfree = z_free; + + if (type == PGP_COMPR_ZIP) + res = deflateInit2(&st->stream, ctx->compress_level, + Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + else + res = deflateInit(&st->stream, ctx->compress_level); + if (res != Z_OK) + { + px_free(st); + return PXE_PGP_COMPRESSION_ERROR; + } + *priv_p = st; + + return ZIP_IN_BLOCK; +} + +/* writes compressed data packet */ + +/* cant handle zero-len incoming data, but shouldnt */ +static int +compress_process(PushFilter * next, void *priv, const uint8 *data, int len) +{ + int res, + n_out; + struct ZipStat *st = priv; + + /* + * process data + */ + while (len > 0) + { + st->stream.next_in = (void *) data; + st->stream.avail_in = len; + st->stream.next_out = st->buf; + st->stream.avail_out = st->buf_len; + res = deflate(&st->stream, 0); + if (res != Z_OK) + return PXE_PGP_COMPRESSION_ERROR; + + n_out = st->buf_len - st->stream.avail_out; + if (n_out > 0) + { + res = pushf_write(next, st->buf, n_out); + if (res < 0) + return res; + } + len = st->stream.avail_in; + } + + return 0; +} + +static int +compress_flush(PushFilter * next, void *priv) +{ + int res, + zres, + n_out; + struct ZipStat *st = priv; + + st->stream.next_in = NULL; + st->stream.avail_in = 0; + while (1) + { + st->stream.next_out = st->buf; + st->stream.avail_out = st->buf_len; + zres = deflate(&st->stream, Z_FINISH); + if (zres != Z_STREAM_END && zres != Z_OK) + return PXE_PGP_COMPRESSION_ERROR; + n_out = st->buf_len - st->stream.avail_out; + if (n_out > 0) + { + res = pushf_write(next, st->buf, n_out); + if (res < 0) + return res; + } + if (zres == Z_STREAM_END) + break; + } + return 0; +} + +static void +compress_free(void *priv) +{ + struct ZipStat *st = priv; + + deflateEnd(&st->stream); + memset(st, 0, sizeof(*st)); + px_free(st); +} + +static const PushFilterOps +compress_filter = { + compress_init, compress_process, compress_flush, compress_free +}; + +int +pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst) +{ + return pushf_create(res, &compress_filter, ctx, dst); +} + +/* + * Decompress + */ +struct DecomprData +{ + int buf_len; /* = ZIP_OUT_BUF */ + int buf_data; /* available data */ + uint8 *pos; + z_stream stream; + int eof; + uint8 buf[ZIP_OUT_BUF]; +}; + +static int +decompress_init(void **priv_p, void *arg, PullFilter *src) +{ + PGP_Context *ctx = arg; + struct DecomprData *dec; + int res; + + if (ctx->compress_algo != PGP_COMPR_ZLIB + && ctx->compress_algo != PGP_COMPR_ZIP) + return PXE_PGP_UNSUPPORTED_COMPR; + + dec = px_alloc(sizeof(*dec)); + memset(dec, 0, sizeof(*dec)); + dec->buf_len = ZIP_OUT_BUF; + *priv_p = dec; + + dec->stream.zalloc = z_alloc; + dec->stream.zfree = z_free; + + if (ctx->compress_algo == PGP_COMPR_ZIP) + res = inflateInit2(&dec->stream, -15); + else + res = inflateInit(&dec->stream); + if (res != Z_OK) + { + px_free(dec); + px_debug("decompress_init: inflateInit error"); + return PXE_PGP_COMPRESSION_ERROR; + } + + return 0; +} + +static int decompress_read(void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + int res; + int flush; + struct DecomprData *dec = priv; + +restart: + if (dec->buf_data > 0) + { + if (len > dec->buf_data) + len = dec->buf_data; + *data_p = dec->pos; + dec->pos += len; + dec->buf_data -= len; + return len; + } + + if (dec->eof) + return 0; + + if (dec->stream.avail_in == 0) { + uint8 *tmp; + res = pullf_read(src, 8192, &tmp); + if (res < 0) + return res; + dec->stream.next_in = tmp; + dec->stream.avail_in = res; + } + + dec->stream.next_out = dec->buf; + dec->stream.avail_out = dec->buf_len; + dec->pos = dec->buf; + + // Z_NO_FLUSH, Z_SYNC_FLUSH, + flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH; + res = inflate(&dec->stream, flush); + if (res != Z_OK && res != Z_STREAM_END) + { + px_debug("decompress_read: inflate error: %d", res); + return PXE_PGP_CORRUPT_DATA; + } + + dec->buf_data = dec->buf_len - dec->stream.avail_out; + if (res == Z_STREAM_END) + dec->eof = 1; + goto restart; +} + +static void decompress_free(void *priv) +{ + struct DecomprData *dec = priv; + inflateEnd(&dec->stream); + memset(dec, 0, sizeof(*dec)); + px_free(dec); +} + +static const PullFilterOps +decompress_filter = { + decompress_init, decompress_read, decompress_free +}; + +int +pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src) +{ + return pullf_create(res, &decompress_filter, ctx, src); +} + +#else /* DISABLE_ZLIB */ + +int +pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst) +{ + return PXE_PGP_UNSUPPORTED_COMPR; +} + +int +pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src) +{ + return PXE_PGP_UNSUPPORTED_COMPR; +} + +#endif + + diff --git a/contrib/pgcrypto/pgp-decrypt.c b/contrib/pgcrypto/pgp-decrypt.c new file mode 100644 index 0000000000..edffc6a344 --- /dev/null +++ b/contrib/pgcrypto/pgp-decrypt.c @@ -0,0 +1,1156 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-decrypt.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +#define NO_CTX_SIZE 0 +#define ALLOW_CTX_SIZE 1 +#define NO_COMPR 0 +#define ALLOW_COMPR 1 +#define NO_MDC 0 +#define NEED_MDC 1 + +#define PKT_NORMAL 1 +#define PKT_STREAM 2 +#define PKT_CONTEXT 3 + +#define MAX_CHUNK (16*1024*1024) + +static int +parse_new_len(PullFilter * src, int *len_p) +{ + uint8 b; + int len; + int pkttype = PKT_NORMAL; + + GETBYTE(src, b); + if (b <= 191) + len = b; + else if (b >= 192 && b <= 223) + { + len = ((unsigned) (b) - 192) << 8; + GETBYTE(src, b); + len += 192 + b; + } + else if (b == 255) + { + GETBYTE(src, b); + len = b; + GETBYTE(src, b); + len = (len << 8) | b; + GETBYTE(src, b); + len = (len << 8) | b; + GETBYTE(src, b); + len = (len << 8) | b; + } + else + { + len = 1 << (b & 0x1F); + pkttype = PKT_STREAM; + } + + if (len < 0 || len > MAX_CHUNK) + { + px_debug("parse_new_len: weird length"); + return PXE_PGP_CORRUPT_DATA; + } + + *len_p = len; + return pkttype; +} + +static int +parse_old_len(PullFilter * src, int *len_p, int lentype) +{ + uint8 b; + int len; + + GETBYTE(src, b); + len = b; + + if (lentype == 1) + { + GETBYTE(src, b); + len = (len << 8) | b; + } + else if (lentype == 2) + { + GETBYTE(src, b); + len = (len << 8) | b; + GETBYTE(src, b); + len = (len << 8) | b; + GETBYTE(src, b); + len = (len << 8) | b; + } + + if (len < 0 || len > MAX_CHUNK) + { + px_debug("parse_old_len: weird length"); + return PXE_PGP_CORRUPT_DATA; + } + *len_p = len; + return PKT_NORMAL; +} + +/* returns pkttype or 0 on eof */ +int +pgp_parse_pkt_hdr(PullFilter * src, uint8 *tag, int *len_p, int allow_ctx) +{ + int lentype; + int res; + uint8 *p; + + /* EOF is normal here, thus we dont use GETBYTE */ + res = pullf_read(src, 1, &p); + if (res < 0) + return res; + if (res == 0) + return 0; + + if ((*p & 0x80) == 0) + { + px_debug("pgp_parse_pkt_hdr: not pkt hdr"); + return PXE_PGP_CORRUPT_DATA; + } + + if (*p & 0x40) + { + *tag = *p & 0x3f; + res = parse_new_len(src, len_p); + } + else + { + lentype = *p & 3; + *tag = (*p >> 2) & 0x0F; + if (lentype == 3) + res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA; + else + res = parse_old_len(src, len_p, lentype); + } + return res; +} + +/* + * Packet reader + */ +struct PktData { + int type; + int len; +}; + +static int pktreader_pull(void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + int res; + struct PktData *pkt = priv; + + /* PKT_CONTEXT means: whatever there is */ + if (pkt->type == PKT_CONTEXT) + return pullf_read(src, len, data_p); + + if (pkt->len == 0) + { + /* this was last chunk in stream */ + if (pkt->type == PKT_NORMAL) + return 0; + + /* next chunk in stream */ + res = parse_new_len(src, &pkt->len); + if (res < 0) + return res; + pkt->type = res; + } + + if (len > pkt->len) + len = pkt->len; + + res = pullf_read(src, len, data_p); + if (res > 0) + pkt->len -= res; + + return res; +} + +static void +pktreader_free(void *priv) +{ + struct PktData *pkt = priv; + memset(pkt, 0, sizeof(*pkt)); + px_free(pkt); +} + +static struct PullFilterOps pktreader_filter = { + NULL, pktreader_pull, pktreader_free +}; + +/* needs helper function to pass several parameters */ +int +pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len, + int pkttype, PGP_Context *ctx) +{ + int res; + struct PktData *pkt = px_alloc(sizeof(*pkt)); + pkt->type = pkttype; + pkt->len = len; + res = pullf_create(pf_p, &pktreader_filter, pkt, src); + if (res < 0) + px_free(pkt); + return res; +} + +/* + * Prefix check filter + */ + +static int prefix_init(void **priv_p, void *arg, PullFilter *src) +{ + PGP_Context *ctx = arg; + int len; + int res; + uint8 *buf; + uint8 tmpbuf[PGP_MAX_BLOCK + 2]; + + len = pgp_get_cipher_block_size(ctx->cipher_algo); + if (len > sizeof(tmpbuf)) + return PXE_BUG; + + res = pullf_read_max(src, len + 2, &buf, tmpbuf); + if (res < 0) + return res; + if (res != len + 2) + { + px_debug("prefix_init: short read"); + memset(tmpbuf, 0, sizeof(tmpbuf)); + return PXE_PGP_CORRUPT_DATA; + } + + if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1]) + { + px_debug("prefix_init: corrupt prefix"); + /* + * The original purpose of the 2-byte check was + * to show user a friendly "wrong key" message. + * This made following possible: + * + * "An Attack on CFB Mode Encryption As Used By OpenPGP" + * by Serge Mister and Robert Zuccherato + * + * To avoid being 'oracle', we delay reporting, which + * basically means we prefer to run into corrupt packet + * header. + * + * We _could_ throw PXE_PGP_CORRUPT_DATA here, but + * there is possibility of attack via timing, so we don't. + */ + ctx->corrupt_prefix = 1; + } + memset(tmpbuf, 0, sizeof(tmpbuf)); + return 0; +} + +static struct PullFilterOps prefix_filter = { + prefix_init, NULL, NULL +}; + + +/* + * Decrypt filter + */ + +static int decrypt_init(void **priv_p, void *arg, PullFilter *src) +{ + PGP_CFB *cfb = arg; + + *priv_p = cfb; + + /* we need to write somewhere, so ask for a buffer */ + return 4096; +} + +static int decrypt_read(void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + PGP_CFB *cfb = priv; + uint8 *tmp; + int res; + + res = pullf_read(src, len, &tmp); + if (res > 0) { + pgp_cfb_decrypt(cfb, tmp, res, buf); + *data_p = buf; + } + return res; +} + +struct PullFilterOps pgp_decrypt_filter = { + decrypt_init, decrypt_read, NULL +}; + + +/* + * MDC hasher filter + */ + +static int mdc_init(void **priv_p, void *arg, PullFilter *src) +{ + PGP_Context *ctx = arg; + *priv_p = ctx; + return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx); +} + +static void mdc_free(void *priv) +{ + PGP_Context *ctx = priv; + if (ctx->use_mdcbuf_filter) + return; + px_md_free(ctx->mdc_ctx); + ctx->mdc_ctx = NULL; +} + +// fixme: clarify +static int mdc_finish(PGP_Context *ctx, PullFilter *src, + int len, uint8 **data_p) +{ + int res; + uint8 hash[20]; + uint8 tmpbuf[22]; + + if (len + 1 > sizeof(tmpbuf)) + return PXE_BUG; + + /* read data */ + res = pullf_read_max(src, len + 1, data_p, tmpbuf); + if (res < 0) + return res; + if (res == 0) + { + if (ctx->mdc_checked == 0) + { + px_debug("no mdc"); + return PXE_PGP_CORRUPT_DATA; + } + return 0; + } + + if (ctx->in_mdc_pkt > 1) + { + px_debug("mdc_finish: several times here?"); + return PXE_PGP_CORRUPT_DATA; + } + ctx->in_mdc_pkt++; + + if (res != 20) + { + px_debug("mdc_finish: read failed, res=%d", res); + return PXE_PGP_CORRUPT_DATA; + } + + /* + * ok, we got the hash, now check + */ + px_md_finish(ctx->mdc_ctx, hash); + res = memcmp(hash, *data_p, 20); + memset(hash, 0, 20); + memset(tmpbuf, 0, sizeof(tmpbuf)); + if (res != 0) + { + px_debug("mdc_finish: mdc failed"); + return PXE_PGP_CORRUPT_DATA; + } + ctx->mdc_checked = 1; + return len; +} + +static int mdc_read(void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + int res; + PGP_Context *ctx = priv; + + /* skip this filter? */ + if (ctx->use_mdcbuf_filter) + return pullf_read(src, len, data_p); + + if (ctx->in_mdc_pkt) + return mdc_finish(ctx, src, len, data_p); + + res = pullf_read(src, len, data_p); + if (res < 0) + return res; + if (res == 0) + { + px_debug("mdc_read: unexpected eof"); + return PXE_PGP_CORRUPT_DATA; + } + px_md_update(ctx->mdc_ctx, *data_p, res); + + return res; +} + +static struct PullFilterOps mdc_filter = { + mdc_init, mdc_read, mdc_free +}; + + +/* + * Combined Pkt reader and MDC hasher. + * + * For the case of SYMENCRYPTED_MDC packet, where + * the data part has 'context length', which means + * that data packet ends 22 bytes before end of parent + * packet, which is silly. + */ +#define MDCBUF_LEN 8192 +struct MDCBufData { + PGP_Context *ctx; + int eof; + int buflen; + int avail; + uint8 *pos; + int mdc_avail; + uint8 mdc_buf[22]; + uint8 buf[MDCBUF_LEN]; +}; + +static int mdcbuf_init(void **priv_p, void *arg, PullFilter *src) +{ + PGP_Context *ctx = arg; + struct MDCBufData *st; + + st = px_alloc(sizeof(*st)); + memset(st, 0, sizeof(*st)); + st->buflen = sizeof(st->buf); + st->ctx = ctx; + *priv_p = st; + + /* take over the work of mdc_filter */ + ctx->use_mdcbuf_filter = 1; + + return 0; +} + +static int mdcbuf_finish(struct MDCBufData *st) +{ + uint8 hash[20]; + int res; + + st->eof = 1; + + if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14) + { + px_debug("mdcbuf_finish: bad MDC pkt hdr"); + return PXE_PGP_CORRUPT_DATA; + } + px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2); + px_md_finish(st->ctx->mdc_ctx, hash); + res = memcmp(hash, st->mdc_buf + 2, 20); + memset(hash, 0, 20); + if (res) + { + px_debug("mdcbuf_finish: MDC does not match"); + res = PXE_PGP_CORRUPT_DATA; + } + return res; +} + +static void mdcbuf_load_data(struct MDCBufData *st, uint8 *src, int len) +{ + uint8 *dst = st->pos + st->avail; + memcpy(dst, src, len); + px_md_update(st->ctx->mdc_ctx, src, len); + st->avail += len; +} + +static void mdcbuf_load_mdc(struct MDCBufData *st, uint8 *src, int len) +{ + memmove(st->mdc_buf + st->mdc_avail, src, len); + st->mdc_avail += len; +} + +static int mdcbuf_refill(struct MDCBufData *st, PullFilter *src) +{ + uint8 *data; + int res; + int need; + + /* put avail data in start */ + if (st->avail > 0 && st->pos != st->buf) + memmove(st->buf, st->pos, st->avail); + st->pos = st->buf; + + /* read new data */ + need = st->buflen + 22 - st->avail - st->mdc_avail; + res = pullf_read(src, need, &data); + if (res < 0) + return res; + if (res == 0) + return mdcbuf_finish(st); + + /* add to buffer */ + if (res >= 22) + { + mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail); + st->mdc_avail = 0; + + mdcbuf_load_data(st, data, res - 22); + mdcbuf_load_mdc(st, data + res - 22, 22); + } + else + { + int canmove = st->mdc_avail + res - 22; + if (canmove > 0) + { + mdcbuf_load_data(st, st->mdc_buf, canmove); + st->mdc_avail -= canmove; + memmove(st->mdc_buf, st->mdc_buf + canmove, st->mdc_avail); + } + mdcbuf_load_mdc(st, data, res); + } + return 0; +} + +static int mdcbuf_read(void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + struct MDCBufData *st = priv; + int res; + + if (!st->eof && len > st->avail) + { + res = mdcbuf_refill(st, src); + if (res < 0) + return res; + } + + if (len > st->avail) + len = st->avail; + + *data_p = st->pos; + st->pos += len; + st->avail -= len; + return len; +} + +static void +mdcbuf_free(void *priv) +{ + struct MDCBufData *st = priv; + px_md_free(st->ctx->mdc_ctx); + st->ctx->mdc_ctx = NULL; + memset(st, 0, sizeof(*st)); + px_free(st); +} + +static struct PullFilterOps mdcbuf_filter = { + mdcbuf_init, mdcbuf_read, mdcbuf_free +}; + + +/* + * Decrypt separate session key + */ +static int +decrypt_key(PGP_Context *ctx, const uint8 *src, int len) +{ + int res; + uint8 algo; + PGP_CFB *cfb; + + res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo, + ctx->s2k.key, ctx->s2k.key_len, 0, NULL); + if (res < 0) + return res; + + pgp_cfb_decrypt(cfb, src, 1, &algo); + src ++; + len --; + + pgp_cfb_decrypt(cfb, src, len, ctx->sess_key); + pgp_cfb_free(cfb); + ctx->sess_key_len = len; + ctx->cipher_algo = algo; + + if (pgp_get_cipher_key_size(algo) != len) { + px_debug("sesskey bad len: algo=%d, expected=%d, got=%d", + algo, pgp_get_cipher_key_size(algo), len); + return PXE_PGP_CORRUPT_DATA; + } + return 0; +} + +/* + * Handle key packet + */ +static int +parse_symenc_sesskey(PGP_Context * ctx, PullFilter * src) +{ + uint8 *p; + int res; + uint8 tmpbuf[PGP_MAX_KEY + 2]; + uint8 ver; + + GETBYTE(src, ver); + GETBYTE(src, ctx->s2k_cipher_algo); + if (ver != 4) + { + px_debug("bad key pkt ver"); + return PXE_PGP_CORRUPT_DATA; + } + + /* + * read S2K info + */ + res = pgp_s2k_read(src, &ctx->s2k); + if (res < 0) + return res; + ctx->s2k_mode = ctx->s2k.mode; + ctx->s2k_digest_algo = ctx->s2k.digest_algo; + + /* + * generate key from password + */ + res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo, + ctx->sym_key, ctx->sym_key_len); + if (res < 0) + return res; + + /* + * do we have separate session key? + */ + res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf); + if (res < 0) + return res; + + if (res == 0) + { + /* + * no, s2k key is session key + */ + memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len); + ctx->sess_key_len = ctx->s2k.key_len; + ctx->cipher_algo = ctx->s2k_cipher_algo; + res = 0; + ctx->use_sess_key = 0; + } + else + { + /* + * yes, decrypt it + */ + if (res < 17 || res > PGP_MAX_KEY + 1) + { + px_debug("expect key, but bad data"); + return PXE_PGP_CORRUPT_DATA; + } + ctx->use_sess_key = 1; + res = decrypt_key(ctx, p, res); + } + + memset(tmpbuf, 0, sizeof(tmpbuf)); + return res; +} + +static int +copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr) +{ + uint8 *data_end = data + len; + uint8 tmpbuf[1024]; + uint8 *tmp_end = tmpbuf + sizeof(tmpbuf); + uint8 *p; + int res; + + p = tmpbuf; + if (*got_cr) { + if (*data != '\n') + *p++ = '\r'; + *got_cr = 0; + } + while (data < data_end) { + if (*data == '\r') + { + if (data + 1 < data_end) + { + if (*(data + 1) == '\n') + data++; + } + else + { + *got_cr = 1; + break; + } + } + *p++ = *data++; + if (p >= tmp_end) + { + res = mbuf_append(dst, tmpbuf, p - tmpbuf); + if (res < 0) + return res; + p = tmpbuf; + } + } + if (p - tmpbuf > 0) + { + res = mbuf_append(dst, tmpbuf, p - tmpbuf); + if (res < 0) + return res; + } + return 0; +} + +static int +parse_literal_data(PGP_Context * ctx, MBuf * dst, PullFilter * pkt) +{ + int type; + int name_len; + int res; + uint8 *buf; + uint8 tmpbuf[4]; + int got_cr = 0; + + GETBYTE(pkt, type); + GETBYTE(pkt, name_len); + + /* skip name */ + while (name_len > 0) + { + res = pullf_read(pkt, name_len, &buf); + if (res < 0) + return res; + if (res == 0) + break; + name_len -= res; + } + if (name_len > 0) + { + px_debug("parse_literal_data: unexpected eof"); + return PXE_PGP_CORRUPT_DATA; + } + + /* skip date */ + res = pullf_read_max(pkt, 4, &buf, tmpbuf); + if (res != 4) + { + px_debug("parse_literal_data: unexpected eof"); + return PXE_PGP_CORRUPT_DATA; + } + memset(tmpbuf, 0, 4); + + /* check if text */ + if (ctx->text_mode) + if (type != 't' && type != 'u') + { + px_debug("parse_literal_data: data type=%c", type); + return PXE_PGP_NOT_TEXT; + } + + ctx->unicode_mode = (type == 'u') ? 1 : 0; + + /* read data */ + while (1) { + res = pullf_read(pkt, 32*1024, &buf); + if (res <= 0) + break; + + if (ctx->text_mode && ctx->convert_crlf) + res = copy_crlf(dst, buf, res, &got_cr); + else + res = mbuf_append(dst, buf, res); + if (res < 0) + break; + } + if (res >= 0 && got_cr) + res = mbuf_append(dst, "\r", 1); + return res; +} + +/* process_data_packets and parse_compressed_data call each other */ +static int process_data_packets(PGP_Context * ctx, MBuf * dst, + PullFilter * src, int allow_compr, int need_mdc); + +static int +parse_compressed_data(PGP_Context * ctx, MBuf * dst, PullFilter * pkt) +{ + int res; + uint8 type; + PullFilter *pf_decompr; + + GETBYTE(pkt, type); + + ctx->compress_algo = type; + switch (type) + { + case PGP_COMPR_NONE: + res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC); + break; + + case PGP_COMPR_ZIP: + case PGP_COMPR_ZLIB: + res = pgp_decompress_filter(&pf_decompr, ctx, pkt); + if (res >= 0) + { + res = process_data_packets(ctx, dst, pf_decompr, + NO_COMPR, NO_MDC); + pullf_free(pf_decompr); + } + break; + + case PGP_COMPR_BZIP2: + px_debug("parse_compressed_data: bzip2 unsupported"); + res = PXE_PGP_UNSUPPORTED_COMPR; + break; + + default: + px_debug("parse_compressed_data: unknown compr type"); + res = PXE_PGP_CORRUPT_DATA; + } + + return res; +} + +static int +process_data_packets(PGP_Context * ctx, MBuf * dst, PullFilter * src, + int allow_compr, int need_mdc) +{ + uint8 tag; + int len, + res; + int got_data = 0; + int got_mdc = 0; + PullFilter *pkt = NULL; + uint8 *tmp; + + while (1) + { + res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE); + if (res <= 0) + break; + + + /* mdc packet should be last */ + if (got_mdc) + { + px_debug("process_data_packets: data after mdc"); + res = PXE_PGP_CORRUPT_DATA; + break; + } + + /* context length inside SYMENC_MDC needs special handling */ + if (need_mdc && res == PKT_CONTEXT) + res = pullf_create(&pkt, &mdcbuf_filter, ctx, src); + else + res = pgp_create_pkt_reader(&pkt, src, len, res, ctx); + if (res < 0) + break; + + switch (tag) + { + case PGP_PKT_LITERAL_DATA: + got_data = 1; + res = parse_literal_data(ctx, dst, pkt); + break; + case PGP_PKT_COMPRESSED_DATA: + if (allow_compr == 0) + { + px_debug("process_data_packets: unexpected compression"); + res = PXE_PGP_CORRUPT_DATA; + } + else if (got_data) + { + /* + * compr data must be alone + */ + px_debug("process_data_packets: only one cmpr pkt allowed"); + res = PXE_PGP_CORRUPT_DATA; + } + else + { + got_data = 1; + res = parse_compressed_data(ctx, dst, pkt); + } + break; + case PGP_PKT_MDC: + if (need_mdc == NO_MDC) + { + px_debug("process_data_packets: unexpected MDC"); + res = PXE_PGP_CORRUPT_DATA; + break; + } + + /* notify mdc_filter */ + ctx->in_mdc_pkt = 1; + + res = pullf_read(pkt, 8192, &tmp); + if (res > 0) + got_mdc = 1; + break; + default: + px_debug("process_data_packets: unexpected pkt tag=%d", tag); + res = PXE_PGP_CORRUPT_DATA; + } + + pullf_free(pkt); + pkt = NULL; + + if (res < 0) + break; + } + + if (pkt) + pullf_free(pkt); + + if (res < 0) + return res; + + if (!got_data) + { + px_debug("process_data_packets: no data"); + res = PXE_PGP_CORRUPT_DATA; + } + if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter) + { + px_debug("process_data_packets: got no mdc"); + res = PXE_PGP_CORRUPT_DATA; + } + return res; +} + +static int +parse_symenc_data(PGP_Context * ctx, PullFilter * pkt, MBuf * dst) +{ + int res; + PGP_CFB *cfb = NULL; + PullFilter *pf_decrypt = NULL; + PullFilter *pf_prefix = NULL; + + res = pgp_cfb_create(&cfb, ctx->cipher_algo, + ctx->sess_key, ctx->sess_key_len, 1, NULL); + if (res < 0) + goto out; + + res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt); + if (res < 0) + goto out; + + res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt); + if (res < 0) + goto out; + + res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC); + +out: + if (pf_prefix) + pullf_free(pf_prefix); + if (pf_decrypt) + pullf_free(pf_decrypt); + if (cfb) + pgp_cfb_free(cfb); + + return res; +} + +static int +parse_symenc_mdc_data(PGP_Context * ctx, PullFilter * pkt, MBuf * dst) +{ + int res; + PGP_CFB *cfb = NULL; + PullFilter *pf_decrypt = NULL; + PullFilter *pf_prefix = NULL; + PullFilter *pf_mdc = NULL; + uint8 ver; + + GETBYTE(pkt, ver); + if (ver != 1) + { + px_debug("parse_symenc_mdc_data: pkt ver != 1"); + return PXE_PGP_CORRUPT_DATA; + } + + res = pgp_cfb_create(&cfb, ctx->cipher_algo, + ctx->sess_key, ctx->sess_key_len, 0, NULL); + if (res < 0) + goto out; + + res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt); + if (res < 0) + goto out; + + res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt); + if (res < 0) + goto out; + + res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc); + if (res < 0) + goto out; + + res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC); + +out: + if (pf_prefix) + pullf_free(pf_prefix); + if (pf_mdc) + pullf_free(pf_mdc); + if (pf_decrypt) + pullf_free(pf_decrypt); + if (cfb) + pgp_cfb_free(cfb); + + return res; +} + +/* + * skip over packet contents + */ +int +pgp_skip_packet(PullFilter *pkt) +{ + int res = 1; + uint8 *tmp; + while (res > 0) + res = pullf_read(pkt, 32*1024, &tmp); + return res < 0 ? res : 0; +} + +/* + * expect to be at packet end, any data is error + */ +int +pgp_expect_packet_end(PullFilter *pkt) +{ + int res = 1; + uint8 *tmp; + while (res > 0) + { + res = pullf_read(pkt, 32*1024, &tmp); + if (res > 0) + { + px_debug("pgp_expect_packet_end: got data"); + return PXE_PGP_CORRUPT_DATA; + } + } + return res < 0 ? res : 0; +} + +int +pgp_decrypt(PGP_Context * ctx, MBuf * msrc, MBuf * mdst) +{ + int res; + PullFilter *src = NULL; + PullFilter *pkt = NULL; + uint8 tag; + int len; + int got_key = 0; + int got_data = 0; + + res = pullf_create_mbuf_reader(&src, msrc); + + while (res >= 0) { + res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE); + if (res <= 0) + break; + + res = pgp_create_pkt_reader(&pkt, src, len, res, ctx); + if (res < 0) + break; + + res = PXE_PGP_CORRUPT_DATA; + switch (tag) { + case PGP_PKT_MARKER: + res = pgp_skip_packet(pkt); + break; + case PGP_PKT_PUBENCRYPTED_SESSKEY: + /* fixme: skip those */ + res = pgp_parse_pubenc_sesskey(ctx, pkt); + got_key = 1; + break; + case PGP_PKT_SYMENCRYPTED_SESSKEY: + if (got_key) + /* Theoretically, there could be several keys, + * both public and symmetric, all of which + * encrypt same session key. Decrypt should try + * with each one, before failing. + */ + px_debug("pgp_decrypt: using first of several keys"); + else + { + got_key = 1; + res = parse_symenc_sesskey(ctx, pkt); + } + break; + case PGP_PKT_SYMENCRYPTED_DATA: + if (!got_key) + px_debug("pgp_decrypt: have data but no key"); + else if (got_data) + px_debug("pgp_decrypt: got second data packet"); + else + { + got_data = 1; + ctx->disable_mdc = 1; + res = parse_symenc_data(ctx, pkt, mdst); + } + break; + case PGP_PKT_SYMENCRYPTED_DATA_MDC: + if (!got_key) + px_debug("pgp_decrypt: have data but no key"); + else if (got_data) + px_debug("pgp_decrypt: several data pkts not supported"); + else + { + got_data = 1; + ctx->disable_mdc = 0; + res = parse_symenc_mdc_data(ctx, pkt, mdst); + } + break; + default: + px_debug("pgp_decrypt: unknown tag: 0x%02x", tag); + } + pullf_free(pkt); + pkt = NULL; + } + + if (pkt) + pullf_free(pkt); + + if (src) + pullf_free(src); + + if (res < 0) + return res; + + if (!got_data || ctx->corrupt_prefix) + res = PXE_PGP_CORRUPT_DATA; + + return res; +} + diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c new file mode 100644 index 0000000000..8aee9bfba2 --- /dev/null +++ b/contrib/pgcrypto/pgp-encrypt.c @@ -0,0 +1,698 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-encrypt.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include +#include + +#include "mbuf.h" +#include "px.h" +#include "pgp.h" + + +#define MDC_DIGEST_LEN 20 +#define STREAM_ID 0xE0 +#define STREAM_BLOCK_SHIFT 14 + +static uint8 * +render_newlen(uint8 *h, int len) +{ + if (len <= 191) + { + *h++ = len & 255; + } + else if (len > 191 && len <= 8383) + { + *h++ = ((len - 192) >> 8) + 192; + *h++ = (len - 192) & 255; + } + else + { + *h++ = 255; + *h++ = (len >> 24) & 255; + *h++ = (len >> 16) & 255; + *h++ = (len >> 8) & 255; + *h++ = len & 255; + } + return h; +} + +static int write_tag_only(PushFilter *dst, int tag) +{ + uint8 hdr = 0xC0 | tag; + return pushf_write(dst, &hdr, 1); +} + +static int +write_normal_header(PushFilter * dst, int tag, int len) +{ + uint8 hdr[8]; + uint8 *h = hdr; + + *h++ = 0xC0 | tag; + h = render_newlen(h, len); + return pushf_write(dst, hdr, h - hdr); +} + + +/* + * MAC writer + */ + +static int +mdc_init(PushFilter * dst, void *init_arg, void **priv_p) +{ + int res; + PX_MD *md; + + res = pgp_load_digest(PGP_DIGEST_SHA1, &md); + if (res < 0) + return res; + + *priv_p = md; + return 0; +} + +static int +mdc_write(PushFilter * dst, void *priv, const uint8 *data, int len) +{ + PX_MD *md = priv; + + px_md_update(md, data, len); + return pushf_write(dst, data, len); +} + +static int +mdc_flush(PushFilter * dst, void *priv) +{ + int res; + uint8 pkt[2 + MDC_DIGEST_LEN]; + PX_MD *md = priv; + + /* + * create mdc pkt + */ + pkt[0] = 0xD3; + pkt[1] = 0x14; /* MDC_DIGEST_LEN */ + px_md_update(md, pkt, 2); + px_md_finish(md, pkt + 2); + + res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN); + memset(pkt, 0, 2 + MDC_DIGEST_LEN); + return res; +} + +static void +mdc_free(void *priv) +{ + PX_MD *md = priv; + + px_md_free(md); +} + +static const PushFilterOps mdc_filter = { + mdc_init, mdc_write, mdc_flush, mdc_free +}; + + +/* + * Encrypted pkt writer + */ +#define ENCBUF 8192 +struct EncStat +{ + PGP_CFB *ciph; + uint8 buf[ENCBUF]; +}; + +static int +encrypt_init(PushFilter * next, void *init_arg, void **priv_p) +{ + struct EncStat *st; + PGP_Context *ctx = init_arg; + PGP_CFB *ciph; + int resync = 1; + int res; + + /* should we use newer packet format? */ + if (ctx->disable_mdc == 0) + { + uint8 ver = 1; + resync = 0; + res = pushf_write(next, &ver, 1); + if (res < 0) + return res; + } + res = pgp_cfb_create(&ciph, ctx->cipher_algo, + ctx->sess_key, ctx->sess_key_len, resync, NULL); + if (res < 0) + return res; + + st = px_alloc(sizeof(*st)); + memset(st, 0, sizeof(*st)); + st->ciph = ciph; + + *priv_p = st; + return ENCBUF; +} + +static int +encrypt_process(PushFilter * next, void *priv, const uint8 *data, int len) +{ + int res; + struct EncStat *st = priv; + int avail = len; + + while (avail > 0) + { + int tmplen = avail > ENCBUF ? ENCBUF : avail; + res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf); + if (res < 0) + return res; + + res = pushf_write(next, st->buf, tmplen); + if (res < 0) + return res; + + data += tmplen; + avail -= tmplen; + } + return 0; +} + +static void +encrypt_free(void *priv) +{ + struct EncStat *st = priv; + + memset(st, 0, sizeof(*st)); + px_free(st); +} + +static const PushFilterOps encrypt_filter = { + encrypt_init, encrypt_process, NULL, encrypt_free +}; + +/* + * Write Streamable pkts + */ + +struct PktStreamStat +{ + int final_done; + int pkt_block; +}; + +static int +pkt_stream_init(PushFilter * next, void *init_arg, void **priv_p) +{ + struct PktStreamStat *st; + + st = px_alloc(sizeof(*st)); + st->final_done = 0; + st->pkt_block = 1 << STREAM_BLOCK_SHIFT; + *priv_p = st; + + return st->pkt_block; +} + +static int +pkt_stream_process(PushFilter * next, void *priv, const uint8 *data, int len) +{ + int res; + uint8 hdr[8]; + uint8 *h = hdr; + struct PktStreamStat *st = priv; + + if (st->final_done) + return PXE_BUG; + + if (len == st->pkt_block) + *h++ = STREAM_ID | STREAM_BLOCK_SHIFT; + else + { + h = render_newlen(h, len); + st->final_done = 1; + } + + res = pushf_write(next, hdr, h - hdr); + if (res < 0) + return res; + + return pushf_write(next, data, len); +} + +static int +pkt_stream_flush(PushFilter * next, void *priv) +{ + int res; + uint8 hdr[8]; + uint8 *h = hdr; + struct PktStreamStat *st = priv; + + /* stream MUST end with normal packet. */ + if (!st->final_done) + { + h = render_newlen(h, 0); + res = pushf_write(next, hdr, h - hdr); + if (res < 0) + return res; + st->final_done = 1; + } + return 0; +} + +static void +pkt_stream_free(void *priv) +{ + struct PktStreamStat *st = priv; + + memset(st, 0, sizeof(*st)); + px_free(st); +} + +static const PushFilterOps pkt_stream_filter = { + pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free +}; + +int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p) +{ + int res; + res = write_tag_only(dst, tag); + if (res < 0) + return res; + + return pushf_create(res_p, &pkt_stream_filter, NULL, dst); +} + +/* + * Text conversion filter + */ + +static int +crlf_process(PushFilter * dst, void *priv, const uint8 *data, int len) +{ + const uint8 * data_end = data + len; + const uint8 * p2, * p1 = data; + int line_len; + static const uint8 crlf[] = { '\r', '\n' }; + int res = 0; + while (p1 < data_end) + { + p2 = memchr(p1, '\n', data_end - p1); + if (p2 == NULL) + p2 = data_end; + + line_len = p2 - p1; + + /* write data */ + res = 0; + if (line_len > 0) + { + res = pushf_write(dst, p1, line_len); + if (res < 0) + break; + p1 += line_len; + } + + /* write crlf */ + while (p1 < data_end && *p1 == '\n') + { + res = pushf_write(dst, crlf, 2); + if (res < 0) + break; + p1++; + } + } + return res; +} + +static const PushFilterOps crlf_filter = { + NULL, crlf_process, NULL, NULL +}; + +/* + * Initialize literal data packet + */ +static int +init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) +{ + int res; + int hdrlen; + uint8 hdr[6]; + uint32 t; + PushFilter *pkt; + int type; + + /* + * Create header + */ + + if (ctx->text_mode) + type = ctx->unicode_mode ? 'u' : 't'; + else + type = 'b'; + + /* + * Store the creation time into packet. + * The goal is to have as few known bytes as possible. + */ + t = (uint32)time(NULL); + + hdr[0] = type; + hdr[1] = 0; + hdr[2] = (t >> 24) & 255; + hdr[3] = (t >> 16) & 255; + hdr[4] = (t >> 8) & 255; + hdr[5] = t & 255; + hdrlen = 6; + + res = write_tag_only(dst, PGP_PKT_LITERAL_DATA); + if (res < 0) + return res; + + res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst); + if (res < 0) + return res; + + res = pushf_write(pkt, hdr, hdrlen); + if (res < 0) + { + pushf_free(pkt); + return res; + } + + *pf_res = pkt; + return 0; +} + +/* + * Initialize compression filter + */ +static int +init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) +{ + int res; + uint8 type = ctx->compress_algo; + PushFilter *pkt; + + res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA); + if (res < 0) + return res; + + res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst); + if (res < 0) + return res; + + res = pushf_write(pkt, &type, 1); + if (res >= 0) + res = pgp_compress_filter(pf_res, ctx, pkt); + + if (res < 0) + pushf_free(pkt); + + return res; +} + +/* + * Initialize encdata packet + */ +static int +init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) +{ + int res; + int tag; + + if (ctx->disable_mdc) + tag = PGP_PKT_SYMENCRYPTED_DATA; + else + tag = PGP_PKT_SYMENCRYPTED_DATA_MDC; + + res = write_tag_only(dst, tag); + if (res < 0) + return res; + + return pushf_create(pf_res, &pkt_stream_filter, ctx, dst); +} + +/* + * write prefix + */ +static int +write_prefix(PGP_Context *ctx, PushFilter * dst) +{ + uint8 prefix[PGP_MAX_BLOCK + 2]; + int res, + bs; + + bs = pgp_get_cipher_block_size(ctx->cipher_algo); + res = px_get_random_bytes(prefix, bs); + if (res < 0) + return res; + + prefix[bs + 0] = prefix[bs - 2]; + prefix[bs + 1] = prefix[bs - 1]; + + res = pushf_write(dst, prefix, bs + 2); + memset(prefix, 0, bs + 2); + return res < 0 ? res : 0; +} + +/* + * write symmetrically encrypted session key packet + */ + +static int +symencrypt_sesskey(PGP_Context *ctx, uint8 *dst) +{ + int res; + PGP_CFB *cfb; + uint8 algo = ctx->cipher_algo; + + res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo, + ctx->s2k.key, ctx->s2k.key_len, 0, NULL); + if (res < 0) + return res; + + pgp_cfb_encrypt(cfb, &algo, 1, dst); + pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1); + + pgp_cfb_free(cfb); + return ctx->sess_key_len + 1; +} + +/* 5.3: Symmetric-Key Encrypted Session-Key */ +static int +write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst) +{ + uint8 pkt[256]; + int pktlen; + int res; + uint8 *p = pkt; + + *p++ = 4; /* 5.3 - version number */ + *p++ = ctx->s2k_cipher_algo; + + *p++ = ctx->s2k.mode; + *p++ = ctx->s2k.digest_algo; + if (ctx->s2k.mode > 0) + { + memcpy(p, ctx->s2k.salt, 8); + p += 8; + } + if (ctx->s2k.mode == 3) + *p++ = ctx->s2k.iter; + + if (ctx->use_sess_key) + { + res = symencrypt_sesskey(ctx, p); + if (res < 0) + return res; + p += res; + } + + pktlen = p - pkt; + res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen); + if (res >= 0) + res = pushf_write(dst, pkt, pktlen); + + memset(pkt, 0, pktlen); + return res; +} + +/* + * key setup + */ +static int +init_s2k_key(PGP_Context * ctx) +{ + int res; + + if (ctx->s2k_cipher_algo < 0) + ctx->s2k_cipher_algo = ctx->cipher_algo; + + res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo); + if (res < 0) + return res; + + return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo, + ctx->sym_key, ctx->sym_key_len); +} + +static int +init_sess_key(PGP_Context *ctx) +{ + int res; + if (ctx->use_sess_key || ctx->pub_key) + { + ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo); + res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len); + if (res < 0) + return res; + } + else + { + ctx->sess_key_len = ctx->s2k.key_len; + memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len); + } + + return 0; +} + +/* + * combine + */ +int +pgp_encrypt(PGP_Context * ctx, MBuf * src, MBuf * dst) +{ + int res; + int len; + uint8 *buf; + PushFilter *pf, *pf_tmp; + + /* + * do we have any key + */ + if (!ctx->sym_key && !ctx->pub_key) + return PXE_ARGUMENT_ERROR; + + /* MBuf writer */ + res = pushf_create_mbuf_writer(&pf, dst); + if (res < 0) + goto out; + + /* + * initialize symkey + */ + if (ctx->sym_key) + { + res = init_s2k_key(ctx); + if (res < 0) + goto out; + } + + res = init_sess_key(ctx); + if (res < 0) + goto out; + + /* + * write keypkt + */ + if (ctx->pub_key) + res = pgp_write_pubenc_sesskey(ctx, pf); + else + res = write_symenc_sesskey(ctx, pf); + if (res < 0) + goto out; + + /* encrypted data pkt */ + res = init_encdata_packet(&pf_tmp, ctx, pf); + if (res < 0) + goto out; + pf = pf_tmp; + + /* encrypter */ + res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf); + if (res < 0) + goto out; + pf = pf_tmp; + + /* hasher */ + if (ctx->disable_mdc == 0) + { + res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf); + if (res < 0) + goto out; + pf = pf_tmp; + } + + /* prefix */ + res = write_prefix(ctx, pf); + if (res < 0) + goto out; + + /* compressor */ + if (ctx->compress_algo > 0 && ctx->compress_level > 0) + { + res = init_compress(&pf_tmp, ctx, pf); + if (res < 0) + goto out; + pf = pf_tmp; + } + + /* data streamer */ + res = init_litdata_packet(&pf_tmp, ctx, pf); + if (res < 0) + goto out; + pf = pf_tmp; + + + /* text conversion? */ + if (ctx->text_mode && ctx->convert_crlf) + { + res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf); + if (res < 0) + goto out; + pf = pf_tmp; + } + + /* + * chain complete + */ + + len = mbuf_grab(src, mbuf_avail(src), &buf); + res = pushf_write(pf, buf, len); + if (res >= 0) + res = pushf_flush(pf); +out: + pushf_free_all(pf); + return res; +} + diff --git a/contrib/pgcrypto/pgp-info.c b/contrib/pgcrypto/pgp-info.c new file mode 100644 index 0000000000..d757e8c921 --- /dev/null +++ b/contrib/pgcrypto/pgp-info.c @@ -0,0 +1,213 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-info.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +static int read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf) +{ + int res = 0; + PGP_PubKey *pk; + + res = pgp_key_alloc(&pk); + if (res < 0) + return res; + + res = _pgp_read_public_key(pkt, pk); + if (res < 0) + goto err; + res = pgp_skip_packet(pkt); + if (res < 0) + goto err; + + res = 0; + if (pk->algo == PGP_PUB_ELG_ENCRYPT) + { + memcpy(keyid_buf, pk->key_id, 8); + res = 1; + } +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]; + + + 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: + 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: + got_data = 1; + break; + case PGP_PKT_SYMENCRYPTED_SESSKEY: + got_symenc_key++; + /* fallthru */ + case PGP_PKT_SIGNATURE: + case PGP_PKT_MARKER: + case PGP_PKT_TRUST: + case PGP_PKT_USER_ID: + case PGP_PKT_USER_ATTR: + case PGP_PKT_PRIV_61: + res = pgp_skip_packet(pkt); + break; + default: + res = PXE_PGP_CORRUPT_DATA; + } + + if (pkt) + pullf_free(pkt); + pkt = NULL; + + if (res < 0 || got_data) + break; + } + + pullf_free(src); + if (pkt) + pullf_free(pkt); + + if (res < 0) + return res; + + /* now check sanity */ + if (got_pub_key && got_pubenc_key) + res = PXE_PGP_CORRUPT_DATA; + + if (got_pub_key > 1) + res = -1; + + if (got_pubenc_key > 1) + res = -1; + + /* + * 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-internal.c b/contrib/pgcrypto/pgp-mpi-internal.c new file mode 100644 index 0000000000..12831b1af7 --- /dev/null +++ b/contrib/pgcrypto/pgp-mpi-internal.c @@ -0,0 +1,50 @@ +/* + * pgp-mpi-internal.c + * OpenPGP MPI functions. + * + * Copyright (c) 2005 Marko Kreen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +int +pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m, + PGP_MPI **c1_p, PGP_MPI **c2_p) +{ + return PXE_PGP_NO_BIGNUM; +} + +int +pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2, + PGP_MPI **msg_p) +{ + return PXE_PGP_NO_BIGNUM; +} + diff --git a/contrib/pgcrypto/pgp-mpi-openssl.c b/contrib/pgcrypto/pgp-mpi-openssl.c new file mode 100644 index 0000000000..c44e1935bd --- /dev/null +++ b/contrib/pgcrypto/pgp-mpi-openssl.c @@ -0,0 +1,197 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-openssl.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ +#include + +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +static BIGNUM * +mpi_to_bn(PGP_MPI *n) +{ + BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL); + if (!bn) + return NULL; + if (BN_num_bits(bn) != n->bits) + { + px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d", + n->bits, BN_num_bits(bn)); + BN_clear_free(bn); + return NULL; + } + return bn; +} + +static PGP_MPI * +bn_to_mpi(BIGNUM *bn) +{ + int res; + PGP_MPI *n; + + res = pgp_mpi_alloc(BN_num_bits(bn), &n); + if (res < 0) + return NULL; + + if (BN_num_bytes(bn) != n->bytes) + { + px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d", + BN_num_bytes(bn), n->bytes); + pgp_mpi_free(n); + return NULL; + } + BN_bn2bin(bn, n->data); + return n; +} + +/* + * Decide the number of bits in the random componont k + * + * It should be in the same range as p for signing (which + * is deprecated), but can be much smaller for encrypting. + * + * Until I research it further, I just mimic gpg behaviour. + * It has a special mapping table, for values <= 5120, + * above that it uses 'arbitrary high number'. Following + * algorihm hovers 10-70 bits above gpg values. And for + * larger p, it uses gpg's algorihm. + * + * The point is - if k gets large, encryption will be + * really slow. It does not matter for decryption. + */ +static int +decide_k_bits(int p_bits) +{ + if (p_bits <= 5120) + return p_bits / 10 + 160; + else + return (p_bits / 8 + 200) * 3 / 2; +} + +int +pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m, + PGP_MPI **c1_p, PGP_MPI **c2_p) +{ + int res = PXE_PGP_MATH_FAILED; + int k_bits; + BIGNUM *m = mpi_to_bn(_m); + BIGNUM *p = mpi_to_bn(pk->elg_p); + BIGNUM *g = mpi_to_bn(pk->elg_g); + BIGNUM *y = mpi_to_bn(pk->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_generate_prime(k, k_bits, 0, NULL, NULL, NULL, NULL)) + 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->elg_p); + BIGNUM *x = mpi_to_bn(pk->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; +} + diff --git a/contrib/pgcrypto/pgp-mpi.c b/contrib/pgcrypto/pgp-mpi.c new file mode 100644 index 0000000000..6d3eff499f --- /dev/null +++ b/contrib/pgcrypto/pgp-mpi.c @@ -0,0 +1,134 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.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 = px_alloc(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) +{ + memset(mpi, 0, sizeof(*mpi) + mpi->bytes); + px_free(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; +} + diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c new file mode 100644 index 0000000000..c17d952b39 --- /dev/null +++ b/contrib/pgcrypto/pgp-pgsql.c @@ -0,0 +1,901 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pgsql.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ + +#include +#include +#include +#include + +#include "mbuf.h" +#include "px.h" +#include "pgp.h" + +/* + * public functions + */ +Datum pgp_sym_encrypt_text(PG_FUNCTION_ARGS); +Datum pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS); +Datum pgp_sym_decrypt_text(PG_FUNCTION_ARGS); +Datum pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS); + +Datum pgp_pub_encrypt_text(PG_FUNCTION_ARGS); +Datum pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS); +Datum pgp_pub_decrypt_text(PG_FUNCTION_ARGS); +Datum pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS); + +Datum pgp_key_id_w(PG_FUNCTION_ARGS); + +Datum pg_armor(PG_FUNCTION_ARGS); +Datum pg_dearmor(PG_FUNCTION_ARGS); + +/* function headers */ + +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); + +/* + * check for NULL arguments + */ +#define CHECK_ARGS() \ + do { \ + int a; \ + for (a = 0; a < PG_NARGS(); a++) { \ + if (PG_ARGISNULL(a)) \ + PG_RETURN_NULL(); \ + } \ + } while (0) + +/* + * Mix user data into RNG. It is for user own interests to have + * RNG state shuffled. + */ +static void add_entropy(text *data1, text *data2, text *data3) +{ + PX_MD *md; + uint8 sha1[20]; + int res; + + if (!data1 && !data2 && !data3) + return; + + res = px_find_digest("sha1", &md); + if (res < 0) + return; + + if (data1) + px_md_update(md, VARDATA(data1), VARSIZE(data1) - VARHDRSZ); + if (data2) + px_md_update(md, VARDATA(data2), VARSIZE(data2) - VARHDRSZ); + if (data3) + px_md_update(md, VARDATA(data3), VARSIZE(data3) - VARHDRSZ); + + px_md_finish(md, sha1); + px_md_free(md); + + res = px_add_entropy(sha1, 20); + memset(sha1, 0, 20); + + if (res < 0) + ereport(NOTICE, (errmsg("add_entropy: %s", px_strerror(res)))); +} + +/* + * 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(src) - VARHDRSZ; + int dst_len; + unsigned char *dst; + unsigned char *csrc = VARDATA(src); + text *res; + + dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to); + if (dst == csrc) + return src; + + dst_len = strlen(dst); + res = palloc(dst_len + VARHDRSZ); + memcpy(VARDATA(res), dst, dst_len); + VARATT_SIZEP(res) = VARHDRSZ + dst_len; + 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) +{ + memset(p, 0, VARSIZE(p)); + pfree(p); +} + +/* + * expect-* arguments storage + */ +struct debug_expect { + int debug; + int expect; + int cipher_algo; + int s2k_mode; + 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_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_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-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)); + /* decrypt debug */ + 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-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(VARDATA(data), VARSIZE(data) - VARHDRSZ); +} + +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, VARDATA(args), VARSIZE(args) - VARHDRSZ, ex); + + if (err) + { + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("%s", px_strerror(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; + + /* + * Add data and key info RNG. + */ + add_entropy(data, key, 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(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, VARDATA(key), VARSIZE(key) - VARHDRSZ); + + /* + * 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); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("pgp_encrypt error: %s", px_strerror(err)))); + } + + /* res_len includes VARHDRSZ */ + res_len = mbuf_steal_data(dst, &restmp); + res = (bytea *) restmp; + VARATT_SIZEP(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(VARDATA(data), VARSIZE(data) - VARHDRSZ); + dst = mbuf_create(VARSIZE(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 = VARDATA(keypsw); + psw_len = VARSIZE(keypsw) - VARHDRSZ; + } + 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, VARDATA(key), VARSIZE(key) - VARHDRSZ); + + /* + * decrypt + */ + if (err >= 0) + err = pgp_decrypt(ctx, src, dst); + + /* + * failed? + */ + if (err < 0) + goto out; + + if (ex.expect) + check_expect(ctx, &ex); + + /* remember the setting */ + got_unicode = pgp_get_unicode_mode(ctx); + +out: + if (src) + mbuf_free(src); + if (ctx) + pgp_free(ctx); + + if (err) + { + px_set_debug_handler(NULL); + if (dst) + mbuf_free(dst); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("pgp_decrypt error: %s", px_strerror(err)))); + } + + res_len = mbuf_steal_data(dst, &restmp); + mbuf_free(dst); + + /* res_len includes VARHDRSZ */ + res = (bytea *) restmp; + VARATT_SIZEP(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); + + /* + * add successfull decryptions also into RNG + */ + add_entropy(res, key, keypsw); + + return res; +} + +/* + * Wrappers for symmetric-key functions + */ +Datum +pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS) +{ + bytea *data, + *key; + text *arg = NULL; + text *res; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + psw = PG_GETARG_BYTEA_P(2); + if (PG_NARGS() > 3) + arg = PG_GETARG_BYTEA_P(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; + + CHECK_ARGS(); + data = PG_GETARG_BYTEA_P(0); + key = PG_GETARG_BYTEA_P(1); + if (PG_NARGS() > 2) + psw = PG_GETARG_BYTEA_P(2); + if (PG_NARGS() > 3) + arg = PG_GETARG_BYTEA_P(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 + */ + +Datum +pg_armor(PG_FUNCTION_ARGS) +{ + bytea *data; + text *res; + int data_len, + res_len, + guess_len; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + data = PG_GETARG_BYTEA_P(0); + data_len = VARSIZE(data) - VARHDRSZ; + + guess_len = pgp_armor_enc_len(data_len); + res = palloc(VARHDRSZ + guess_len); + + res_len = pgp_armor_encode(VARDATA(data), data_len, VARDATA(res)); + if (res_len > guess_len) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("Overflow - encode estimate too small"))); + VARATT_SIZEP(res) = VARHDRSZ + res_len; + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} + +Datum +pg_dearmor(PG_FUNCTION_ARGS) +{ + text *data; + bytea *res; + int data_len, + res_len, + guess_len; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + data = PG_GETARG_TEXT_P(0); + data_len = VARSIZE(data) - VARHDRSZ; + + guess_len = pgp_armor_dec_len(data_len); + res = palloc(VARHDRSZ + guess_len); + + res_len = pgp_armor_decode(VARDATA(data), data_len, VARDATA(res)); + if (res_len < 0) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("dearmor: %s", px_strerror(res_len)))); + if (res_len > guess_len) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("Overflow - decode estimate too small"))); + VARATT_SIZEP(res) = VARHDRSZ + res_len; + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} + +/* + * Wrappers for PGP key id + */ + +Datum +pgp_key_id_w(PG_FUNCTION_ARGS) +{ + bytea *data; + text *res; + int res_len; + MBuf *buf; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + data = PG_GETARG_BYTEA_P(0); + buf = create_mbuf_from_vardata(data); + res = palloc(VARHDRSZ + 17); + + px_set_debug_handler(show_debug); + res_len = pgp_get_keyid(buf, VARDATA(res)); + px_set_debug_handler(NULL); + mbuf_free(buf); + if (res_len < 0) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("%s", px_strerror(res_len)))); + VARATT_SIZEP(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 0000000000..ad4ceb2f7a --- /dev/null +++ b/contrib/pgcrypto/pgp-pubdec.c @@ -0,0 +1,193 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubdec.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ +#include + +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.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_CORRUPT_DATA; + + 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_CORRUPT_DATA; + } + return 0; +} + +/* 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_MPI *c1, *c2; + PGP_PubKey *pk; + uint8 *msg; + int msglen; + PGP_MPI *m; + + pk = ctx->pub_key; + if (pk == NULL) { + px_debug("no pubkey?"); + return PXE_BUG; + } + if (!pk->elg_p || !pk->elg_g || !pk->elg_y || !pk->elg_x) { + px_debug("seckey not loaded?"); + 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_KEYID; + } + + GETBYTE(pkt, algo); + if (algo != PGP_PUB_ELG_ENCRYPT) + { + px_debug("unknown public-key algo=%d", algo); + if (algo == PGP_PUB_RSA_ENCRYPT || algo == PGP_PUB_RSA_ENCRYPT_SIGN) + return PXE_PGP_RSA_UNSUPPORTED; + else + return PXE_PGP_UNKNOWN_PUBALGO; + } + + /* + * read elgamal encrypted data + */ + res = pgp_mpi_read(pkt, &c1); + if (res < 0) + return res; + res = pgp_mpi_read(pkt, &c2); + if (res < 0) + return res; + + /* + * decrypt + */ + res = pgp_elgamal_decrypt(pk, c1, c2, &m); + 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"); + return PXE_PGP_CORRUPT_DATA; + } + msglen = m->bytes - (msg - m->data); + + res = control_cksum(msg, msglen); + if (res < 0) + return res; + + /* + * got sesskey + */ + ctx->cipher_algo = *msg; + ctx->sess_key_len = msglen - 3; + memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len); + + 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 0000000000..7a0ba33409 --- /dev/null +++ b/contrib/pgcrypto/pgp-pubenc.c @@ -0,0 +1,230 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubenc.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.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) +{ + int res; + uint8 *buf, *p; + int pad_len = res_len - 2 - data_len; + + if (pad_len < 8) + return PXE_BUG; + + buf = px_alloc(res_len); + buf[0] = 0x02; + res = px_get_random_bytes(buf + 1, pad_len); + if (res < 0) + { + px_free(buf); + return res; + } + + /* pad must not contain zero bytes */ + p = buf + 1; + while (p < buf + 1 + pad_len) + { + if (*p == 0) + { + res = px_get_random_bytes(p, 1); + if (res < 0) + break; + } + if (*p != 0) + p++; + } + + if (res < 0) + { + memset(buf, 0, res_len); + px_free(buf); + return res; + } + + buf[pad_len + 1] = 0; + memcpy(buf + pad_len + 2, data, data_len); + *res_p = buf; + + return 0; +} + +/* + * Decide the padded message length in bytes. + * It should be as large as possible, but not larger + * than p. + * + * To get max size (and assuming p may have weird sizes): + * ((p->bytes * 8 - 6) > p->bits) ? (p->bytes - 1) : p->bytes + * + * Following mirrors gnupg behaviour. + */ +static int +decide_msglen(PGP_MPI *p) +{ + return p->bytes - 1; +} + +static int +create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p) +{ + uint8 *secmsg; + int res, i, full_bytes; + unsigned cksum = 0; + int klen = ctx->sess_key_len; + uint8 *padded = NULL; + PGP_MPI *m = NULL; + PGP_PubKey *pk = ctx->pub_key; + + /* + * Refuse to operate with keys < 1024 + */ + if (pk->elg_p->bits < 1024) + return PXE_PGP_SHORT_ELGAMAL_KEY; + + /* calc checksum */ + for (i = 0; i < klen; i++) + cksum += ctx->sess_key[i]; + + /* + * create "secret message" + */ + secmsg = px_alloc(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 + */ + full_bytes = decide_msglen(pk->elg_p); + 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) + { + memset(padded, 0, full_bytes); + px_free(padded); + } + memset(secmsg, 0, klen + 3); + px_free(secmsg); + + if (res >= 0) + *msg_p = m; + + return res; +} + +int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst) +{ + int res; + PGP_PubKey *pk = ctx->pub_key; + PGP_MPI *m = NULL, *c1 = NULL, *c2 = NULL; + uint8 ver = 3; + uint8 algo = PGP_PUB_ELG_ENCRYPT; + PushFilter *pkt = NULL; + + if (pk == NULL) { + px_debug("no pubkey?\n"); + return PXE_BUG; + } + if (!pk->elg_p || !pk->elg_g || !pk->elg_y) { + px_debug("pubkey not loaded?\n"); + return PXE_BUG; + } + + /* + * sesskey packet + */ + res = create_secmsg(ctx, &m); + if (res < 0) + goto err; + + /* + * encrypt it + */ + res = pgp_elgamal_encrypt(pk, m, &c1, &c2); + if (res < 0) + goto err; + + /* + * 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; + res = pgp_mpi_write(pkt, c1); + if (res < 0) + goto err; + res = pgp_mpi_write(pkt, c2); + if (res < 0) + goto err; + + /* + * done, signal packet end + */ + res = pushf_flush(pkt); +err: + if (pkt) + pushf_free(pkt); + if (m) + pgp_mpi_free(m); + if (c1) + pgp_mpi_free(c1); + if (c2) + pgp_mpi_free(c2); + + return res; +} + + diff --git a/contrib/pgcrypto/pgp-pubkey.c b/contrib/pgcrypto/pgp-pubkey.c new file mode 100644 index 0000000000..6a00947c87 --- /dev/null +++ b/contrib/pgcrypto/pgp-pubkey.c @@ -0,0 +1,448 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubkey.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +#define PXE_PGP_BAD_KEY -90 + +int pgp_key_alloc(PGP_PubKey **pk_p) +{ + PGP_PubKey *pk; + pk = px_alloc(sizeof(*pk)); + memset(pk, 0, sizeof(*pk)); + *pk_p = pk; + return 0; +} + +void pgp_key_free(PGP_PubKey *pk) +{ + if (pk->elg_p) + pgp_mpi_free(pk->elg_p); + if (pk->elg_g) + pgp_mpi_free(pk->elg_g); + if (pk->elg_y) + pgp_mpi_free(pk->elg_y); + if (pk->elg_x) + pgp_mpi_free(pk->elg_x); + memset(pk, 0, sizeof(*pk)); + px_free(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->elg_p->bytes; + len += 2 + pk->elg_g->bytes; + len += 2 + pk->elg_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->elg_p); + pgp_mpi_hash(md, pk->elg_g); + pgp_mpi_hash(md, pk->elg_y); + break; + } + + px_md_finish(md, hash); + px_md_free(md); + + memcpy(pk->key_id, hash + 12, 8); + memset(hash, 0, 20); + + return 0; +} + +int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey *pk) +{ + int res; + + /* get version */ + GETBYTE(pkt, pk->ver); + if (pk->ver != 4) { + px_debug("\tunsupported version: %d", pk->ver); + return PXE_PGP_NOT_V4_KEYPKT; + } + + /* read time */ + res = pullf_read_fixed(pkt, 4, pk->time); + if (res < 0) + return res; + + /* pubkey algorithm */ + GETBYTE(pkt, pk->algo); + + switch (pk->algo) { + case PGP_PUB_RSA_ENCRYPT_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_SIGN: + case PGP_PUB_DSA_SIGN: + res = pgp_skip_packet(pkt); + break; + case PGP_PUB_ELG_ENCRYPT: + res = pgp_mpi_read(pkt, &pk->elg_p); + if (res < 0) break; + res = pgp_mpi_read(pkt, &pk->elg_g); + if (res < 0) break; + res = pgp_mpi_read(pkt, &pk->elg_y); + if (res < 0) break; + + res = calc_key_id(pk); + break; + default: + px_debug("unknown public algo: %d", pk->algo); + res = PXE_PGP_UNKNOWN_PUBALGO; + } + + 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->elg_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: + memset(got_sha1, 0, 20); + 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->elg_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, + 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; + + /* first read public key part */ + res = _pgp_read_public_key(pkt, pk); + if (res < 0) + return res; + + /* skip key? */ + if (pk->algo != PGP_PUB_ELG_ENCRYPT) + return 0; + + /* + * 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_ENCRYPT_SIGN: + case PGP_PUB_RSA_ENCRYPT: + case PGP_PUB_RSA_SIGN: + case PGP_PUB_DSA_SIGN: + px_debug("unsupported public algo: %d", pk->algo); + res = PXE_PGP_UNSUPPORTED_PUBALGO; + break; + case PGP_PUB_ELG_ENCRYPT: + res = pgp_mpi_read(pf_key, &pk->elg_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); + + return res; +} + +static int +internal_read_key(PullFilter *src, PGP_PubKey **pk_p, + const uint8 *key, int key_len, int pubtype) +{ + PullFilter *pkt = NULL; + int res; + uint8 tag; + int len; + PGP_PubKey *pk = NULL; + int got_key = 0; + int n_subkey = 0; + + res = pgp_key_alloc(&pk); + if (res < 0) + return res; + + /* + * Search for Elgamal key. + * + * Error out on anything fancy. + */ + res = PXE_PGP_KEYPKT_CORRUPT; + 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: + if (got_key) + { + res = PXE_PGP_MULTIPLE_KEYS; + break; + } + got_key = 1; + n_subkey = 0; + /* fallthru */ + case PGP_PKT_SECRET_SUBKEY: + if (tag == PGP_PKT_SECRET_SUBKEY) + n_subkey++; + + if (n_subkey > 1) + res = PXE_PGP_MULTIPLE_SUBKEYS; + else if (pubtype == 1) + res = process_secret_key(pkt, pk, key, key_len); + else + res = PXE_PGP_EXPECT_PUBLIC_KEY; + break; + case PGP_PKT_PUBLIC_KEY: + if (got_key) + { + res = PXE_PGP_MULTIPLE_KEYS; + break; + } + got_key = 1; + n_subkey = 0; + /* fallthru */ + case PGP_PKT_PUBLIC_SUBKEY: + if (tag == PGP_PKT_PUBLIC_SUBKEY) + n_subkey++; + + if (n_subkey > 1) + res = PXE_PGP_MULTIPLE_SUBKEYS; + else if (pubtype == 0) + res = _pgp_read_public_key(pkt, pk); + else + res = PXE_PGP_EXPECT_SECRET_KEY; + 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 (res < 0) + break; + + if (pk->algo == PGP_PUB_ELG_ENCRYPT) + break; + } + + if (pkt) + pullf_free(pkt); + + if (res < 0) + pgp_key_free(pk); + else { + if (pk->algo == PGP_PUB_ELG_ENCRYPT) + *pk_p = pk; + else { + pgp_key_free(pk); + px_debug("non-elg"); + res = PXE_PGP_NO_USABLE_KEY; + } + } + return res < 0 ? res : 0; +} + +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 0000000000..0916a0074e --- /dev/null +++ b/contrib/pgcrypto/pgp-s2k.c @@ -0,0 +1,299 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-s2k.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ + +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.h" + +static int +calc_s2k_simple(PGP_S2K * s2k, PX_MD *md, const uint8 *key, + unsigned key_len) +{ + unsigned md_bs, + md_rlen; + uint8 buf[PGP_MAX_DIGEST]; + unsigned preload; + unsigned remain; + uint8 *dst = s2k->key; + + md_bs = px_md_block_size(md); + 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; + } + } + return 0; +} + +static int +calc_s2k_salted(PGP_S2K * s2k, PX_MD *md, const uint8 *key, unsigned key_len) +{ + unsigned md_bs, + md_rlen; + uint8 buf[PGP_MAX_DIGEST]; + unsigned preload = 0; + uint8 *dst; + unsigned remain; + + md_bs = px_md_block_size(md); + 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; + } + } + return 0; +} + +static int +calc_s2k_iter_salted(PGP_S2K * s2k, PX_MD *md, const uint8 *key, + unsigned key_len) +{ + unsigned md_bs, + md_rlen; + uint8 buf[PGP_MAX_DIGEST]; + uint8 *dst; + unsigned preload = 0; + unsigned remain, + c, + cval, + curcnt, + count; + + cval = s2k->iter; + count = ((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6); + + md_bs = px_md_block_size(md); + 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; + } + } + return 0; +} + +/* + * Decide S2K_ISALTED iteration count + * + * Too small: weak + * Too big: slow + * gpg defaults to 96 => 65536 iters + * let it float a bit: 96 + 32 => 262144 iters + */ +static int +decide_count(unsigned rand_byte) +{ + return 96 + (rand_byte & 0x1F); +} + +int +pgp_s2k_fill(PGP_S2K *s2k, int mode,int digest_algo) +{ + int res = 0; + uint8 tmp; + + s2k->mode = mode; + s2k->digest_algo = digest_algo; + + switch (s2k->mode) { + case 0: + break; + case 1: + res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT); + break; + case 3: + res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT); + if (res < 0) + break; + res = px_get_random_bytes(&tmp, 1); + if (res < 0) + break; + s2k->iter = decide_count(tmp); + 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 0000000000..8c7144104d --- /dev/null +++ b/contrib/pgcrypto/pgp.c @@ -0,0 +1,351 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ + +#include + +#include "px.h" +#include "mbuf.h" +#include "pgp.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_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; + const char *int_name; +}; + +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 = px_alloc(sizeof *ctx); + memset(ctx, 0, sizeof *ctx); + + ctx->cipher_algo = def_cipher_algo; + ctx->s2k_cipher_algo = def_s2k_cipher_algo; + ctx->s2k_mode = def_s2k_mode; + 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); + memset(ctx, 0, sizeof *ctx); + px_free(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_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 0000000000..7f31aa3d73 --- /dev/null +++ b/contrib/pgcrypto/pgp.h @@ -0,0 +1,273 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp.h,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ + +enum +{ + PGP_S2K_SIMPLE = 0, + PGP_S2K_SALTED = 1, + PGP_S2K_ISALTED = 3 +} PGP_S2K_TYPE; + +enum +{ + 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 */ +} PGP_PKT_TYPE; + +enum +{ + 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 +} PGP_PUB_ALGO_TYPE; + +enum +{ + 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 +} PGP_SYMENC_TYPE; + +enum +{ + PGP_COMPR_NONE = 0, /* must */ + PGP_COMPR_ZIP = 1, /* should */ + PGP_COMPR_ZLIB = 2, + PGP_COMPR_BZIP2 = 3 +} PGP_COMPR_TYPE; + +enum +{ + 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 +} PGP_DIGEST_TYPE; + +#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; + /* calculated: */ + uint8 key[PGP_MAX_KEY]; + uint8 key_len; +}; + + +struct PGP_Context +{ + /* + * parameters + */ + PGP_S2K s2k; + int s2k_mode; + 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; + 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; +}; + +struct PGP_MPI { + uint8 *data; + int bits; + int bytes; +}; + +struct PGP_PubKey { + uint8 ver; + uint8 time[4]; + uint8 algo; + /* public */ + PGP_MPI *elg_p; + PGP_MPI *elg_g; + PGP_MPI *elg_y; + /* secret */ + PGP_MPI *elg_x; + + uint8 key_id[8]; +}; + +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_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 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 recync, 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); + +int pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst); +int pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst); +unsigned pgp_armor_enc_len(unsigned len); +unsigned pgp_armor_dec_len(unsigned len); + +int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst); +int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src); + +extern void (*pgp_packet_debug) (int tag, uint8 *buf, int len); + +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); + +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); + +extern struct PullFilterOps pgp_decrypt_filter; + diff --git a/contrib/pgcrypto/sha2.c b/contrib/pgcrypto/sha2.c new file mode 100644 index 0000000000..9c35107bdc --- /dev/null +++ b/contrib/pgcrypto/sha2.c @@ -0,0 +1,895 @@ +/* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ */ +/* $OpenBSD: sha2.c,v 1.6 2004/05/03 02:57:36 millert Exp $ */ + +/* + * FILE: sha2.c + * AUTHOR: Aaron D. Gifford + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * 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. + * 3. Neither the name of the copyright holder nor the names of 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 CONTRIBUTOR(S) ``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 CONTRIBUTOR(S) 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. + * + * $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ + */ + +#include + +#include "sha2.h" + +#undef bcopy +#undef bzero +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bzero(ptr, len) memset((ptr), 0, (len)) + +/* + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + uint32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + uint64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (uint64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX *); +void SHA256_Transform(SHA256_CTX *, const uint8 *); +void SHA512_Transform(SHA512_CTX *, const uint8 *); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static uint32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static uint32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static uint64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static uint64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static uint64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + + +/*** SHA-256: *********************************************************/ +void +SHA256_Init(SHA256_CTX *context) +{ + if (context == NULL) + return; + bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); + bzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do { \ + W256[j] = (uint32)data[3] | ((uint32)data[2] << 8) | \ + ((uint32)data[1] << 16) | ((uint32)data[0] << 24); \ + data += 4; \ + T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ + j++; \ +} while(0) + +#define ROUND256(a,b,c,d,e,f,g,h) do { \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ + j++; \ +} while(0) + +void +SHA256_Transform(SHA256_CTX *context, const uint8 *data) +{ + uint32 a, b, c, d, e, f, g, h, s0, s1; + uint32 T1, *W256; + int j; + + W256 = (uint32 *)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void +SHA256_Transform(SHA256_CTX *context, const uint8 *data) +{ + uint32 a, b, c, d, e, f, g, h, s0, s1; + uint32 T1, T2, *W256; + int j; + + W256 = (uint32 *)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + W256[j] = (uint32)data[3] | ((uint32)data[2] << 8) | + ((uint32)data[1] << 16) | ((uint32)data[0] << 24); + data += 4; + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void +SHA256_Update(SHA256_CTX *context, const uint8 *data, size_t len) +{ + size_t freespace, usedspace; + + /* Calling with no data is valid (we do nothing) */ + if (len == 0) + return; + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void +SHA256_Final(uint8 digest[], SHA256_CTX *context) +{ + uint32 *d = (uint32 *)digest; + unsigned int usedspace; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != NULL) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(uint64 *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + bzero(context, sizeof(*context)); + usedspace = 0; +} + + +/*** SHA-512: *********************************************************/ +void +SHA512_Init(SHA512_CTX *context) +{ + if (context == NULL) + return; + bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do { \ + W512[j] = (uint64)data[7] | ((uint64)data[6] << 8) | \ + ((uint64)data[5] << 16) | ((uint64)data[4] << 24) | \ + ((uint64)data[3] << 32) | ((uint64)data[2] << 40) | \ + ((uint64)data[1] << 48) | ((uint64)data[0] << 56); \ + data += 8; \ + T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ + j++; \ +} while(0) + + +#define ROUND512(a,b,c,d,e,f,g,h) do { \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ + j++; \ +} while(0) + +void +SHA512_Transform(SHA512_CTX *context, const uint8 *data) +{ + uint64 a, b, c, d, e, f, g, h, s0, s1; + uint64 T1, *W512 = (uint64 *)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void +SHA512_Transform(SHA512_CTX *context, const uint8 *data) +{ + uint64 a, b, c, d, e, f, g, h, s0, s1; + uint64 T1, T2, *W512 = (uint64 *)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + W512[j] = (uint64)data[7] | ((uint64)data[6] << 8) | + ((uint64)data[5] << 16) | ((uint64)data[4] << 24) | + ((uint64)data[3] << 32) | ((uint64)data[2] << 40) | + ((uint64)data[1] << 48) | ((uint64)data[0] << 56); + data += 8; + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void +SHA512_Update(SHA512_CTX *context, const uint8 *data, size_t len) +{ + size_t freespace, usedspace; + + /* Calling with no data is valid (we do nothing) */ + if (len == 0) + return; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void +SHA512_Last(SHA512_CTX *context) +{ + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(uint64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(uint64 *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, context->buffer); +} + +void +SHA512_Final(uint8 digest[], SHA512_CTX *context) +{ + uint64 *d = (uint64 *)digest; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != NULL) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(*context)); +} + + +/*** SHA-384: *********************************************************/ +void +SHA384_Init(SHA384_CTX *context) +{ + if (context == NULL) + return; + bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void +SHA384_Update(SHA384_CTX *context, const uint8 *data, size_t len) +{ + SHA512_Update((SHA512_CTX *)context, data, len); +} + +void +SHA384_Final(uint8 digest[], SHA384_CTX *context) +{ + uint64 *d = (uint64 *)digest; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != NULL) { + SHA512_Last((SHA512_CTX *)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(*context)); +} diff --git a/contrib/pgcrypto/sha2.h b/contrib/pgcrypto/sha2.h new file mode 100644 index 0000000000..2dfb13ceb1 --- /dev/null +++ b/contrib/pgcrypto/sha2.h @@ -0,0 +1,80 @@ +/* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.h,v 1.1 2005/07/10 13:46:29 momjian Exp $ */ +/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */ + +/* + * FILE: sha2.h + * AUTHOR: Aaron D. Gifford + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * 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. + * 3. Neither the name of the copyright holder nor the names of 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 CONTRIBUTOR(S) ``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 CONTRIBUTOR(S) 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. + * + * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ + */ + +#ifndef _SHA2_H +#define _SHA2_H + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +typedef struct _SHA256_CTX { + uint32 state[8]; + uint64 bitcount; + uint8 buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64 state[8]; + uint64 bitcount[2]; + uint8 buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +typedef SHA512_CTX SHA384_CTX; + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX *, const uint8 *, size_t); +void SHA256_Final(uint8[SHA256_DIGEST_LENGTH], SHA256_CTX *); + +void SHA384_Init(SHA384_CTX *); +void SHA384_Update(SHA384_CTX *, const uint8 *, size_t); +void SHA384_Final(uint8[SHA384_DIGEST_LENGTH], SHA384_CTX *); + +void SHA512_Init(SHA512_CTX *); +void SHA512_Update(SHA512_CTX *, const uint8 *, size_t); +void SHA512_Final(uint8[SHA512_DIGEST_LENGTH], SHA512_CTX *); + +#endif /* _SHA2_H */ diff --git a/contrib/pgcrypto/sql/pgp-armor.sql b/contrib/pgcrypto/sql/pgp-armor.sql new file mode 100644 index 0000000000..040c4ac038 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-armor.sql @@ -0,0 +1,56 @@ +-- +-- PGP Armor +-- + +select armor(''); +select armor('test'); +select dearmor(armor('')); +select dearmor(armor('zooka')); + +select armor('0123456789abcdef0123456789abcdef0123456789abcdef +0123456789abcdef0123456789abcdef0123456789abcdef'); + +-- lots formatting +select dearmor(' a pgp msg: + +-----BEGIN PGP MESSAGE----- +Comment: Some junk + +em9va2E= + + =D5cR + +-----END PGP MESSAGE-----'); + +-- lots messages +select 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----- +'); + +-- bad crc +select dearmor(' +-----BEGIN PGP MESSAGE----- + +em9va2E= +=ZZZZ +-----END PGP MESSAGE----- +'); diff --git a/contrib/pgcrypto/sql/pgp-compression.sql b/contrib/pgcrypto/sql/pgp-compression.sql new file mode 100644 index 0000000000..f71c176da5 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-compression.sql @@ -0,0 +1,31 @@ +-- +-- 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'); + diff --git a/contrib/pgcrypto/sql/pgp-decrypt.sql b/contrib/pgcrypto/sql/pgp-decrypt.sql new file mode 100644 index 0000000000..93535ab016 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-decrypt.sql @@ -0,0 +1,266 @@ +-- +-- pgp_descrypt 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 encode(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'), 'hex'); +-- expected: 0225e3ede6f2587b076d021a189ff60aad67e066 + +select encode(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'), 'hex'); +-- expected: da39a3ee5e6b4b0d3255bfef95601890afd80709 + +select encode(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'), 'hex'); +-- expected: 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c + +-- Checking CRLF +select encode(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'), 'hex'); +-- expected: 9353062be7720f1446d30b9e75573a4833886784 + +select encode(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'), 'hex'); +-- expected: 7efefcab38467f7484d6fa43dc86cf5281bd78e2 diff --git a/contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql b/contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql new file mode 100644 index 0000000000..80fb4d123c --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql @@ -0,0 +1,3 @@ + +-- no random source + diff --git a/contrib/pgcrypto/sql/pgp-encrypt.sql b/contrib/pgcrypto/sql/pgp-encrypt.sql new file mode 100644 index 0000000000..b663e051ae --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-encrypt.sql @@ -0,0 +1,96 @@ +-- +-- 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 pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'); + + +-- 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 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 encode(pgp_sym_decrypt_bytea( + pgp_sym_encrypt('1\n2\n3\r\n', 'key', 'convert-crlf=1'), + 'key'), 'hex'); + +-- conversion should be lossless +select encode(digest(pgp_sym_decrypt( + pgp_sym_encrypt('\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'), + 'key', 'convert-crlf=1'), 'sha1'), 'hex') as result, + encode(digest('\r\n0\n1\r\r\n\n2\r', 'sha1'), 'hex') as expect; + diff --git a/contrib/pgcrypto/sql/pgp-info.sql b/contrib/pgcrypto/sql/pgp-info.sql new file mode 100644 index 0000000000..d979bb93d9 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-info.sql @@ -0,0 +1,21 @@ +-- +-- 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(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(data)) as data_key_id +from encdata order by id; + diff --git a/contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql b/contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql new file mode 100644 index 0000000000..b4aec5daf6 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql @@ -0,0 +1,3 @@ + +-- no bignum support + diff --git a/contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql b/contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql new file mode 100644 index 0000000000..13fe090c67 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql @@ -0,0 +1,437 @@ +-- +-- 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) + +mQGiBELII7wRBACFuaAvb11cIvjJK9LkZr4cYuYhLWh3DJdojNNnLNiym5OEksvY +05cw8OgqKtPzICU7o/mHXTWhzJYUt3i50/AeYygI8Q0uATS6RnDAKNlES1EMoHKz +2a5iFbYs4bm4IwlkvYd8uWjcu+U0YLbxir39u+anIc6eT+q3WiH/q3zDRwCgkT98 +cnIG8iO8PdwDSP8G4Lt6TYED/R45GvCzJ4onQALLE92KkLUz8aFWSl05r84kczEN +SxiP9Ss6m465RmwWHfwYAu4b+c4GeNyU8fIU2EM8cezchC+edEi3xu1s+pCV0Dk4 +18DGC8WKCICO30vBynuNmYg7W/7Zd4wtjss454fMW7+idVDNM701mmXBtI1nsBtG +7Z4tA/9FxjFbJK9jh24RewfjHpLYqcfCo2SsUjOwsnMZ5yg2yv9KyVVQhRqwmrqt +q8MRyjGmfoD9PPdCgvqgzy0hHvAHUtTm2zUczGTG+0g4hNIklxC/Mv6J4KE+NWTh +uB4acqofHyaw2WnKOuRUsoDi6rG5AyjNMyAK/vVcEGj7J1tk27QjRWxnYW1hbCA0 +MDk2IDx0ZXN0NDA5NkBleGFtcGxlLm9yZz6IXgQTEQIAHgUCQsgjvAIbAwYLCQgH +AwIDFQIDAxYCAQIeAQIXgAAKCRBj+HX2P2d0oAEDAJ9lI+CNmb42z3+a6TnVusM6 +FI7oLwCfUwA1zEcRdsT3nIkoYh0iKxFSDFW5BA0EQsgkdhAQAJQbLXlgcJ/jq+Xh +Eujb77/eeftFJObNIRYD9fmJ7HFIXbUcknEpbs+cRH/nrj5dGSY3OT3jCXOUtvec +sCoX/CpZWL0oqDjAiZtNSFiulw5Gav4gHYkWKgKdSo+2rkavEPqKIVHvMeXaJtGT +d7v/AmL/P8T7gls93o5WFBOLtPbDvWqaKRy2U5TAhl1laiM0vGALRVjvSCgnGw9g +FpSnXbO3AfenUSjDzZujfGLHtU44ixHSS/D4DepiF3YaYLsN4CBqZRv6FbMZD5W3 +DnJY4kS1kH0MzdcF19TlcZ3itTCcGIt1tMKf84mccPoqdMzH7vumBGTeFEly5Afp +9berJcirqh2fzlunN0GS02z6SGWnjTbDlkNDxuxPSBbpcpNyD3jpYAUqSwRsZ/+5 +zkzcbGtDmvy9sJ5lAXkxGoIoQ1tEVX/LOHnh2NQHK8ourVOnr7MS0nozssITZJ5E +XqtHiREjiYEuPyZiVZKJHLWuYYaF+n40znnz3sJuXFRreHhHbbvRdlYUU5mJV+XZ +BLgKuS33NdpGeMIngnCc/9IQ6OZb6ixc94kbkd3w2PVr8CbKlu/IHTjWOO2mAo+D ++OydlYl23FiM3KOyMP1HcEOJMB/nwkMtrvd+522Lu9n77ktKfot9IPrQDIQTyXjR +3pCOFtCOBnk2tJHMPoG9jn9ah/LHAAMHEACDZ5I/MHGfmiKg2hrmqBu2J2j/deC8 +CpwcyDH1ovQ0gHvb9ESa+CVRU2Wdy2CD7Q9SmtMverB5eneL418iPVRcQdwRmQ2y +IH4udlBa6ce9HTUCaecAZ4/tYBnaC0Av/9l9tz14eYcwRMDpB+bnkhgF+PZ1KAfD +9wcY2aHbtsf3lZBc5h4owPJkxpe/BNzuJxW3q4VpSbLsZhwnCZ2wg7DRwP44wFIk +00ptmoBY59gsU6I40XtzrF8JDr0cA57xND5RY21Z8lnnYRE1Tc8h5REps9ZIxW3/ +yl91404bPLqxczpUHQAMSTAmBaStPYX1nS51uofOhLs5SKPCUmxfGKIOhsD0oLUn +78DnkONVGeXzBibSwwtbgfMzee4G8wSUfJ7w8WXz1TyanaGLnJ+DuKASSOrFoBCD +HEDuWZWgSL74NOQupFRk0gxOPmqU94Y8HziQWma/cETbmD83q8rxN+GM2oBxQkQG +xcbqMTHE7aVhV3tymbSWVaYhww3oIwsZS9oUIi1DnPEowS6CpVRrwdvLjLJnJzzV +O3AFPn9eZ1Q7R1tNx+zZ4OOfhvI/OlRJ3HBx2L53embkbdY9gFYCCdTjPyjKoDIx +kALgCajjCYMNUsAKNSd6mMCQ8TtvukSzkZS1RGKP27ohsdnzIVsiEAbxDMMcI4k1 +ul0LExUTCXSjeIhJBBgRAgAJBQJCyCR2AhsMAAoJEGP4dfY/Z3Sg19sAn0NDS8pb +qrMpQAxSb7zRTmcXEFd9AJ435H0ttP/NhLHXC9ezgbCMmpXMOQ== +=kRxT +-----END PGP PUBLIC KEY BLOCK----- +', ' +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +lQG7BELII7wRBACFuaAvb11cIvjJK9LkZr4cYuYhLWh3DJdojNNnLNiym5OEksvY +05cw8OgqKtPzICU7o/mHXTWhzJYUt3i50/AeYygI8Q0uATS6RnDAKNlES1EMoHKz +2a5iFbYs4bm4IwlkvYd8uWjcu+U0YLbxir39u+anIc6eT+q3WiH/q3zDRwCgkT98 +cnIG8iO8PdwDSP8G4Lt6TYED/R45GvCzJ4onQALLE92KkLUz8aFWSl05r84kczEN +SxiP9Ss6m465RmwWHfwYAu4b+c4GeNyU8fIU2EM8cezchC+edEi3xu1s+pCV0Dk4 +18DGC8WKCICO30vBynuNmYg7W/7Zd4wtjss454fMW7+idVDNM701mmXBtI1nsBtG +7Z4tA/9FxjFbJK9jh24RewfjHpLYqcfCo2SsUjOwsnMZ5yg2yv9KyVVQhRqwmrqt +q8MRyjGmfoD9PPdCgvqgzy0hHvAHUtTm2zUczGTG+0g4hNIklxC/Mv6J4KE+NWTh +uB4acqofHyaw2WnKOuRUsoDi6rG5AyjNMyAK/vVcEGj7J1tk2wAAoJCUNy6awTkw +XfbLbpqh0fvDst7jDLa0I0VsZ2FtYWwgNDA5NiA8dGVzdDQwOTZAZXhhbXBsZS5v +cmc+iF4EExECAB4FAkLII7wCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQY/h1 +9j9ndKABAwCeNEOVK87EzXYbtxYBsnjrUI948NIAn2+f3BXiBFDV5NvqPwIZ0m77 +Fwy4nQRMBELIJHYQEACUGy15YHCf46vl4RLo2++/3nn7RSTmzSEWA/X5iexxSF21 +HJJxKW7PnER/564+XRkmNzk94wlzlLb3nLAqF/wqWVi9KKg4wImbTUhYrpcORmr+ +IB2JFioCnUqPtq5GrxD6iiFR7zHl2ibRk3e7/wJi/z/E+4JbPd6OVhQTi7T2w71q +mikctlOUwIZdZWojNLxgC0VY70goJxsPYBaUp12ztwH3p1Eow82bo3xix7VOOIsR +0kvw+A3qYhd2GmC7DeAgamUb+hWzGQ+Vtw5yWOJEtZB9DM3XBdfU5XGd4rUwnBiL +dbTCn/OJnHD6KnTMx+77pgRk3hRJcuQH6fW3qyXIq6odn85bpzdBktNs+khlp402 +w5ZDQ8bsT0gW6XKTcg946WAFKksEbGf/uc5M3GxrQ5r8vbCeZQF5MRqCKENbRFV/ +yzh54djUByvKLq1Tp6+zEtJ6M7LCE2SeRF6rR4kRI4mBLj8mYlWSiRy1rmGGhfp+ +NM55897CblxUa3h4R2270XZWFFOZiVfl2QS4Crkt9zXaRnjCJ4JwnP/SEOjmW+os +XPeJG5Hd8Nj1a/AmypbvyB041jjtpgKPg/jsnZWJdtxYjNyjsjD9R3BDiTAf58JD +La73fudti7vZ++5LSn6LfSD60AyEE8l40d6QjhbQjgZ5NrSRzD6BvY5/WofyxwAD +BxAAg2eSPzBxn5oioNoa5qgbtido/3XgvAqcHMgx9aL0NIB72/REmvglUVNlnctg +g+0PUprTL3qweXp3i+NfIj1UXEHcEZkNsiB+LnZQWunHvR01AmnnAGeP7WAZ2gtA +L//Zfbc9eHmHMETA6Qfm55IYBfj2dSgHw/cHGNmh27bH95WQXOYeKMDyZMaXvwTc +7icVt6uFaUmy7GYcJwmdsIOw0cD+OMBSJNNKbZqAWOfYLFOiONF7c6xfCQ69HAOe +8TQ+UWNtWfJZ52ERNU3PIeURKbPWSMVt/8pfdeNOGzy6sXM6VB0ADEkwJgWkrT2F +9Z0udbqHzoS7OUijwlJsXxiiDobA9KC1J+/A55DjVRnl8wYm0sMLW4HzM3nuBvME +lHye8PFl89U8mp2hi5yfg7igEkjqxaAQgxxA7lmVoEi++DTkLqRUZNIMTj5qlPeG +PB84kFpmv3BE25g/N6vK8TfhjNqAcUJEBsXG6jExxO2lYVd7cpm0llWmIcMN6CML +GUvaFCItQ5zxKMEugqVUa8Hby4yyZyc81TtwBT5/XmdUO0dbTcfs2eDjn4byPzpU +Sdxwcdi+d3pm5G3WPYBWAgnU4z8oyqAyMZAC4Amo4wmDDVLACjUnepjAkPE7b7pE +s5GUtURij9u6IbHZ8yFbIhAG8QzDHCOJNbpdCxMVEwl0o3gAAckBdfKuasiNUn5G +L5XRnSvaOFzftr8zteOlZChCSNvzH5k+i1j7RJbWq06OeKRywPzjfjgM2MvRzI43 +ICeISQQYEQIACQUCQsgkdgIbDAAKCRBj+HX2P2d0oNfbAJ9+G3SeXrk+dWwo9EGi +hqMi2GVTsgCfeoQJPsc8FLYUgfymc/3xqAVLUtg= +=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) + +lQHhBELIIUgRBACp401L6jXrLB28c3YA4sM3OJKnxM1GT9YTkWyE3Vyte65H8WU9 +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+sAKqROqe6dLjJ7vebQP4DAwL3TCgrYdj6 ++GAnoSqGa87twi8a6QRRYIlEx3ddUCDCjzkJmRfF+LFtvX3OtWWK0+Syi3kj2IK9 +YT7pF7QfRWxnYW1hbCAxMDI0IDx0ZXN0QGV4YW1wbGUub3JnPoheBBMRAgAeBQJC +yCFIAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEBwpvA0YF3NkOtsAn1ynoCyM +6GIvHDOewwmF4Z/jGQfzAJ9Q+MwIubi0ASfJifaEM23sIHwHop0BVwRCyCFKEAQA +h5SNbbJMAsJ+sQbcWEzdku8AdYB5zY7Qyf9EOvn0g39bzANhxmmb6gbRlQN0ioym +lDwraTKUAfuCZgNcg/0PsxFGb9nDcvjIV8qdVpnq1PuzMFuBbmGI6weg7Pj01dlP +iO0wt1lLX+SubktqbYxI+h31c3RDZqxj+KAgxR8YNGMAAwYD+wQs2He1Z5+p4OSg +MERiNzF0acZUYmc0e+/96gfL0ft3IP+SSFo6hEBrkKVhZKoPSSRr5KpNaEobhdxs +nKjUaw/qyoaFcNMzb4sFk8wq5UlCkR+h72u6hv8FuleCV8SJUT1U2JjtlXJR2Pey +9ifh8rZfu57UbdwdHa0viWc4Dilh/gMDAvdMKCth2Pr4YCCPsELdgJuzhGfDNRSg +nKMRWBWHSJRk6JmCjM1iJQNHc4mMhR8gvi2TeqYLOhYjcF7nr/LA+JvLV+adj/mI +SQQYEQIACQUCQsghSgIbDAAKCRAcKbwNGBdzZO2vAJ4hRaLcNcdl/qK8rt0N5zbZ +saCh6QCfR1O48O8nYN93SPSfIFZK5rEmdv8= +=Y6Qv +-----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----- +'); + +-- 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; + +-- 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; + +-- 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; + diff --git a/contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql b/contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql new file mode 100644 index 0000000000..89d05a7a36 --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql @@ -0,0 +1,45 @@ +-- +-- 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; + +-- 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 pgp_pub_decrypt_bytea( + pgp_pub_encrypt('Secret msg', dearmor(pubkey)), + dearmor(seckey)) +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 0000000000..85c24683be --- /dev/null +++ b/contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql @@ -0,0 +1,3 @@ + +-- zlib is disabled + diff --git a/contrib/pgcrypto/sql/sha2.sql b/contrib/pgcrypto/sql/sha2.sql new file mode 100644 index 0000000000..f1d0ca63f0 --- /dev/null +++ b/contrib/pgcrypto/sql/sha2.sql @@ -0,0 +1,28 @@ +-- +-- SHA2 family +-- + +-- SHA256 +SELECT encode(digest('', 'sha256'), 'hex'); +SELECT encode(digest('a', 'sha256'), 'hex'); +SELECT encode(digest('abc', 'sha256'), 'hex'); +SELECT encode(digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha256'), 'hex'); +SELECT encode(digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'sha256'), 'hex'); + +-- SHA384 +SELECT encode(digest('', 'sha384'), 'hex'); +SELECT encode(digest('a', 'sha384'), 'hex'); +SELECT encode(digest('abc', 'sha384'), 'hex'); +SELECT encode(digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha384'), 'hex'); +SELECT encode(digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha384'), 'hex'); +SELECT encode(digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha384'), 'hex'); + +-- SHA512 +SELECT encode(digest('', 'sha512'), 'hex'); +SELECT encode(digest('a', 'sha512'), 'hex'); +SELECT encode(digest('abc', 'sha512'), 'hex'); +SELECT encode(digest('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 'sha512'), 'hex'); +SELECT encode(digest('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', 'sha512'), 'hex'); +SELECT encode(digest('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'sha512'), 'hex'); + + -- 2.40.0