Add missing pgcrypto files from previous commit.
authorBruce Momjian <bruce@momjian.us>
Sun, 10 Jul 2005 13:46:29 +0000 (13:46 +0000)
committerBruce Momjian <bruce@momjian.us>
Sun, 10 Jul 2005 13:46:29 +0000 (13:46 +0000)
44 files changed:
contrib/pgcrypto/expected/pgp-armor.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-compression.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-decrypt.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-encrypt-DISABLED.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-encrypt.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-info.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-pubkey-DISABLED.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-pubkey-decrypt.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-pubkey-encrypt.out [new file with mode: 0644]
contrib/pgcrypto/expected/pgp-zlib-DISABLED.out [new file with mode: 0644]
contrib/pgcrypto/expected/sha2.out [new file with mode: 0644]
contrib/pgcrypto/fortuna.c [new file with mode: 0644]
contrib/pgcrypto/fortuna.h [new file with mode: 0644]
contrib/pgcrypto/mbuf.c [new file with mode: 0644]
contrib/pgcrypto/mbuf.h [new file with mode: 0644]
contrib/pgcrypto/pgp-armor.c [new file with mode: 0644]
contrib/pgcrypto/pgp-cfb.c [new file with mode: 0644]
contrib/pgcrypto/pgp-compress.c [new file with mode: 0644]
contrib/pgcrypto/pgp-decrypt.c [new file with mode: 0644]
contrib/pgcrypto/pgp-encrypt.c [new file with mode: 0644]
contrib/pgcrypto/pgp-info.c [new file with mode: 0644]
contrib/pgcrypto/pgp-mpi-internal.c [new file with mode: 0644]
contrib/pgcrypto/pgp-mpi-openssl.c [new file with mode: 0644]
contrib/pgcrypto/pgp-mpi.c [new file with mode: 0644]
contrib/pgcrypto/pgp-pgsql.c [new file with mode: 0644]
contrib/pgcrypto/pgp-pubdec.c [new file with mode: 0644]
contrib/pgcrypto/pgp-pubenc.c [new file with mode: 0644]
contrib/pgcrypto/pgp-pubkey.c [new file with mode: 0644]
contrib/pgcrypto/pgp-s2k.c [new file with mode: 0644]
contrib/pgcrypto/pgp.c [new file with mode: 0644]
contrib/pgcrypto/pgp.h [new file with mode: 0644]
contrib/pgcrypto/sha2.c [new file with mode: 0644]
contrib/pgcrypto/sha2.h [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-armor.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-compression.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-decrypt.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-encrypt-DISABLED.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-encrypt.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-info.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-pubkey-DISABLED.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-pubkey-decrypt.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-pubkey-encrypt.sql [new file with mode: 0644]
contrib/pgcrypto/sql/pgp-zlib-DISABLED.sql [new file with mode: 0644]
contrib/pgcrypto/sql/sha2.sql [new file with mode: 0644]

diff --git a/contrib/pgcrypto/expected/pgp-armor.out b/contrib/pgcrypto/expected/pgp-armor.out
new file mode 100644 (file)
index 0000000..ba7d426
--- /dev/null
@@ -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 (file)
index 0000000..32b350b
--- /dev/null
@@ -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 (file)
index 0000000..8ecb56f
--- /dev/null
@@ -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 (file)
index 0000000..4122300
--- /dev/null
@@ -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 (file)
index 0000000..b04bae5
--- /dev/null
@@ -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 (file)
index 0000000..300d41a
--- /dev/null
@@ -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 (file)
index 0000000..d35c097
--- /dev/null
@@ -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 (file)
index 0000000..28881ad
--- /dev/null
@@ -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 (file)
index 0000000..a7b1c02
--- /dev/null
@@ -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 (file)
index 0000000..6f4eccd
--- /dev/null
@@ -0,0 +1 @@
+-- zlib is disabled
diff --git a/contrib/pgcrypto/expected/sha2.out b/contrib/pgcrypto/expected/sha2.out
new file mode 100644 (file)
index 0000000..20bdf0e
--- /dev/null
@@ -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 (file)
index 0000000..ff02a97
--- /dev/null
@@ -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 <postgres.h>
+#include <sys/time.h>
+#include <time.h>
+
+#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 (file)
index 0000000..b576eb9
--- /dev/null
@@ -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 (file)
index 0000000..eb5dff9
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..6042a4f
--- /dev/null
@@ -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 (file)
index 0000000..20f443f
--- /dev/null
@@ -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 <postgres.h>
+
+#include <string.h>
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+/*
+ * BASE64 - duplicated :(
+ */
+
+static const unsigned char _base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int
+b64_encode(const uint8 *src, unsigned len, uint8 *dst)
+{
+       uint8      *p,
+                          *lend = dst + 76;
+       const uint8 *s,
+                          *end = src + len;
+       int                     pos = 2;
+       unsigned long buf = 0;
+
+       s = src;
+       p = dst;
+
+       while (s < end)
+       {
+               buf |= *s << (pos << 3);
+               pos--;
+               s++;
+
+               /*
+                * write it out
+                */
+               if (pos < 0)
+               {
+                       *p++ = _base64[(buf >> 18) & 0x3f];
+                       *p++ = _base64[(buf >> 12) & 0x3f];
+                       *p++ = _base64[(buf >> 6) & 0x3f];
+                       *p++ = _base64[buf & 0x3f];
+
+                       pos = 2;
+                       buf = 0;
+               }
+               if (p >= lend)
+               {
+                       *p++ = '\n';
+                       lend = p + 76;
+               }
+       }
+       if (pos != 2)
+       {
+               *p++ = _base64[(buf >> 18) & 0x3f];
+               *p++ = _base64[(buf >> 12) & 0x3f];
+               *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
+               *p++ = '=';
+       }
+
+       return p - dst;
+}
+
+/* probably should use lookup table */
+static int
+b64_decode(const uint8 *src, unsigned len, uint8 *dst)
+{
+       const uint8 *srcend = src + len,
+               *s = src;
+       uint8      *p = dst;
+       char            c;
+       unsigned        b = 0;
+       unsigned long buf = 0;
+       int                     pos = 0,
+               end = 0;
+
+       while (s < srcend)
+       {
+               c = *s++;
+               if (c >= 'A' && c <= 'Z')
+                       b = c - 'A';
+               else if (c >= 'a' && c <= 'z')
+                       b = c - 'a' + 26;
+               else if (c >= '0' && c <= '9')
+                       b = c - '0' + 52;
+               else if (c == '+')
+                       b = 62;
+               else if (c == '/')
+                       b = 63;
+               else if (c == '=')
+               {
+                       /*
+                        * end sequence
+                        */
+                       if (!end)
+                       {
+                               if (pos == 2)
+                                       end = 1;
+                               else if (pos == 3)
+                                       end = 2;
+                               else
+                                       return PXE_PGP_CORRUPT_ARMOR;
+                       }
+                       b = 0;
+               }
+               else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+                       continue;
+               else
+                       return PXE_PGP_CORRUPT_ARMOR;
+
+               /*
+                * add it to buffer
+                */
+               buf = (buf << 6) + b;
+               pos++;
+               if (pos == 4)
+               {
+                       *p++ = (buf >> 16) & 255;
+                       if (end == 0 || end > 1)
+                               *p++ = (buf >> 8) & 255;
+                       if (end == 0 || end > 2)
+                               *p++ = buf & 255;
+                       buf = 0;
+                       pos = 0;
+               }
+       }
+
+       if (pos != 0)
+               return PXE_PGP_CORRUPT_ARMOR;
+       return p - dst;
+}
+
+static unsigned
+b64_enc_len(unsigned srclen)
+{
+       /*
+        * 3 bytes will be converted to 4, linefeed after 76 chars
+        */
+       return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
+}
+
+static unsigned
+b64_dec_len(unsigned srclen)
+{
+       return (srclen * 3) >> 2;
+}
+
+/*
+ * PGP armor
+ */
+
+static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n\n";
+static const char *armor_footer = "\n-----END PGP MESSAGE-----\n";
+
+/* CRC24 implementation from rfc2440 */
+#define CRC24_INIT 0x00b704ceL
+#define CRC24_POLY 0x01864cfbL
+static long
+crc24(const uint8 *data, unsigned len)
+{
+       unsigned        crc = CRC24_INIT;
+       int                     i;
+
+       while (len--)
+       {
+               crc ^= (*data++) << 16;
+               for (i = 0; i < 8; i++)
+               {
+                       crc <<= 1;
+                       if (crc & 0x1000000)
+                               crc ^= CRC24_POLY;
+               }
+       }
+       return crc & 0xffffffL;
+}
+
+int
+pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst)
+{
+       int                     n;
+       uint8      *pos = dst;
+       unsigned        crc = crc24(src, len);
+
+       n = strlen(armor_header);
+       memcpy(pos, armor_header, n);
+       pos += n;
+
+       n = b64_encode(src, len, pos);
+       pos += n;
+
+       if (*(pos - 1) != '\n')
+               *pos++ = '\n';
+
+       *pos++ = '=';
+       pos[3] = _base64[crc & 0x3f];
+       crc >>= 6;
+       pos[2] = _base64[crc & 0x3f];
+       crc >>= 6;
+       pos[1] = _base64[crc & 0x3f];
+       crc >>= 6;
+       pos[0] = _base64[crc & 0x3f];
+       pos += 4;
+
+       n = strlen(armor_footer);
+       memcpy(pos, armor_footer, n);
+       pos += n;
+
+       return pos - dst;
+}
+
+static const uint8 *
+find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
+{
+       const uint8 *p = data;
+       if (!strlen)
+               return NULL;
+       if (data_end - data < strlen)
+               return NULL;
+       while (p < data_end) {
+               p = memchr(p, str[0], data_end - p);
+               if (p == NULL)
+                       return NULL;
+               if (p + strlen > data_end)
+                       return NULL;
+               if (memcmp(p, str, strlen) == 0)
+                       return p;
+               p++;
+       }
+       return NULL;
+}
+
+static int
+find_header(const uint8 *data, const uint8 *datend,
+               const uint8 **start_p, int is_end)
+{
+       const uint8 *p = data;
+       static const char *start_sep = "-----BEGIN";
+       static const char *end_sep = "-----END";
+       const char *sep = is_end ? end_sep : start_sep;
+
+       /* find header line */
+       while (1)
+       {
+               p = find_str(p, datend, sep, strlen(sep));
+               if (p == NULL)
+                       return PXE_PGP_CORRUPT_ARMOR;
+               /* it must start at beginning of line */
+               if (p == data || *(p - 1) == '\n')
+                       break;
+               p += strlen(sep);
+       }
+       *start_p = p;
+       p += strlen(sep);
+
+       /* check if header text ok */
+       for (; p < datend && *p != '-'; p++)
+       {
+               /* various junk can be there, but definitely not line-feed  */
+               if (*p >= ' ')
+                       continue;
+               return PXE_PGP_CORRUPT_ARMOR;
+       }
+       if (datend - p < 5 || memcmp(p, sep, 5) != 0)
+               return PXE_PGP_CORRUPT_ARMOR;
+       p += 5;
+
+       /* check if at end of line */
+       if (p < datend)
+       {
+               if (*p != '\n' && *p != '\r')
+                       return PXE_PGP_CORRUPT_ARMOR;
+               if (*p == '\r')
+                       p++;
+               if (p < datend && *p == '\n')
+                       p++;
+       }
+       return p - *start_p;
+}
+
+int
+pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
+{
+       const uint8 *p = src;
+       const uint8 *data_end = src + len;
+       long            crc;
+       const uint8 *base64_start, *armor_end;
+       const uint8 *base64_end = NULL;
+       uint8           buf[4];
+       int                     hlen;
+       int                     res = PXE_PGP_CORRUPT_ARMOR;
+
+       /* armor start */
+       hlen = find_header(src, data_end, &p, 0);
+       if (hlen <= 0)
+               goto out;
+       p += hlen;
+
+       /* armor end */
+       hlen = find_header(p, data_end, &armor_end, 1);
+       if (hlen <= 0)
+               goto out;
+       
+       /* skip comments - find empty line */
+       while (p < armor_end && *p != '\n' && *p != '\r')
+       {
+               p = memchr(p, '\n', armor_end - p);
+               if (!p)
+                       goto out;
+
+               /* step to start of next line */
+               p++;
+       }
+       base64_start = p;
+       
+       /* find crc pos */
+       for (p = armor_end; p >= base64_start; p--)
+               if (*p == '=')
+               {
+                       base64_end = p - 1;
+                       break;
+               }
+       if (base64_end == NULL)
+               goto out;
+
+       /* decode crc */
+       if (b64_decode(p + 1, 4, buf) != 3)
+               goto out;
+       crc = (((long)buf[0]) << 16) + (((long)buf[1]) << 8) + (long)buf[2];
+
+       /* decode data */
+       res = b64_decode(base64_start, base64_end - base64_start, dst);
+
+       /* check crc */
+       if (res >= 0 && crc24(dst, res) != crc)
+               res = PXE_PGP_CORRUPT_ARMOR;
+out:
+       return res;
+}
+
+unsigned
+pgp_armor_enc_len(unsigned len)
+{
+       return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
+}
+
+unsigned
+pgp_armor_dec_len(unsigned len)
+{
+       return b64_dec_len(len);
+}
+
diff --git a/contrib/pgcrypto/pgp-cfb.c b/contrib/pgcrypto/pgp-cfb.c
new file mode 100644 (file)
index 0000000..52f3722
--- /dev/null
@@ -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 <postgres.h>
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+typedef int (*mix_data_t)(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
+
+struct PGP_CFB
+{
+       PX_Cipher  *ciph;
+       int                     block_size;
+       int                     pos;
+       int                     block_no;
+       int                     resync;
+       uint8           fr[PGP_MAX_BLOCK];
+       uint8           fre[PGP_MAX_BLOCK];
+       uint8           encbuf[PGP_MAX_BLOCK];
+};
+
+int
+pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
+               int resync, uint8 *iv)
+{
+       int res;
+       PX_Cipher *ciph;
+       PGP_CFB *ctx;
+
+       res = pgp_load_cipher(algo, &ciph);
+       if (res < 0)
+               return res;
+
+       res = px_cipher_init(ciph, key, key_len, NULL);
+       if (res < 0)
+       {
+               px_cipher_free(ciph);
+               return res;
+       }
+
+       ctx = px_alloc(sizeof(*ctx));
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->ciph = ciph;
+       ctx->block_size = px_cipher_block_size(ciph);
+       ctx->resync = resync;
+
+       if (iv)
+               memcpy(ctx->fr, iv, ctx->block_size);
+
+       *ctx_p = ctx;
+       return 0;
+}
+
+void
+pgp_cfb_free(PGP_CFB *ctx)
+{
+       px_cipher_free(ctx->ciph);
+       memset(ctx, 0, sizeof(*ctx));
+       px_free(ctx);
+}
+
+/*
+ * Data processing for normal CFB.  (PGP_PKT_SYMENCRYPTED_DATA_MDC)
+ */
+static int
+mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+       int i;
+       for (i = ctx->pos; i < ctx->pos + len; i++)
+               *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+       ctx->pos += len;
+       return len;
+}
+
+static int
+mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+       int i;
+       for (i = ctx->pos; i < ctx->pos + len; i++)
+       {
+               ctx->encbuf[i] = *data++;
+               *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+       }
+       ctx->pos += len;
+       return len;
+}
+
+/*
+ * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
+ *
+ * The goal is to hide the horror from the rest of the code,
+ * thus its all concentrated here.
+ */
+static int
+mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+       int i,n;
+       /* block #2 is 2 bytes long */
+       if (ctx->block_no == 2)
+       {
+               n = 2 - ctx->pos;
+               if (len < n)
+                       n = len;
+               for (i = ctx->pos; i < ctx->pos + n; i++)
+                       *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+
+               ctx->pos += n;
+               len -= n;
+
+               if (ctx->pos == 2)
+               {
+                       memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
+                       memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
+                       ctx->pos = 0;
+                       return n;
+               }
+       }
+       for (i = ctx->pos; i < ctx->pos + len; i++)
+               *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
+       ctx->pos += len;
+       return len;
+}
+
+static int
+mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+       int i,n;
+       /* block #2 is 2 bytes long */
+       if (ctx->block_no == 2)
+       {
+               n = 2 - ctx->pos;
+               if (len < n)
+                       n = len;
+               for (i = ctx->pos; i < ctx->pos + n; i++)
+               {
+                       ctx->encbuf[i] = *data++;
+                       *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+               }
+               ctx->pos += n;
+               len -= n;
+
+               if (ctx->pos == 2)
+               {
+                       memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
+                       memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
+                       ctx->pos = 0;
+                       return n;
+               }
+       }
+       for (i = ctx->pos; i < ctx->pos + len; i++)
+       {
+               ctx->encbuf[i] = *data++;
+               *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
+       }
+       ctx->pos += len;
+       return len;
+}
+
+/*
+ * common code for both encrypt and decrypt.
+ */
+static int
+cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
+               mix_data_t mix_data)
+{
+       int n;
+       int res;
+
+       while (len > 0 && ctx->pos > 0)
+       {
+               n = ctx->block_size - ctx->pos;
+               if (len < n)
+                       n = len;
+
+               n = mix_data(ctx, data, n, dst);
+               data += n;
+               dst += n;
+               len -= n;
+
+               if (ctx->pos == ctx->block_size)
+               {
+                       memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
+                       ctx->pos = 0;
+               }
+       }
+
+       while (len > 0)
+       {
+               px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, ctx->fre);
+               if (ctx->block_no < 5)
+                       ctx->block_no++;
+
+               n = ctx->block_size;
+               if (len < n)
+                       n = len;
+
+               res = mix_data(ctx, data, n, dst);
+               data += res;
+               dst += res;
+               len -= res;
+
+               if (ctx->pos == ctx->block_size)
+               {
+                       memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
+                       ctx->pos = 0;
+               }
+       }
+       return 0;
+}
+
+/*
+ * public interface
+ */
+
+int
+pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+       mix_data_t mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
+       return cfb_process(ctx, data, len, dst, mix);
+}
+
+int
+pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
+{
+       mix_data_t mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
+       return cfb_process(ctx, data, len, dst, mix);
+}
+
diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c
new file mode 100644 (file)
index 0000000..4faf0e4
--- /dev/null
@@ -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 <postgres.h>
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+
+/*
+ * Compressed pkt writer
+ */
+
+#ifndef DISABLE_ZLIB
+
+#include <zlib.h>
+#define ZIP_OUT_BUF 8192
+#define ZIP_IN_BLOCK 8192
+
+struct ZipStat
+{
+       uint8           type;
+       int                     buf_len;
+       int                     hdr_done;
+       z_stream        stream;
+       uint8           buf[ZIP_OUT_BUF];
+};
+
+static void *
+z_alloc(void *priv, unsigned n_items, unsigned item_len)
+{
+       return px_alloc(n_items * item_len);
+}
+
+static void
+z_free(void *priv, void *addr)
+{
+       px_free(addr);
+}
+
+static int
+compress_init(PushFilter * next, void *init_arg, void **priv_p)
+{
+       int                     res;
+       struct ZipStat *st;
+       PGP_Context *ctx = init_arg;
+       uint8           type = ctx->compress_algo;
+
+       if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
+               return PXE_PGP_UNSUPPORTED_COMPR;
+
+       /*
+        * init
+        */
+       st = px_alloc(sizeof(*st));
+       memset(st, 0, sizeof(*st));
+       st->buf_len = ZIP_OUT_BUF;
+       st->stream.zalloc = z_alloc;
+       st->stream.zfree = z_free;
+
+       if (type == PGP_COMPR_ZIP)
+               res = deflateInit2(&st->stream, ctx->compress_level,
+                                                  Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+       else
+               res = deflateInit(&st->stream, ctx->compress_level);
+       if (res != Z_OK)
+       {
+               px_free(st);
+               return PXE_PGP_COMPRESSION_ERROR;
+       }
+       *priv_p = st;
+
+       return ZIP_IN_BLOCK;
+}
+
+/* writes compressed data packet */
+
+/* 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 (file)
index 0000000..edffc6a
--- /dev/null
@@ -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 <postgres.h>
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+#define NO_CTX_SIZE            0
+#define ALLOW_CTX_SIZE 1
+#define NO_COMPR               0
+#define ALLOW_COMPR            1
+#define NO_MDC                 0
+#define NEED_MDC               1
+
+#define PKT_NORMAL 1
+#define PKT_STREAM 2
+#define PKT_CONTEXT 3
+
+#define MAX_CHUNK (16*1024*1024)
+
+static int
+parse_new_len(PullFilter * src, int *len_p)
+{
+       uint8           b;
+       int                     len;
+       int                     pkttype = PKT_NORMAL;
+
+       GETBYTE(src, b);
+       if (b <= 191)
+               len = b;
+       else if (b >= 192 && b <= 223)
+       {
+               len = ((unsigned) (b) - 192) << 8;
+               GETBYTE(src, b);
+               len += 192 + b;
+       }
+       else if (b == 255)
+       {
+               GETBYTE(src, b);
+               len = b;
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+       }
+       else
+       {
+               len = 1 << (b & 0x1F);
+               pkttype = PKT_STREAM;
+       }
+       
+       if (len < 0 || len > MAX_CHUNK)
+       {
+               px_debug("parse_new_len: weird length");
+               return PXE_PGP_CORRUPT_DATA;
+       }
+
+       *len_p = len;
+       return pkttype;
+}
+
+static int
+parse_old_len(PullFilter * src, int *len_p, int lentype)
+{
+       uint8           b;
+       int                     len;
+
+       GETBYTE(src, b);
+       len = b;
+
+       if (lentype == 1)
+       {
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+       }
+       else if (lentype == 2)
+       {
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+               GETBYTE(src, b);
+               len = (len << 8) | b;
+       }
+
+       if (len < 0 || len > MAX_CHUNK)
+       {
+               px_debug("parse_old_len: weird length");
+               return PXE_PGP_CORRUPT_DATA;
+       }
+       *len_p = len;
+       return PKT_NORMAL;
+}
+
+/* returns pkttype or 0 on eof */
+int
+pgp_parse_pkt_hdr(PullFilter * src, uint8 *tag, int *len_p, int allow_ctx)
+{
+       int                     lentype;
+       int                     res;
+       uint8           *p;
+
+       /* EOF is normal here, thus we dont use GETBYTE */
+       res = pullf_read(src, 1, &p);
+       if (res < 0)
+               return res;
+       if (res == 0)
+               return 0;
+
+       if ((*p & 0x80) == 0)
+       {
+               px_debug("pgp_parse_pkt_hdr: not pkt hdr");
+               return PXE_PGP_CORRUPT_DATA;
+       }
+
+       if (*p & 0x40)
+       {
+               *tag = *p & 0x3f;
+               res = parse_new_len(src, len_p);
+       }
+       else
+       {
+               lentype = *p & 3;
+               *tag = (*p >> 2) & 0x0F;
+               if (lentype == 3)
+                       res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
+               else
+                       res = parse_old_len(src, len_p, lentype);
+       }
+       return res;
+}
+
+/*
+ * Packet reader
+ */
+struct PktData {
+       int type;
+       int len;
+};
+
+static int pktreader_pull(void *priv, PullFilter *src, int len,
+               uint8 **data_p, uint8 *buf, int buflen)
+{
+       int res;
+       struct PktData *pkt = priv;
+
+       /* PKT_CONTEXT means: whatever there is */
+       if (pkt->type == PKT_CONTEXT)
+               return pullf_read(src, len, data_p);
+
+       if (pkt->len == 0)
+       {
+               /* this was last chunk in stream */
+               if (pkt->type == PKT_NORMAL)
+                       return 0;
+
+               /* next chunk in stream */
+               res = parse_new_len(src, &pkt->len);
+               if (res < 0)
+                       return res;
+               pkt->type = res;
+       }
+
+       if (len > pkt->len)
+               len = pkt->len;
+
+       res = pullf_read(src, len, data_p);
+       if (res > 0)
+               pkt->len -= res;
+
+       return res;
+}
+
+static void
+pktreader_free(void *priv)
+{
+       struct PktData *pkt = priv;
+       memset(pkt, 0, sizeof(*pkt));
+       px_free(pkt);
+}
+
+static struct PullFilterOps pktreader_filter = {
+       NULL, pktreader_pull, pktreader_free
+};
+
+/* needs helper function to pass several parameters */
+int
+pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
+                                 int pkttype, PGP_Context *ctx)
+{
+       int res;
+       struct PktData *pkt = px_alloc(sizeof(*pkt));
+       pkt->type = pkttype;
+       pkt->len = len;
+       res = pullf_create(pf_p, &pktreader_filter, pkt, src);
+       if (res < 0)
+               px_free(pkt);
+       return res;
+}
+
+/*
+ * Prefix check filter
+ */
+
+static int prefix_init(void **priv_p, void *arg, PullFilter *src)
+{
+       PGP_Context *ctx = arg;
+       int len;
+       int res;
+       uint8 *buf;
+       uint8 tmpbuf[PGP_MAX_BLOCK + 2];
+
+       len = pgp_get_cipher_block_size(ctx->cipher_algo);
+       if (len > sizeof(tmpbuf))
+               return PXE_BUG;
+
+       res = pullf_read_max(src, len + 2, &buf, tmpbuf);
+       if (res < 0)
+               return res;
+       if (res != len + 2)
+       {
+               px_debug("prefix_init: short read");
+               memset(tmpbuf, 0, sizeof(tmpbuf));
+               return PXE_PGP_CORRUPT_DATA;
+       }
+
+       if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
+       {
+               px_debug("prefix_init: corrupt prefix");
+               /*
+                * The original purpose of the 2-byte check was
+                * to show user a friendly "wrong key" message.
+                * This made following possible:
+                *
+                *   "An Attack on CFB Mode Encryption As Used By OpenPGP"
+                *   by Serge Mister and Robert Zuccherato
+                *
+                * To avoid being 'oracle', we delay reporting, which
+                * basically means we prefer to run into corrupt packet
+                * header.
+                *
+                * We _could_ throw PXE_PGP_CORRUPT_DATA here, but
+                * there is possibility of attack via timing, so we don't.
+                */
+               ctx->corrupt_prefix = 1;
+       }
+       memset(tmpbuf, 0, sizeof(tmpbuf));
+       return 0;
+}
+
+static struct PullFilterOps prefix_filter = {
+       prefix_init, NULL, NULL
+};
+
+
+/*
+ * Decrypt filter
+ */
+
+static int decrypt_init(void **priv_p, void *arg, PullFilter *src)
+{
+       PGP_CFB *cfb = arg;
+
+       *priv_p = cfb;
+
+       /* we need to write somewhere, so ask for a buffer */
+       return 4096;
+}
+
+static int decrypt_read(void *priv, PullFilter *src, int len,
+               uint8 **data_p, uint8 *buf, int buflen)
+{
+       PGP_CFB *cfb = priv;
+       uint8 *tmp;
+       int res;
+
+       res = pullf_read(src, len, &tmp);
+       if (res > 0) {
+               pgp_cfb_decrypt(cfb, tmp, res, buf);
+               *data_p = buf;
+       }
+       return res;
+}
+
+struct PullFilterOps pgp_decrypt_filter = {
+       decrypt_init, decrypt_read, NULL
+};
+
+
+/*
+ * MDC hasher filter
+ */
+
+static int mdc_init(void **priv_p, void *arg, PullFilter *src)
+{
+       PGP_Context *ctx = arg;
+       *priv_p = ctx;
+       return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
+}
+
+static void mdc_free(void *priv)
+{
+       PGP_Context *ctx = priv;
+       if (ctx->use_mdcbuf_filter)
+               return;
+       px_md_free(ctx->mdc_ctx);
+       ctx->mdc_ctx = NULL;
+}
+
+// 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 (file)
index 0000000..8aee9bf
--- /dev/null
@@ -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 <postgres.h>
+#include <time.h>
+
+#include "mbuf.h"
+#include "px.h"
+#include "pgp.h"
+
+
+#define MDC_DIGEST_LEN 20
+#define STREAM_ID 0xE0
+#define STREAM_BLOCK_SHIFT     14
+
+static uint8 *
+render_newlen(uint8 *h, int len)
+{
+       if (len <= 191)
+       {
+               *h++ = len & 255;
+       }
+       else if (len > 191 && len <= 8383)
+       {
+               *h++ = ((len - 192) >> 8) + 192;
+               *h++ = (len - 192) & 255;
+       }
+       else
+       {
+               *h++ = 255;
+               *h++ = (len >> 24) & 255;
+               *h++ = (len >> 16) & 255;
+               *h++ = (len >> 8) & 255;
+               *h++ = len & 255;
+       }
+       return h;
+}
+
+static int write_tag_only(PushFilter *dst, int tag)
+{
+       uint8 hdr = 0xC0 | tag;
+       return pushf_write(dst, &hdr, 1);
+}
+
+static int
+write_normal_header(PushFilter * dst, int tag, int len)
+{
+       uint8           hdr[8];
+       uint8      *h = hdr;
+
+       *h++ = 0xC0 | tag;
+       h = render_newlen(h, len);
+       return pushf_write(dst, hdr, h - hdr);
+}
+
+
+/*
+ * MAC writer
+ */
+
+static int
+mdc_init(PushFilter * dst, void *init_arg, void **priv_p)
+{
+       int                     res;
+       PX_MD      *md;
+
+       res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
+       if (res < 0)
+               return res;
+
+       *priv_p = md;
+       return 0;
+}
+
+static int
+mdc_write(PushFilter * dst, void *priv, const uint8 *data, int len)
+{
+       PX_MD      *md = priv;
+
+       px_md_update(md, data, len);
+       return pushf_write(dst, data, len);
+}
+
+static int
+mdc_flush(PushFilter * dst, void *priv)
+{
+       int                     res;
+       uint8           pkt[2 + MDC_DIGEST_LEN];
+       PX_MD      *md = priv;
+
+       /*
+        * create mdc pkt
+        */
+       pkt[0] = 0xD3;
+       pkt[1] = 0x14; /* MDC_DIGEST_LEN */
+       px_md_update(md, pkt, 2);
+       px_md_finish(md, pkt + 2);
+
+       res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN);
+       memset(pkt, 0, 2 + MDC_DIGEST_LEN);
+       return res;
+}
+
+static void
+mdc_free(void *priv)
+{
+       PX_MD      *md = priv;
+
+       px_md_free(md);
+}
+
+static const PushFilterOps mdc_filter = {
+       mdc_init, mdc_write, mdc_flush, mdc_free
+};
+
+
+/*
+ * Encrypted pkt writer
+ */
+#define ENCBUF 8192
+struct EncStat
+{
+       PGP_CFB    *ciph;
+       uint8       buf[ENCBUF];
+};
+
+static int
+encrypt_init(PushFilter * next, void *init_arg, void **priv_p)
+{
+       struct EncStat *st;
+       PGP_Context *ctx = init_arg;
+       PGP_CFB *ciph;
+       int resync = 1;
+       int res;
+
+       /* should we use newer packet format? */
+       if (ctx->disable_mdc == 0)
+       {
+               uint8 ver = 1;
+               resync = 0;
+               res = pushf_write(next, &ver, 1);
+               if (res < 0)
+                       return res;
+       }
+       res = pgp_cfb_create(&ciph, ctx->cipher_algo,
+                       ctx->sess_key, ctx->sess_key_len, resync, NULL);
+       if (res < 0)
+               return res;
+
+       st = px_alloc(sizeof(*st));
+       memset(st, 0, sizeof(*st));
+       st->ciph = ciph;
+       
+       *priv_p = st;
+       return ENCBUF;
+}
+
+static int
+encrypt_process(PushFilter * next, void *priv, const uint8 *data, int len)
+{
+       int                     res;
+       struct EncStat *st = priv;
+       int avail = len;
+
+       while (avail > 0)
+       {
+               int tmplen = avail > ENCBUF ? ENCBUF : avail;
+               res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
+               if (res < 0)
+                       return res;
+
+               res = pushf_write(next, st->buf, tmplen);
+               if (res < 0)
+                       return res;
+
+               data += tmplen;
+               avail -= tmplen;
+       }
+       return 0;
+}
+
+static void
+encrypt_free(void *priv)
+{
+       struct EncStat *st = priv;
+
+       memset(st, 0, sizeof(*st));
+       px_free(st);
+}
+
+static const PushFilterOps encrypt_filter = {
+       encrypt_init, encrypt_process, NULL, encrypt_free
+};
+
+/*
+ * Write Streamable pkts
+ */
+
+struct PktStreamStat
+{
+       int                     final_done;
+       int                     pkt_block;
+};
+
+static int
+pkt_stream_init(PushFilter * next, void *init_arg, void **priv_p)
+{
+       struct PktStreamStat *st;
+
+       st = px_alloc(sizeof(*st));
+       st->final_done = 0;
+       st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
+       *priv_p = st;
+
+       return st->pkt_block;
+}
+
+static int
+pkt_stream_process(PushFilter * next, void *priv, const uint8 *data, int len)
+{
+       int                     res;
+       uint8           hdr[8];
+       uint8      *h = hdr;
+       struct PktStreamStat *st = priv;
+
+       if (st->final_done)
+               return PXE_BUG;
+
+       if (len == st->pkt_block)
+               *h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
+       else
+       {
+               h = render_newlen(h, len);
+               st->final_done = 1;
+       }
+
+       res = pushf_write(next, hdr, h - hdr);
+       if (res < 0)
+               return res;
+
+       return pushf_write(next, data, len);
+}
+
+static int
+pkt_stream_flush(PushFilter * next, void *priv)
+{
+       int                     res;
+       uint8           hdr[8];
+       uint8      *h = hdr;
+       struct PktStreamStat *st = priv;
+
+       /* stream MUST end with normal packet. */
+       if (!st->final_done)
+       {
+               h = render_newlen(h, 0);
+               res = pushf_write(next, hdr, h - hdr);
+               if (res < 0)
+                       return res;
+               st->final_done = 1;
+       }
+       return 0;
+}
+
+static void
+pkt_stream_free(void *priv)
+{
+       struct PktStreamStat *st = priv;
+
+       memset(st, 0, sizeof(*st));
+       px_free(st);
+}
+
+static const PushFilterOps pkt_stream_filter = {
+       pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
+};
+
+int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
+{
+       int res;
+       res = write_tag_only(dst, tag);
+       if (res < 0)
+               return res;
+
+       return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
+}
+
+/*
+ * Text conversion filter
+ */
+
+static int
+crlf_process(PushFilter * dst, void *priv, const uint8 *data, int len)
+{
+       const uint8 * data_end = data + len;
+       const uint8 * p2, * p1 = data;
+       int line_len;
+       static const uint8 crlf[] = { '\r', '\n' };
+       int res = 0;
+       while (p1 < data_end)
+       {
+               p2 = memchr(p1, '\n', data_end - p1);
+               if (p2 == NULL)
+                       p2 = data_end;
+               
+               line_len = p2 - p1;
+
+               /* write data */
+               res = 0;
+               if (line_len > 0)
+               {
+                       res = pushf_write(dst, p1, line_len);
+                       if (res < 0)
+                               break;
+                       p1 += line_len;
+               }
+
+               /* write crlf */
+               while (p1 < data_end && *p1 == '\n')
+               {
+                       res = pushf_write(dst, crlf, 2);
+                       if (res < 0)
+                               break;
+                       p1++;
+               }
+       }
+       return res;
+}
+
+static const PushFilterOps crlf_filter = {
+       NULL, crlf_process, NULL, NULL
+};
+
+/*
+ * Initialize literal data packet
+ */
+static int
+init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+       int                     res;
+       int                     hdrlen;
+       uint8           hdr[6];
+       uint32          t;
+       PushFilter      *pkt;
+       int                     type;
+
+       /*
+        * Create header
+        */
+
+       if (ctx->text_mode)
+               type = ctx->unicode_mode ? 'u' : 't';
+       else
+               type = 'b';
+
+       /*
+        * Store the creation time into packet.
+        * The goal is to have as few known bytes as possible.
+        */
+       t = (uint32)time(NULL);
+
+       hdr[0] = type;
+       hdr[1] = 0;
+       hdr[2] = (t >> 24) & 255;
+       hdr[3] = (t >> 16) & 255;
+       hdr[4] = (t >> 8) & 255;
+       hdr[5] = t & 255;
+       hdrlen = 6;
+
+       res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
+       if (res < 0)
+               return res;
+
+       res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
+       if (res < 0)
+               return res;
+
+       res = pushf_write(pkt, hdr, hdrlen);
+       if (res < 0)
+       {
+               pushf_free(pkt);
+               return res;
+       }
+
+       *pf_res = pkt;
+       return 0;
+}
+
+/*
+ * Initialize compression filter
+ */
+static int
+init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+       int res;
+       uint8 type = ctx->compress_algo;
+       PushFilter *pkt;
+
+       res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
+       if (res < 0)
+               return res;
+
+       res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
+       if (res < 0)
+               return res;
+
+       res = pushf_write(pkt, &type, 1);
+       if (res >= 0)
+               res = pgp_compress_filter(pf_res, ctx, pkt);
+
+       if (res < 0)
+               pushf_free(pkt);
+
+       return res;
+}
+
+/*
+ * Initialize encdata packet
+ */
+static int
+init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+{
+       int                     res;
+       int                     tag;
+
+       if (ctx->disable_mdc)
+               tag = PGP_PKT_SYMENCRYPTED_DATA;
+       else
+               tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
+
+       res = write_tag_only(dst, tag);
+       if (res < 0)
+               return res;
+
+       return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
+}
+
+/*
+ * write prefix
+ */
+static int
+write_prefix(PGP_Context *ctx, PushFilter * dst)
+{
+       uint8           prefix[PGP_MAX_BLOCK + 2];
+       int                     res,
+                               bs;
+
+       bs = pgp_get_cipher_block_size(ctx->cipher_algo);
+       res = px_get_random_bytes(prefix, bs);
+       if (res < 0)
+               return res;
+
+       prefix[bs + 0] = prefix[bs - 2];
+       prefix[bs + 1] = prefix[bs - 1];
+
+       res = pushf_write(dst, prefix, bs + 2);
+       memset(prefix, 0, bs + 2);
+       return res < 0 ? res : 0;
+}
+
+/*
+ * write symmetrically encrypted session key packet
+ */
+
+static int
+symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
+{
+       int res;
+       PGP_CFB *cfb;
+       uint8 algo = ctx->cipher_algo;
+
+       res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
+                       ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
+       if (res < 0)
+               return res;
+       
+       pgp_cfb_encrypt(cfb, &algo, 1, dst);
+       pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
+
+       pgp_cfb_free(cfb);
+       return ctx->sess_key_len + 1;
+}
+
+/* 5.3: Symmetric-Key Encrypted Session-Key */
+static int
+write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
+{
+       uint8           pkt[256];
+       int                     pktlen;
+       int                     res;
+       uint8           *p = pkt;
+
+       *p++ = 4;                                       /* 5.3 - version number  */
+       *p++ = ctx->s2k_cipher_algo;
+
+       *p++ = ctx->s2k.mode;
+       *p++ = ctx->s2k.digest_algo;
+       if (ctx->s2k.mode > 0)
+       {
+               memcpy(p, ctx->s2k.salt, 8);
+               p += 8;
+       }
+       if (ctx->s2k.mode == 3)
+               *p++ = ctx->s2k.iter;
+
+       if (ctx->use_sess_key)
+       {
+               res = symencrypt_sesskey(ctx, p);
+               if (res < 0)
+                       return res;
+               p += res;
+       }
+
+       pktlen = p - pkt;
+       res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
+       if (res >= 0)
+               res = pushf_write(dst, pkt, pktlen);
+
+       memset(pkt, 0, pktlen);
+       return res;
+}
+
+/*
+ * key setup
+ */
+static int
+init_s2k_key(PGP_Context * ctx)
+{
+       int                     res;
+
+       if (ctx->s2k_cipher_algo < 0)
+               ctx->s2k_cipher_algo = ctx->cipher_algo;
+
+       res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo);
+       if (res < 0)
+               return res;
+
+       return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
+                       ctx->sym_key, ctx->sym_key_len);
+}
+
+static int
+init_sess_key(PGP_Context *ctx)
+{
+       int res;
+       if (ctx->use_sess_key || ctx->pub_key)
+       {
+               ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
+               res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
+               if (res < 0)
+                       return res;
+       }
+       else
+       {
+               ctx->sess_key_len = ctx->s2k.key_len;
+               memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
+       }
+
+       return 0;
+}
+
+/*
+ * combine
+ */
+int
+pgp_encrypt(PGP_Context * ctx, MBuf * src, MBuf * dst)
+{
+       int                     res;
+       int                     len;
+       uint8      *buf;
+       PushFilter *pf, *pf_tmp;
+
+       /*
+        * do we have any key
+        */
+       if (!ctx->sym_key && !ctx->pub_key)
+               return PXE_ARGUMENT_ERROR;
+
+       /* MBuf writer */
+       res = pushf_create_mbuf_writer(&pf, dst);
+       if (res < 0)
+               goto out;
+
+       /*
+        * initialize symkey
+        */
+       if (ctx->sym_key)
+       {
+               res = init_s2k_key(ctx);
+               if (res < 0)
+                       goto out;
+       }
+       
+       res = init_sess_key(ctx);
+       if (res < 0)
+               goto out;
+
+       /*
+        * write keypkt
+        */
+       if (ctx->pub_key)
+               res = pgp_write_pubenc_sesskey(ctx, pf);
+       else
+               res = write_symenc_sesskey(ctx, pf);
+       if (res < 0)
+               goto out;
+
+       /* encrypted data pkt */
+       res = init_encdata_packet(&pf_tmp, ctx, pf);
+       if (res < 0)
+               goto out;
+       pf = pf_tmp;
+
+       /* encrypter */
+       res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
+       if (res < 0)
+               goto out;
+       pf = pf_tmp;
+
+       /* hasher */
+       if (ctx->disable_mdc == 0)
+       {
+               res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
+               if (res < 0)
+                       goto out;
+               pf = pf_tmp;
+       }
+
+       /* prefix */
+       res = write_prefix(ctx, pf);
+       if (res < 0)
+               goto out;
+
+       /* compressor */
+       if (ctx->compress_algo > 0 && ctx->compress_level > 0)
+       {
+               res = init_compress(&pf_tmp, ctx, pf);
+               if (res < 0)
+                       goto out;
+               pf = pf_tmp;
+       }
+
+       /* data streamer */
+       res = init_litdata_packet(&pf_tmp, ctx, pf);
+       if (res < 0)
+               goto out;
+       pf = pf_tmp;
+
+       
+       /* text conversion? */
+       if (ctx->text_mode && ctx->convert_crlf)
+       {
+               res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
+               if (res < 0)
+                       goto out;
+               pf = pf_tmp;
+       }
+
+       /*
+        * chain complete
+        */
+
+       len = mbuf_grab(src, mbuf_avail(src), &buf);
+       res = pushf_write(pf, buf, len);
+       if (res >= 0)
+               res = pushf_flush(pf);
+out:
+       pushf_free_all(pf);
+       return res;
+}
+
diff --git a/contrib/pgcrypto/pgp-info.c b/contrib/pgcrypto/pgp-info.c
new file mode 100644 (file)
index 0000000..d757e8c
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..12831b1
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..c44e193
--- /dev/null
@@ -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 <postgres.h>
+
+#include <openssl/bn.h>
+
+#include "px.h"
+#include "mbuf.h"
+#include "pgp.h"
+
+static BIGNUM *
+mpi_to_bn(PGP_MPI *n)
+{
+       BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL);
+       if (!bn)
+               return NULL;
+       if (BN_num_bits(bn) != n->bits)
+       {
+               px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
+                               n->bits, BN_num_bits(bn));
+               BN_clear_free(bn);
+               return NULL;
+       }
+       return bn;
+}
+
+static PGP_MPI *
+bn_to_mpi(BIGNUM *bn)
+{
+       int res;
+       PGP_MPI *n;
+
+       res = pgp_mpi_alloc(BN_num_bits(bn), &n);
+       if (res < 0)
+               return NULL;
+
+       if (BN_num_bytes(bn) != n->bytes)
+       {
+               px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
+                               BN_num_bytes(bn), n->bytes);
+               pgp_mpi_free(n);
+               return NULL;
+       }
+       BN_bn2bin(bn, n->data);
+       return n;
+}
+
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'.  Following
+ * algorihm hovers 10-70 bits above gpg values.  And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow.  It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+       if (p_bits <= 5120)
+               return p_bits / 10 + 160;
+       else
+               return (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
+               PGP_MPI **c1_p, PGP_MPI **c2_p)
+{
+       int res = PXE_PGP_MATH_FAILED;
+       int k_bits;
+       BIGNUM *m = mpi_to_bn(_m);
+       BIGNUM *p = mpi_to_bn(pk->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 (file)
index 0000000..6d3eff4
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..c17d952
--- /dev/null
@@ -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 <postgres.h>
+#include <fmgr.h>
+#include <parser/scansup.h>
+#include <mb/pg_wchar.h>
+
+#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 (file)
index 0000000..ad4ceb2
--- /dev/null
@@ -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 <postgres.h>
+
+#include <openssl/bn.h>
+
+#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 (file)
index 0000000..7a0ba33
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..6a00947
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..0916a00
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..8c71441
--- /dev/null
@@ -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 <postgres.h>
+
+#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 (file)
index 0000000..7f31aa3
--- /dev/null
@@ -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 (file)
index 0000000..9c35107
--- /dev/null
@@ -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 <me@aarongifford.com>
+ * 
+ * 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 <postgres.h>
+
+#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 <sys/types.h> (which in turn includes
+ * <machine/endian.h> 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 (file)
index 0000000..2dfb13c
--- /dev/null
@@ -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 <me@aarongifford.com>
+ * 
+ * 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 (file)
index 0000000..040c4ac
--- /dev/null
@@ -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 (file)
index 0000000..f71c176
--- /dev/null
@@ -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 (file)
index 0000000..93535ab
--- /dev/null
@@ -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 (file)
index 0000000..80fb4d1
--- /dev/null
@@ -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 (file)
index 0000000..b663e05
--- /dev/null
@@ -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 (file)
index 0000000..d979bb9
--- /dev/null
@@ -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 (file)
index 0000000..b4aec5d
--- /dev/null
@@ -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 (file)
index 0000000..13fe090
--- /dev/null
@@ -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 (file)
index 0000000..89d05a7
--- /dev/null
@@ -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 (file)
index 0000000..85c2468
--- /dev/null
@@ -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 (file)
index 0000000..f1d0ca6
--- /dev/null
@@ -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');
+
+