On Fri, Nov 06, 2020 at 04:34:34PM +0900, Michael Paquier wrote:
> The attached patch set does a bit of rework to make the Postgres code
> more consistent with OpenSSL, similarly to the work I did for all the
> SHA2 implementations with EVP in [1]:
> - 0001 is something stolen from the SHA2 set, adding to resowner.c
> control of EVP contexts, so as it is possible to clean up anything
> allocated by OpenSSL.
> - 0002 is the central piece, that moves the duplicated
> implementation.  src/common/ and pgcrypto/ use the same code, but I
> have reused pgcrypto as it was already doing the init/update/final
> split similarly to PostgreSQL.  New APIs are designed to control MD5
> contexts, similarly to the work done for SHA2.  Upon using this patch,
> note that pgcrypto+OpenSSL uses our in-core implementation instead of
> OpenSSL's one, but that's fixed in 0003.  We have a set of three
> convenience routines used to generate MD5-hashed passwords, that I
> have moved to a new file in src/common/md5_common.c, aimed at being
> shared between all the implementations.
> - 0003 adds the MD5 implementation based on OpenSSL's EVP, ending the
> work.

The CF bot has been complaining on Windows and this issue is fixed in
the attached.  A refresh of src/tools/msvc for pgcrypto was just
missing.
--
Michael
From f81ff379f10bb18cb2a44607262d0f27050afc3e Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Thu, 5 Nov 2020 15:53:00 +0900
Subject: [PATCH v2 1/3] Add APIs to control EVP contexts for resource owners

This will be used by a set of upcoming patches for EVP contexts with
SHA2 and MD5.
---
 src/include/utils/resowner_private.h  |  7 +++
 src/backend/utils/resowner/resowner.c | 65 +++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h
index a781a7a2aa..5ce6fcf882 100644
--- a/src/include/utils/resowner_private.h
+++ b/src/include/utils/resowner_private.h
@@ -95,4 +95,11 @@ extern void ResourceOwnerRememberJIT(ResourceOwner owner,
 extern void ResourceOwnerForgetJIT(ResourceOwner owner,
 								   Datum handle);
 
+/* support for EVP context management */
+extern void ResourceOwnerEnlargeEVP(ResourceOwner owner);
+extern void ResourceOwnerRememberEVP(ResourceOwner owner,
+									 Datum handle);
+extern void ResourceOwnerForgetEVP(ResourceOwner owner,
+								   Datum handle);
+
 #endif							/* RESOWNER_PRIVATE_H */
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index 8bc2c4e9ea..1efb5e98b4 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -20,6 +20,10 @@
  */
 #include "postgres.h"
 
+#ifdef USE_OPENSSL
+#include <openssl/evp.h>
+#endif
+
 #include "common/hashfn.h"
 #include "jit/jit.h"
 #include "storage/bufmgr.h"
@@ -128,6 +132,7 @@ typedef struct ResourceOwnerData
 	ResourceArray filearr;		/* open temporary files */
 	ResourceArray dsmarr;		/* dynamic shmem segments */
 	ResourceArray jitarr;		/* JIT contexts */
+	ResourceArray evparr;		/* EVP contexts */
 
 	/* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
 	int			nlocks;			/* number of owned locks */
@@ -175,6 +180,7 @@ static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
 static void PrintSnapshotLeakWarning(Snapshot snapshot);
 static void PrintFileLeakWarning(File file);
 static void PrintDSMLeakWarning(dsm_segment *seg);
+static void PrintEVPLeakWarning(Datum handle);
 
 
 /*****************************************************************************
@@ -444,6 +450,7 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name)
 	ResourceArrayInit(&(owner->filearr), FileGetDatum(-1));
 	ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
 	ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->evparr), PointerGetDatum(NULL));
 
 	return owner;
 }
@@ -553,6 +560,17 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
 
 			jit_release_context(context);
 		}
+
+		/* Ditto for EVP contexts */
+		while (ResourceArrayGetAny(&(owner->evparr), &foundres))
+		{
+			if (isCommit)
+				PrintEVPLeakWarning(foundres);
+#ifdef USE_OPENSSL
+			EVP_MD_CTX_destroy((EVP_MD_CTX *) DatumGetPointer(foundres));
+#endif
+			ResourceOwnerForgetEVP(owner, foundres);
+		}
 	}
 	else if (phase == RESOURCE_RELEASE_LOCKS)
 	{
@@ -725,6 +743,7 @@ ResourceOwnerDelete(ResourceOwner owner)
 	Assert(owner->filearr.nitems == 0);
 	Assert(owner->dsmarr.nitems == 0);
 	Assert(owner->jitarr.nitems == 0);
+	Assert(owner->evparr.nitems == 0);
 	Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
 
 	/*
@@ -752,6 +771,7 @@ ResourceOwnerDelete(ResourceOwner owner)
 	ResourceArrayFree(&(owner->filearr));
 	ResourceArrayFree(&(owner->dsmarr));
 	ResourceArrayFree(&(owner->jitarr));
+	ResourceArrayFree(&(owner->evparr));
 
 	pfree(owner);
 }
@@ -1370,3 +1390,48 @@ ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
 		elog(ERROR, "JIT context %p is not owned by resource owner %s",
 			 DatumGetPointer(handle), owner->name);
 }
+
+/*
+ * Make sure there is room for at least one more entry in a ResourceOwner's
+ * EVP context reference array.
+ *
+ * This is separate from actually inserting an entry because if we run out of
+ * memory, it's critical to do so *before* acquiring the resource.
+ */
+void
+ResourceOwnerEnlargeEVP(ResourceOwner owner)
+{
+	ResourceArrayEnlarge(&(owner->evparr));
+}
+
+/*
+ * Remember that an EVP context is owned by a ResourceOwner
+ *
+ * Caller must have previously done ResourceOwnerEnlargeEVP()
+ */
+void
+ResourceOwnerRememberEVP(ResourceOwner owner, Datum handle)
+{
+	ResourceArrayAdd(&(owner->evparr), handle);
+}
+
+/*
+ * Forget that an EVP context is owned by a ResourceOwner
+ */
+void
+ResourceOwnerForgetEVP(ResourceOwner owner, Datum handle)
+{
+	if (!ResourceArrayRemove(&(owner->evparr), handle))
+		elog(ERROR, "EVP context %p is not owned by resource owner %s",
+			 DatumGetPointer(handle), owner->name);
+}
+
+/*
+ * Debugging subroutine
+ */
+static void
+PrintEVPLeakWarning(Datum handle)
+{
+	elog(WARNING, "EVP context reference leak: context %p still referenced",
+		 DatumGetPointer(handle));
+}
-- 
2.29.2

From 53e99eceefdc240ae8e8921b5da7e0c5c4eceb54 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Tue, 10 Nov 2020 13:23:03 +0900
Subject: [PATCH v2 2/3] Refactor MD5 implementations in the tree

This removes the duplicated MD5 implementations present in both
src/common/ and contrib/pgcrypto/, reworking the MD5 interface to be
similar to what OpenSSL provides.  This will ease the work of a
follow-up patch to make Postgres use OpenSSL EVP for MD5.

The original APIs used for MD5-hashed passwords are moved to a separate
file called md5_common.c, aimed at being shared between all MD5
implementations.
---
 src/include/common/md5.h    |  13 +-
 src/common/Makefile         |   1 +
 src/common/md5.c            | 719 ++++++++++++++++++++++--------------
 src/common/md5_common.c     | 144 ++++++++
 contrib/pgcrypto/Makefile   |   2 +-
 contrib/pgcrypto/internal.c |  24 +-
 contrib/pgcrypto/md5.c      | 397 --------------------
 contrib/pgcrypto/md5.h      |  79 ----
 src/tools/msvc/Mkvcbuild.pm |  11 +-
 9 files changed, 619 insertions(+), 771 deletions(-)
 create mode 100644 src/common/md5_common.c
 delete mode 100644 contrib/pgcrypto/md5.c
 delete mode 100644 contrib/pgcrypto/md5.h

diff --git a/src/include/common/md5.h b/src/include/common/md5.h
index 8695f10dff..7cd1eec559 100644
--- a/src/include/common/md5.h
+++ b/src/include/common/md5.h
@@ -1,10 +1,8 @@
 /*-------------------------------------------------------------------------
  *
  * md5.h
- *	  Interface to libpq/md5.c
+ *	  Interface to common/md5.c
  *
- * These definitions are needed by both frontend and backend code to work
- * with MD5-encrypted passwords.
  *
  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
@@ -19,6 +17,15 @@
 #define MD5_PASSWD_CHARSET	"0123456789abcdef"
 #define MD5_PASSWD_LEN	35
 
+/* Interface for MD5 implementations */
+extern void *pg_md5_create(void);
+extern void pg_md5_free(void *ctx);
+/* These return 0 on success, or -1 on failure */
+extern int pg_md5_init(void *ctx);
+extern int pg_md5_update(void *ctx, const uint8 *data, size_t len);
+extern int pg_md5_final(void *ctx, uint8 *dest);
+
+/* Utilities common to all the implementations, as of md5_common.c */
 extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum);
 extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf);
 extern bool pg_md5_encrypt(const char *passwd, const char *salt,
diff --git a/src/common/Makefile b/src/common/Makefile
index 25c55bd642..69de65fab5 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -64,6 +64,7 @@ OBJS_COMMON = \
 	kwlookup.o \
 	link-canary.o \
 	md5.o \
+	md5_common.o \
 	pg_get_line.o \
 	pg_lzcompress.o \
 	pgfnames.o \
diff --git a/src/common/md5.c b/src/common/md5.c
index 5f790c6800..5b4b2d155e 100644
--- a/src/common/md5.c
+++ b/src/common/md5.c
@@ -17,6 +17,37 @@
  *	  src/common/md5.c
  */
 
+/*    $KAME: md5.c,v 1.3 2000/02/22 14:01:17 itojun Exp $     */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ */
+
 #ifndef FRONTEND
 #include "postgres.h"
 #else
@@ -25,324 +56,466 @@
 
 #include "common/md5.h"
 
-
 /*
- *	PRIVATE FUNCTIONS
+ * In backend, use palloc/pfree to ease the error handling.  In frontend,
+ * use malloc to be able to return a failure status back to the caller.
  */
+#ifndef FRONTEND
+#define ALLOC(size) palloc(size)
+#define FREE(ptr) pfree(ptr)
+#else
+#define ALLOC(size) malloc(size)
+#define FREE(ptr) free(ptr)
+#endif
 
+#define MD5_BUFLEN 64
 
-/*
- *	The returned array is allocated using malloc.  the caller should free it
- *	when it is no longer needed.
- */
-static uint8 *
-createPaddedCopyWithLength(const uint8 *b, uint32 *l)
+/* internal context data for MD5 */
+typedef struct
 {
-	uint8	   *ret;
-	uint32		q;
-	uint32		len,
-				newLen448;
-	uint32		len_high,
-				len_low;		/* 64-bit value split into 32-bit sections */
+	union
+	{
+		uint32      md5_state32[4];
+		uint8       md5_state8[16];
+	} md5_st;
 
-	len = ((b == NULL) ? 0 : *l);
-	newLen448 = len + 64 - (len % 64) - 8;
-	if (newLen448 <= len)
-		newLen448 += 64;
+#define md5_sta     md5_st.md5_state32[0]
+#define md5_stb     md5_st.md5_state32[1]
+#define md5_stc     md5_st.md5_state32[2]
+#define md5_std     md5_st.md5_state32[3]
+#define md5_st8     md5_st.md5_state8
 
-	*l = newLen448 + 8;
-	if ((ret = (uint8 *) malloc(sizeof(uint8) * *l)) == NULL)
-		return NULL;
+	union
+	{
+		uint64      md5_count64;
+		uint8       md5_count8[8];
+	} md5_count;
+#define md5_n   md5_count.md5_count64
+#define md5_n8  md5_count.md5_count8
 
-	if (b != NULL)
-		memcpy(ret, b, sizeof(uint8) * len);
+	unsigned int md5_i;
+	uint8       md5_buf[MD5_BUFLEN];
+} md5_ctxt;
 
-	/* pad */
-	ret[len] = 0x80;
-	for (q = len + 1; q < newLen448; q++)
-		ret[q] = 0x00;
+#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
 
-	/* append length as a 64 bit bitcount */
-	len_low = len;
-	/* split into two 32-bit values */
-	/* we only look at the bottom 32-bits */
-	len_high = len >> 29;
-	len_low <<= 3;
-	q = newLen448;
-	ret[q++] = (len_low & 0xff);
-	len_low >>= 8;
-	ret[q++] = (len_low & 0xff);
-	len_low >>= 8;
-	ret[q++] = (len_low & 0xff);
-	len_low >>= 8;
-	ret[q++] = (len_low & 0xff);
-	ret[q++] = (len_high & 0xff);
-	len_high >>= 8;
-	ret[q++] = (len_high & 0xff);
-	len_high >>= 8;
-	ret[q++] = (len_high & 0xff);
-	len_high >>= 8;
-	ret[q] = (len_high & 0xff);
+#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
+#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
+#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
+#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
 
-	return ret;
-}
+#define ROUND1(a, b, c, d, k, s, i) \
+do { \
+	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
+	(a) = SHIFT((a), (s)); \
+	(a) = (b) + (a); \
+} while (0)
 
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define ROT_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define ROUND2(a, b, c, d, k, s, i) \
+do { \
+	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
+	(a) = SHIFT((a), (s)); \
+	(a) = (b) + (a); \
+} while (0)
+
+#define ROUND3(a, b, c, d, k, s, i) \
+do { \
+	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
+	(a) = SHIFT((a), (s)); \
+	(a) = (b) + (a); \
+} while (0)
+
+#define ROUND4(a, b, c, d, k, s, i) \
+do { \
+	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
+	(a) = SHIFT((a), (s)); \
+	(a) = (b) + (a); \
+} while (0)
+
+#define Sa	 7
+#define Sb	12
+#define Sc	17
+#define Sd	22
+
+#define Se	 5
+#define Sf	 9
+#define Sg	14
+#define Sh	20
+
+#define Si	 4
+#define Sj	11
+#define Sk	16
+#define Sl	23
+
+#define Sm	 6
+#define Sn	10
+#define So	15
+#define Sp	21
+
+#define MD5_A0	0x67452301
+#define MD5_B0	0xefcdab89
+#define MD5_C0	0x98badcfe
+#define MD5_D0	0x10325476
+
+/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
+static const uint32 T[65] = {
+	0,
+	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+
+	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+	0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+
+	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+
+	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+};
+
+static const uint8 md5_paddat[MD5_BUFLEN] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+#ifdef WORDS_BIGENDIAN
+static uint32 X[16];
+#endif
 
 static void
-doTheRounds(uint32 X[16], uint32 state[4])
+md5_calc(const uint8 *b64, md5_ctxt *ctxt)
 {
-	uint32		a,
-				b,
-				c,
-				d;
+	uint32		A = ctxt->md5_sta;
+	uint32		B = ctxt->md5_stb;
+	uint32		C = ctxt->md5_stc;
+	uint32		D = ctxt->md5_std;
 
-	a = state[0];
-	b = state[1];
-	c = state[2];
-	d = state[3];
+#ifndef WORDS_BIGENDIAN
+	const uint32 *X = (const uint32 *) b64;
+#else
+	/* 4 byte words */
+	/* what a brute force but fast! */
+	uint8	   *y = (uint8 *) X;
 
-	/* round 1 */
-	a = b + ROT_LEFT((a + F(b, c, d) + X[0] + 0xd76aa478), 7);	/* 1 */
-	d = a + ROT_LEFT((d + F(a, b, c) + X[1] + 0xe8c7b756), 12); /* 2 */
-	c = d + ROT_LEFT((c + F(d, a, b) + X[2] + 0x242070db), 17); /* 3 */
-	b = c + ROT_LEFT((b + F(c, d, a) + X[3] + 0xc1bdceee), 22); /* 4 */
-	a = b + ROT_LEFT((a + F(b, c, d) + X[4] + 0xf57c0faf), 7);	/* 5 */
-	d = a + ROT_LEFT((d + F(a, b, c) + X[5] + 0x4787c62a), 12); /* 6 */
-	c = d + ROT_LEFT((c + F(d, a, b) + X[6] + 0xa8304613), 17); /* 7 */
-	b = c + ROT_LEFT((b + F(c, d, a) + X[7] + 0xfd469501), 22); /* 8 */
-	a = b + ROT_LEFT((a + F(b, c, d) + X[8] + 0x698098d8), 7);	/* 9 */
-	d = a + ROT_LEFT((d + F(a, b, c) + X[9] + 0x8b44f7af), 12); /* 10 */
-	c = d + ROT_LEFT((c + F(d, a, b) + X[10] + 0xffff5bb1), 17);	/* 11 */
-	b = c + ROT_LEFT((b + F(c, d, a) + X[11] + 0x895cd7be), 22);	/* 12 */
-	a = b + ROT_LEFT((a + F(b, c, d) + X[12] + 0x6b901122), 7); /* 13 */
-	d = a + ROT_LEFT((d + F(a, b, c) + X[13] + 0xfd987193), 12);	/* 14 */
-	c = d + ROT_LEFT((c + F(d, a, b) + X[14] + 0xa679438e), 17);	/* 15 */
-	b = c + ROT_LEFT((b + F(c, d, a) + X[15] + 0x49b40821), 22);	/* 16 */
+	y[0] = b64[3];
+	y[1] = b64[2];
+	y[2] = b64[1];
+	y[3] = b64[0];
+	y[4] = b64[7];
+	y[5] = b64[6];
+	y[6] = b64[5];
+	y[7] = b64[4];
+	y[8] = b64[11];
+	y[9] = b64[10];
+	y[10] = b64[9];
+	y[11] = b64[8];
+	y[12] = b64[15];
+	y[13] = b64[14];
+	y[14] = b64[13];
+	y[15] = b64[12];
+	y[16] = b64[19];
+	y[17] = b64[18];
+	y[18] = b64[17];
+	y[19] = b64[16];
+	y[20] = b64[23];
+	y[21] = b64[22];
+	y[22] = b64[21];
+	y[23] = b64[20];
+	y[24] = b64[27];
+	y[25] = b64[26];
+	y[26] = b64[25];
+	y[27] = b64[24];
+	y[28] = b64[31];
+	y[29] = b64[30];
+	y[30] = b64[29];
+	y[31] = b64[28];
+	y[32] = b64[35];
+	y[33] = b64[34];
+	y[34] = b64[33];
+	y[35] = b64[32];
+	y[36] = b64[39];
+	y[37] = b64[38];
+	y[38] = b64[37];
+	y[39] = b64[36];
+	y[40] = b64[43];
+	y[41] = b64[42];
+	y[42] = b64[41];
+	y[43] = b64[40];
+	y[44] = b64[47];
+	y[45] = b64[46];
+	y[46] = b64[45];
+	y[47] = b64[44];
+	y[48] = b64[51];
+	y[49] = b64[50];
+	y[50] = b64[49];
+	y[51] = b64[48];
+	y[52] = b64[55];
+	y[53] = b64[54];
+	y[54] = b64[53];
+	y[55] = b64[52];
+	y[56] = b64[59];
+	y[57] = b64[58];
+	y[58] = b64[57];
+	y[59] = b64[56];
+	y[60] = b64[63];
+	y[61] = b64[62];
+	y[62] = b64[61];
+	y[63] = b64[60];
+#endif
 
-	/* round 2 */
-	a = b + ROT_LEFT((a + G(b, c, d) + X[1] + 0xf61e2562), 5);	/* 17 */
-	d = a + ROT_LEFT((d + G(a, b, c) + X[6] + 0xc040b340), 9);	/* 18 */
-	c = d + ROT_LEFT((c + G(d, a, b) + X[11] + 0x265e5a51), 14);	/* 19 */
-	b = c + ROT_LEFT((b + G(c, d, a) + X[0] + 0xe9b6c7aa), 20); /* 20 */
-	a = b + ROT_LEFT((a + G(b, c, d) + X[5] + 0xd62f105d), 5);	/* 21 */
-	d = a + ROT_LEFT((d + G(a, b, c) + X[10] + 0x02441453), 9); /* 22 */
-	c = d + ROT_LEFT((c + G(d, a, b) + X[15] + 0xd8a1e681), 14);	/* 23 */
-	b = c + ROT_LEFT((b + G(c, d, a) + X[4] + 0xe7d3fbc8), 20); /* 24 */
-	a = b + ROT_LEFT((a + G(b, c, d) + X[9] + 0x21e1cde6), 5);	/* 25 */
-	d = a + ROT_LEFT((d + G(a, b, c) + X[14] + 0xc33707d6), 9); /* 26 */
-	c = d + ROT_LEFT((c + G(d, a, b) + X[3] + 0xf4d50d87), 14); /* 27 */
-	b = c + ROT_LEFT((b + G(c, d, a) + X[8] + 0x455a14ed), 20); /* 28 */
-	a = b + ROT_LEFT((a + G(b, c, d) + X[13] + 0xa9e3e905), 5); /* 29 */
-	d = a + ROT_LEFT((d + G(a, b, c) + X[2] + 0xfcefa3f8), 9);	/* 30 */
-	c = d + ROT_LEFT((c + G(d, a, b) + X[7] + 0x676f02d9), 14); /* 31 */
-	b = c + ROT_LEFT((b + G(c, d, a) + X[12] + 0x8d2a4c8a), 20);	/* 32 */
+	ROUND1(A, B, C, D, 0, Sa, 1);
+	ROUND1(D, A, B, C, 1, Sb, 2);
+	ROUND1(C, D, A, B, 2, Sc, 3);
+	ROUND1(B, C, D, A, 3, Sd, 4);
+	ROUND1(A, B, C, D, 4, Sa, 5);
+	ROUND1(D, A, B, C, 5, Sb, 6);
+	ROUND1(C, D, A, B, 6, Sc, 7);
+	ROUND1(B, C, D, A, 7, Sd, 8);
+	ROUND1(A, B, C, D, 8, Sa, 9);
+	ROUND1(D, A, B, C, 9, Sb, 10);
+	ROUND1(C, D, A, B, 10, Sc, 11);
+	ROUND1(B, C, D, A, 11, Sd, 12);
+	ROUND1(A, B, C, D, 12, Sa, 13);
+	ROUND1(D, A, B, C, 13, Sb, 14);
+	ROUND1(C, D, A, B, 14, Sc, 15);
+	ROUND1(B, C, D, A, 15, Sd, 16);
 
-	/* round 3 */
-	a = b + ROT_LEFT((a + H(b, c, d) + X[5] + 0xfffa3942), 4);	/* 33 */
-	d = a + ROT_LEFT((d + H(a, b, c) + X[8] + 0x8771f681), 11); /* 34 */
-	c = d + ROT_LEFT((c + H(d, a, b) + X[11] + 0x6d9d6122), 16);	/* 35 */
-	b = c + ROT_LEFT((b + H(c, d, a) + X[14] + 0xfde5380c), 23);	/* 36 */
-	a = b + ROT_LEFT((a + H(b, c, d) + X[1] + 0xa4beea44), 4);	/* 37 */
-	d = a + ROT_LEFT((d + H(a, b, c) + X[4] + 0x4bdecfa9), 11); /* 38 */
-	c = d + ROT_LEFT((c + H(d, a, b) + X[7] + 0xf6bb4b60), 16); /* 39 */
-	b = c + ROT_LEFT((b + H(c, d, a) + X[10] + 0xbebfbc70), 23);	/* 40 */
-	a = b + ROT_LEFT((a + H(b, c, d) + X[13] + 0x289b7ec6), 4); /* 41 */
-	d = a + ROT_LEFT((d + H(a, b, c) + X[0] + 0xeaa127fa), 11); /* 42 */
-	c = d + ROT_LEFT((c + H(d, a, b) + X[3] + 0xd4ef3085), 16); /* 43 */
-	b = c + ROT_LEFT((b + H(c, d, a) + X[6] + 0x04881d05), 23); /* 44 */
-	a = b + ROT_LEFT((a + H(b, c, d) + X[9] + 0xd9d4d039), 4);	/* 45 */
-	d = a + ROT_LEFT((d + H(a, b, c) + X[12] + 0xe6db99e5), 11);	/* 46 */
-	c = d + ROT_LEFT((c + H(d, a, b) + X[15] + 0x1fa27cf8), 16);	/* 47 */
-	b = c + ROT_LEFT((b + H(c, d, a) + X[2] + 0xc4ac5665), 23); /* 48 */
+	ROUND2(A, B, C, D, 1, Se, 17);
+	ROUND2(D, A, B, C, 6, Sf, 18);
+	ROUND2(C, D, A, B, 11, Sg, 19);
+	ROUND2(B, C, D, A, 0, Sh, 20);
+	ROUND2(A, B, C, D, 5, Se, 21);
+	ROUND2(D, A, B, C, 10, Sf, 22);
+	ROUND2(C, D, A, B, 15, Sg, 23);
+	ROUND2(B, C, D, A, 4, Sh, 24);
+	ROUND2(A, B, C, D, 9, Se, 25);
+	ROUND2(D, A, B, C, 14, Sf, 26);
+	ROUND2(C, D, A, B, 3, Sg, 27);
+	ROUND2(B, C, D, A, 8, Sh, 28);
+	ROUND2(A, B, C, D, 13, Se, 29);
+	ROUND2(D, A, B, C, 2, Sf, 30);
+	ROUND2(C, D, A, B, 7, Sg, 31);
+	ROUND2(B, C, D, A, 12, Sh, 32);
 
-	/* round 4 */
-	a = b + ROT_LEFT((a + I(b, c, d) + X[0] + 0xf4292244), 6);	/* 49 */
-	d = a + ROT_LEFT((d + I(a, b, c) + X[7] + 0x432aff97), 10); /* 50 */
-	c = d + ROT_LEFT((c + I(d, a, b) + X[14] + 0xab9423a7), 15);	/* 51 */
-	b = c + ROT_LEFT((b + I(c, d, a) + X[5] + 0xfc93a039), 21); /* 52 */
-	a = b + ROT_LEFT((a + I(b, c, d) + X[12] + 0x655b59c3), 6); /* 53 */
-	d = a + ROT_LEFT((d + I(a, b, c) + X[3] + 0x8f0ccc92), 10); /* 54 */
-	c = d + ROT_LEFT((c + I(d, a, b) + X[10] + 0xffeff47d), 15);	/* 55 */
-	b = c + ROT_LEFT((b + I(c, d, a) + X[1] + 0x85845dd1), 21); /* 56 */
-	a = b + ROT_LEFT((a + I(b, c, d) + X[8] + 0x6fa87e4f), 6);	/* 57 */
-	d = a + ROT_LEFT((d + I(a, b, c) + X[15] + 0xfe2ce6e0), 10);	/* 58 */
-	c = d + ROT_LEFT((c + I(d, a, b) + X[6] + 0xa3014314), 15); /* 59 */
-	b = c + ROT_LEFT((b + I(c, d, a) + X[13] + 0x4e0811a1), 21);	/* 60 */
-	a = b + ROT_LEFT((a + I(b, c, d) + X[4] + 0xf7537e82), 6);	/* 61 */
-	d = a + ROT_LEFT((d + I(a, b, c) + X[11] + 0xbd3af235), 10);	/* 62 */
-	c = d + ROT_LEFT((c + I(d, a, b) + X[2] + 0x2ad7d2bb), 15); /* 63 */
-	b = c + ROT_LEFT((b + I(c, d, a) + X[9] + 0xeb86d391), 21); /* 64 */
+	ROUND3(A, B, C, D, 5, Si, 33);
+	ROUND3(D, A, B, C, 8, Sj, 34);
+	ROUND3(C, D, A, B, 11, Sk, 35);
+	ROUND3(B, C, D, A, 14, Sl, 36);
+	ROUND3(A, B, C, D, 1, Si, 37);
+	ROUND3(D, A, B, C, 4, Sj, 38);
+	ROUND3(C, D, A, B, 7, Sk, 39);
+	ROUND3(B, C, D, A, 10, Sl, 40);
+	ROUND3(A, B, C, D, 13, Si, 41);
+	ROUND3(D, A, B, C, 0, Sj, 42);
+	ROUND3(C, D, A, B, 3, Sk, 43);
+	ROUND3(B, C, D, A, 6, Sl, 44);
+	ROUND3(A, B, C, D, 9, Si, 45);
+	ROUND3(D, A, B, C, 12, Sj, 46);
+	ROUND3(C, D, A, B, 15, Sk, 47);
+	ROUND3(B, C, D, A, 2, Sl, 48);
 
-	state[0] += a;
-	state[1] += b;
-	state[2] += c;
-	state[3] += d;
-}
+	ROUND4(A, B, C, D, 0, Sm, 49);
+	ROUND4(D, A, B, C, 7, Sn, 50);
+	ROUND4(C, D, A, B, 14, So, 51);
+	ROUND4(B, C, D, A, 5, Sp, 52);
+	ROUND4(A, B, C, D, 12, Sm, 53);
+	ROUND4(D, A, B, C, 3, Sn, 54);
+	ROUND4(C, D, A, B, 10, So, 55);
+	ROUND4(B, C, D, A, 1, Sp, 56);
+	ROUND4(A, B, C, D, 8, Sm, 57);
+	ROUND4(D, A, B, C, 15, Sn, 58);
+	ROUND4(C, D, A, B, 6, So, 59);
+	ROUND4(B, C, D, A, 13, Sp, 60);
+	ROUND4(A, B, C, D, 4, Sm, 61);
+	ROUND4(D, A, B, C, 11, Sn, 62);
+	ROUND4(C, D, A, B, 2, So, 63);
+	ROUND4(B, C, D, A, 9, Sp, 64);
 
-static int
-calculateDigestFromBuffer(const uint8 *b, uint32 len, uint8 sum[16])
-{
-	register uint32 i,
-				j,
-				k,
-				newI;
-	uint32		l;
-	uint8	   *input;
-	register uint32 *wbp;
-	uint32		workBuff[16],
-				state[4];
-
-	l = len;
-
-	state[0] = 0x67452301;
-	state[1] = 0xEFCDAB89;
-	state[2] = 0x98BADCFE;
-	state[3] = 0x10325476;
-
-	if ((input = createPaddedCopyWithLength(b, &l)) == NULL)
-		return 0;
-
-	for (i = 0;;)
-	{
-		if ((newI = i + 16 * 4) > l)
-			break;
-		k = i + 3;
-		for (j = 0; j < 16; j++)
-		{
-			wbp = (workBuff + j);
-			*wbp = input[k--];
-			*wbp <<= 8;
-			*wbp |= input[k--];
-			*wbp <<= 8;
-			*wbp |= input[k--];
-			*wbp <<= 8;
-			*wbp |= input[k];
-			k += 7;
-		}
-		doTheRounds(workBuff, state);
-		i = newI;
-	}
-	free(input);
-
-	j = 0;
-	for (i = 0; i < 4; i++)
-	{
-		k = state[i];
-		sum[j++] = (k & 0xff);
-		k >>= 8;
-		sum[j++] = (k & 0xff);
-		k >>= 8;
-		sum[j++] = (k & 0xff);
-		k >>= 8;
-		sum[j++] = (k & 0xff);
-	}
-	return 1;
+	ctxt->md5_sta += A;
+	ctxt->md5_stb += B;
+	ctxt->md5_stc += C;
+	ctxt->md5_std += D;
 }
 
 static void
-bytesToHex(uint8 b[16], char *s)
+md5_pad(md5_ctxt *ctxt)
 {
-	static const char *hex = "0123456789abcdef";
-	int			q,
-				w;
+	unsigned int gap;
 
-	for (q = 0, w = 0; q < 16; q++)
+	/* Don't count up padding. Keep md5_n. */
+	gap = MD5_BUFLEN - ctxt->md5_i;
+	if (gap > 8)
 	{
-		s[w++] = hex[(b[q] >> 4) & 0x0F];
-		s[w++] = hex[b[q] & 0x0F];
+		memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat,
+				gap - sizeof(ctxt->md5_n));
 	}
-	s[w] = '\0';
+	else
+	{
+		/* including gap == 8 */
+		memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap);
+		md5_calc(ctxt->md5_buf, ctxt);
+		memmove(ctxt->md5_buf, md5_paddat + gap,
+				MD5_BUFLEN - sizeof(ctxt->md5_n));
+	}
+
+	/* 8 byte word */
+#ifndef WORDS_BIGENDIAN
+	memmove(&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8);
+#else
+	ctxt->md5_buf[56] = ctxt->md5_n8[7];
+	ctxt->md5_buf[57] = ctxt->md5_n8[6];
+	ctxt->md5_buf[58] = ctxt->md5_n8[5];
+	ctxt->md5_buf[59] = ctxt->md5_n8[4];
+	ctxt->md5_buf[60] = ctxt->md5_n8[3];
+	ctxt->md5_buf[61] = ctxt->md5_n8[2];
+	ctxt->md5_buf[62] = ctxt->md5_n8[1];
+	ctxt->md5_buf[63] = ctxt->md5_n8[0];
+#endif
+
+	md5_calc(ctxt->md5_buf, ctxt);
+}
+
+static void
+md5_result(uint8 *digest, md5_ctxt *ctxt)
+{
+	/* 4 byte words */
+#ifndef WORDS_BIGENDIAN
+	memmove(digest, &ctxt->md5_st8[0], 16);
+#else
+	digest[0] = ctxt->md5_st8[3];
+	digest[1] = ctxt->md5_st8[2];
+	digest[2] = ctxt->md5_st8[1];
+	digest[3] = ctxt->md5_st8[0];
+	digest[4] = ctxt->md5_st8[7];
+	digest[5] = ctxt->md5_st8[6];
+	digest[6] = ctxt->md5_st8[5];
+	digest[7] = ctxt->md5_st8[4];
+	digest[8] = ctxt->md5_st8[11];
+	digest[9] = ctxt->md5_st8[10];
+	digest[10] = ctxt->md5_st8[9];
+	digest[11] = ctxt->md5_st8[8];
+	digest[12] = ctxt->md5_st8[15];
+	digest[13] = ctxt->md5_st8[14];
+	digest[14] = ctxt->md5_st8[13];
+	digest[15] = ctxt->md5_st8[12];
+#endif
+}
+
+
+/* External routines for this MD5 implementation */
+
+/*
+ * pg_md5_create
+ *
+ * Allocate a MD5 context.  Returns NULL on failure.
+ */
+void *
+pg_md5_create(void)
+{
+	md5_ctxt	   *ctxt;
+
+	ctxt = ALLOC(sizeof(md5_ctxt));
+	memset(ctxt, 0, sizeof(md5_ctxt));
+	return ctxt;
 }
 
 /*
- *	PUBLIC FUNCTIONS
+ * pg_md5_init
+ *
+ * Initialize a MD5 context.  Note that this implementation is designed
+ * to never fail, so this always returns 0.
  */
-
-/*
- *	pg_md5_hash
- *
- *	Calculates the MD5 sum of the bytes in a buffer.
- *
- *	SYNOPSIS	  #include "md5.h"
- *				  int pg_md5_hash(const void *buff, size_t len, char *hexsum)
- *
- *	INPUT		  buff	  the buffer containing the bytes that you want
- *						  the MD5 sum of.
- *				  len	  number of bytes in the buffer.
- *
- *	OUTPUT		  hexsum  the MD5 sum as a '\0'-terminated string of
- *						  hexadecimal digits.  an MD5 sum is 16 bytes long.
- *						  each byte is represented by two hexadecimal
- *						  characters.  you thus need to provide an array
- *						  of 33 characters, including the trailing '\0'.
- *
- *	RETURNS		  false on failure (out of memory for internal buffers) or
- *				  true on success.
- *
- *	STANDARDS	  MD5 is described in RFC 1321.
- *
- *	AUTHOR		  Sverre H. Huseby <sverr...@online.no>
- *
- */
-bool
-pg_md5_hash(const void *buff, size_t len, char *hexsum)
+int
+pg_md5_init(void *ctx)
 {
-	uint8		sum[16];
+	md5_ctxt	   *ctxt = (md5_ctxt *) ctx;
 
-	if (!calculateDigestFromBuffer(buff, len, sum))
-		return false;
-
-	bytesToHex(sum, hexsum);
-	return true;
-}
-
-bool
-pg_md5_binary(const void *buff, size_t len, void *outbuf)
-{
-	if (!calculateDigestFromBuffer(buff, len, outbuf))
-		return false;
-	return true;
+	ctxt->md5_n = 0;
+	ctxt->md5_i = 0;
+	ctxt->md5_sta = MD5_A0;
+	ctxt->md5_stb = MD5_B0;
+	ctxt->md5_stc = MD5_C0;
+	ctxt->md5_std = MD5_D0;
+	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
+	return 0;
 }
 
 
 /*
- * Computes MD5 checksum of "passwd" (a null-terminated string) followed
- * by "salt" (which need not be null-terminated).
+ * pg_md5_update
  *
- * Output format is "md5" followed by a 32-hex-digit MD5 checksum.
- * Hence, the output buffer "buf" must be at least 36 bytes long.
- *
- * Returns true if okay, false on error (out of memory).
+ * Update a MD5 context.  Note that this implementation is designed
+ * to never fail, so this always returns 0.
  */
-bool
-pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len,
-			   char *buf)
+int
+pg_md5_update(void *ctx, const uint8 *data, size_t len)
 {
-	size_t		passwd_len = strlen(passwd);
+	unsigned int gap,
+				i;
+	md5_ctxt   *ctxt = (md5_ctxt *) ctx;
 
-	/* +1 here is just to avoid risk of unportable malloc(0) */
-	char	   *crypt_buf = malloc(passwd_len + salt_len + 1);
-	bool		ret;
+	ctxt->md5_n += len * 8;		/* byte to bit */
+	gap = MD5_BUFLEN - ctxt->md5_i;
 
-	if (!crypt_buf)
-		return false;
+	if (len >= gap)
+	{
+		memmove(ctxt->md5_buf + ctxt->md5_i, data, gap);
+		md5_calc(ctxt->md5_buf, ctxt);
 
-	/*
-	 * Place salt at the end because it may be known by users trying to crack
-	 * the MD5 output.
-	 */
-	memcpy(crypt_buf, passwd, passwd_len);
-	memcpy(crypt_buf + passwd_len, salt, salt_len);
+		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN)
+			md5_calc(data + i, ctxt);
 
-	strcpy(buf, "md5");
-	ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3);
+		ctxt->md5_i = len - i;
+		memmove(ctxt->md5_buf, data + i, ctxt->md5_i);
+	}
+	else
+	{
+		memmove(ctxt->md5_buf + ctxt->md5_i, data, len);
+		ctxt->md5_i += len;
+	}
 
-	free(crypt_buf);
-
-	return ret;
+	return 0;
+}
+
+/*
+ * pg_md5_final
+ *
+ * Finalize a MD5 context.  Note that this implementation is designed
+ * to never fail, so this always returns 0.
+ */
+int
+pg_md5_final(void *ctx, uint8 *dest)
+{
+	md5_pad(ctx);
+	md5_result(dest, ctx);
+
+	return 0;
+}
+
+/*
+ * pg_md5_free
+ *
+ * Free a MD5 context.
+ */
+void
+pg_md5_free(void *ctx)
+{
+	md5_ctxt	*ctxt = (md5_ctxt *) ctx;
+
+	explicit_bzero(ctxt, sizeof(md5_ctxt));
+	FREE(ctx);
 }
diff --git a/src/common/md5_common.c b/src/common/md5_common.c
new file mode 100644
index 0000000000..1ecc832dab
--- /dev/null
+++ b/src/common/md5_common.c
@@ -0,0 +1,144 @@
+/*
+ * md5_common.c
+ *
+ * Routines shared between all MD5 implementations used for MD5-encrypted
+ * passwords.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/common/md5_common.c
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/md5.h"
+
+static void
+bytesToHex(uint8 b[16], char *s)
+{
+	static const char *hex = "0123456789abcdef";
+	int			q,
+				w;
+
+	for (q = 0, w = 0; q < 16; q++)
+	{
+		s[w++] = hex[(b[q] >> 4) & 0x0F];
+		s[w++] = hex[b[q] & 0x0F];
+	}
+	s[w] = '\0';
+}
+
+/*
+ *	pg_md5_hash
+ *
+ *	Calculates the MD5 sum of the bytes in a buffer.
+ *
+ *	SYNOPSIS	  #include "md5.h"
+ *				  int pg_md5_hash(const void *buff, size_t len, char *hexsum)
+ *
+ *	INPUT		  buff	  the buffer containing the bytes that you want
+ *						  the MD5 sum of.
+ *				  len	  number of bytes in the buffer.
+ *
+ *	OUTPUT		  hexsum  the MD5 sum as a '\0'-terminated string of
+ *						  hexadecimal digits.  an MD5 sum is 16 bytes long.
+ *						  each byte is represented by two hexadecimal
+ *						  characters.  you thus need to provide an array
+ *						  of 33 characters, including the trailing '\0'.
+ *
+ *	RETURNS		  false on failure (out of memory for internal buffers
+ *				  or MD5 computation failure) or true on success.
+ *
+ *	STANDARDS	  MD5 is described in RFC 1321.
+ *
+ *	AUTHOR		  Sverre H. Huseby <sverr...@online.no>
+ *
+ */
+
+bool
+pg_md5_hash(const void *buff, size_t len, char *hexsum)
+{
+	uint8		sum[16];
+	void	   *ctx;
+
+	ctx = pg_md5_create();
+	if (ctx == NULL)
+		return false;
+
+	if (pg_md5_init(ctx) < 0 ||
+		pg_md5_update(ctx, buff, len) < 0 ||
+		pg_md5_final(ctx, sum) < 0)
+	{
+		pg_md5_free(ctx);
+		return false;
+	}
+
+	bytesToHex(sum, hexsum);
+	pg_md5_free(ctx);
+	return true;
+}
+
+bool
+pg_md5_binary(const void *buff, size_t len, void *outbuf)
+{
+	void	   *ctx;
+
+	ctx = pg_md5_create();
+	if (ctx == NULL)
+		return false;
+
+	if (pg_md5_init(ctx) < 0 ||
+		pg_md5_update(ctx, buff, len) < 0 ||
+		pg_md5_final(ctx, outbuf) < 0)
+	{
+		pg_md5_free(ctx);
+		return false;
+	}
+
+	pg_md5_free(ctx);
+	return true;
+}
+
+
+/*
+ * Computes MD5 checksum of "passwd" (a null-terminated string) followed
+ * by "salt" (which need not be null-terminated).
+ *
+ * Output format is "md5" followed by a 32-hex-digit MD5 checksum.
+ * Hence, the output buffer "buf" must be at least 36 bytes long.
+ *
+ * Returns true if okay, false on error (out of memory).
+ */
+bool
+pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len,
+			   char *buf)
+{
+	size_t		passwd_len = strlen(passwd);
+
+	/* +1 here is just to avoid risk of unportable malloc(0) */
+	char	   *crypt_buf = malloc(passwd_len + salt_len + 1);
+	bool		ret;
+
+	if (!crypt_buf)
+		return false;
+
+	/*
+	 * Place salt at the end because it may be known by users trying to crack
+	 * the MD5 output.
+	 */
+	memcpy(crypt_buf, passwd, passwd_len);
+	memcpy(crypt_buf + passwd_len, salt, salt_len);
+
+	strcpy(buf, "md5");
+	ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3);
+
+	free(crypt_buf);
+
+	return ret;
+}
diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index 61eabd2fc0..d881e85add 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -1,6 +1,6 @@
 # contrib/pgcrypto/Makefile
 
-INT_SRCS = md5.c sha1.c internal.c internal-sha2.c blf.c rijndael.c \
+INT_SRCS = sha1.c internal.c internal-sha2.c blf.c rijndael.c \
 		pgp-mpi-internal.c imath.c
 INT_TESTS = sha2
 
diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c
index 06469d41c0..ef85128bde 100644
--- a/contrib/pgcrypto/internal.c
+++ b/contrib/pgcrypto/internal.c
@@ -34,11 +34,12 @@
 #include <time.h>
 
 #include "blf.h"
-#include "md5.h"
 #include "px.h"
 #include "rijndael.h"
 #include "sha1.h"
 
+#include "common/md5.h"
+
 #ifndef MD5_DIGEST_LENGTH
 #define MD5_DIGEST_LENGTH 16
 #endif
@@ -96,34 +97,33 @@ int_md5_block_len(PX_MD *h)
 static void
 int_md5_update(PX_MD *h, const uint8 *data, unsigned dlen)
 {
-	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+	void    *ctx = h->p.ptr;
 
-	MD5Update(ctx, data, dlen);
+	pg_md5_update(ctx, data, dlen);
 }
 
 static void
 int_md5_reset(PX_MD *h)
 {
-	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+	void    *ctx = h->p.ptr;
 
-	MD5Init(ctx);
+	pg_md5_init(ctx);
 }
 
 static void
 int_md5_finish(PX_MD *h, uint8 *dst)
 {
-	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+	void    *ctx = h->p.ptr;
 
-	MD5Final(dst, ctx);
+	pg_md5_final(ctx, dst);
 }
 
 static void
 int_md5_free(PX_MD *h)
 {
-	MD5_CTX    *ctx = (MD5_CTX *) h->p.ptr;
+	void    *ctx = h->p.ptr;
 
-	px_memset(ctx, 0, sizeof(*ctx));
-	pfree(ctx);
+	pg_md5_free(ctx);
 	pfree(h);
 }
 
@@ -180,9 +180,9 @@ int_sha1_free(PX_MD *h)
 static void
 init_md5(PX_MD *md)
 {
-	MD5_CTX    *ctx;
+	void    *ctx;
 
-	ctx = palloc0(sizeof(*ctx));
+	ctx = pg_md5_create();
 
 	md->p.ptr = ctx;
 
diff --git a/contrib/pgcrypto/md5.c b/contrib/pgcrypto/md5.c
deleted file mode 100644
index 15d7c9bcdc..0000000000
--- a/contrib/pgcrypto/md5.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*	   $KAME: md5.c,v 1.3 2000/02/22 14:01:17 itojun Exp $	   */
-
-/*
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *	  notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *	  notice, this list of conditions and the following disclaimer in the
- *	  documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- *	  may be used to endorse or promote products derived from this software
- *	  without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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/md5.c
- */
-
-#include "postgres.h"
-
-#include <sys/param.h>
-
-#include "md5.h"
-
-#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
-
-#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
-#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
-#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
-#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
-
-#define ROUND1(a, b, c, d, k, s, i) \
-do { \
-	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
-	(a) = SHIFT((a), (s)); \
-	(a) = (b) + (a); \
-} while (0)
-
-#define ROUND2(a, b, c, d, k, s, i) \
-do { \
-	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
-	(a) = SHIFT((a), (s)); \
-	(a) = (b) + (a); \
-} while (0)
-
-#define ROUND3(a, b, c, d, k, s, i) \
-do { \
-	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
-	(a) = SHIFT((a), (s)); \
-	(a) = (b) + (a); \
-} while (0)
-
-#define ROUND4(a, b, c, d, k, s, i) \
-do { \
-	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
-	(a) = SHIFT((a), (s)); \
-	(a) = (b) + (a); \
-} while (0)
-
-#define Sa	 7
-#define Sb	12
-#define Sc	17
-#define Sd	22
-
-#define Se	 5
-#define Sf	 9
-#define Sg	14
-#define Sh	20
-
-#define Si	 4
-#define Sj	11
-#define Sk	16
-#define Sl	23
-
-#define Sm	 6
-#define Sn	10
-#define So	15
-#define Sp	21
-
-#define MD5_A0	0x67452301
-#define MD5_B0	0xefcdab89
-#define MD5_C0	0x98badcfe
-#define MD5_D0	0x10325476
-
-/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
-static const uint32 T[65] = {
-	0,
-	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
-	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
-	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
-	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
-
-	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
-	0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
-	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
-	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
-
-	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
-	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
-	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
-	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
-
-	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
-	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
-	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
-	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
-};
-
-static const uint8 md5_paddat[MD5_BUFLEN] = {
-	0x80, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void md5_calc(const uint8 *, md5_ctxt *);
-
-void
-md5_init(md5_ctxt *ctxt)
-{
-	ctxt->md5_n = 0;
-	ctxt->md5_i = 0;
-	ctxt->md5_sta = MD5_A0;
-	ctxt->md5_stb = MD5_B0;
-	ctxt->md5_stc = MD5_C0;
-	ctxt->md5_std = MD5_D0;
-	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
-}
-
-void
-md5_loop(md5_ctxt *ctxt, const uint8 *input, unsigned len)
-{
-	unsigned int gap,
-				i;
-
-	ctxt->md5_n += len * 8;		/* byte to bit */
-	gap = MD5_BUFLEN - ctxt->md5_i;
-
-	if (len >= gap)
-	{
-		memmove(ctxt->md5_buf + ctxt->md5_i, input, gap);
-		md5_calc(ctxt->md5_buf, ctxt);
-
-		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN)
-			md5_calc(input + i, ctxt);
-
-		ctxt->md5_i = len - i;
-		memmove(ctxt->md5_buf, input + i, ctxt->md5_i);
-	}
-	else
-	{
-		memmove(ctxt->md5_buf + ctxt->md5_i, input, len);
-		ctxt->md5_i += len;
-	}
-}
-
-void
-md5_pad(md5_ctxt *ctxt)
-{
-	unsigned int gap;
-
-	/* Don't count up padding. Keep md5_n. */
-	gap = MD5_BUFLEN - ctxt->md5_i;
-	if (gap > 8)
-	{
-		memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat,
-				gap - sizeof(ctxt->md5_n));
-	}
-	else
-	{
-		/* including gap == 8 */
-		memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap);
-		md5_calc(ctxt->md5_buf, ctxt);
-		memmove(ctxt->md5_buf, md5_paddat + gap,
-				MD5_BUFLEN - sizeof(ctxt->md5_n));
-	}
-
-	/* 8 byte word */
-#ifndef WORDS_BIGENDIAN
-	memmove(&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8);
-#else
-	ctxt->md5_buf[56] = ctxt->md5_n8[7];
-	ctxt->md5_buf[57] = ctxt->md5_n8[6];
-	ctxt->md5_buf[58] = ctxt->md5_n8[5];
-	ctxt->md5_buf[59] = ctxt->md5_n8[4];
-	ctxt->md5_buf[60] = ctxt->md5_n8[3];
-	ctxt->md5_buf[61] = ctxt->md5_n8[2];
-	ctxt->md5_buf[62] = ctxt->md5_n8[1];
-	ctxt->md5_buf[63] = ctxt->md5_n8[0];
-#endif
-
-	md5_calc(ctxt->md5_buf, ctxt);
-}
-
-void
-md5_result(uint8 *digest, md5_ctxt *ctxt)
-{
-	/* 4 byte words */
-#ifndef WORDS_BIGENDIAN
-	memmove(digest, &ctxt->md5_st8[0], 16);
-#else
-	digest[0] = ctxt->md5_st8[3];
-	digest[1] = ctxt->md5_st8[2];
-	digest[2] = ctxt->md5_st8[1];
-	digest[3] = ctxt->md5_st8[0];
-	digest[4] = ctxt->md5_st8[7];
-	digest[5] = ctxt->md5_st8[6];
-	digest[6] = ctxt->md5_st8[5];
-	digest[7] = ctxt->md5_st8[4];
-	digest[8] = ctxt->md5_st8[11];
-	digest[9] = ctxt->md5_st8[10];
-	digest[10] = ctxt->md5_st8[9];
-	digest[11] = ctxt->md5_st8[8];
-	digest[12] = ctxt->md5_st8[15];
-	digest[13] = ctxt->md5_st8[14];
-	digest[14] = ctxt->md5_st8[13];
-	digest[15] = ctxt->md5_st8[12];
-#endif
-}
-
-#ifdef WORDS_BIGENDIAN
-static uint32 X[16];
-#endif
-
-static void
-md5_calc(const uint8 *b64, md5_ctxt *ctxt)
-{
-	uint32		A = ctxt->md5_sta;
-	uint32		B = ctxt->md5_stb;
-	uint32		C = ctxt->md5_stc;
-	uint32		D = ctxt->md5_std;
-
-#ifndef WORDS_BIGENDIAN
-	const uint32 *X = (const uint32 *) b64;
-#else
-	/* 4 byte words */
-	/* what a brute force but fast! */
-	uint8	   *y = (uint8 *) X;
-
-	y[0] = b64[3];
-	y[1] = b64[2];
-	y[2] = b64[1];
-	y[3] = b64[0];
-	y[4] = b64[7];
-	y[5] = b64[6];
-	y[6] = b64[5];
-	y[7] = b64[4];
-	y[8] = b64[11];
-	y[9] = b64[10];
-	y[10] = b64[9];
-	y[11] = b64[8];
-	y[12] = b64[15];
-	y[13] = b64[14];
-	y[14] = b64[13];
-	y[15] = b64[12];
-	y[16] = b64[19];
-	y[17] = b64[18];
-	y[18] = b64[17];
-	y[19] = b64[16];
-	y[20] = b64[23];
-	y[21] = b64[22];
-	y[22] = b64[21];
-	y[23] = b64[20];
-	y[24] = b64[27];
-	y[25] = b64[26];
-	y[26] = b64[25];
-	y[27] = b64[24];
-	y[28] = b64[31];
-	y[29] = b64[30];
-	y[30] = b64[29];
-	y[31] = b64[28];
-	y[32] = b64[35];
-	y[33] = b64[34];
-	y[34] = b64[33];
-	y[35] = b64[32];
-	y[36] = b64[39];
-	y[37] = b64[38];
-	y[38] = b64[37];
-	y[39] = b64[36];
-	y[40] = b64[43];
-	y[41] = b64[42];
-	y[42] = b64[41];
-	y[43] = b64[40];
-	y[44] = b64[47];
-	y[45] = b64[46];
-	y[46] = b64[45];
-	y[47] = b64[44];
-	y[48] = b64[51];
-	y[49] = b64[50];
-	y[50] = b64[49];
-	y[51] = b64[48];
-	y[52] = b64[55];
-	y[53] = b64[54];
-	y[54] = b64[53];
-	y[55] = b64[52];
-	y[56] = b64[59];
-	y[57] = b64[58];
-	y[58] = b64[57];
-	y[59] = b64[56];
-	y[60] = b64[63];
-	y[61] = b64[62];
-	y[62] = b64[61];
-	y[63] = b64[60];
-#endif
-
-	ROUND1(A, B, C, D, 0, Sa, 1);
-	ROUND1(D, A, B, C, 1, Sb, 2);
-	ROUND1(C, D, A, B, 2, Sc, 3);
-	ROUND1(B, C, D, A, 3, Sd, 4);
-	ROUND1(A, B, C, D, 4, Sa, 5);
-	ROUND1(D, A, B, C, 5, Sb, 6);
-	ROUND1(C, D, A, B, 6, Sc, 7);
-	ROUND1(B, C, D, A, 7, Sd, 8);
-	ROUND1(A, B, C, D, 8, Sa, 9);
-	ROUND1(D, A, B, C, 9, Sb, 10);
-	ROUND1(C, D, A, B, 10, Sc, 11);
-	ROUND1(B, C, D, A, 11, Sd, 12);
-	ROUND1(A, B, C, D, 12, Sa, 13);
-	ROUND1(D, A, B, C, 13, Sb, 14);
-	ROUND1(C, D, A, B, 14, Sc, 15);
-	ROUND1(B, C, D, A, 15, Sd, 16);
-
-	ROUND2(A, B, C, D, 1, Se, 17);
-	ROUND2(D, A, B, C, 6, Sf, 18);
-	ROUND2(C, D, A, B, 11, Sg, 19);
-	ROUND2(B, C, D, A, 0, Sh, 20);
-	ROUND2(A, B, C, D, 5, Se, 21);
-	ROUND2(D, A, B, C, 10, Sf, 22);
-	ROUND2(C, D, A, B, 15, Sg, 23);
-	ROUND2(B, C, D, A, 4, Sh, 24);
-	ROUND2(A, B, C, D, 9, Se, 25);
-	ROUND2(D, A, B, C, 14, Sf, 26);
-	ROUND2(C, D, A, B, 3, Sg, 27);
-	ROUND2(B, C, D, A, 8, Sh, 28);
-	ROUND2(A, B, C, D, 13, Se, 29);
-	ROUND2(D, A, B, C, 2, Sf, 30);
-	ROUND2(C, D, A, B, 7, Sg, 31);
-	ROUND2(B, C, D, A, 12, Sh, 32);
-
-	ROUND3(A, B, C, D, 5, Si, 33);
-	ROUND3(D, A, B, C, 8, Sj, 34);
-	ROUND3(C, D, A, B, 11, Sk, 35);
-	ROUND3(B, C, D, A, 14, Sl, 36);
-	ROUND3(A, B, C, D, 1, Si, 37);
-	ROUND3(D, A, B, C, 4, Sj, 38);
-	ROUND3(C, D, A, B, 7, Sk, 39);
-	ROUND3(B, C, D, A, 10, Sl, 40);
-	ROUND3(A, B, C, D, 13, Si, 41);
-	ROUND3(D, A, B, C, 0, Sj, 42);
-	ROUND3(C, D, A, B, 3, Sk, 43);
-	ROUND3(B, C, D, A, 6, Sl, 44);
-	ROUND3(A, B, C, D, 9, Si, 45);
-	ROUND3(D, A, B, C, 12, Sj, 46);
-	ROUND3(C, D, A, B, 15, Sk, 47);
-	ROUND3(B, C, D, A, 2, Sl, 48);
-
-	ROUND4(A, B, C, D, 0, Sm, 49);
-	ROUND4(D, A, B, C, 7, Sn, 50);
-	ROUND4(C, D, A, B, 14, So, 51);
-	ROUND4(B, C, D, A, 5, Sp, 52);
-	ROUND4(A, B, C, D, 12, Sm, 53);
-	ROUND4(D, A, B, C, 3, Sn, 54);
-	ROUND4(C, D, A, B, 10, So, 55);
-	ROUND4(B, C, D, A, 1, Sp, 56);
-	ROUND4(A, B, C, D, 8, Sm, 57);
-	ROUND4(D, A, B, C, 15, Sn, 58);
-	ROUND4(C, D, A, B, 6, So, 59);
-	ROUND4(B, C, D, A, 13, Sp, 60);
-	ROUND4(A, B, C, D, 4, Sm, 61);
-	ROUND4(D, A, B, C, 11, Sn, 62);
-	ROUND4(C, D, A, B, 2, So, 63);
-	ROUND4(B, C, D, A, 9, Sp, 64);
-
-	ctxt->md5_sta += A;
-	ctxt->md5_stb += B;
-	ctxt->md5_stc += C;
-	ctxt->md5_std += D;
-}
diff --git a/contrib/pgcrypto/md5.h b/contrib/pgcrypto/md5.h
deleted file mode 100644
index 3e6e8da5e7..0000000000
--- a/contrib/pgcrypto/md5.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*	contrib/pgcrypto/md5.h */
-/*	   $KAME: md5.h,v 1.3 2000/02/22 14:01:18 itojun Exp $	   */
-
-/*
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *	  notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *	  notice, this list of conditions and the following disclaimer in the
- *	  documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- *	  may be used to endorse or promote products derived from this software
- *	  without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
- */
-
-#ifndef _NETINET6_MD5_H_
-#define _NETINET6_MD5_H_
-
-#define MD5_BUFLEN	64
-
-typedef struct
-{
-	union
-	{
-		uint32		md5_state32[4];
-		uint8		md5_state8[16];
-	}			md5_st;
-
-#define md5_sta		md5_st.md5_state32[0]
-#define md5_stb		md5_st.md5_state32[1]
-#define md5_stc		md5_st.md5_state32[2]
-#define md5_std		md5_st.md5_state32[3]
-#define md5_st8		md5_st.md5_state8
-
-	union
-	{
-		uint64		md5_count64;
-		uint8		md5_count8[8];
-	}			md5_count;
-#define md5_n	md5_count.md5_count64
-#define md5_n8	md5_count.md5_count8
-
-	unsigned int md5_i;
-	uint8		md5_buf[MD5_BUFLEN];
-} md5_ctxt;
-
-extern void md5_init(md5_ctxt *);
-extern void md5_loop(md5_ctxt *, const uint8 *, unsigned int);
-extern void md5_pad(md5_ctxt *);
-extern void md5_result(uint8 *, md5_ctxt *);
-
-/* compatibility */
-#define MD5_CTX		md5_ctxt
-#define MD5Init(x)	md5_init((x))
-#define MD5Update(x, y, z)	md5_loop((x), (y), (z))
-#define MD5Final(x, y) \
-do {				\
-	md5_pad((y));		\
-	md5_result((x), (y));	\
-} while (0)
-
-#endif							/* ! _NETINET6_MD5_H_ */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 90594bd41b..055863c9b2 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -122,7 +122,7 @@ sub mkvcbuild
 	  archive.c base64.c checksum_helper.c
 	  config_info.c controldata_utils.c d2s.c encnames.c exec.c
 	  f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
-	  keywords.c kwlookup.c link-canary.c md5.c
+	  keywords.c kwlookup.c link-canary.c md5.c md5_common.c
 	  pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
 	  saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
 	  wait_error.c wchar.c);
@@ -463,11 +463,10 @@ sub mkvcbuild
 	else
 	{
 		$pgcrypto->AddFiles(
-			'contrib/pgcrypto', 'md5.c',
-			'sha1.c',           'internal.c',
-			'internal-sha2.c',  'blf.c',
-			'rijndael.c',       'pgp-mpi-internal.c',
-			'imath.c');
+			'contrib/pgcrypto',   'sha1.c',
+			'internal.c',         'internal-sha2.c',
+			'blf.c',              'rijndael.c',
+			'pgp-mpi-internal.c', 'imath.c');
 	}
 	$pgcrypto->AddReference($postgres);
 	$pgcrypto->AddLibrary('ws2_32.lib');
-- 
2.29.2

From 677c3d3dcc202593ba76ad180b235cf1217d2594 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Tue, 10 Nov 2020 13:24:15 +0900
Subject: [PATCH v2 3/3] Add MD5 implementation based on OpenSSL

This makes use of OpenSSL EVP to compute MD5 hashes, using the new API
interface introduced previously.
---
 src/common/Makefile         |   8 +-
 src/common/md5_openssl.c    | 157 ++++++++++++++++++++++++++++++++++++
 src/tools/msvc/Mkvcbuild.pm |   4 +-
 3 files changed, 165 insertions(+), 4 deletions(-)
 create mode 100644 src/common/md5_openssl.c

diff --git a/src/common/Makefile b/src/common/Makefile
index 69de65fab5..4571a8ac23 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -63,7 +63,6 @@ OBJS_COMMON = \
 	keywords.o \
 	kwlookup.o \
 	link-canary.o \
-	md5.o \
 	md5_common.o \
 	pg_get_line.o \
 	pg_lzcompress.o \
@@ -83,9 +82,12 @@ OBJS_COMMON = \
 ifeq ($(with_openssl),yes)
 OBJS_COMMON += \
 	protocol_openssl.o \
-	sha2_openssl.o
+	sha2_openssl.o \
+	md5_openssl.o
 else
-OBJS_COMMON += sha2.o
+OBJS_COMMON += \
+	md5.o \
+	sha2.o
 endif
 
 # A few files are currently only built for frontend, not server
diff --git a/src/common/md5_openssl.c b/src/common/md5_openssl.c
new file mode 100644
index 0000000000..56bef35ee8
--- /dev/null
+++ b/src/common/md5_openssl.c
@@ -0,0 +1,157 @@
+/*-------------------------------------------------------------------------
+ *
+ * md5_openssl.c
+ *	  Set of wrapper routines on top of OpenSSL to support MD5.
+ *
+ * This should only be used if code is compiled with OpenSSL support.
+ *
+ * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		  src/common/md52_openssl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <openssl/evp.h>
+
+#include "common/md5.h"
+#ifndef FRONTEND
+#include "utils/memutils.h"
+#include "utils/resowner.h"
+#include "utils/resowner_private.h"
+#endif
+
+/*
+ * In backend, use palloc/pfree to ease the error handling.  In frontend,
+ * use malloc to be able to return a failure status back to the caller.
+ */
+#ifndef FRONTEND
+#define ALLOC(size) palloc(size)
+#define FREE(ptr) pfree(ptr)
+#else
+#define ALLOC(size) malloc(size)
+#define FREE(ptr) free(ptr)
+#endif
+
+/*
+ * pg_md5_create
+ *
+ * Allocate a MD5 context.  Returns NULL on failure.
+ */
+void *
+pg_md5_create(void)
+{
+	void	   *ctx;
+
+#ifndef FRONTEND
+	ResourceOwnerEnlargeEVP(CurrentResourceOwner);
+#endif
+
+	ctx = EVP_MD_CTX_create();
+
+	if (ctx == NULL)
+	{
+#ifndef FRONTEND
+		elog(ERROR, "out of memory");
+#else
+		return NULL;
+#endif
+	}
+
+#ifndef FRONTEND
+	ResourceOwnerRememberEVP(CurrentResourceOwner,
+							 PointerGetDatum(ctx));
+#endif
+
+	return ctx;
+}
+
+/*
+ * pg_md5_init
+ *
+ * Initialize a MD5 context.  Returns 0 on success, and -1 on failure.
+ */
+int
+pg_md5_init(void *ctx)
+{
+	int			status = 0;
+
+	if (ctx == NULL)
+		return 0;
+
+	status = EVP_DigestInit_ex((EVP_MD_CTX *) ctx,
+							   EVP_md5(), NULL);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_md5_update
+ *
+ * Update a MD5 context.  Returns 0 on success, and -1 on failure.
+ */
+int
+pg_md5_update(void *ctx, const uint8 *data, size_t len)
+{
+	int			status;
+
+	if (ctx == NULL)
+		return 0;
+
+	status = EVP_DigestUpdate((EVP_MD_CTX *) ctx, data, len);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_md5_final
+ *
+ * Finalize a MD5 context.  Returns 0 on success, and -1 on failure.
+ */
+int
+pg_md5_final(void *ctx, uint8 *dest)
+{
+	int			status;
+
+	if (ctx == NULL)
+		return 0;
+
+	status = EVP_DigestFinal_ex((EVP_MD_CTX *) ctx, dest, 0);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_md5_free
+ *
+ * Free a MD5 context.
+ */
+void
+pg_md5_free(void *ctx)
+{
+	if (ctx == NULL)
+		return;
+
+	EVP_MD_CTX_destroy((EVP_MD_CTX *) ctx);
+
+#ifndef FRONTEND
+	ResourceOwnerForgetEVP(CurrentResourceOwner,
+						   PointerGetDatum(ctx));
+#endif
+}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 055863c9b2..eb9e401674 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -122,18 +122,20 @@ sub mkvcbuild
 	  archive.c base64.c checksum_helper.c
 	  config_info.c controldata_utils.c d2s.c encnames.c exec.c
 	  f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
-	  keywords.c kwlookup.c link-canary.c md5.c md5_common.c
+	  keywords.c kwlookup.c link-canary.c md5_common.c
 	  pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
 	  saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
 	  wait_error.c wchar.c);
 
 	if ($solution->{options}->{openssl})
 	{
+		push(@pgcommonallfiles, 'md5_openssl.c');
 		push(@pgcommonallfiles, 'sha2_openssl.c');
 		push(@pgcommonallfiles, 'protocol_openssl.c');
 	}
 	else
 	{
+		push(@pgcommonallfiles, 'md5.c');
 		push(@pgcommonallfiles, 'sha2.c');
 	}
 
-- 
2.29.2

Attachment: signature.asc
Description: PGP signature

Reply via email to