diff --git a/contrib/pgcrypto/crypt-blowfish.c b/contrib/pgcrypto/crypt-blowfish.c
index fbaa3d776a08fb439158ddb41cde4c67f73079b8..4054e6a06fc758e2bd388080ee0b6aeb523de42e 100644
--- a/contrib/pgcrypto/crypt-blowfish.c
+++ b/contrib/pgcrypto/crypt-blowfish.c
@@ -602,6 +602,17 @@ _crypt_blowfish_rn(const char *key, const char *setting,
 	if (size < 7 + 22 + 31 + 1)
 		return NULL;
 
+	/*
+	 * Blowfish salt value must be formatted as follows: "$2a$" or "$2x$", a
+	 * two digit cost parameter, "$", and 22 digits from the alphabet
+	 * "./0-9A-Za-z". -- from the PHP crypt docs. Apparently we enforce a few
+	 * more restrictions on the count in the salt as well.
+	 */
+	if (strlen(setting) < 29)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid salt")));
+
 	if (setting[0] != '$' ||
 		setting[1] != '2' ||
 		(setting[2] != 'a' && setting[2] != 'x') ||
@@ -611,14 +622,18 @@ _crypt_blowfish_rn(const char *key, const char *setting,
 		(setting[4] == '3' && setting[5] > '1') ||
 		setting[6] != '$')
 	{
-		return NULL;
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid salt")));
 	}
 
 	count = (BF_word) 1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
 	if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16))
 	{
 		px_memset(data.binary.salt, 0, sizeof(data.binary.salt));
-		return NULL;
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid salt")));
 	}
 	BF_swap(data.binary.salt, 4);
 
diff --git a/contrib/pgcrypto/crypt-des.c b/contrib/pgcrypto/crypt-des.c
index 4ed44beeff51707a2ca1b86842bbca7da4e5b647..2108be8c379b3de74042ff0dc4f71b56557fc782 100644
--- a/contrib/pgcrypto/crypt-des.c
+++ b/contrib/pgcrypto/crypt-des.c
@@ -681,9 +681,19 @@ px_crypt_des(const char *key, const char *setting)
 	if (*setting == _PASSWORD_EFMT1)
 	{
 		/*
-		 * "new"-style: setting - underscore, 4 bytes of count, 4 bytes of
-		 * salt key - unlimited characters
+		 * "new"-style: setting must be a 9-character (underscore, then 4
+		 * bytes of count, then 4 bytes of salt) string. See CRYPT(3) under
+		 * the "Extended crypt" heading for further details.
+		 *
+		 * Unlimited characters of the input key are used. This is known as
+		 * the "Extended crypt" DES method.
+		 *
 		 */
+		if (strlen(setting) < 9)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("invalid salt")));
+
 		for (i = 1, count = 0L; i < 5; i++)
 			count |= ascii_to_bin(setting[i]) << (i - 1) * 6;
 
@@ -723,10 +733,16 @@ px_crypt_des(const char *key, const char *setting)
 #endif   /* !DISABLE_XDES */
 	{
 		/*
-		 * "old"-style: setting - 2 bytes of salt key - up to 8 characters
+		 * "old"-style: setting - 2 bytes of salt key - only up to the first 8
+		 * characters of the input key are used.
 		 */
 		count = 25;
 
+		if (strlen(setting) < 2)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("invalid salt")));
+
 		salt = (ascii_to_bin(setting[1]) << 6)
 			| ascii_to_bin(setting[0]);
 
diff --git a/contrib/pgcrypto/expected/crypt-blowfish.out b/contrib/pgcrypto/expected/crypt-blowfish.out
index 329d78f6254621d3e1dedfe86afb8c0b18a03f3d..d79b0c047b4c77a0312acbb517c869959a6e67a7 100644
--- a/contrib/pgcrypto/expected/crypt-blowfish.out
+++ b/contrib/pgcrypto/expected/crypt-blowfish.out
@@ -13,6 +13,15 @@ SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
  $2a$06$RQiOJ.3ELirrXwxIZY8q0OR3CVJrAfda1z26CCHPnB6mmVZD8p0/C
 (1 row)
 
+-- error, salt too short:
+SELECT crypt('foox', '$2a$');
+ERROR:  invalid salt
+-- error, first digit of count in salt invalid
+SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O');
+ERROR:  invalid salt
+-- error, count in salt too small
+SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O');
+ERROR:  invalid salt
 CREATE TABLE ctest (data text, res text, salt text);
 INSERT INTO ctest VALUES ('password', '', '');
 UPDATE ctest SET salt = gen_salt('bf', 8);
diff --git a/contrib/pgcrypto/expected/crypt-des.out b/contrib/pgcrypto/expected/crypt-des.out
index b8b605037d48b1b35fcda93fe66a735aa06122bc..a462dcd580a896295e8f298b752333236154db17 100644
--- a/contrib/pgcrypto/expected/crypt-des.out
+++ b/contrib/pgcrypto/expected/crypt-des.out
@@ -13,6 +13,10 @@ SELECT crypt('foox', 'NB');
  NB53EGGqrrb5E
 (1 row)
 
+-- We are supposed to pass in a 2-character salt.
+-- error since salt is too short:
+SELECT crypt('password', 'a');
+ERROR:  invalid salt
 CREATE TABLE ctest (data text, res text, salt text);
 INSERT INTO ctest VALUES ('password', '', '');
 UPDATE ctest SET salt = gen_salt('des');
diff --git a/contrib/pgcrypto/expected/crypt-xdes.out b/contrib/pgcrypto/expected/crypt-xdes.out
index cdcdefb1996997f4a7f9b54f3efef46acd20b219..8cf907512f6f7fbbc219788b5fbb862774ac5707 100644
--- a/contrib/pgcrypto/expected/crypt-xdes.out
+++ b/contrib/pgcrypto/expected/crypt-xdes.out
@@ -13,6 +13,30 @@ SELECT crypt('foox', '_J9..j2zz');
  _J9..j2zzAYKMvO2BYRY
 (1 row)
 
+-- check XDES handling of keys longer than 8 chars
+SELECT crypt('longlongpassword', '_J9..j2zz');
+        crypt         
+----------------------
+ _J9..j2zz4BeseiQNwUg
+(1 row)
+
+-- error, salt too short
+SELECT crypt('foox', '_J9..BWH');
+ERROR:  invalid salt
+-- error, count specified in the second argument is 0
+SELECT crypt('password', '_........');
+ERROR:  crypt(3) returned NULL
+-- error, count will wind up still being 0 due to invalid encoding
+-- of the count: only chars ``./0-9A-Za-z' are valid
+SELECT crypt('password', '_..!!!!!!');
+ERROR:  crypt(3) returned NULL
+-- count should be non-zero here, will work
+SELECT crypt('password', '_/!!!!!!!');
+        crypt         
+----------------------
+ _/!!!!!!!zqM49hRzxko
+(1 row)
+
 CREATE TABLE ctest (data text, res text, salt text);
 INSERT INTO ctest VALUES ('password', '', '');
 UPDATE ctest SET salt = gen_salt('xdes', 1001);
diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c
index 7b003a76ca663bd418ac858d0a6e7680325e87c8..e3246fc5b9d5f4194735eeefd0f013db9272acff 100644
--- a/contrib/pgcrypto/px-crypt.c
+++ b/contrib/pgcrypto/px-crypt.c
@@ -42,7 +42,7 @@ run_crypt_des(const char *psw, const char *salt,
 	char	   *res;
 
 	res = px_crypt_des(psw, salt);
-	if (strlen(res) > len - 1)
+	if (res == NULL || strlen(res) > len - 1)
 		return NULL;
 	strcpy(buf, res);
 	return buf;
diff --git a/contrib/pgcrypto/sql/crypt-blowfish.sql b/contrib/pgcrypto/sql/crypt-blowfish.sql
index 60c114005552093ba07c83d79a63fc96a3f87aa6..3b5a681c3f5cd56d5376f4a56f466fcc110f7f24 100644
--- a/contrib/pgcrypto/sql/crypt-blowfish.sql
+++ b/contrib/pgcrypto/sql/crypt-blowfish.sql
@@ -6,6 +6,15 @@ SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
 
 SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
 
+-- error, salt too short:
+SELECT crypt('foox', '$2a$');
+
+-- error, first digit of count in salt invalid
+SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O');
+
+-- error, count in salt too small
+SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O');
+
 CREATE TABLE ctest (data text, res text, salt text);
 INSERT INTO ctest VALUES ('password', '', '');
 
diff --git a/contrib/pgcrypto/sql/crypt-des.sql b/contrib/pgcrypto/sql/crypt-des.sql
index fabdc652fc986808dc6a7c3a0d5dc21ed31ac7b0..a85ec1e655510d8d66e7f6f478ce63e7375e25c9 100644
--- a/contrib/pgcrypto/sql/crypt-des.sql
+++ b/contrib/pgcrypto/sql/crypt-des.sql
@@ -6,6 +6,10 @@ SELECT crypt('', 'NB');
 
 SELECT crypt('foox', 'NB');
 
+-- We are supposed to pass in a 2-character salt.
+-- error since salt is too short:
+SELECT crypt('password', 'a');
+
 CREATE TABLE ctest (data text, res text, salt text);
 INSERT INTO ctest VALUES ('password', '', '');
 
diff --git a/contrib/pgcrypto/sql/crypt-xdes.sql b/contrib/pgcrypto/sql/crypt-xdes.sql
index d4a74f76bde5276b2474a443a04d5e5e34caa602..8171cd872be21e128ca7343979b2cb8400901400 100644
--- a/contrib/pgcrypto/sql/crypt-xdes.sql
+++ b/contrib/pgcrypto/sql/crypt-xdes.sql
@@ -6,6 +6,22 @@ SELECT crypt('', '_J9..j2zz');
 
 SELECT crypt('foox', '_J9..j2zz');
 
+-- check XDES handling of keys longer than 8 chars
+SELECT crypt('longlongpassword', '_J9..j2zz');
+
+-- error, salt too short
+SELECT crypt('foox', '_J9..BWH');
+
+-- error, count specified in the second argument is 0
+SELECT crypt('password', '_........');
+
+-- error, count will wind up still being 0 due to invalid encoding
+-- of the count: only chars ``./0-9A-Za-z' are valid
+SELECT crypt('password', '_..!!!!!!');
+
+-- count should be non-zero here, will work
+SELECT crypt('password', '_/!!!!!!!');
+
 CREATE TABLE ctest (data text, res text, salt text);
 INSERT INTO ctest VALUES ('password', '', '');