diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c
index 829e48258d..6ef7e67711 100644
--- a/crypto/hash-gcrypt.c
+++ b/crypto/hash-gcrypt.c
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash algorithms
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -110,7 +111,111 @@ qcrypto_gcrypt_hash_bytesv(QCryptoHashAlgorithm alg,
     return -1;
 }
 
+static
+int qcrypto_gcrypt_hash_accumulate_new_ctx(QCryptoHashAlgorithm alg,
+                                           qcrypto_hash_accumulate_ctx_t **accumulate_ctx,
+                                           Error **errp)
+{
+    int ret;
+
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    ret = gcry_md_open((gcry_md_hd_t *) accumulate_ctx, qcrypto_hash_alg_map[alg], 0);
+
+    if (ret < 0) {
+        error_setg(errp,
+                   "Unable to initialize hash algorithm: %s",
+                   gcry_strerror(ret));
+        return -1;
+    }
+
+    return 0;
+}
+
+static
+int qcrypto_gcrypt_hash_accumulate_free_ctx(qcrypto_hash_accumulate_ctx_t *hash_ctx,
+                                            Error **errp)
+{
+    if (hash_ctx != NULL) {
+        gcry_md_close((gcry_md_hd_t) hash_ctx);
+    }
+
+    return 0;
+}
+
+static
+int qcrypto_gcrypt_hash_accumulate_bytesv(QCryptoHashAlgorithm alg,
+                                          qcrypto_hash_accumulate_ctx_t *accumulate_ctx,
+                                          const struct iovec *iov,
+                                          size_t niov,
+                                          uint8_t **result,
+                                          size_t *resultlen,
+                                          Error **errp)
+{
+    int i, ret;
+    gcry_md_hd_t ctx_copy;
+    unsigned char *digest;
+
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    for (i = 0; i < niov; i++) {
+        gcry_md_write((gcry_md_hd_t) accumulate_ctx, iov[i].iov_base, iov[i].iov_len);
+    }
+
+    ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]);
+    if (ret <= 0) {
+        error_setg(errp,
+                   "Unable to get hash length: %s",
+                   gcry_strerror(ret));
+        return -1;
+    }
+
+    if (*resultlen == 0) {
+        *resultlen = ret;
+        *result = g_new0(uint8_t, *resultlen);
+    } else if (*resultlen != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *resultlen, ret);
+        return -1;
+    }
+
+    /*
+     * Make a copy so we don't distort the main context
+     * by calculating the intermediate hash
+     */
+    ret = gcry_md_copy(&ctx_copy, (gcry_md_hd_t) accumulate_ctx);
+    if (ret <= 0) {
+        error_setg(errp, "Unable to make copy: %s", gcry_strerror(ret));
+        return -1;
+    }
+
+    digest = gcry_md_read(ctx_copy, 0);
+    if (!digest) {
+        error_setg(errp,
+                   "No digest produced");
+        return -1;
+    }
+    memcpy(*result, digest, *resultlen);
+    gcry_md_close(ctx_copy);
+
+    return 0;
+}
+
 
 QCryptoHashDriver qcrypto_hash_lib_driver = {
     .hash_bytesv = qcrypto_gcrypt_hash_bytesv,
+    .hash_accumulate_bytesv = qcrypto_gcrypt_hash_accumulate_bytesv,
+    .accumulate_new_ctx = qcrypto_gcrypt_hash_accumulate_new_ctx,
+    .accumulate_free_ctx = qcrypto_gcrypt_hash_accumulate_free_ctx,
 };
diff --git a/crypto/hash-glib.c b/crypto/hash-glib.c
index 82de9db705..c0d1d72c88 100644
--- a/crypto/hash-glib.c
+++ b/crypto/hash-glib.c
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash algorithms
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -95,6 +96,94 @@ qcrypto_glib_hash_bytesv(QCryptoHashAlgorithm alg,
 }
 
 
+static
+int qcrypto_glib_hash_accumulate_new_ctx(QCryptoHashAlgorithm alg,
+                                         qcrypto_hash_accumulate_ctx_t **accumulate_ctx,
+                                         Error **errp)
+{
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    *accumulate_ctx = g_checksum_new(qcrypto_hash_alg_map[alg]);
+
+    return 0;
+}
+
+static
+int qcrypto_glib_hash_accumulate_free_ctx(qcrypto_hash_accumulate_ctx_t *hash_ctx,
+                                          Error **errp)
+{
+    if (hash_ctx != NULL) {
+        g_checksum_free((GChecksum *) hash_ctx);
+    }
+
+    return 0;
+}
+
+
+static
+int qcrypto_glib_hash_accumulate_bytesv(QCryptoHashAlgorithm alg,
+                                        qcrypto_hash_accumulate_ctx_t *accumulate_ctx,
+                                        const struct iovec *iov,
+                                        size_t niov,
+                                        uint8_t **result,
+                                        size_t *resultlen,
+                                        Error **errp)
+{
+    int i, ret;
+    GChecksum *ctx_copy;
+
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    for (i = 0; i < niov; i++) {
+        g_checksum_update((GChecksum *) accumulate_ctx, iov[i].iov_base, iov[i].iov_len);
+    }
+
+    ret = g_checksum_type_get_length(qcrypto_hash_alg_map[alg]);
+    if (ret < 0) {
+        error_setg(errp, "%s",
+                   "Unable to get hash length");
+        return -1;
+    }
+    if (*resultlen == 0) {
+        *resultlen = ret;
+        *result = g_new0(uint8_t, *resultlen);
+    } else if (*resultlen != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *resultlen, ret);
+        return -1;
+    }
+
+    /*
+    Make a copy so we don't distort the main context
+    by calculating the intermediate hash.
+    */
+    ctx_copy = g_checksum_copy((GChecksum *) accumulate_ctx);
+    if (ctx_copy == NULL) {
+        error_setg(errp, "Unable to make copy: %s", __func__);
+        return -1;
+    }
+
+    g_checksum_get_digest((GChecksum *) ctx_copy, *result, resultlen);
+    g_checksum_free(ctx_copy);
+
+    return 0;
+}
+
+
 QCryptoHashDriver qcrypto_hash_lib_driver = {
     .hash_bytesv = qcrypto_glib_hash_bytesv,
+    .hash_accumulate_bytesv = qcrypto_glib_hash_accumulate_bytesv,
+    .accumulate_new_ctx = qcrypto_glib_hash_accumulate_new_ctx,
+    .accumulate_free_ctx = qcrypto_glib_hash_accumulate_free_ctx,
 };
diff --git a/crypto/hash-gnutls.c b/crypto/hash-gnutls.c
index 17911ac5d1..9464893213 100644
--- a/crypto/hash-gnutls.c
+++ b/crypto/hash-gnutls.c
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash algorithms
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2021 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -99,6 +100,87 @@ qcrypto_gnutls_hash_bytesv(QCryptoHashAlgorithm alg,
 }
 
 
+static
+int qcrypto_gnutls_hash_accumulate_new_ctx(QCryptoHashAlgorithm alg,
+                                           qcrypto_hash_accumulate_ctx_t **hash_ctx,
+                                           Error **errp)
+{
+    int ret;
+
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    ret = gnutls_hash_init((gnutls_hash_hd_t *) hash_ctx, qcrypto_hash_alg_map[alg]);
+    if (ret < 0) {
+        error_setg(errp,
+                   "Unable to initialize hash algorithm: %s",
+                   gnutls_strerror(ret));
+        return -1;
+    }
+
+    return 0;
+}
+
+static
+int qcrypto_gnutls_hash_accumulate_free_ctx(qcrypto_hash_accumulate_ctx_t *hash_ctx,
+                                            Error **errp)
+{
+    if (hash_ctx != NULL) {
+        gnutls_hash_deinit((gnutls_hash_hd_t) hash_ctx, NULL);
+    }
+
+    return 0;
+}
+
+static
+int qcrypto_gnutls_hash_accumulate_bytesv(QCryptoHashAlgorithm alg,
+                                          qcrypto_hash_accumulate_ctx_t *hash_ctx,
+                                          const struct iovec *iov,
+                                          size_t niov,
+                                          uint8_t **result,
+                                          size_t *resultlen,
+                                          Error **errp)
+{
+    int i, ret;
+
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
+    if (*resultlen == 0) {
+        *resultlen = ret;
+        *result = g_new0(uint8_t, *resultlen);
+    } else if (*resultlen != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *resultlen, ret);
+        return -1;
+    }
+
+    for (i = 0; i < niov; i++) {
+        gnutls_hash((gnutls_hash_hd_t) hash_ctx,
+                    iov[i].iov_base, iov[i].iov_len);
+    }
+
+    /* Make a copy so we don't distort the main context */
+    gnutls_hash_hd_t copy = gnutls_hash_copy((gnutls_hash_hd_t) hash_ctx);
+    gnutls_hash_deinit(copy, *result);
+
+    return 0;
+}
+
+
 QCryptoHashDriver qcrypto_hash_lib_driver = {
     .hash_bytesv = qcrypto_gnutls_hash_bytesv,
+    .hash_accumulate_bytesv = qcrypto_gnutls_hash_accumulate_bytesv,
+    .accumulate_new_ctx = qcrypto_gnutls_hash_accumulate_new_ctx,
+    .accumulate_free_ctx = qcrypto_gnutls_hash_accumulate_free_ctx,
 };
diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c
index 1ca1a41062..e21d0c6cf9 100644
--- a/crypto/hash-nettle.c
+++ b/crypto/hash-nettle.c
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash algorithms
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2016 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -155,7 +156,99 @@ qcrypto_nettle_hash_bytesv(QCryptoHashAlgorithm alg,
     return 0;
 }
 
+static
+int qcrypto_nettle_hash_accumulate_new_ctx(QCryptoHashAlgorithm alg,
+                                           qcrypto_hash_accumulate_ctx_t **hash_ctx,
+                                           Error **errp)
+{
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    *((union qcrypto_hash_ctx **) hash_ctx) = g_malloc(sizeof(union qcrypto_hash_ctx));
+
+    qcrypto_hash_alg_map[alg].init(*((union qcrypto_hash_ctx **) accumulate_ctx));
+
+    return 0;
+}
+
+static
+int qcrypto_nettle_hash_accumulate_free_ctx(qcrypto_hash_accumulate_ctx_t *hash_ctx,
+                                            Error **errp)
+{
+    g_free((union qcrypto_hash_ctx *) hash_ctx);
+    return 0;
+}
+
+static
+int qcrypto_nettle_hash_accumulate_bytesv(QCryptoHashAlgorithm alg,
+                                          qcrypto_hash_accumulate_ctx_t *hash_ctx,
+                                          const struct iovec *iov,
+                                          size_t niov,
+                                          uint8_t **result,
+                                          size_t *resultlen,
+                                          Error **errp)
+{
+    union qcrypto_hash_ctx *ctx_copy;
+    int i;
+
+    if (!qcrypto_hash_supports(alg)) {
+        error_setg(errp,
+                   "Unknown hash algorithm %d",
+                   alg);
+        return -1;
+    }
+
+    for (i = 0; i < niov; i++) {
+        /* Some versions of nettle have functions
+         * declared with 'int' instead of 'size_t'
+         * so to be safe avoid writing more than
+         * UINT_MAX bytes at a time
+         */
+        size_t len = iov[i].iov_len;
+        uint8_t *base = iov[i].iov_base;
+        while (len) {
+            size_t shortlen = MIN(len, UINT_MAX);
+            qcrypto_hash_alg_map[alg].write((union qcrypto_hash_ctx *) hash_ctx,
+                                            len, base);
+            len -= shortlen;
+            base += len;
+        }
+    }
+
+    if (*resultlen == 0) {
+        *resultlen = qcrypto_hash_alg_map[alg].len;
+        *result = g_new0(uint8_t, *resultlen);
+    } else if (*resultlen != qcrypto_hash_alg_map[alg].len) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %zu",
+                   *resultlen, qcrypto_hash_alg_map[alg].len);
+        return -1;
+    }
+
+    /*
+    Make a copy so we don't distort the main context
+    by calculating the intermediate hash
+    */
+    ctx_copy = g_new(union qcrypto_hash_ctx, 1);
+    memcpy(ctx_copy, (union qcrypto_hash_ctx *) hash_ctx,
+           sizeof(union qcrypto_hash_ctx));
+
+    qcrypto_hash_alg_map[alg].result(ctx_copy,
+                                     *resultlen, *result);
+
+    g_free(ctx_copy);
+
+    return 0;
+}
+
 
 QCryptoHashDriver qcrypto_hash_lib_driver = {
     .hash_bytesv = qcrypto_nettle_hash_bytesv,
+    .hash_accumulate_bytesv = qcrypto_nettle_hash_accumulate_bytesv,
+    .accumulate_new_ctx = qcrypto_nettle_hash_accumulate_new_ctx,
+    .accumulate_free_ctx = qcrypto_nettle_hash_accumulate_free_ctx,
 };
diff --git a/crypto/hash.c b/crypto/hash.c
index b0f8228bdc..0d45ce1e1b 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash algorithms
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -77,6 +78,47 @@ int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
     return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
 }
 
+int qcrypto_hash_accumulate_bytesv(QCryptoHashAlgorithm alg,
+                                   qcrypto_hash_accumulate_ctx_t *accumulate_ctx,
+                                   const struct iovec *iov,
+                                   size_t niov,
+                                   uint8_t **result,
+                                   size_t *resultlen,
+                                   Error **errp)
+{
+#ifdef CONFIG_AF_ALG
+    qemu_log_mask(LOG_UNIMP, "%s: AF_ALG support unimplemented.\n", __func__);
+    return 1;
+#else
+    return qcrypto_hash_lib_driver.hash_accumulate_bytesv(alg, accumulate_ctx,
+                                                          iov, niov, result,
+                                                          resultlen, NULL);
+#endif /* CONFIG_AF_ALG */
+}
+
+int qcrypto_hash_accumulate_new_ctx(QCryptoHashAlgorithm alg,
+                                    qcrypto_hash_accumulate_ctx_t **accumulate_ctx,
+                                    Error **errp)
+{
+#ifdef CONFIG_AF_ALG
+    qemu_log_mask(LOG_UNIMP, "%s: AF_ALG support unimplemented.\n", __func__);
+    return 1;
+#else
+    return qcrypto_hash_lib_driver.accumulate_new_ctx(alg, accumulate_ctx, errp);
+#endif /* CONFIG_AF_ALG */
+}
+
+int qcrypto_hash_accumulate_free_ctx(qcrypto_hash_accumulate_ctx_t *accumulate_ctx,
+                                     Error **errp)
+{
+#ifdef CONFIG_AF_ALG
+    qemu_log_mask(LOG_UNIMP, "%s: AF_ALG support unimplemented.\n", __func__);
+    return 1;
+#else
+    return qcrypto_hash_lib_driver.accumulate_free_ctx(accumulate_ctx, errp);
+#endif /* CONFIG_AF_ALG */
+}
+
 static const char hex[] = "0123456789abcdef";
 
 int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
diff --git a/crypto/hashpriv.h b/crypto/hashpriv.h
index cee26ccb47..49b3927208 100644
--- a/crypto/hashpriv.h
+++ b/crypto/hashpriv.h
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash driver supports
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
  *
  * Authors:
@@ -24,6 +25,16 @@ struct QCryptoHashDriver {
                        uint8_t **result,
                        size_t *resultlen,
                        Error **errp);
+    int (*hash_accumulate_bytesv)(QCryptoHashAlgorithm alg,
+                                  void *hash_ctx,
+                                  const struct iovec *iov,
+                                  size_t niov,
+                                  uint8_t **result,
+                                  size_t *resultlen,
+                                  Error **errp);
+    int (*accumulate_new_ctx)(QCryptoHashAlgorithm alg, void **hash_ctx,
+                              Error **errp);
+    int (*accumulate_free_ctx)(void *hash_ctx, Error **errp);
 };
 
 extern QCryptoHashDriver qcrypto_hash_lib_driver;
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 54d87aa2a1..fb8ae2d099 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -1,6 +1,7 @@
 /*
  * QEMU Crypto hash algorithms
  *
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
  * Copyright (c) 2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -25,6 +26,8 @@
 
 /* See also "QCryptoHashAlgorithm" defined in qapi/crypto.json */
 
+typedef void qcrypto_hash_accumulate_ctx_t;
+
 /**
  * qcrypto_hash_supports:
  * @alg: the hash algorithm
@@ -120,6 +123,68 @@ int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
                          char **digest,
                          Error **errp);
 
+/**
+ * qcrypto_hash_accumulate_bytesv:
+ * @alg: the hash algorithm
+ * @accumulate_ctx: pointer to the algorithm's context for further hash operations
+ * @iov: the array of memory regions to hash
+ * @niov: the length of @iov
+ * @result: pointer to hold output hash
+ * @resultlen: pointer to hold length of @result
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Computes the hash across all the memory regions
+ * present in @iov using the existing hash context
+ * given in @accumulate_ctx. The @result pointer will be
+ * filled with raw bytes representing the computed
+ * hash, which will have length @resultlen. The
+ * memory pointer in @result must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_accumulate_bytesv(QCryptoHashAlgorithm alg,
+                                   qcrypto_hash_accumulate_ctx_t *accumulate_ctx,
+                                   const struct iovec *iov,
+                                   size_t niov,
+                                   uint8_t **result,
+                                   size_t *resultlen,
+                                   Error **errp);
+
+/**
+ * qcrypto_hash_accumulate_new_ctx:
+ * @alg: the hash algorithm
+ * @accumulate_ctx: pointer to the pointer holding the algorithm's
+ *                  context for further hash operations. The pointer will
+ *                  be modified to point to the memory this function
+ *                  allocates to hold the context.
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Creates a new hashing context for the chosen algorithm for
+ * usage with qcrypto_hash_accumulate_bytesv().
+ * This is useful for when one has multiple inputs to compute a hash, but
+ * not all are available at a single point in time, making qcrypto_hash_bytesv()
+ * inadequate. The @accumulate_ctx pointer must be released with a call to
+ * qcrypto_hash_accumulate_free_ctx() once all hash operations are complete.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_accumulate_new_ctx(QCryptoHashAlgorithm alg,
+                                    qcrypto_hash_accumulate_ctx_t **accumulate_ctx,
+                                    Error **errp);
+
+/**
+ * qcrypto_hash_accumulate_free_ctx:
+ * @accumulate_ctx: pointer to the algorithm's context for further hash operations
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * frees a hashing context for the chosen algorithm.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_accumulate_free_ctx(qcrypto_hash_accumulate_ctx_t *accumulate_ctx,
+                                     Error **errp);
+
 /**
  * qcrypto_hash_digest:
  * @alg: the hash algorithm
