mirror of https://github.com/postgres/postgres
This adds a new routine, pg_strong_random() for generating random bytes, for use in both frontend and backend. At the moment, it's only used in the backend, but the upcoming SCRAM authentication patches need strong random numbers in libpq as well. pg_strong_random() is based on, and replaces, the existing implementation in pgcrypto. It can acquire strong random numbers from a number of sources, depending on what's available: - OpenSSL RAND_bytes(), if built with OpenSSL - On Windows, the native cryptographic functions are used - /dev/urandom Unlike the current pgcrypto function, the source is chosen by configure. That makes it easier to test different implementations, and ensures that we don't accidentally fall back to a less secure implementation, if the primary source fails. All of those methods are quite reliable, it would be pretty surprising for them to fail, so we'd rather find out by failing hard. If no strong random source is available, we fall back to using erand48(), seeded from current timestamp, like PostmasterRandom() was. That isn't cryptographically secure, but allows us to still work on platforms that don't have any of the above stronger sources. Because it's not very secure, the built-in implementation is only used if explicitly requested with --disable-strong-random. This replaces the more complicated Fortuna algorithm we used to have in pgcrypto, which is unfortunate, but all modern platforms have /dev/urandom, so it doesn't seem worth the maintenance effort to keep that. pgcrypto functions that require strong random numbers will be disabled with --disable-strong-random. Original patch by Magnus Hagander, tons of further work by Michael Paquier and me. Discussion: https://www.postgresql.org/message-id/CAB7nPqRy3krN8quR9XujMVVHYtXJ0_60nqgVc6oUk8ygyVkZsA@mail.gmail.com Discussion: https://www.postgresql.org/message-id/CAB7nPqRWkNYRRPJA7-cF+LfroYV10pvjdz6GNvxk-Eee9FypKA@mail.gmail.compull/18/head
parent
5dc851afde
commit
fe0a0b5993
@ -0,0 +1,42 @@ |
||||
-- |
||||
-- 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'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret message', 'key', 'compress-algo=1'), |
||||
'key', 'expect-compress-algo=1'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret message', 'key', 'compress-algo=2'), |
||||
'key', 'expect-compress-algo=2'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- 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'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
@ -0,0 +1,424 @@ |
||||
-- |
||||
-- 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 |
||||
-- check BUG #11905, problem with messages 6 less than a power of 2. |
||||
select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',65530); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- expected: true |
||||
-- Negative tests |
||||
-- Decryption with a certain incorrect key yields an apparent Literal Data |
||||
-- packet reporting its content to be binary data. Ciphertext source: |
||||
-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave |
||||
-- rise to that property. |
||||
select pgp_sym_decrypt(dearmor(' |
||||
-----BEGIN PGP MESSAGE----- |
||||
|
||||
ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV |
||||
VsxxqLSPzNLAeIspJk5G |
||||
=mSd/ |
||||
-----END PGP MESSAGE----- |
||||
'), 'wrong-key', 'debug=1'); |
||||
NOTICE: dbg: prefix_init: corrupt prefix |
||||
NOTICE: dbg: parse_literal_data: data type=b |
||||
NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr |
||||
ERROR: Wrong key or corrupt data |
||||
-- Routine text/binary mismatch. |
||||
select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- Decryption with a certain incorrect key yields an apparent BZip2-compressed |
||||
-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key') |
||||
-- until the random prefix gave rise to that property. |
||||
select pgp_sym_decrypt(dearmor(' |
||||
-----BEGIN PGP MESSAGE----- |
||||
|
||||
ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP |
||||
GXsd65oYJZp3Khz0qfyn |
||||
=Nmpq |
||||
-----END PGP MESSAGE----- |
||||
'), 'wrong-key', 'debug=1'); |
||||
NOTICE: dbg: prefix_init: corrupt prefix |
||||
NOTICE: dbg: parse_compressed_data: bzip2 unsupported |
||||
NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr |
||||
ERROR: Wrong key or corrupt data |
||||
-- Routine use of BZip2 compression. Ciphertext source: |
||||
-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \ |
||||
-- --personal-cipher-preferences aes --no-emit-version --batch \ |
||||
-- --symmetric --passphrase key --armor |
||||
select pgp_sym_decrypt(dearmor(' |
||||
-----BEGIN PGP MESSAGE----- |
||||
|
||||
jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe |
||||
QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R |
||||
UCAAw2JRIISttRHMfDpDuZJpvYo= |
||||
=AZ9M |
||||
-----END PGP MESSAGE----- |
||||
'), 'key', 'debug=1'); |
||||
NOTICE: dbg: parse_compressed_data: bzip2 unsupported |
||||
ERROR: Unsupported compression algorithm |
@ -0,0 +1,161 @@ |
||||
-- |
||||
-- PGP encrypt |
||||
-- |
||||
-- ensure consistent test output regardless of the default bytea format |
||||
SET bytea_output TO escape; |
||||
select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), 'key'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- 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 |
||||
'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- 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 |
||||
'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- bytea as text |
||||
select pgp_sym_decrypt(pgp_sym_encrypt_bytea('Binary', 'baz'), 'baz'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- text as bytea |
||||
select pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- algorithm change |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'), |
||||
'key', 'expect-cipher-algo=bf'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes'), |
||||
'key', 'expect-cipher-algo=aes128'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'), |
||||
'key', 'expect-cipher-algo=aes192'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- s2k change |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=0'), |
||||
'key', 'expect-s2k-mode=0'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=1'), |
||||
'key', 'expect-s2k-mode=1'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'), |
||||
'key', 'expect-s2k-mode=3'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- s2k count change |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'), |
||||
'key', 'expect-s2k-count=1024'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- s2k_count rounds up |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'), |
||||
'key', 'expect-s2k-count=65000000'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- s2k digest change |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'), |
||||
'key', 'expect-s2k-digest-algo=md5'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'), |
||||
'key', 'expect-s2k-digest-algo=sha1'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- sess key |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=0'), |
||||
'key', 'expect-sess-key=0'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1'), |
||||
'key', 'expect-sess-key=1'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=bf'), |
||||
'key', 'expect-sess-key=1, expect-cipher-algo=bf'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes192'), |
||||
'key', 'expect-sess-key=1, expect-cipher-algo=aes192'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes256'), |
||||
'key', 'expect-sess-key=1, expect-cipher-algo=aes256'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- no mdc |
||||
select pgp_sym_decrypt( |
||||
pgp_sym_encrypt('Secret.', 'key', 'disable-mdc=1'), |
||||
'key', 'expect-disable-mdc=1'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- crlf |
||||
select encode(pgp_sym_decrypt_bytea( |
||||
pgp_sym_encrypt(E'1\n2\n3\r\n', 'key', 'convert-crlf=1'), |
||||
'key'), 'hex'); |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- conversion should be lossless |
||||
select encode(digest(pgp_sym_decrypt( |
||||
pgp_sym_encrypt(E'\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'), |
||||
'key', 'convert-crlf=1'), 'sha1'), 'hex') as result, |
||||
encode(digest(E'\r\n0\n1\r\r\n\n2\r', 'sha1'), 'hex') as expect; |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
@ -0,0 +1,62 @@ |
||||
-- |
||||
-- PGP Public Key Encryption |
||||
-- |
||||
-- ensure consistent test output regardless of the default bytea format |
||||
SET bytea_output TO escape; |
||||
-- successful encrypt/decrypt |
||||
select pgp_pub_decrypt( |
||||
pgp_pub_encrypt('Secret msg', dearmor(pubkey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=1; |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_pub_decrypt( |
||||
pgp_pub_encrypt('Secret msg', dearmor(pubkey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=2; |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_pub_decrypt( |
||||
pgp_pub_encrypt('Secret msg', dearmor(pubkey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=3; |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
select pgp_pub_decrypt( |
||||
pgp_pub_encrypt('Secret msg', dearmor(pubkey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=6; |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- try with rsa-sign only |
||||
select pgp_pub_decrypt( |
||||
pgp_pub_encrypt('Secret msg', dearmor(pubkey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=4; |
||||
ERROR: No encryption key found |
||||
-- try with secret key |
||||
select pgp_pub_decrypt( |
||||
pgp_pub_encrypt('Secret msg', dearmor(seckey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=1; |
||||
ERROR: Refusing to encrypt with secret key |
||||
-- does text-to-bytea works |
||||
select pgp_pub_decrypt_bytea( |
||||
pgp_pub_encrypt('Secret msg', dearmor(pubkey)), |
||||
dearmor(seckey)) |
||||
from keytbl where keytbl.id=1; |
||||
ERROR: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
||||
-- 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: pg_random_bytes() is not supported by this build |
||||
DETAIL: This functionality requires a source of strong random numbers |
||||
HINT: You need to rebuild PostgreSQL using --enable-strong-random |
@ -1,463 +0,0 @@ |
||||
/*
|
||||
* 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. |
||||
* |
||||
* contrib/pgcrypto/fortuna.c |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include <sys/time.h> |
||||
#include <time.h> |
||||
|
||||
#include "px.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) |
||||
|
||||
/*
|
||||
* Skip reseed if pool 0 has less than this many |
||||
* bytes added since last reseed. |
||||
*/ |
||||
#define POOL0_FILL (256/8) |
||||
|
||||
/*
|
||||
* Algorithm constants |
||||
*/ |
||||
|
||||
/* 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 reseed_count; |
||||
struct timeval last_reseed_time; |
||||
unsigned pool0_bytes; |
||||
unsigned rnd_pos; |
||||
int tricks_done; |
||||
}; |
||||
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); |
||||
px_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]); |
||||
} |
||||
|
||||
/*
|
||||
* 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]; |
||||
} |
||||
|
||||
/*
|
||||
* This is called 'cipher in counter mode'. |
||||
*/ |
||||
static void |
||||
encrypt_counter(FState *st, uint8 *dst) |
||||
{ |
||||
ciph_encrypt(&st->ciph, st->counter, dst); |
||||
inc_counter(st); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* The time between reseed must be at least RESEED_INTERVAL |
||||
* microseconds. |
||||
*/ |
||||
static int |
||||
enough_time_passed(FState *st) |
||||
{ |
||||
int ok; |
||||
struct timeval tv; |
||||
struct timeval *last = &st->last_reseed_time; |
||||
|
||||
gettimeofday(&tv, NULL); |
||||
|
||||
/* check how much time has passed */ |
||||
ok = 0; |
||||
if (tv.tv_sec > last->tv_sec + 1) |
||||
ok = 1; |
||||
else if (tv.tv_sec == last->tv_sec + 1) |
||||
{ |
||||
if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) |
||||
ok = 1; |
||||
} |
||||
else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) |
||||
ok = 1; |
||||
|
||||
/* reseed will happen, update last_reseed_time */ |
||||
if (ok) |
||||
memcpy(last, &tv, sizeof(tv)); |
||||
|
||||
px_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]; |
||||
|
||||
/* set pool as empty */ |
||||
st->pool0_bytes = 0; |
||||
|
||||
/*
|
||||
* 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); |
||||
|
||||
px_memset(&key_md, 0, sizeof(key_md)); |
||||
px_memset(buf, 0, BLOCK); |
||||
} |
||||
|
||||
/*
|
||||
* Pick a random pool. This uses key bytes as random source. |
||||
*/ |
||||
static unsigned |
||||
get_rand_pool(FState *st) |
||||
{ |
||||
unsigned rnd; |
||||
|
||||
/*
|
||||
* This slightly prefers lower pools - that is OK. |
||||
*/ |
||||
rnd = st->key[st->rnd_pos] % NUM_POOLS; |
||||
|
||||
st->rnd_pos++; |
||||
if (st->rnd_pos >= BLOCK) |
||||
st->rnd_pos = 0; |
||||
|
||||
return rnd; |
||||
} |
||||
|
||||
/*
|
||||
* update pools |
||||
*/ |
||||
static void |
||||
add_entropy(FState *st, const uint8 *data, unsigned len) |
||||
{ |
||||
unsigned pos; |
||||
uint8 hash[BLOCK]; |
||||
MD_CTX md; |
||||
|
||||
/* hash given data */ |
||||
md_init(&md); |
||||
md_update(&md, data, len); |
||||
md_result(&md, hash); |
||||
|
||||
/*
|
||||
* Make sure the pool 0 is initialized, then update randomly. |
||||
*/ |
||||
if (st->reseed_count == 0) |
||||
pos = 0; |
||||
else |
||||
pos = get_rand_pool(st); |
||||
md_update(&st->pool[pos], hash, BLOCK); |
||||
|
||||
if (pos == 0) |
||||
st->pool0_bytes += len; |
||||
|
||||
px_memset(hash, 0, BLOCK); |
||||
px_memset(&md, 0, sizeof(md)); |
||||
} |
||||
|
||||
/*
|
||||
* Just take 2 next blocks as new key |
||||
*/ |
||||
static void |
||||
rekey(FState *st) |
||||
{ |
||||
encrypt_counter(st, st->key); |
||||
encrypt_counter(st, st->key + CIPH_BLOCK); |
||||
ciph_init(&st->ciph, st->key, BLOCK); |
||||
} |
||||
|
||||
/*
|
||||
* Hide public constants. (counter, pools > 0) |
||||
* |
||||
* This can also be viewed as spreading the startup |
||||
* entropy over all of the components. |
||||
*/ |
||||
static void |
||||
startup_tricks(FState *st) |
||||
{ |
||||
int i; |
||||
uint8 buf[BLOCK]; |
||||
|
||||
/* Use next block as counter. */ |
||||
encrypt_counter(st, st->counter); |
||||
|
||||
/* Now shuffle pools, excluding #0 */ |
||||
for (i = 1; i < NUM_POOLS; i++) |
||||
{ |
||||
encrypt_counter(st, buf); |
||||
encrypt_counter(st, buf + CIPH_BLOCK); |
||||
md_update(&st->pool[i], buf, BLOCK); |
||||
} |
||||
px_memset(buf, 0, BLOCK); |
||||
|
||||
/* Hide the key. */ |
||||
rekey(st); |
||||
|
||||
/* This can be done only once. */ |
||||
st->tricks_done = 1; |
||||
} |
||||
|
||||
static void |
||||
extract_data(FState *st, unsigned count, uint8 *dst) |
||||
{ |
||||
unsigned n; |
||||
unsigned block_nr = 0; |
||||
|
||||
/* Should we reseed? */ |
||||
if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0) |
||||
if (enough_time_passed(st)) |
||||
reseed(st); |
||||
|
||||
/* Do some randomization on first call */ |
||||
if (!st->tricks_done) |
||||
startup_tricks(st); |
||||
|
||||
while (count > 0) |
||||
{ |
||||
/* produce bytes */ |
||||
encrypt_counter(st, st->result); |
||||
|
||||
/* copy result */ |
||||
if (count > CIPH_BLOCK) |
||||
n = CIPH_BLOCK; |
||||
else |
||||
n = count; |
||||
memcpy(dst, st->result, n); |
||||
dst += n; |
||||
count -= n; |
||||
|
||||
/* must not give out too many bytes with one key */ |
||||
block_nr++; |
||||
if (block_nr > (RESEED_BYTES / CIPH_BLOCK)) |
||||
{ |
||||
rekey(st); |
||||
block_nr = 0; |
||||
} |
||||
} |
||||
/* Set new key for next request. */ |
||||
rekey(st); |
||||
} |
||||
|
||||
/*
|
||||
* public interface |
||||
*/ |
||||
|
||||
static FState main_state; |
||||
static int init_done = 0; |
||||
|
||||
void |
||||
fortuna_add_entropy(const uint8 *data, unsigned len) |
||||
{ |
||||
if (!init_done) |
||||
{ |
||||
init_state(&main_state); |
||||
init_done = 1; |
||||
} |
||||
if (!data || !len) |
||||
return; |
||||
add_entropy(&main_state, 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); |
||||
} |
@ -1,38 +0,0 @@ |
||||
/*
|
||||
* 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. |
||||
* |
||||
* contrib/pgcrypto/fortuna.h |
||||
*/ |
||||
|
||||
#ifndef __FORTUNA_H |
||||
#define __FORTUNA_H |
||||
|
||||
void fortuna_get_bytes(unsigned len, uint8 *dst); |
||||
void fortuna_add_entropy(const uint8 *data, unsigned len); |
||||
|
||||
#endif |
@ -1,247 +0,0 @@ |
||||
/*
|
||||
* random.c |
||||
* Acquire randomness from system. For seeding RNG. |
||||
* |
||||
* Copyright (c) 2001 Marko Kreen |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
* contrib/pgcrypto/random.c |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include "px.h" |
||||
#include "utils/memdebug.h" |
||||
|
||||
/* how many bytes to ask from system random provider */ |
||||
#define RND_BYTES 32 |
||||
|
||||
/*
|
||||
* Try to read from /dev/urandom or /dev/random on these OS'es. |
||||
* |
||||
* The list can be pretty liberal, as the device not existing |
||||
* is expected event. |
||||
*/ |
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ |
||||
|| defined(__NetBSD__) || defined(__DragonFly__) \
|
||||
|| defined(__darwin__) || defined(__SOLARIS__) \
|
||||
|| defined(__hpux) || defined(__HPUX__) \
|
||||
|| defined(__CYGWIN__) || defined(_AIX) |
||||
|
||||
#define TRY_DEV_RANDOM |
||||
|
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
static int |
||||
safe_read(int fd, void *buf, size_t count) |
||||
{ |
||||
int done = 0; |
||||
char *p = buf; |
||||
int res; |
||||
|
||||
while (count) |
||||
{ |
||||
res = read(fd, p, count); |
||||
if (res <= 0) |
||||
{ |
||||
if (errno == EINTR) |
||||
continue; |
||||
return PXE_DEV_READ_ERROR; |
||||
} |
||||
p += res; |
||||
done += res; |
||||
count -= res; |
||||
} |
||||
return done; |
||||
} |
||||
|
||||
static uint8 * |
||||
try_dev_random(uint8 *dst) |
||||
{ |
||||
int fd; |
||||
int res; |
||||
|
||||
fd = open("/dev/urandom", O_RDONLY, 0); |
||||
if (fd == -1) |
||||
{ |
||||
fd = open("/dev/random", O_RDONLY, 0); |
||||
if (fd == -1) |
||||
return dst; |
||||
} |
||||
res = safe_read(fd, dst, RND_BYTES); |
||||
close(fd); |
||||
if (res > 0) |
||||
dst += res; |
||||
return dst; |
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* Try to find randomness on Windows |
||||
*/ |
||||
#ifdef WIN32 |
||||
|
||||
#define TRY_WIN32_GENRAND |
||||
#define TRY_WIN32_PERFC |
||||
|
||||
#include <windows.h> |
||||
#include <wincrypt.h> |
||||
|
||||
/*
|
||||
* this function is from libtomcrypt |
||||
* |
||||
* try to use Microsoft crypto API |
||||
*/ |
||||
static uint8 * |
||||
try_win32_genrand(uint8 *dst) |
||||
{ |
||||
int res; |
||||
HCRYPTPROV h = 0; |
||||
|
||||
res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, |
||||
(CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)); |
||||
if (!res) |
||||
res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, |
||||
CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET); |
||||
if (!res) |
||||
return dst; |
||||
|
||||
res = CryptGenRandom(h, RND_BYTES, dst); |
||||
if (res == TRUE) |
||||
dst += RND_BYTES; |
||||
|
||||
CryptReleaseContext(h, 0); |
||||
return dst; |
||||
} |
||||
|
||||
static uint8 * |
||||
try_win32_perfc(uint8 *dst) |
||||
{ |
||||
int res; |
||||
LARGE_INTEGER time; |
||||
|
||||
res = QueryPerformanceCounter(&time); |
||||
if (!res) |
||||
return dst; |
||||
|
||||
memcpy(dst, &time, sizeof(time)); |
||||
return dst + sizeof(time); |
||||
} |
||||
#endif /* WIN32 */ |
||||
|
||||
|
||||
/*
|
||||
* If we are not on Windows, then hopefully we are |
||||
* on a unix-like system. Use the usual suspects |
||||
* for randomness. |
||||
*/ |
||||
#ifndef WIN32 |
||||
|
||||
#define TRY_UNIXSTD |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/time.h> |
||||
#include <time.h> |
||||
#include <unistd.h> |
||||
|
||||
/*
|
||||
* Everything here is predictible, only needs some patience. |
||||
* |
||||
* But there is a chance that the system-specific functions |
||||
* did not work. So keep faith and try to slow the attacker down. |
||||
*/ |
||||
static uint8 * |
||||
try_unix_std(uint8 *dst) |
||||
{ |
||||
pid_t pid; |
||||
int x; |
||||
PX_MD *md; |
||||
struct timeval tv; |
||||
int res; |
||||
|
||||
/* process id */ |
||||
pid = getpid(); |
||||
memcpy(dst, (uint8 *) &pid, sizeof(pid)); |
||||
dst += sizeof(pid); |
||||
|
||||
/* time */ |
||||
gettimeofday(&tv, NULL); |
||||
memcpy(dst, (uint8 *) &tv, sizeof(tv)); |
||||
dst += sizeof(tv); |
||||
|
||||
/* pointless, but should not hurt */ |
||||
x = random(); |
||||
memcpy(dst, (uint8 *) &x, sizeof(x)); |
||||
dst += sizeof(x); |
||||
|
||||
/* hash of uninitialized stack and heap allocations */ |
||||
res = px_find_digest("sha1", &md); |
||||
if (res >= 0) |
||||
{ |
||||
uint8 *ptr; |
||||
uint8 stack[8192]; |
||||
int alloc = 32 * 1024; |
||||
|
||||
VALGRIND_MAKE_MEM_DEFINED(stack, sizeof(stack)); |
||||
px_md_update(md, stack, sizeof(stack)); |
||||
ptr = px_alloc(alloc); |
||||
VALGRIND_MAKE_MEM_DEFINED(ptr, alloc); |
||||
px_md_update(md, ptr, alloc); |
||||
px_free(ptr); |
||||
|
||||
px_md_finish(md, dst); |
||||
px_md_free(md); |
||||
|
||||
dst += 20; |
||||
} |
||||
|
||||
return dst; |
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* try to extract some randomness for initial seeding |
||||
* |
||||
* dst should have room for 1024 bytes. |
||||
*/ |
||||
unsigned |
||||
px_acquire_system_randomness(uint8 *dst) |
||||
{ |
||||
uint8 *p = dst; |
||||
|
||||
#ifdef TRY_DEV_RANDOM |
||||
p = try_dev_random(p); |
||||
#endif |
||||
#ifdef TRY_WIN32_GENRAND |
||||
p = try_win32_genrand(p); |
||||
#endif |
||||
#ifdef TRY_WIN32_PERFC |
||||
p = try_win32_perfc(p); |
||||
#endif |
||||
#ifdef TRY_UNIXSTD |
||||
p = try_unix_std(p); |
||||
#endif |
||||
return p - dst; |
||||
} |
@ -0,0 +1,158 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* backend_random.c |
||||
* Backend random number generation routine. |
||||
* |
||||
* pg_backend_random() function fills a buffer with random bytes. Normally, |
||||
* it is just a thin wrapper around pg_strong_random(), but when compiled |
||||
* with --disable-strong-random, we provide a built-in implementation. |
||||
* |
||||
* This function is used for generating nonces in authentication, and for |
||||
* random salt generation in pgcrypto. The built-in implementation is not |
||||
* cryptographically strong, but if the user asked for it, we'll go ahead |
||||
* and use it anyway. |
||||
* |
||||
* The built-in implementation uses the standard erand48 algorithm, with |
||||
* a seed shared between all backends. |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/utils/misc/backend_random.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include <sys/time.h> |
||||
|
||||
#include "miscadmin.h" |
||||
#include "storage/lwlock.h" |
||||
#include "storage/shmem.h" |
||||
#include "utils/backend_random.h" |
||||
#include "utils/timestamp.h" |
||||
|
||||
#ifdef HAVE_STRONG_RANDOM |
||||
|
||||
Size |
||||
BackendRandomShmemSize(void) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
void |
||||
BackendRandomShmemInit(void) |
||||
{ |
||||
/* do nothing */ |
||||
} |
||||
|
||||
bool |
||||
pg_backend_random(char *dst, int len) |
||||
{ |
||||
/* should not be called in postmaster */ |
||||
Assert (IsUnderPostmaster || !IsPostmasterEnvironment); |
||||
|
||||
return pg_strong_random(dst, len); |
||||
} |
||||
|
||||
#else |
||||
|
||||
/*
|
||||
* Seed for the PRNG, stored in shared memory. |
||||
* |
||||
* Protected by BackendRandomLock. |
||||
*/ |
||||
typedef struct |
||||
{ |
||||
bool initialized; |
||||
unsigned short seed[3]; |
||||
} BackendRandomShmemStruct; |
||||
|
||||
static BackendRandomShmemStruct *BackendRandomShmem; |
||||
|
||||
Size |
||||
BackendRandomShmemSize(void) |
||||
{ |
||||
return sizeof(BackendRandomShmemStruct); |
||||
} |
||||
|
||||
void |
||||
BackendRandomShmemInit(void) |
||||
{ |
||||
bool found; |
||||
|
||||
BackendRandomShmem = (BackendRandomShmemStruct *) |
||||
ShmemInitStruct("Backend PRNG state", |
||||
BackendRandomShmemSize(), |
||||
&found); |
||||
|
||||
if (!IsUnderPostmaster) |
||||
{ |
||||
Assert(!found); |
||||
|
||||
BackendRandomShmem->initialized = false; |
||||
} |
||||
else |
||||
Assert(found); |
||||
} |
||||
|
||||
bool |
||||
pg_backend_random(char *dst, int len) |
||||
{ |
||||
int i; |
||||
char *end = dst + len; |
||||
|
||||
/* should not be called in postmaster */ |
||||
Assert (IsUnderPostmaster || !IsPostmasterEnvironment); |
||||
|
||||
LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE); |
||||
|
||||
/*
|
||||
* Seed the PRNG on the first use. |
||||
*/ |
||||
if (!BackendRandomShmem->initialized) |
||||
{ |
||||
struct timeval now; |
||||
|
||||
gettimeofday(&now, NULL); |
||||
|
||||
BackendRandomShmem->seed[0] = now.tv_sec; |
||||
BackendRandomShmem->seed[1] = (unsigned short) (now.tv_usec); |
||||
BackendRandomShmem->seed[2] = (unsigned short) (now.tv_usec >> 16); |
||||
|
||||
/*
|
||||
* Mix in the cancel key, generated by the postmaster. This adds |
||||
* what little entropy the postmaster had to the seed. |
||||
*/ |
||||
BackendRandomShmem->seed[0] ^= (MyCancelKey); |
||||
BackendRandomShmem->seed[1] ^= (MyCancelKey >> 16); |
||||
|
||||
BackendRandomShmem->initialized = true; |
||||
} |
||||
|
||||
for (i = 0; dst < end; i++) |
||||
{ |
||||
uint32 r; |
||||
int j; |
||||
|
||||
/*
|
||||
* pg_jrand48 returns a 32-bit integer. Fill the next 4 bytes from it. |
||||
*/ |
||||
r = (uint32) pg_jrand48(BackendRandomShmem->seed); |
||||
|
||||
for (j = 0; j < 4 && dst < end; j++) |
||||
{ |
||||
*(dst++) = (char) (r & 0xFF); |
||||
r >>= 8; |
||||
} |
||||
} |
||||
LWLockRelease(BackendRandomLock); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
#endif /* HAVE_STRONG_RANDOM */ |
@ -0,0 +1,19 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* backend_random.h |
||||
* Declarations for backend random number generation |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* |
||||
* src/include/utils/backend_random.h |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef BACKEND_RANDOM_H |
||||
#define BACKEND_RANDOM_H |
||||
|
||||
extern Size BackendRandomShmemSize(void); |
||||
extern void BackendRandomShmemInit(void); |
||||
extern bool pg_backend_random(char *dst, int len); |
||||
|
||||
#endif /* BACKEND_RANDOM_H */ |
@ -0,0 +1,149 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_strong_random.c |
||||
* generate a cryptographically secure random number |
||||
* |
||||
* Our definition of "strong" is that it's suitable for generating random |
||||
* salts and query cancellation keys, during authentication. |
||||
* |
||||
* Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* |
||||
* IDENTIFICATION |
||||
* src/port/pg_strong_random.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#ifndef FRONTEND |
||||
#include "postgres.h" |
||||
#else |
||||
#include "postgres_fe.h" |
||||
#endif |
||||
|
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <sys/time.h> |
||||
|
||||
#ifdef USE_OPENSSL |
||||
#include <openssl/rand.h> |
||||
#endif |
||||
#ifdef WIN32 |
||||
#include <Wincrypt.h> |
||||
#endif |
||||
|
||||
#ifdef WIN32 |
||||
/*
|
||||
* Cache a global crypto provider that only gets freed when the process |
||||
* exits, in case we need random numbers more than once. |
||||
*/ |
||||
static HCRYPTPROV hProvider = 0; |
||||
#endif |
||||
|
||||
#if defined(USE_DEV_URANDOM) |
||||
/*
|
||||
* Read (random) bytes from a file. |
||||
*/ |
||||
static bool |
||||
random_from_file(char *filename, void *buf, size_t len) |
||||
{ |
||||
int f; |
||||
char *p = buf; |
||||
ssize_t res; |
||||
|
||||
f = open(filename, O_RDONLY, 0); |
||||
if (f == -1) |
||||
return false; |
||||
|
||||
while (len) |
||||
{ |
||||
res = read(f, p, len); |
||||
if (res <= 0) |
||||
{ |
||||
if (errno == EINTR) |
||||
continue; /* interrupted by signal, just retry */ |
||||
|
||||
close(f); |
||||
return false; |
||||
} |
||||
|
||||
p += res; |
||||
len -= res; |
||||
} |
||||
|
||||
close(f); |
||||
return true; |
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* pg_strong_random |
||||
* |
||||
* Generate requested number of random bytes. The returned bytes are |
||||
* cryptographically secure, suitable for use e.g. in authentication. |
||||
* |
||||
* We rely on system facilities for actually generating the numbers. |
||||
* We support a number of sources: |
||||
* |
||||
* 1. OpenSSL's RAND_bytes() |
||||
* 2. Windows' CryptGenRandom() function |
||||
* 3. /dev/urandom |
||||
* |
||||
* The configure script will choose which one to use, and set |
||||
* a USE_*_RANDOM flag accordingly. |
||||
* |
||||
* Returns true on success, and false if none of the sources |
||||
* were available. NB: It is important to check the return value! |
||||
* Proceeding with key generation when no random data was available |
||||
* would lead to predictable keys and security issues. |
||||
*/ |
||||
bool |
||||
pg_strong_random(void *buf, size_t len) |
||||
{ |
||||
/*
|
||||
* When built with OpenSSL, use OpenSSL's RAND_bytes function. |
||||
*/ |
||||
#if defined(USE_OPENSSL_RANDOM) |
||||
if (RAND_bytes(buf, len) == 1) |
||||
return true; |
||||
return false; |
||||
|
||||
/*
|
||||
* Windows has CryptoAPI for strong cryptographic numbers. |
||||
*/ |
||||
#elif defined(USE_WIN32_RANDOM) |
||||
if (hProvider == 0) |
||||
{ |
||||
if (!CryptAcquireContext(&hProvider, |
||||
NULL, |
||||
MS_DEF_PROV, |
||||
PROV_RSA_FULL, |
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) |
||||
{ |
||||
/*
|
||||
* On failure, set back to 0 in case the value was for some reason |
||||
* modified. |
||||
*/ |
||||
hProvider = 0; |
||||
} |
||||
} |
||||
/* Re-check in case we just retrieved the provider */ |
||||
if (hProvider != 0) |
||||
{ |
||||
if (CryptGenRandom(hProvider, len, buf)) |
||||
return true; |
||||
} |
||||
return false; |
||||
|
||||
/*
|
||||
* Read /dev/urandom ourselves. |
||||
*/ |
||||
#elif defined(USE_DEV_URANDOM) |
||||
if (random_from_file("/dev/urandom", buf, len)) |
||||
return true; |
||||
return false; |
||||
|
||||
#else |
||||
/* The autoconf script should not have allowed this */ |
||||
#error no source of random numbers configured |
||||
#endif |
||||
} |
Loading…
Reference in new issue