diff --git a/ChangeLog b/ChangeLog
index d4a20095a61e1b8e8650bb9e43d0999ae03ac3e3..00d7b2c89be8254936b3c898706d45a49fa23792 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2022-07-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* md-internal.h (MD_FILL_OR_RETURN): New file, new macro.
+
 2022-06-20  Niels Möller  <nisse@lysator.liu.se>
 
 	* testsuite/sha1-test.c (test_sha1_compress): New function.
diff --git a/Makefile.in b/Makefile.in
index 65911e2a05bb399f2279d387d20485cae19112bb..ba5364076bcc9b0da50a2f9310b3454a08cf7cd3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -260,7 +260,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \
 	aes-internal.h block-internal.h blowfish-internal.h camellia-internal.h \
 	ghash-internal.h gost28147-internal.h poly1305-internal.h \
 	serpent-internal.h cast128_sboxes.h desinfo.h desCode.h \
-	ripemd160-internal.h sha2-internal.h \
+	ripemd160-internal.h md-internal.h sha2-internal.h \
 	memxor-internal.h nettle-internal.h nettle-write.h \
 	ctr-internal.h chacha-internal.h sha3-internal.h \
 	salsa20-internal.h umac-internal.h hogweed-internal.h \
diff --git a/md-internal.h b/md-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe520c63ce152172bc7b758d86f071b2dad8e1bf
--- /dev/null
+++ b/md-internal.h
@@ -0,0 +1,57 @@
+/* md-internal.h
+
+   Copyright (C) 2001, 2010, 2022 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_MD_INTERNAL_H_INCLUDED
+#define NETTLE_MD_INTERNAL_H_INCLUDED
+
+/* Internal helper macros for Merkle-Damgård hash functions. Assumes the context
+   structs includes the following fields:
+
+     uint8_t block[...];		// Buffer holding one block
+     unsigned int index;		// Index into block
+*/
+
+#define MD_FILL_OR_RETURN(ctx, length, data)			\
+  do {								\
+    unsigned __md_left = sizeof((ctx)->block) - (ctx)->index;	\
+    if ((length) < __md_left)					\
+      {								\
+	memcpy((ctx)->block + (ctx)->index, (data), (length));	\
+	(ctx)->index += (length);				\
+	return;							\
+      }								\
+    memcpy((ctx)->block + (ctx)->index, (data), __md_left);	\
+    (data) += __md_left;					\
+    (length) -= __md_left;					\
+    (ctx)->index = 0;						\
+  } while(0)
+
+#endif /* NETTLE_MD_INTERNAL_H_INCLUDED */