diff --git a/configure b/configure
index f4f2f8b7ce8b264e887db5a1d65c64b9003b9ca9..551fc720b7fb7cba33c36c32a451a84271181e46 100755
--- a/configure
+++ b/configure
@@ -739,6 +739,7 @@ GENHTML
 LCOV
 GCOV
 enable_debug
+enable_strong_random
 enable_rpath
 default_port
 WANTED_LANGUAGES
@@ -806,6 +807,7 @@ with_pgport
 enable_rpath
 enable_spinlocks
 enable_atomics
+enable_strong_random
 enable_debug
 enable_profiling
 enable_coverage
@@ -1478,6 +1480,7 @@ Optional Features:
                           executables
   --disable-spinlocks     do not use spinlocks
   --disable-atomics       do not use atomic operations
+  --disable-strong-random do not use a strong random number source
   --enable-debug          build with debugging symbols (-g)
   --enable-profiling      build with profiling enabled
   --enable-coverage       build with coverage testing instrumentation
@@ -3192,6 +3195,34 @@ fi
 
 
 
+#
+# Random number generation
+#
+
+
+# Check whether --enable-strong-random was given.
+if test "${enable_strong_random+set}" = set; then :
+  enableval=$enable_strong_random;
+  case $enableval in
+    yes)
+      :
+      ;;
+    no)
+      :
+      ;;
+    *)
+      as_fn_error $? "no argument expected for --enable-strong-random option" "$LINENO" 5
+      ;;
+  esac
+
+else
+  enable_strong_random=yes
+
+fi
+
+
+
+
 #
 # --enable-debug adds -g to compiler flags
 #
@@ -14982,6 +15013,84 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
+# Select random number source
+#
+# You can override this logic by setting the appropriate USE_*RANDOM flag to 1
+# in the template or configure command line.
+
+# If not selected manually, try to select a source automatically.
+if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then
+  if test x"$with_openssl" = x"yes" ; then
+    USE_OPENSSL_RANDOM=1
+  elif test "$PORTNAME" = x"win32" ; then
+    USE_WIN32_RANDOM=1
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
+$as_echo_n "checking for /dev/urandom... " >&6; }
+if ${ac_cv_file__dev_urandom+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/dev/urandom"; then
+  ac_cv_file__dev_urandom=yes
+else
+  ac_cv_file__dev_urandom=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_urandom" >&5
+$as_echo "$ac_cv_file__dev_urandom" >&6; }
+if test "x$ac_cv_file__dev_urandom" = xyes; then :
+
+fi
+
+
+    if test x"$ac_cv_file__dev_urandom" = x"yes" ; then
+      USE_DEV_URANDOM=1
+    fi
+  fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5
+$as_echo_n "checking which random number source to use... " >&6; }
+if test "$enable_strong_random" = yes ; then
+  if test x"$USE_OPENSSL_RANDOM" = x"1" ; then
+
+$as_echo "#define USE_OPENSSL_RANDOM 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
+$as_echo "OpenSSL" >&6; }
+  elif test x"$USE_WIN32_RANDOM" = x"1" ; then
+
+$as_echo "#define USE_WIN32_RANDOM 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
+$as_echo "Windows native" >&6; }
+  elif test x"$USE_DEV_URANDOM" = x"1" ; then
+
+$as_echo "#define USE_DEV_URANDOM 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
+$as_echo "/dev/urandom" >&6; }
+  else
+    as_fn_error $? "
+no source of strong random numbers was found
+PostgreSQL can use OpenSSL or /dev/urandom as a source of random numbers,
+for authentication protocols. You can use --disable-strong-random to use of a built-in
+pseudo random number generator, but that may be insecure." "$LINENO" 5
+  fi
+
+$as_echo "#define HAVE_STRONG_RANDOM 1" >>confdefs.h
+
+else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: weak builtin PRNG" >&5
+$as_echo "weak builtin PRNG" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+*** Not using a strong random number source may be insecure." >&5
+$as_echo "$as_me: WARNING:
+*** Not using a strong random number source may be insecure." >&2;}
+fi
+
 # If not set in template file, set bytes to use libc memset()
 if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
   MEMSET_LOOP_LIMIT=1024
diff --git a/configure.in b/configure.in
index 9f7611caebe8f58100a28f8d9c2ac88c2f1c7767..595e047d0e29656c246f5828259f4f45d9aa7f56 100644
--- a/configure.in
+++ b/configure.in
@@ -193,6 +193,13 @@ PGAC_ARG_BOOL(enable, spinlocks, yes,
 PGAC_ARG_BOOL(enable, atomics, yes,
               [do not use atomic operations])
 
+#
+# Random number generation
+#
+PGAC_ARG_BOOL(enable, strong-random, yes,
+              [do not use a strong random number source])
+AC_SUBST(enable_strong_random)
+
 #
 # --enable-debug adds -g to compiler flags
 #
@@ -1965,6 +1972,51 @@ else
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
+# Select random number source
+#
+# You can override this logic by setting the appropriate USE_*RANDOM flag to 1
+# in the template or configure command line.
+
+# If not selected manually, try to select a source automatically.
+if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then
+  if test x"$with_openssl" = x"yes" ; then
+    USE_OPENSSL_RANDOM=1
+  elif test "$PORTNAME" = x"win32" ; then
+    USE_WIN32_RANDOM=1
+  else
+    AC_CHECK_FILE([/dev/urandom], [], [])
+
+    if test x"$ac_cv_file__dev_urandom" = x"yes" ; then
+      USE_DEV_URANDOM=1
+    fi
+  fi
+fi
+
+AC_MSG_CHECKING([which random number source to use])
+if test "$enable_strong_random" = yes ; then
+  if test x"$USE_OPENSSL_RANDOM" = x"1" ; then
+    AC_DEFINE(USE_OPENSSL_RANDOM, 1, [Define to use OpenSSL for random number generation])
+    AC_MSG_RESULT([OpenSSL])
+  elif test x"$USE_WIN32_RANDOM" = x"1" ; then
+    AC_DEFINE(USE_WIN32_RANDOM, 1, [Define to use native Windows API for random number generation])
+    AC_MSG_RESULT([Windows native])
+  elif test x"$USE_DEV_URANDOM" = x"1" ; then
+    AC_DEFINE(USE_DEV_URANDOM, 1, [Define to use /dev/urandom for random number generation])
+    AC_MSG_RESULT([/dev/urandom])
+  else
+    AC_MSG_ERROR([
+no source of strong random numbers was found
+PostgreSQL can use OpenSSL or /dev/urandom as a source of random numbers,
+for authentication protocols. You can use --disable-strong-random to use of a built-in
+pseudo random number generator, but that may be insecure.])
+  fi
+  AC_DEFINE(HAVE_STRONG_RANDOM, 1, [Define to use have a strong random number source])
+else
+    AC_MSG_RESULT([weak builtin PRNG])
+    AC_MSG_WARN([
+*** Not using a strong random number source may be insecure.])
+fi
+
 # If not set in template file, set bytes to use libc memset()
 if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
   MEMSET_LOOP_LIMIT=1024
diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index 805db7626b4ec519f5a2e41675d36513146f81ce..f65d84d1f35a95e5482c733959796d179302ebe3 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -1,7 +1,7 @@
 # contrib/pgcrypto/Makefile
 
 INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \
-		fortuna.c random.c pgp-mpi-internal.c imath.c
+		pgp-mpi-internal.c imath.c
 INT_TESTS = sha2
 
 OSSL_SRCS = openssl.c pgp-mpi-openssl.c
diff --git a/contrib/pgcrypto/expected/pgp-compression_1.out b/contrib/pgcrypto/expected/pgp-compression_1.out
new file mode 100644
index 0000000000000000000000000000000000000000..25d5c35bf794aaf9f5fbfca1a6f53da7601d0746
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-compression_1.out
@@ -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
diff --git a/contrib/pgcrypto/expected/pgp-decrypt_1.out b/contrib/pgcrypto/expected/pgp-decrypt_1.out
new file mode 100644
index 0000000000000000000000000000000000000000..d9e1e386a2550e260d66e66833ae09f53589910b
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-decrypt_1.out
@@ -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
diff --git a/contrib/pgcrypto/expected/pgp-encrypt_1.out b/contrib/pgcrypto/expected/pgp-encrypt_1.out
new file mode 100644
index 0000000000000000000000000000000000000000..2291e662ecddafb4c6368c971b5fb31bfb9d5893
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-encrypt_1.out
@@ -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
diff --git a/contrib/pgcrypto/expected/pgp-pubkey-encrypt_1.out b/contrib/pgcrypto/expected/pgp-pubkey-encrypt_1.out
new file mode 100644
index 0000000000000000000000000000000000000000..3b1822ed916d5e792d74683deac699ade1492559
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-pubkey-encrypt_1.out
@@ -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
diff --git a/contrib/pgcrypto/fortuna.c b/contrib/pgcrypto/fortuna.c
deleted file mode 100644
index 50282034796f825bac010d4807588c52dd74ca90..0000000000000000000000000000000000000000
--- a/contrib/pgcrypto/fortuna.c
+++ /dev/null
@@ -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);
-}
diff --git a/contrib/pgcrypto/fortuna.h b/contrib/pgcrypto/fortuna.h
deleted file mode 100644
index bf9f4768d16137883eef287df20f96cbb6830a57..0000000000000000000000000000000000000000
--- a/contrib/pgcrypto/fortuna.h
+++ /dev/null
@@ -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
diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c
index 02ff976c25a6e89c929208ececccfdf1b698a66c..2516092ba4ec4db85ebe4568b5fcaf836c0c7548 100644
--- a/contrib/pgcrypto/internal.c
+++ b/contrib/pgcrypto/internal.c
@@ -38,7 +38,6 @@
 #include "sha1.h"
 #include "blf.h"
 #include "rijndael.h"
-#include "fortuna.h"
 
 /*
  * System reseeds should be separated at least this much.
@@ -615,65 +614,3 @@ px_find_cipher(const char *name, PX_Cipher **res)
 	*res = c;
 	return 0;
 }
-
-/*
- * Randomness provider
- */
-
-static time_t seed_time = 0;
-static time_t check_time = 0;
-
-static void
-system_reseed(void)
-{
-	uint8		buf[1024];
-	int			n;
-	time_t		t;
-	int			skip = 1;
-
-	t = time(NULL);
-
-	if (seed_time == 0)
-		skip = 0;
-	else if ((t - seed_time) < SYSTEM_RESEED_MIN)
-		skip = 1;
-	else if ((t - seed_time) > SYSTEM_RESEED_MAX)
-		skip = 0;
-	else if (check_time == 0 ||
-			 (t - check_time) > SYSTEM_RESEED_CHECK_TIME)
-	{
-		check_time = t;
-
-		/* roll dice */
-		px_get_random_bytes(buf, 1);
-		skip = buf[0] >= SYSTEM_RESEED_CHANCE;
-	}
-	/* clear 1 byte */
-	px_memset(buf, 0, sizeof(buf));
-
-	if (skip)
-		return;
-
-	n = px_acquire_system_randomness(buf);
-	if (n > 0)
-		fortuna_add_entropy(buf, n);
-
-	seed_time = t;
-	px_memset(buf, 0, sizeof(buf));
-}
-
-int
-px_get_random_bytes(uint8 *dst, unsigned count)
-{
-	system_reseed();
-	fortuna_get_bytes(count, dst);
-	return 0;
-}
-
-int
-px_add_entropy(const uint8 *data, unsigned count)
-{
-	system_reseed();
-	fortuna_add_entropy(data, count);
-	return 0;
-}
diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index f3e3a924867686204fbcff5cf49b69846df92f57..1d3e58d925d9df25cf395e2e6bed5ef930c9a5b6 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -712,49 +712,3 @@ px_find_cipher(const char *name, PX_Cipher **res)
 	*res = c;
 	return 0;
 }
-
-
-static int	openssl_random_init = 0;
-
-/*
- * OpenSSL random should re-feeded occasionally. From /dev/urandom
- * preferably.
- */
-static void
-init_openssl_rand(void)
-{
-	if (RAND_get_rand_method() == NULL)
-	{
-#ifdef HAVE_RAND_OPENSSL
-		RAND_set_rand_method(RAND_OpenSSL());
-#else
-		RAND_set_rand_method(RAND_SSLeay());
-#endif
-	}
-	openssl_random_init = 1;
-}
-
-int
-px_get_random_bytes(uint8 *dst, unsigned count)
-{
-	int			res;
-
-	if (!openssl_random_init)
-		init_openssl_rand();
-
-	res = RAND_bytes(dst, count);
-	if (res == 1)
-		return count;
-
-	return PXE_OSSL_RAND_ERROR;
-}
-
-int
-px_add_entropy(const uint8 *data, unsigned count)
-{
-	/*
-	 * estimate 0 bits
-	 */
-	RAND_add(data, count, 0);
-	return 0;
-}
diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c
index 27b96c7cc4a6022842d58ebf697e9aabad505368..d815de30734f5782073cf712427288185b15ae6a 100644
--- a/contrib/pgcrypto/pgcrypto.c
+++ b/contrib/pgcrypto/pgcrypto.c
@@ -34,6 +34,7 @@
 #include <ctype.h>
 
 #include "parser/scansup.h"
+#include "utils/backend_random.h"
 #include "utils/builtins.h"
 #include "utils/uuid.h"
 
@@ -422,7 +423,7 @@ PG_FUNCTION_INFO_V1(pg_random_bytes);
 Datum
 pg_random_bytes(PG_FUNCTION_ARGS)
 {
-	int			err;
+#ifdef HAVE_STRONG_RANDOM
 	int			len = PG_GETARG_INT32(0);
 	bytea	   *res;
 
@@ -435,13 +436,13 @@ pg_random_bytes(PG_FUNCTION_ARGS)
 	SET_VARSIZE(res, VARHDRSZ + len);
 
 	/* generate result */
-	err = px_get_random_bytes((uint8 *) VARDATA(res), len);
-	if (err < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("Random generator error: %s", px_strerror(err))));
+	if (!pg_strong_random(VARDATA(res), len))
+		px_THROW_ERROR(PXE_NO_RANDOM);
 
 	PG_RETURN_BYTEA_P(res);
+#else
+	px_THROW_ERROR(PXE_NO_RANDOM);
+#endif
 }
 
 /* SQL function: gen_random_uuid() returns uuid */
@@ -451,14 +452,14 @@ Datum
 pg_random_uuid(PG_FUNCTION_ARGS)
 {
 	uint8	   *buf = (uint8 *) palloc(UUID_LEN);
-	int			err;
 
-	/* generate random bits */
-	err = px_get_random_bytes(buf, UUID_LEN);
-	if (err < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("Random generator error: %s", px_strerror(err))));
+	/*
+	 * Generate random bits. pg_backend_random() will do here, we don't
+	 * promis UUIDs to be cryptographically random, when built with
+	 * --disable-strong-random.
+	 */
+	if (!pg_backend_random((char *) buf, UUID_LEN))
+		px_THROW_ERROR(PXE_NO_RANDOM);
 
 	/*
 	 * Set magic numbers for a "version 4" (pseudorandom) UUID, see
diff --git a/contrib/pgcrypto/pgp-encrypt.c b/contrib/pgcrypto/pgp-encrypt.c
index c9148fd2fc6d0f630ba1116a5d753157791d9d85..be933bf86c1a4e77029ef15be50ecb201528eaa2 100644
--- a/contrib/pgcrypto/pgp-encrypt.c
+++ b/contrib/pgcrypto/pgp-encrypt.c
@@ -37,6 +37,8 @@
 #include "px.h"
 #include "pgp.h"
 
+#include "utils/backend_random.h"
+
 
 #define MDC_DIGEST_LEN 20
 #define STREAM_ID 0xE0
@@ -477,14 +479,14 @@ init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
 static int
 write_prefix(PGP_Context *ctx, PushFilter *dst)
 {
+#ifdef HAVE_STRONG_RANDOM
 	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;
+	if (!pg_backend_random((char *) prefix, bs))
+		return PXE_NO_RANDOM;
 
 	prefix[bs + 0] = prefix[bs - 2];
 	prefix[bs + 1] = prefix[bs - 1];
@@ -492,6 +494,9 @@ write_prefix(PGP_Context *ctx, PushFilter *dst)
 	res = pushf_write(dst, prefix, bs + 2);
 	px_memset(prefix, 0, bs + 2);
 	return res < 0 ? res : 0;
+#else
+	return PXE_NO_RANDOM;
+#endif
 }
 
 /*
@@ -578,14 +583,15 @@ init_s2k_key(PGP_Context *ctx)
 static int
 init_sess_key(PGP_Context *ctx)
 {
-	int			res;
-
 	if (ctx->use_sess_key || ctx->pub_key)
 	{
+#ifdef HAVE_STRONG_RANDOM
 		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;
+		if (!pg_strong_random((char *) ctx->sess_key, ctx->sess_key_len))
+			return PXE_NO_RANDOM;
+#else
+		return PXE_NO_RANDOM;
+#endif
 	}
 	else
 	{
diff --git a/contrib/pgcrypto/pgp-mpi-internal.c b/contrib/pgcrypto/pgp-mpi-internal.c
index be95f2d092690a4dd8378e4b21ea24dddd37f57c..cb70fcba6cc13d0d5ee08c5a99d6ed7abf1852c3 100644
--- a/contrib/pgcrypto/pgp-mpi-internal.c
+++ b/contrib/pgcrypto/pgp-mpi-internal.c
@@ -57,17 +57,16 @@ mp_clear_free(mpz_t *a)
 static int
 mp_px_rand(uint32 bits, mpz_t *res)
 {
-	int			err;
+#ifdef HAVE_STRONG_RANDOM
 	unsigned	bytes = (bits + 7) / 8;
 	int			last_bits = bits & 7;
 	uint8	   *buf;
 
 	buf = px_alloc(bytes);
-	err = px_get_random_bytes(buf, bytes);
-	if (err < 0)
+	if (!pg_strong_random((char *) buf, bytes))
 	{
 		px_free(buf);
-		return err;
+		return PXE_NO_RANDOM;
 	}
 
 	/* clear unnecessary bits and set last bit to one */
@@ -84,6 +83,9 @@ mp_px_rand(uint32 bits, mpz_t *res)
 	px_free(buf);
 
 	return 0;
+#else
+	return PXE_NO_RANDOM;
+#endif
 }
 
 static void
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 1f65b667cab3747cf2af2216b577284f31e3051c..ce16db71d878c279df9dc40bb930534d4a135a0b 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -61,65 +61,6 @@ PG_FUNCTION_INFO_V1(pg_armor);
 PG_FUNCTION_INFO_V1(pg_dearmor);
 PG_FUNCTION_INFO_V1(pgp_armor_headers);
 
-/*
- * Mix a block of data into RNG.
- */
-static void
-add_block_entropy(PX_MD *md, text *data)
-{
-	uint8		sha1[20];
-
-	px_md_reset(md);
-	px_md_update(md, (uint8 *) VARDATA(data), VARSIZE(data) - VARHDRSZ);
-	px_md_finish(md, sha1);
-
-	px_add_entropy(sha1, 20);
-
-	px_memset(sha1, 0, 20);
-}
-
-/*
- * 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		rnd[3];
-
-	if (!data1 && !data2 && !data3)
-		return;
-
-	if (px_get_random_bytes(rnd, 3) < 0)
-		return;
-
-	if (px_find_digest("sha1", &md) < 0)
-		return;
-
-	/*
-	 * Try to make the feeding unpredictable.
-	 *
-	 * Prefer data over keys, as it's rather likely that key is same in
-	 * several calls.
-	 */
-
-	/* chance: 7/8 */
-	if (data1 && rnd[0] >= 32)
-		add_block_entropy(md, data1);
-
-	/* chance: 5/8 */
-	if (data2 && rnd[1] >= 160)
-		add_block_entropy(md, data2);
-
-	/* chance: 5/8 */
-	if (data3 && rnd[2] >= 160)
-		add_block_entropy(md, data3);
-
-	px_md_free(md);
-	px_memset(rnd, 0, sizeof(rnd));
-}
-
 /*
  * returns src in case of no conversion or error
  */
@@ -432,11 +373,7 @@ init_work(PGP_Context **ctx_p, int is_text,
 						 VARSIZE(args) - VARHDRSZ, ex);
 
 	if (err)
-	{
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("%s", px_strerror(err))));
-	}
+		px_THROW_ERROR(err);
 
 	if (ex->debug)
 		px_set_debug_handler(show_debug);
@@ -459,11 +396,6 @@ encrypt_internal(int is_pubenc, int is_text,
 	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))
@@ -516,9 +448,7 @@ encrypt_internal(int is_pubenc, int is_text,
 		pgp_free(ctx);
 		mbuf_free(src);
 		mbuf_free(dst);
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("%s", px_strerror(err))));
+		px_THROW_ERROR(err);
 	}
 
 	/* res_len includes VARHDRSZ */
@@ -605,9 +535,7 @@ decrypt_internal(int is_pubenc, int need_text, text *data,
 	{
 		px_set_debug_handler(NULL);
 		mbuf_free(dst);
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("%s", px_strerror(err))));
+		px_THROW_ERROR(err);
 	}
 
 	res_len = mbuf_steal_data(dst, &restmp);
@@ -629,11 +557,6 @@ decrypt_internal(int is_pubenc, int need_text, text *data,
 	}
 	px_set_debug_handler(NULL);
 
-	/*
-	 * add successful decryptions also into RNG
-	 */
-	add_entropy(res, key, keypsw);
-
 	return res;
 }
 
@@ -985,9 +908,7 @@ pg_dearmor(PG_FUNCTION_ARGS)
 
 	ret = pgp_armor_decode((uint8 *) VARDATA(data), data_len, &buf);
 	if (ret < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("%s", px_strerror(ret))));
+		px_THROW_ERROR(ret);
 	res = palloc(VARHDRSZ + buf.len);
 	SET_VARSIZE(res, VARHDRSZ + buf.len);
 	memcpy(VARDATA(res), buf.data, buf.len);
@@ -1041,9 +962,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 										&state->nheaders, &state->keys,
 										&state->values);
 		if (res < 0)
-			ereport(ERROR,
-					(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-					 errmsg("%s", px_strerror(res))));
+			px_THROW_ERROR(res);
 
 		MemoryContextSwitchTo(oldcontext);
 		funcctx->user_fctx = state;
@@ -1092,9 +1011,7 @@ pgp_key_id_w(PG_FUNCTION_ARGS)
 	res_len = pgp_get_keyid(buf, VARDATA(res));
 	mbuf_free(buf);
 	if (res_len < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
-				 errmsg("%s", px_strerror(res_len))));
+		px_THROW_ERROR(res_len);
 	SET_VARSIZE(res, VARHDRSZ + res_len);
 
 	PG_FREE_IF_COPY(data, 0);
diff --git a/contrib/pgcrypto/pgp-pubenc.c b/contrib/pgcrypto/pgp-pubenc.c
index 3b43bb61c05a02d183a00103acb9baa75f41f6ce..443987666431f9c0b3ce9ffbc78b11738449a4c4 100644
--- a/contrib/pgcrypto/pgp-pubenc.c
+++ b/contrib/pgcrypto/pgp-pubenc.c
@@ -39,7 +39,7 @@
 static int
 pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
 {
-	int			res;
+#ifdef HAVE_STRONG_RANDOM
 	uint8	   *buf,
 			   *p;
 	int			pad_len = res_len - 2 - data_len;
@@ -49,11 +49,11 @@ pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
 
 	buf = px_alloc(res_len);
 	buf[0] = 0x02;
-	res = px_get_random_bytes(buf + 1, pad_len);
-	if (res < 0)
+
+	if (!pg_strong_random((char *) buf + 1, pad_len))
 	{
 		px_free(buf);
-		return res;
+		return PXE_NO_RANDOM;
 	}
 
 	/* pad must not contain zero bytes */
@@ -62,26 +62,26 @@ pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
 	{
 		if (*p == 0)
 		{
-			res = px_get_random_bytes(p, 1);
-			if (res < 0)
+			if (!pg_strong_random((char *) p, 1))
+			{
+				px_memset(buf, 0, res_len);
+				px_free(buf);
 				break;
+			}
 		}
 		if (*p != 0)
 			p++;
 	}
 
-	if (res < 0)
-	{
-		px_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;
+
+#else
+	return PXE_NO_RANDOM;
+#endif
 }
 
 static int
diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c
index 3551d44d62bd3494d63b1a604445a848bfba6071..a0fd8969efe2c7203f5320dff20036bfa61384b1 100644
--- a/contrib/pgcrypto/pgp-s2k.c
+++ b/contrib/pgcrypto/pgp-s2k.c
@@ -34,6 +34,8 @@
 #include "px.h"
 #include "pgp.h"
 
+#include "utils/backend_random.h"
+
 static int
 calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
 				unsigned key_len)
@@ -233,15 +235,14 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count)
 		case PGP_S2K_SIMPLE:
 			break;
 		case PGP_S2K_SALTED:
-			res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT);
+			if (!pg_backend_random((char *) s2k->salt, PGP_S2K_SALT))
+				return PXE_NO_RANDOM;
 			break;
 		case PGP_S2K_ISALTED:
-			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;
+			if (!pg_backend_random((char *) s2k->salt, PGP_S2K_SALT))
+				return PXE_NO_RANDOM;
+			if (!pg_backend_random((char *) &tmp, 1))
+				return PXE_NO_RANDOM;
 			s2k->iter = decide_s2k_iter(tmp, count);
 			break;
 		default:
diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c
index 3d423938502721b633ed75c9dc5612549bab3c53..6c72c4ae8304d97fa99dd7757aa79f99ba0ed9d4 100644
--- a/contrib/pgcrypto/px-crypt.c
+++ b/contrib/pgcrypto/px-crypt.c
@@ -34,6 +34,7 @@
 #include "px.h"
 #include "px-crypt.h"
 
+#include "utils/backend_random.h"
 
 static char *
 run_crypt_des(const char *psw, const char *salt,
@@ -132,7 +133,6 @@ static struct generator gen_list[] = {
 int
 px_gen_salt(const char *salt_type, char *buf, int rounds)
 {
-	int			res;
 	struct generator *g;
 	char	   *p;
 	char		rbuf[16];
@@ -153,9 +153,8 @@ px_gen_salt(const char *salt_type, char *buf, int rounds)
 			return PXE_BAD_SALT_ROUNDS;
 	}
 
-	res = px_get_random_bytes((uint8 *) rbuf, g->input_len);
-	if (res < 0)
-		return res;
+	if (!pg_backend_random(rbuf, g->input_len))
+		return PXE_NO_RANDOM;
 
 	p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN);
 	px_memset(rbuf, 0, sizeof(rbuf));
diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c
index b01701ea7509eb8217d9c8c1dfbc55968a3bffa4..a5c02f3612d3b673c9c70330ea400e210ca457d1 100644
--- a/contrib/pgcrypto/px.c
+++ b/contrib/pgcrypto/px.c
@@ -51,7 +51,6 @@ static const struct error_desc px_err_list[] = {
 	{PXE_CIPHER_INIT, "Cipher cannot be initialized ?"},
 	{PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
 	{PXE_DEV_READ_ERROR, "Error reading from random device"},
-	{PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"},
 	{PXE_BUG, "pgcrypto bug"},
 	{PXE_ARGUMENT_ERROR, "Illegal argument to function"},
 	{PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
@@ -86,6 +85,39 @@ static const struct error_desc px_err_list[] = {
 	{0, NULL},
 };
 
+/*
+ * Call ereport(ERROR, ...), with an error code and message corresponding to
+ * the PXE_* error code given as argument.
+ *
+ * This is similar to px_strerror(err), but for some errors, we fill in the
+ * error code and detail fields more appropriately.
+ */
+void
+px_THROW_ERROR(int err)
+{
+	if (err == PXE_NO_RANDOM)
+	{
+#ifdef HAVE_STRONG_RANDOM
+		ereport(ERROR,
+				(errcode(ERRCODE_INTERNAL_ERROR),
+				 errmsg("could not generate a random number")));
+#else
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("pg_random_bytes() is not supported by this build"),
+				 errdetail("This functionality requires a source of strong random numbers"),
+				 errhint("You need to rebuild PostgreSQL using --enable-strong-random")));
+#endif
+	}
+	else
+	{
+		/* For other errors, use the message from the above list. */
+		ereport(ERROR,
+				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+				 errmsg("%s", px_strerror(err))));
+	}
+}
+
 const char *
 px_strerror(int err)
 {
diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h
index 800c552bf6089dfd77ecc48faa0f7b0e94832bff..00fc6f0c015285fe81427a5069b615a4de09335e 100644
--- a/contrib/pgcrypto/px.h
+++ b/contrib/pgcrypto/px.h
@@ -71,7 +71,6 @@ void		px_free(void *p);
 #define PXE_CIPHER_INIT				-8
 #define PXE_HASH_UNUSABLE_FOR_HMAC	-9
 #define PXE_DEV_READ_ERROR			-10
-#define PXE_OSSL_RAND_ERROR			-11
 #define PXE_BUG						-12
 #define PXE_ARGUMENT_ERROR			-13
 #define PXE_UNKNOWN_SALT_ALGO		-14
@@ -189,11 +188,7 @@ int			px_find_hmac(const char *name, PX_HMAC **res);
 int			px_find_cipher(const char *name, PX_Cipher **res);
 int			px_find_combo(const char *name, PX_Combo **res);
 
-int			px_get_random_bytes(uint8 *dst, unsigned count);
-int			px_add_entropy(const uint8 *data, unsigned count);
-
-unsigned	px_acquire_system_randomness(uint8 *dst);
-
+void		px_THROW_ERROR(int err) pg_attribute_noreturn();
 const char *px_strerror(int err);
 
 const char *px_resolve_alias(const PX_Alias *aliases, const char *name);
diff --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c
deleted file mode 100644
index d72679e412d405dd7cdb136c5be0d6ef203f10a7..0000000000000000000000000000000000000000
--- a/contrib/pgcrypto/random.c
+++ /dev/null
@@ -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;
-}
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 296611d4256b06171eb3aa4f34a08bb4383fe819..98594a487e6ed6c38fc6191ba1eab36f763ca904 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1096,6 +1096,23 @@ su - postgres
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term><option>--disable-strong-random</option></term>
+       <listitem>
+        <para>
+         Allow the build to succeed even if <productname>PostgreSQL</>
+         has no support for strong random numbers on the platform.
+         A source of random numbers is needed for some authentication
+         protocols, as well as some routines in <xref linkend="pgcrypto">
+         module. --disable-strong-random disables functionality that
+         requires cryptographically strong random numbers, and substitutes
+         a weak pseudo-random-number-generator for the generation of
+         authentication salt values and query cancel keys. It may make
+         authentication less secure.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term><option>--disable-thread-safety</option></term>
        <listitem>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index aa1fa658ed0e2c6468426fdb6ff94003b12e509c..d39d6ca8670f6676aa898ac4d2ae3c6979808d6e 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -197,6 +197,7 @@ enable_dtrace	= @enable_dtrace@
 enable_coverage	= @enable_coverage@
 enable_tap_tests	= @enable_tap_tests@
 enable_thread_safety	= @enable_thread_safety@
+enable_strong_random	= @enable_strong_random@
 
 python_includespec	= @python_includespec@
 python_libdir		= @python_libdir@
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 0ba85301149a03be96f127b455d179645b23d95a..5d166db5744515a6e08b1a7937e27af780eb61c6 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -33,6 +33,7 @@
 #include "miscadmin.h"
 #include "replication/walsender.h"
 #include "storage/ipc.h"
+#include "utils/backend_random.h"
 
 
 /*----------------------------------------------------------------
@@ -43,9 +44,21 @@ static void sendAuthRequest(Port *port, AuthRequest areq, char *extradata,
 				int extralen);
 static void auth_failed(Port *port, int status, char *logdetail);
 static char *recv_password_packet(Port *port);
-static int	recv_and_check_password_packet(Port *port, char **logdetail);
 
 
+/*----------------------------------------------------------------
+ * MD5 authentication
+ *----------------------------------------------------------------
+ */
+static int CheckMD5Auth(Port *port, char **logdetail);
+
+/*----------------------------------------------------------------
+ * Plaintext password authentication
+ *----------------------------------------------------------------
+ */
+
+static int CheckPasswordAuth(Port *port, char **logdetail);
+
 /*----------------------------------------------------------------
  * Ident authentication
  *----------------------------------------------------------------
@@ -536,13 +549,11 @@ ClientAuthentication(Port *port)
 						(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
 						 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
 			/* include the salt to use for computing the response */
-			sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4);
-			status = recv_and_check_password_packet(port, &logdetail);
+			status = CheckMD5Auth(port, &logdetail);
 			break;
 
 		case uaPassword:
-			sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
-			status = recv_and_check_password_packet(port, &logdetail);
+			status = CheckPasswordAuth(port, &logdetail);
 			break;
 
 		case uaPAM:
@@ -696,23 +707,48 @@ recv_password_packet(Port *port)
  *----------------------------------------------------------------
  */
 
-/*
- * Called when we have sent an authorization request for a password.
- * Get the response and check it.
- * On error, optionally store a detail string at *logdetail.
+static int
+CheckMD5Auth(Port *port, char **logdetail)
+{
+	char		md5Salt[4];		/* Password salt */
+	char	   *passwd;
+	int			result;
+
+	pg_backend_random(md5Salt, 4);
+
+	sendAuthRequest(port, AUTH_REQ_MD5, md5Salt, 4);
+
+	passwd = recv_password_packet(port);
+
+	if (passwd == NULL)
+		return STATUS_EOF;		/* client wouldn't send password */
+
+	result = md5_crypt_verify(port, port->user_name, passwd, md5Salt, 4, logdetail);
+
+	pfree(passwd);
+
+	return result;
+}
+
+/*----------------------------------------------------------------
+ * Plaintext password authentication
+ *----------------------------------------------------------------
  */
+
 static int
-recv_and_check_password_packet(Port *port, char **logdetail)
+CheckPasswordAuth(Port *port, char **logdetail)
 {
 	char	   *passwd;
 	int			result;
 
+	sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
+
 	passwd = recv_password_packet(port);
 
 	if (passwd == NULL)
 		return STATUS_EOF;		/* client wouldn't send password */
 
-	result = md5_crypt_verify(port, port->user_name, passwd, logdetail);
+	result = md5_crypt_verify(port, port->user_name, passwd, NULL, 0, logdetail);
 
 	pfree(passwd);
 
@@ -920,7 +956,7 @@ pg_GSS_recvauth(Port *port)
 				 (unsigned int) port->gss->outbuf.length);
 
 			sendAuthRequest(port, AUTH_REQ_GSS_CONT,
-							port->gss->outbuf.value, port->gss->outbuf.length);
+						  port->gss->outbuf.value, port->gss->outbuf.length);
 
 			gss_release_buffer(&lmin_s, &port->gss->outbuf);
 		}
@@ -1166,7 +1202,7 @@ pg_SSPI_recvauth(Port *port)
 			port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
 
 			sendAuthRequest(port, AUTH_REQ_GSS_CONT,
-							port->gss->outbuf.value, port->gss->outbuf.length);
+						  port->gss->outbuf.value, port->gss->outbuf.length);
 
 			FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
 		}
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index d84a18033048698ff288eb46b5f6f19ae64d955f..35b657adbbe2e14f965d36fc608e2c759da21234 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -36,7 +36,7 @@
  */
 int
 md5_crypt_verify(const Port *port, const char *role, char *client_pass,
-				 char **logdetail)
+				 char *md5_salt, int md5_salt_len, char **logdetail)
 {
 	int			retval = STATUS_ERROR;
 	char	   *shadow_pass,
@@ -91,13 +91,14 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass,
 	switch (port->hba->auth_method)
 	{
 		case uaMD5:
+			Assert(md5_salt != NULL && md5_salt_len > 0);
 			crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
 			if (isMD5(shadow_pass))
 			{
 				/* stored password already encrypted, only do salt */
 				if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
-									port->md5Salt,
-									sizeof(port->md5Salt), crypt_pwd))
+									md5_salt, md5_salt_len,
+									crypt_pwd))
 				{
 					pfree(crypt_pwd);
 					return STATUS_ERROR;
@@ -118,8 +119,7 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass,
 					return STATUS_ERROR;
 				}
 				if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
-									port->md5Salt,
-									sizeof(port->md5Salt),
+									md5_salt, md5_salt_len,
 									crypt_pwd))
 				{
 					pfree(crypt_pwd);
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 24add74512fa2086d0044c6fc12dfbdbe7d776a3..f0ed5233711b66c67d44352cee819f86a6af21c2 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -164,7 +164,7 @@
 typedef struct bkend
 {
 	pid_t		pid;			/* process id of backend */
-	long		cancel_key;		/* cancel key for cancels for this backend */
+	int32		cancel_key;		/* cancel key for cancels for this backend */
 	int			child_slot;		/* PMChildSlot for this backend, if any */
 
 	/*
@@ -358,13 +358,15 @@ static volatile bool avlauncher_needs_signal = false;
 static volatile bool StartWorkerNeeded = true;
 static volatile bool HaveCrashedWorker = false;
 
+#ifndef HAVE_STRONG_RANDOM
 /*
- * State for assigning random salts and cancel keys.
+ * State for assigning cancel keys.
  * Also, the global MyCancelKey passes the cancel key assigned to a given
  * backend from the postmaster to that backend (via fork).
  */
 static unsigned int random_seed = 0;
 static struct timeval random_start_time;
+#endif
 
 #ifdef USE_BONJOUR
 static DNSServiceRef bonjour_sdref = NULL;
@@ -403,8 +405,7 @@ static void processCancelRequest(Port *port, void *pkt);
 static int	initMasks(fd_set *rmask);
 static void report_fork_failure_to_client(Port *port, int errnum);
 static CAC_state canAcceptConnections(void);
-static long PostmasterRandom(void);
-static void RandomSalt(char *salt, int len);
+static bool RandomCancelKey(int32 *cancel_key);
 static void signal_child(pid_t pid, int signal);
 static bool SignalSomeChildren(int signal, int targets);
 static void TerminateChildren(int signal);
@@ -471,7 +472,7 @@ typedef struct
 	InheritableSocket portsocket;
 	char		DataDir[MAXPGPATH];
 	pgsocket	ListenSocket[MAXLISTEN];
-	long		MyCancelKey;
+	int32		MyCancelKey;
 	int			MyPMChildSlot;
 #ifndef WIN32
 	unsigned long UsedShmemSegID;
@@ -1292,8 +1293,10 @@ PostmasterMain(int argc, char *argv[])
 	 * Remember postmaster startup time
 	 */
 	PgStartTime = GetCurrentTimestamp();
-	/* PostmasterRandom wants its own copy */
+#ifndef HAVE_STRONG_RANDOM
+	/* RandomCancelKey wants its own copy */
 	gettimeofday(&random_start_time, NULL);
+#endif
 
 	/*
 	 * We're ready to rock and roll...
@@ -2344,15 +2347,6 @@ ConnCreate(int serverFd)
 		return NULL;
 	}
 
-	/*
-	 * Precompute password salt values to use for this connection. It's
-	 * slightly annoying to do this long in advance of knowing whether we'll
-	 * need 'em or not, but we must do the random() calls before we fork, not
-	 * after.  Else the postmaster's random sequence won't get advanced, and
-	 * all backends would end up using the same salt...
-	 */
-	RandomSalt(port->md5Salt, sizeof(port->md5Salt));
-
 	/*
 	 * Allocate GSSAPI specific state struct
 	 */
@@ -3905,7 +3899,14 @@ BackendStartup(Port *port)
 	 * backend will have its own copy in the forked-off process' value of
 	 * MyCancelKey, so that it can transmit the key to the frontend.
 	 */
-	MyCancelKey = PostmasterRandom();
+	if (!RandomCancelKey(&MyCancelKey))
+	{
+		ereport(LOG,
+				(errcode(ERRCODE_OUT_OF_MEMORY),
+				 errmsg("could not acquire random number")));
+		return STATUS_ERROR;
+	}
+
 	bn->cancel_key = MyCancelKey;
 
 	/* Pass down canAcceptConnections state */
@@ -4218,8 +4219,10 @@ BackendRun(Port *port)
 	 * generator state.  We have to clobber the static random_seed *and* start
 	 * a new random sequence in the random() library function.
 	 */
+#ifndef HAVE_STRONG_RANDOM
 	random_seed = 0;
 	random_start_time.tv_usec = 0;
+#endif
 	/* slightly hacky way to convert timestamptz into integers */
 	TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
 	srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
@@ -5068,63 +5071,42 @@ StartupPacketTimeoutHandler(void)
 
 
 /*
- * RandomSalt
+ * Generate a random cancel key.
  */
-static void
-RandomSalt(char *salt, int len)
+static bool
+RandomCancelKey(int32 *cancel_key)
 {
-	long		rand;
-	int			i;
-
+#ifdef HAVE_STRONG_RANDOM
+	return pg_strong_random((char *) cancel_key, sizeof(int32));
+#else
 	/*
-	 * We use % 255, sacrificing one possible byte value, so as to ensure that
-	 * all bits of the random() value participate in the result. While at it,
-	 * add one to avoid generating any null bytes.
+	 * If built with --disable-strong-random, use plain old erand48.
+	 *
+	 * We cannot use pg_backend_random() in postmaster, because it stores
+	 * its state in shared memory.
 	 */
-	for (i = 0; i < len; i++)
-	{
-		rand = PostmasterRandom();
-		salt[i] = (rand % 255) + 1;
-	}
-}
+	static unsigned short seed[3];
 
-/*
- * PostmasterRandom
- *
- * Caution: use this only for values needed during connection-request
- * processing.  Otherwise, the intended property of having an unpredictable
- * delay between random_start_time and random_stop_time will be broken.
- */
-static long
-PostmasterRandom(void)
-{
 	/*
 	 * Select a random seed at the time of first receiving a request.
 	 */
 	if (random_seed == 0)
 	{
-		do
-		{
-			struct timeval random_stop_time;
+		struct timeval random_stop_time;
 
-			gettimeofday(&random_stop_time, NULL);
+		gettimeofday(&random_stop_time, NULL);
 
-			/*
-			 * We are not sure how much precision is in tv_usec, so we swap
-			 * the high and low 16 bits of 'random_stop_time' and XOR them
-			 * with 'random_start_time'. On the off chance that the result is
-			 * 0, we loop until it isn't.
-			 */
-			random_seed = random_start_time.tv_usec ^
-				((random_stop_time.tv_usec << 16) |
-				 ((random_stop_time.tv_usec >> 16) & 0xffff));
-		}
-		while (random_seed == 0);
+		seed[0] = (unsigned short) random_start_time.tv_usec;
+		seed[1] = (unsigned short) (random_stop_time.tv_usec) ^ (random_start_time.tv_usec >> 16);
+		seed[2] = (unsigned short) (random_stop_time.tv_usec >> 16);
 
-		srandom(random_seed);
+		random_seed = 1;
 	}
 
-	return random();
+	*cancel_key = pg_jrand48(seed);
+
+	return true;
+#endif
 }
 
 /*
@@ -5295,16 +5277,23 @@ StartAutovacuumWorker(void)
 	 */
 	if (canAcceptConnections() == CAC_OK)
 	{
+		/*
+		 * Compute the cancel key that will be assigned to this session.
+		 * We probably don't need cancel keys for autovac workers, but
+		 * we'd better have something random in the field to prevent
+		 * unfriendly people from sending cancels to them.
+		 */
+		if (!RandomCancelKey(&MyCancelKey))
+		{
+			ereport(LOG,
+					(errcode(ERRCODE_INTERNAL_ERROR),
+					 errmsg("could not acquire random number")));
+			return;
+		}
+
 		bn = (Backend *) malloc(sizeof(Backend));
 		if (bn)
 		{
-			/*
-			 * Compute the cancel key that will be assigned to this session.
-			 * We probably don't need cancel keys for autovac workers, but
-			 * we'd better have something random in the field to prevent
-			 * unfriendly people from sending cancels to them.
-			 */
-			MyCancelKey = PostmasterRandom();
 			bn->cancel_key = MyCancelKey;
 
 			/* Autovac workers are not dead_end and need a child slot */
@@ -5592,8 +5581,25 @@ bgworker_should_start_now(BgWorkerStartTime start_time)
 static bool
 assign_backendlist_entry(RegisteredBgWorker *rw)
 {
-	Backend    *bn = malloc(sizeof(Backend));
+	Backend    *bn;
 
+	/*
+	 * Compute the cancel key that will be assigned to this session. We
+	 * probably don't need cancel keys for background workers, but we'd better
+	 * have something random in the field to prevent unfriendly people from
+	 * sending cancels to them.
+	 */
+	if (!RandomCancelKey(&MyCancelKey))
+	{
+		ereport(LOG,
+				(errcode(ERRCODE_INTERNAL_ERROR),
+				 errmsg("could not acquire random number")));
+
+		rw->rw_crashed_at = GetCurrentTimestamp();
+		return false;
+	}
+
+	bn = malloc(sizeof(Backend));
 	if (bn == NULL)
 	{
 		ereport(LOG,
@@ -5610,15 +5616,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw)
 		return false;
 	}
 
-	/*
-	 * Compute the cancel key that will be assigned to this session. We
-	 * probably don't need cancel keys for background workers, but we'd better
-	 * have something random in the field to prevent unfriendly people from
-	 * sending cancels to them.
-	 */
-	MyCancelKey = PostmasterRandom();
 	bn->cancel_key = MyCancelKey;
-
 	bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
 	bn->bkend_type = BACKEND_TYPE_BGWORKER;
 	bn->dead_end = false;
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index c04b17fa8ead59f8190a3fa7d880197e9cff9235..01bddcea16c4471af840db90deb2d21dbeeb017d 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -43,6 +43,7 @@
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
 #include "storage/spin.h"
+#include "utils/backend_random.h"
 #include "utils/snapmgr.h"
 
 
@@ -141,6 +142,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 		size = add_size(size, BTreeShmemSize());
 		size = add_size(size, SyncScanShmemSize());
 		size = add_size(size, AsyncShmemSize());
+		size = add_size(size, BackendRandomShmemSize());
 #ifdef EXEC_BACKEND
 		size = add_size(size, ShmemBackendArraySize());
 #endif
@@ -253,6 +255,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 	BTreeShmemInit();
 	SyncScanShmemInit();
 	AsyncShmemInit();
+	BackendRandomShmemInit();
 
 #ifdef EXEC_BACKEND
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
index f8996cd21a552089d08978936cd7418f9232aee9..0dcf7effd417ec85c9b383b8f65c65e637cdacd6 100644
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ b/src/backend/storage/lmgr/lwlocknames.txt
@@ -47,3 +47,4 @@ CommitTsLock						39
 ReplicationOriginLock				40
 MultiXactTruncationLock				41
 OldSnapshotTimeMapLock				42
+BackendRandomLock				43
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index c564ae396dac5d06cb08db7e90bcb57eb948c691..6ab03cea17034334a7341268d469c64e0730ee14 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -38,7 +38,7 @@ volatile uint32 CritSectionCount = 0;
 int			MyProcPid;
 pg_time_t	MyStartTime;
 struct Port *MyProcPort;
-long		MyCancelKey;
+int32		MyCancelKey;
 int			MyPMChildSlot;
 
 /*
diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index a5b487d0b64de0e169423e721d897b748fe3e2df..0ad1b8b59540f1e006abf30be27cd854e2da39d8 100644
--- a/src/backend/utils/misc/Makefile
+++ b/src/backend/utils/misc/Makefile
@@ -14,8 +14,9 @@ include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
 
-OBJS = guc.o help_config.o pg_config.o pg_controldata.o pg_rusage.o \
-       ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o
+OBJS = backend_random.o guc.o help_config.o pg_config.o pg_controldata.o \
+       pg_rusage.o ps_status.o rls.o sampling.o superuser.o timeout.o \
+       tzparser.o
 
 # This location might depend on the installation directories. Therefore
 # we can't subsitute it into pg_config.h.
diff --git a/src/backend/utils/misc/backend_random.c b/src/backend/utils/misc/backend_random.c
new file mode 100644
index 0000000000000000000000000000000000000000..1bc239d1ddc89eee787512897fa14bcdfb97a6e6
--- /dev/null
+++ b/src/backend/utils/misc/backend_random.c
@@ -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 */
diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h
index 5725bb409e82dc350a2aa317d074ea0a655b8705..f51e0fd46b68609b891ddf668dfc0cd927dcd2d6 100644
--- a/src/include/libpq/crypt.h
+++ b/src/include/libpq/crypt.h
@@ -16,6 +16,6 @@
 #include "libpq/libpq-be.h"
 
 extern int md5_crypt_verify(const Port *port, const char *role,
-				 char *client_pass, char **logdetail);
+				 char *client_pass, char *md5_salt, int md5_salt_len, char **logdetail);
 
 #endif
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index b91eca5b2c1400616682a307e4d82d03bb713d58..66647ad003260c01d7ab7af61dcf6b56f88361cb 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -144,7 +144,6 @@ typedef struct Port
 	 * Information that needs to be held during the authentication cycle.
 	 */
 	HbaLine    *hba;
-	char		md5Salt[4];		/* Password salt */
 
 	/*
 	 * Information that really has no business at all being in struct Port,
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index d06eca54b46fea36df5b5252b063359d955cf36a..999440fdec10bbb49651cfaa0ea8834c4349df0b 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -163,7 +163,7 @@ extern PGDLLIMPORT int MyProcPid;
 extern PGDLLIMPORT pg_time_t MyStartTime;
 extern PGDLLIMPORT struct Port *MyProcPort;
 extern PGDLLIMPORT struct Latch *MyLatch;
-extern long MyCancelKey;
+extern int32 MyCancelKey;
 extern int	MyPMChildSlot;
 
 extern char OutputFileName[];
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 7dbfa90bf4971f2739448d370a8fdce3f8d766d1..42a3fc862e9665e1e4f5af66353ee73b3434a81a 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -497,6 +497,9 @@
 /* Define to 1 if you have the `strlcpy' function. */
 #undef HAVE_STRLCPY
 
+/* Define to use have a strong random number source */
+#undef HAVE_STRONG_RANDOM
+
 /* Define to 1 if you have the `strtoll' function. */
 #undef HAVE_STRTOLL
 
@@ -814,6 +817,9 @@
 /* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */
 #undef USE_BSD_AUTH
 
+/* Define to use /dev/urandom for random number generation */
+#undef USE_DEV_URANDOM
+
 /* Define to 1 if you want float4 values to be passed by value.
    (--enable-float4-byval) */
 #undef USE_FLOAT4_BYVAL
@@ -842,6 +848,9 @@
 /* Define to build with OpenSSL support. (--with-openssl) */
 #undef USE_OPENSSL
 
+/* Define to use OpenSSL for random number generation */
+#undef USE_OPENSSL_RANDOM
+
 /* Define to 1 to build with PAM support. (--with-pam) */
 #undef USE_PAM
 
@@ -869,6 +878,9 @@
 /* Define to select unnamed POSIX semaphores. */
 #undef USE_UNNAMED_POSIX_SEMAPHORES
 
+/* Define to use native Windows API for random number generation */
+#undef USE_WIN32_RANDOM
+
 /* Define to select Win32-style semaphores. */
 #undef USE_WIN32_SEMAPHORES
 
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 8892c3cb4fa453b614cdc5a35db202952d5072e9..ceb8b7956eee08d40aa105a6cb4ddaa2b84369dc 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -348,6 +348,9 @@
 /* Define to 1 if you have the <string.h> header file. */
 #define HAVE_STRING_H 1
 
+/* Define to use have a strong random number source */
+#define HAVE_STRONG_RANDOM 1
+
 /* Define to 1 if you have the `strtoll' function. */
 //#define HAVE_STRTOLL 1
 
@@ -616,6 +619,9 @@
 /* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */
 /* #undef USE_BSD_AUTH */
 
+/* Define to use /dev/urandom for random number generation */
+/* #undef USE_DEV_URANDOM */
+
 /* Define to 1 if you want 64-bit integer timestamp and interval support.
    (--enable-integer-datetimes) */
 /* #undef USE_INTEGER_DATETIMES */
@@ -629,6 +635,9 @@
 /* Define to build with OpenSSL support. (--with-openssl) */
 /* #undef USE_OPENSSL */
 
+/* Define to use OpenSSL for random number generation */
+/* #undef USE_OPENSSL_RANDOM */
+
 /* Define to 1 to build with PAM support. (--with-pam) */
 /* #undef USE_PAM */
 
@@ -657,6 +666,9 @@
 /* Define to select unnamed POSIX semaphores. */
 /* #undef USE_UNNAMED_POSIX_SEMAPHORES */
 
+/* Define to use native Windows API for random number generation */
+#define USE_WIN32_RANDOM 1
+
 /* Define to select Win32-style semaphores. */
 #define USE_WIN32_SEMAPHORES 1
 
diff --git a/src/include/port.h b/src/include/port.h
index 8a63958535b39963cfc410ac1cfede1c5b215468..f2b9882b7b76ccdd94a5fc5f08da72014ea4c9d4 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -361,6 +361,7 @@ extern off_t ftello(FILE *stream);
 
 extern double pg_erand48(unsigned short xseed[3]);
 extern long pg_lrand48(void);
+extern long pg_jrand48(unsigned short xseed[3]);
 extern void pg_srand48(long seed);
 
 #ifndef HAVE_FLS
@@ -454,6 +455,11 @@ extern int	pg_codepage_to_encoding(UINT cp);
 extern char *inet_net_ntop(int af, const void *src, int bits,
 			  char *dst, size_t size);
 
+/* port/pg_strong_random.c */
+#ifdef HAVE_STRONG_RANDOM
+extern bool pg_strong_random(void *buf, size_t len);
+#endif
+
 /* port/pgcheckdir.c */
 extern int	pg_check_dir(const char *dir);
 
diff --git a/src/include/utils/backend_random.h b/src/include/utils/backend_random.h
new file mode 100644
index 0000000000000000000000000000000000000000..16a6a26523deb3f39224606497aa9cbb91c89cb7
--- /dev/null
+++ b/src/include/utils/backend_random.h
@@ -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 */
diff --git a/src/port/Makefile b/src/port/Makefile
index bc9b63add0479459d146550c0338e1a22a478400..81f01b25bbc6949df930de17a198107282ccd375 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -35,6 +35,10 @@ OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
 	pgstrcasecmp.o pqsignal.o \
 	qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
 
+ifeq ($(enable_strong_random), yes)
+OBJS += pg_strong_random.o
+endif
+
 # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
 OBJS_SRV = $(OBJS:%.o=%_srv.o)
 
diff --git a/src/port/erand48.c b/src/port/erand48.c
index 9d471197c354056c8903a5a9e1c6b0023419f1d1..716816bc361ba3ee5e89822e2c8c59a6b4fdf959 100644
--- a/src/port/erand48.c
+++ b/src/port/erand48.c
@@ -91,6 +91,13 @@ pg_lrand48(void)
 	return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
 }
 
+long
+pg_jrand48(unsigned short xseed[3])
+{
+	_dorand48(xseed);
+	return ((long) xseed[2] << 16) + ((long) xseed[1]);
+}
+
 void
 pg_srand48(long seed)
 {
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
new file mode 100644
index 0000000000000000000000000000000000000000..6d3aa38efdd3d63990bb0a68f65af8adc9f16e73
--- /dev/null
+++ b/src/port/pg_strong_random.c
@@ -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
+}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index de764dd4d44b28a37e18357f1ce99544a43cceff..db566f9c88ca69157a48c53143dadf246e994770 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -91,8 +91,8 @@ sub mkvcbuild
 	  chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
 	  srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
 	  erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
-	  pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
-	  mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
+	  pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
+	  pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
 	  sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
 	  win32env.c win32error.c win32security.c win32setlocale.c);
 
@@ -425,7 +425,6 @@ sub mkvcbuild
 			'sha1.c',             'sha2.c',
 			'internal.c',         'internal-sha2.c',
 			'blf.c',              'rijndael.c',
-			'fortuna.c',          'random.c',
 			'pgp-mpi-internal.c', 'imath.c');
 	}
 	$pgcrypto->AddReference($postgres);