summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/common/checksum
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/checksum')
-rw-r--r--src/VBox/Runtime/common/checksum/Makefile.kup0
-rw-r--r--src/VBox/Runtime/common/checksum/RTSha1Digest.cpp201
-rw-r--r--src/VBox/Runtime/common/checksum/RTSha256Digest.cpp201
-rw-r--r--src/VBox/Runtime/common/checksum/adler32.cpp181
-rw-r--r--src/VBox/Runtime/common/checksum/alt-md2.cpp282
-rw-r--r--src/VBox/Runtime/common/checksum/alt-md4.cpp293
-rw-r--r--src/VBox/Runtime/common/checksum/alt-md5.cpp374
-rw-r--r--src/VBox/Runtime/common/checksum/alt-sha1.cpp535
-rw-r--r--src/VBox/Runtime/common/checksum/alt-sha256.cpp693
-rw-r--r--src/VBox/Runtime/common/checksum/alt-sha3.cpp642
-rw-r--r--src/VBox/Runtime/common/checksum/alt-sha512.cpp805
-rw-r--r--src/VBox/Runtime/common/checksum/crc16ccitt.cpp118
-rw-r--r--src/VBox/Runtime/common/checksum/crc32-zlib.cpp99
-rw-r--r--src/VBox/Runtime/common/checksum/crc32.cpp196
-rw-r--r--src/VBox/Runtime/common/checksum/crc32c.cpp132
-rw-r--r--src/VBox/Runtime/common/checksum/crc64.cpp196
-rw-r--r--src/VBox/Runtime/common/checksum/ipv4.cpp774
-rw-r--r--src/VBox/Runtime/common/checksum/ipv6.cpp136
-rw-r--r--src/VBox/Runtime/common/checksum/manifest-file.cpp94
-rw-r--r--src/VBox/Runtime/common/checksum/manifest.cpp593
-rw-r--r--src/VBox/Runtime/common/checksum/manifest2.cpp1477
-rw-r--r--src/VBox/Runtime/common/checksum/manifest3.cpp667
-rw-r--r--src/VBox/Runtime/common/checksum/md2str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/md4str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/md5str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-md2.cpp96
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-md4.cpp94
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-md5.cpp84
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-sha1.cpp100
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-sha256.cpp150
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-sha3.cpp270
-rw-r--r--src/VBox/Runtime/common/checksum/openssl-sha512.cpp151
-rw-r--r--src/VBox/Runtime/common/checksum/sha1str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/sha224str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/sha256str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/sha384str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/sha512str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/sha512t224str.cpp59
-rw-r--r--src/VBox/Runtime/common/checksum/sha512t256str.cpp59
39 files changed, 10224 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/checksum/Makefile.kup b/src/VBox/Runtime/common/checksum/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/Makefile.kup
diff --git a/src/VBox/Runtime/common/checksum/RTSha1Digest.cpp b/src/VBox/Runtime/common/checksum/RTSha1Digest.cpp
new file mode 100644
index 00000000..ad05f1b0
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/RTSha1Digest.cpp
@@ -0,0 +1,201 @@
+/* $Id: RTSha1Digest.cpp $ */
+/** @file
+ * IPRT - SHA1 digest creation
+ *
+ * @todo Replace this with generic RTCrDigest based implementation. Too much
+ * stupid code duplication.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/file.h>
+
+
+RTR3DECL(int) RTSha1Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+ *ppszDigest = NULL;
+
+ /* Initialize the hash context. */
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+
+ /* Buffer size for progress callback */
+ double rdMulti = 100.0 / (cbBuf ? (double)cbBuf : 1.0);
+
+ /* Working buffer */
+ char *pvTmp = (char*)pvBuf;
+
+ /* Process the memory in blocks */
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ size_t cbRead = RT_MIN(cbBuf - cbReadTotal, _1M);
+ RTSha1Update(&Ctx, pvTmp, cbRead);
+ cbReadTotal += cbRead;
+ pvTmp += cbRead;
+
+ /* Call the progress callback if one is defined */
+ if (pfnProgressCallback)
+ {
+ rc = pfnProgressCallback((unsigned)((double)cbReadTotal * rdMulti), pvUser);
+ if (RT_FAILURE(rc))
+ break; /* canceled */
+ }
+ /* Finished? */
+ if (cbReadTotal == cbBuf)
+ break;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /* Finally calculate & format the SHA1 sum */
+ uint8_t abHash[RTSHA1_HASH_SIZE];
+ RTSha1Final(&Ctx, abHash);
+
+ char *pszDigest;
+ rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSha1ToString(abHash, pszDigest, RTSHA1_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ *ppszDigest = pszDigest;
+ else
+ RTStrFree(pszDigest);
+ }
+ }
+
+ return rc;
+}
+
+RTR3DECL(int) RTSha1DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
+
+ *ppszDigest = NULL;
+
+ /* Open the file to calculate a SHA1 sum of */
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Fetch the file size. Only needed if there is a progress callback. */
+ double rdMulti = 0.0;
+ if (pfnProgressCallback)
+ {
+ uint64_t cbFile;
+ rc = RTFileQuerySize(hFile, &cbFile);
+ if (RT_FAILURE(rc))
+ {
+ RTFileClose(hFile);
+ return rc;
+ }
+ rdMulti = 100.0 / (cbFile ? (double)cbFile : 1.0);
+ }
+
+ /* Allocate a reasonably large buffer, fall back on a tiny one. */
+ void *pvBufFree;
+ size_t cbBuf = _1M;
+ void *pvBuf = pvBufFree = RTMemTmpAlloc(cbBuf);
+ if (!pvBuf)
+ {
+ cbBuf = 0x1000;
+ pvBuf = alloca(cbBuf);
+ }
+
+ /* Initialize the hash context. */
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+
+ /* Read that file in blocks */
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ size_t cbRead;
+ rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead);
+ if (RT_FAILURE(rc) || !cbRead)
+ break;
+ RTSha1Update(&Ctx, pvBuf, cbRead);
+ cbReadTotal += cbRead;
+
+ /* Call the progress callback if one is defined */
+ if (pfnProgressCallback)
+ {
+ rc = pfnProgressCallback((unsigned)((double)cbReadTotal * rdMulti), pvUser);
+ if (RT_FAILURE(rc))
+ break; /* canceled */
+ }
+ }
+ RTMemTmpFree(pvBufFree);
+ RTFileClose(hFile);
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Finally calculate & format the SHA1 sum */
+ uint8_t abHash[RTSHA1_HASH_SIZE];
+ RTSha1Final(&Ctx, abHash);
+
+ char *pszDigest;
+ rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSha1ToString(abHash, pszDigest, RTSHA1_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ *ppszDigest = pszDigest;
+ else
+ RTStrFree(pszDigest);
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp b/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp
new file mode 100644
index 00000000..c6da7e9f
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp
@@ -0,0 +1,201 @@
+/* $Id: RTSha256Digest.cpp $ */
+/** @file
+ * IPRT - SHA256 digest creation
+ *
+ * @todo Replace this with generic RTCrDigest based implementation. Too much
+ * stupid code duplication.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/file.h>
+
+
+RTR3DECL(int) RTSha256Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+ *ppszDigest = NULL;
+
+ /* Initialize the hash context. */
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+
+ /* Buffer size for progress callback */
+ double rdMulti = 100.0 / (cbBuf ? (double)cbBuf : 1);
+
+ /* Working buffer */
+ char *pvTmp = (char*)pvBuf;
+
+ /* Process the memory in blocks */
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ size_t cbRead = RT_MIN(cbBuf - cbReadTotal, _1M);
+ RTSha256Update(&Ctx, pvTmp, cbRead);
+ cbReadTotal += cbRead;
+ pvTmp += cbRead;
+
+ /* Call the progress callback if one is defined */
+ if (pfnProgressCallback)
+ {
+ rc = pfnProgressCallback((unsigned)((double)cbReadTotal * rdMulti), pvUser);
+ if (RT_FAILURE(rc))
+ break; /* canceled */
+ }
+ /* Finished? */
+ if (cbReadTotal == cbBuf)
+ break;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /* Finally calculate & format the SHA256 sum */
+ uint8_t abHash[RTSHA256_HASH_SIZE];
+ RTSha256Final(&Ctx, abHash);
+
+ char *pszDigest;
+ rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSha256ToString(abHash, pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ *ppszDigest = pszDigest;
+ else
+ RTStrFree(pszDigest);
+ }
+ }
+
+ return rc;
+}
+
+RTR3DECL(int) RTSha256DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
+
+ *ppszDigest = NULL;
+
+ /* Initialize the hash context. */
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+
+ /* Open the file to calculate a SHA256 sum of */
+ RTFILE hFile;
+ int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Fetch the file size. Only needed if there is a progress callback. */
+ double rdMulti = 0.0;
+ if (pfnProgressCallback)
+ {
+ uint64_t cbFile;
+ rc = RTFileQuerySize(hFile, &cbFile);
+ if (RT_FAILURE(rc))
+ {
+ RTFileClose(hFile);
+ return rc;
+ }
+ rdMulti = 100.0 / (cbFile ? (double)cbFile : 1.0);
+ }
+
+ /* Allocate a reasonably large buffer, fall back on a tiny one. */
+ void *pvBufFree;
+ size_t cbBuf = _1M;
+ void *pvBuf = pvBufFree = RTMemTmpAlloc(cbBuf);
+ if (!pvBuf)
+ {
+ cbBuf = 0x1000;
+ pvBuf = alloca(cbBuf);
+ }
+
+ /* Read that file in blocks */
+ size_t cbReadTotal = 0;
+ for (;;)
+ {
+ size_t cbRead;
+ rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead);
+ if (RT_FAILURE(rc) || !cbRead)
+ break;
+ RTSha256Update(&Ctx, pvBuf, cbRead);
+ cbReadTotal += cbRead;
+
+ /* Call the progress callback if one is defined */
+ if (pfnProgressCallback)
+ {
+ rc = pfnProgressCallback((unsigned)((double)cbReadTotal * rdMulti), pvUser);
+ if (RT_FAILURE(rc))
+ break; /* canceled */
+ }
+ }
+ RTMemTmpFree(pvBufFree);
+ RTFileClose(hFile);
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Finally calculate & format the SHA256 sum */
+ uint8_t abHash[RTSHA256_HASH_SIZE];
+ RTSha256Final(&Ctx, abHash);
+
+ char *pszDigest;
+ rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSha256ToString(abHash, pszDigest, RTSHA256_DIGEST_LEN + 1);
+ if (RT_SUCCESS(rc))
+ *ppszDigest = pszDigest;
+ else
+ RTStrFree(pszDigest);
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/adler32.cpp b/src/VBox/Runtime/common/checksum/adler32.cpp
new file mode 100644
index 00000000..1e6bbd1e
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/adler32.cpp
@@ -0,0 +1,181 @@
+/* $Id: adler32.cpp $ */
+/** @file
+ * IPRT - Adler-32
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crc.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define RTCRC_ADLER_32_NUMBER 65521
+
+
+RTDECL(uint32_t) RTCrcAdler32(void const *pv, size_t cb)
+{
+ /* Don't want to do the unrolling twice. */
+ return RTCrcAdler32Process(RTCrcAdler32Start(), pv, cb);
+}
+
+
+RTDECL(uint32_t) RTCrcAdler32Start(void)
+{
+ return 1;
+}
+
+
+RTDECL(uint32_t) RTCrcAdler32Process(uint32_t u32Crc, void const *pv, size_t cb)
+{
+ uint8_t const *pbSrc = (uint8_t const *)pv;
+ uint32_t a = u32Crc & 0xffff;
+ uint32_t b = u32Crc >> 16;
+ if (cb < 64 /* randomly selected number */)
+ {
+ while (cb-- > 0)
+ {
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ }
+ }
+ else
+ {
+ switch (((uintptr_t)pbSrc & 0x3))
+ {
+ case 0:
+ break;
+
+ case 1:
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ cb--;
+ RT_FALL_THRU();
+
+ case 2:
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ cb--;
+ RT_FALL_THRU();
+
+ case 3:
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ cb--;
+ break;
+ }
+
+ while (cb >= 4)
+ {
+ uint32_t u32 = *(uint32_t const *)pbSrc;
+ pbSrc += 4;
+
+ a += u32 & 0xff;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+
+ a += (u32 >> 8) & 0xff;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+
+ a += (u32 >> 16) & 0xff;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+
+ a += (u32 >> 24) & 0xff;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+
+ cb -= 4;
+ }
+
+ switch (cb)
+ {
+ case 0:
+ break;
+
+ case 3:
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ cb--;
+ RT_FALL_THRU();
+
+ case 2:
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ cb--;
+ RT_FALL_THRU();
+
+ case 1:
+ a += *pbSrc++;
+ a %= RTCRC_ADLER_32_NUMBER;
+ b += a;
+ b %= RTCRC_ADLER_32_NUMBER;
+ cb--;
+ break;
+ }
+ }
+
+ return a | (b << 16);
+}
+
+
+RTDECL(uint32_t) RTCrcAdler32Finish(uint32_t u32Crc)
+{
+ return u32Crc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/alt-md2.cpp b/src/VBox/Runtime/common/checksum/alt-md2.cpp
new file mode 100644
index 00000000..258cf510
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-md2.cpp
@@ -0,0 +1,282 @@
+/* $Id: alt-md2.cpp $ */
+/** @file
+ * IPRT - Message-Digest Algorithm 2, Alternative Implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The MD2 block size. */
+#define RTMD2_BLOCK_SIZE 16
+/** The offset of the buffer into RTMD2ALTPRIVATECTX::abStateX. */
+#define RTMD2_BUF_OFF RTMD2_BLOCK_SIZE
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/types.h>
+
+
+/** Our private context structure. */
+typedef struct RTMD2ALTPRIVATECTX
+{
+ /** The state (X).
+ * The staging buffer starts byte 16. */
+ uint8_t abStateX[RTMD2_BLOCK_SIZE * 3];
+ /** The checksum. */
+ uint8_t abChecksum[RTMD2_BLOCK_SIZE];
+ /** The number of buffered bytes. */
+ uint8_t cbBuffer;
+} RTMD2ALTPRIVATECTX;
+
+#define RT_MD2_PRIVATE_ALT_CONTEXT
+#include <iprt/md2.h>
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+AssertCompile(RT_SIZEOFMEMB(RTMD2CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTMD2CONTEXT, AltPrivate));
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** PI substitation used by MD2. */
+static uint8_t const g_PiSubst[256] =
+{
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,
+ 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,
+ 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,
+ 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,
+ 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,
+ 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,
+ 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,
+ 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,
+ 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,
+ 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,
+ 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,
+ 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
+ 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,
+ 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
+ 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20,
+};
+
+
+RTDECL(void) RTMd2Init(PRTMD2CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbBuffer = 0;
+ RT_ZERO(pCtx->AltPrivate.abStateX);
+ RT_ZERO(pCtx->AltPrivate.abChecksum);
+}
+RT_EXPORT_SYMBOL(RTMd2Init);
+
+
+
+/**
+ * Initializes the processing of a whole block directly from the input buffer.
+ *
+ * This will update the checksum as well as initializing abStateX.
+ *
+ * @param pCtx The MD2 context.
+ * @param pbBlock The block.
+ */
+DECLINLINE(void) rtMd2BlockInit(PRTMD2CONTEXT pCtx, const uint8_t *pbBlock)
+{
+ uint8_t bL = pCtx->AltPrivate.abChecksum[15];
+ for (unsigned j = 0; j < RTMD2_BLOCK_SIZE; j++)
+ {
+ uint8_t bIn = pbBlock[j];
+ pCtx->AltPrivate.abStateX[j + RTMD2_BLOCK_SIZE] = bIn;
+ pCtx->AltPrivate.abStateX[j + RTMD2_BLOCK_SIZE * 2] = bIn ^ pCtx->AltPrivate.abStateX[j];
+ bL = pCtx->AltPrivate.abChecksum[j] ^= g_PiSubst[bIn ^ bL];
+ }
+}
+
+
+/**
+ * Special version of rtMd2BlockInit that does not update the checksum.
+ *
+ * This is used in the final round when adding the checksum to the calculation.
+ *
+ * @param pCtx The MD2 context.
+ * @param pbBlock The block (i.e. the checksum).
+ */
+DECLINLINE(void) rtMd2BlockInitNoChecksum(PRTMD2CONTEXT pCtx, const uint8_t *pbBlock)
+{
+ for (unsigned j = 0; j < RTMD2_BLOCK_SIZE; j++)
+ {
+ uint8_t bIn = pbBlock[j];
+ pCtx->AltPrivate.abStateX[j + RTMD2_BLOCK_SIZE] = bIn;
+ pCtx->AltPrivate.abStateX[j + RTMD2_BLOCK_SIZE * 2] = bIn ^ pCtx->AltPrivate.abStateX[j];
+ }
+}
+
+
+/**
+ * Initalizes the abStateX from a full buffer and update the checksum.
+ *
+ * The buffer is part of the abStateX structure (bytes 16 thru 31), so this
+ * is a somewhat reduced version of rtMd2BlockInit.
+ *
+ * @param pCtx The MD2 context.
+ */
+DECLINLINE(void) rtMd2BlockInitBuffered(PRTMD2CONTEXT pCtx)
+{
+ uint8_t bL = pCtx->AltPrivate.abChecksum[15];
+ for (unsigned j = 0; j < RTMD2_BLOCK_SIZE; j++)
+ {
+ uint8_t bIn = pCtx->AltPrivate.abStateX[j + RTMD2_BLOCK_SIZE];
+ pCtx->AltPrivate.abStateX[j + RTMD2_BLOCK_SIZE * 2] = bIn ^ pCtx->AltPrivate.abStateX[j];
+ bL = pCtx->AltPrivate.abChecksum[j] ^= g_PiSubst[bIn ^ bL];
+ }
+}
+
+
+/**
+ * Process the current block.
+ *
+ * Requires one of the rtMd2BlockInit functions to be called first.
+ *
+ * @param pCtx The MD2 context.
+ */
+DECLINLINE(void) rtMd2BlockProcess(PRTMD2CONTEXT pCtx)
+{
+ uint8_t bT = 0;
+ for (unsigned j = 0; j < 18; j++) /* 18 rounds */
+ {
+ for (unsigned k = 0; k < RTMD2_BLOCK_SIZE * 3; k++)
+ pCtx->AltPrivate.abStateX[k] = bT = pCtx->AltPrivate.abStateX[k] ^ g_PiSubst[bT];
+ bT += (uint8_t)j;
+ }
+}
+
+
+RTDECL(void) RTMd2Update(PRTMD2CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ Assert(pCtx->AltPrivate.cbBuffer < RTMD2_BLOCK_SIZE);
+ uint8_t const *pbBuf = (uint8_t const *)pvBuf;
+
+ /*
+ * Deal with buffered bytes first.
+ */
+ if (pCtx->AltPrivate.cbBuffer)
+ {
+ uint8_t cbMissing = RTMD2_BLOCK_SIZE - pCtx->AltPrivate.cbBuffer;
+ if (cbBuf >= cbMissing)
+ {
+ memcpy(&pCtx->AltPrivate.abStateX[RTMD2_BUF_OFF + pCtx->AltPrivate.cbBuffer], pbBuf, cbMissing);
+ pbBuf += cbMissing;
+ cbBuf -= cbMissing;
+
+ rtMd2BlockInitBuffered(pCtx);
+ rtMd2BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbBuffer = 0;
+ }
+ else
+ {
+ memcpy(&pCtx->AltPrivate.abStateX[RTMD2_BUF_OFF + pCtx->AltPrivate.cbBuffer], pbBuf, cbBuf);
+ pCtx->AltPrivate.cbBuffer += (uint8_t)cbBuf;
+ return;
+ }
+ }
+
+ /*
+ * Process full blocks directly from the input buffer.
+ */
+ while (cbBuf >= RTMD2_BLOCK_SIZE)
+ {
+ rtMd2BlockInit(pCtx, pbBuf);
+ rtMd2BlockProcess(pCtx);
+
+ pbBuf += RTMD2_BLOCK_SIZE;
+ cbBuf -= RTMD2_BLOCK_SIZE;
+ }
+
+ /*
+ * Stash any remaining bytes into the context buffer.
+ */
+ if (cbBuf > 0)
+ {
+ memcpy(&pCtx->AltPrivate.abStateX[RTMD2_BUF_OFF], pbBuf, cbBuf);
+ pCtx->AltPrivate.cbBuffer = (uint8_t)cbBuf;
+ }
+}
+RT_EXPORT_SYMBOL(RTMd2Update);
+
+
+RTDECL(void) RTMd2Final(PRTMD2CONTEXT pCtx, uint8_t pabDigest[RTMD2_HASH_SIZE])
+{
+ Assert(pCtx->AltPrivate.cbBuffer < RTMD2_BLOCK_SIZE);
+
+ /*
+ * Pad the message to a multiple of 16 bytes. This is done even if the
+ * message already is a multiple of 16.
+ */
+ unsigned cbPad = RTMD2_BLOCK_SIZE - pCtx->AltPrivate.cbBuffer;
+ memset(&pCtx->AltPrivate.abStateX[RTMD2_BUF_OFF + pCtx->AltPrivate.cbBuffer], cbPad, cbPad);
+ rtMd2BlockInitBuffered(pCtx);
+ rtMd2BlockProcess(pCtx);
+ pCtx->AltPrivate.cbBuffer = 0;
+
+ /*
+ * Add the checksum.
+ */
+ rtMd2BlockInitNoChecksum(pCtx, pCtx->AltPrivate.abChecksum);
+ rtMd2BlockProcess(pCtx);
+
+ /*
+ * Done. Just copy out the digest.
+ */
+ memcpy(pabDigest, pCtx->AltPrivate.abStateX, RTMD2_HASH_SIZE);
+
+ RT_ZERO(pCtx->AltPrivate);
+ pCtx->AltPrivate.cbBuffer = UINT8_MAX;
+}
+RT_EXPORT_SYMBOL(RTMd2Final);
+
+
+RTDECL(void) RTMd2(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD2_HASH_SIZE])
+{
+ RTMD2CONTEXT Ctx;
+ RTMd2Init(&Ctx);
+ RTMd2Update(&Ctx, pvBuf, cbBuf);
+ RTMd2Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTMd2);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-md4.cpp b/src/VBox/Runtime/common/checksum/alt-md4.cpp
new file mode 100644
index 00000000..36ee8227
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-md4.cpp
@@ -0,0 +1,293 @@
+/* $Id: alt-md4.cpp $ */
+/** @file
+ * IPRT - Message-Digest Algorithm 4, Alternative Implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The MD4 block size in bytes. */
+#define RTMD4_BLOCK_SIZE 64
+/** The MD4 block size in bits. */
+#define RTMD4_BLOCK_SIZE_IN_BITS (RTMD4_BLOCK_SIZE * 8)
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/types.h>
+
+
+/** Our private context structure. */
+typedef struct RTMD4ALTPRIVATECTX
+{
+ uint32_t uA;
+ uint32_t uB;
+ uint32_t uC;
+ uint32_t uD;
+ /** Message length in bits. */
+ uint64_t cTotalBits;
+ /** Input buffer. cTotalBits indicates how much is present. */
+ union
+ {
+ uint8_t abBuffer[RTMD4_BLOCK_SIZE];
+ uint32_t aX[RTMD4_BLOCK_SIZE / 4];
+ } u;
+} RTMD4ALTPRIVATECTX;
+
+
+#define RT_MD4_PRIVATE_ALT_CONTEXT
+#include <iprt/md4.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+AssertCompile(RT_SIZEOFMEMB(RTMD4CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTMD4CONTEXT, AltPrivate));
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** MD4 padding. */
+static const uint8_t g_abMd4Padding[RTMD4_BLOCK_SIZE] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+
+
+
+RTDECL(void) RTMd4Init(PRTMD4CONTEXT pCtx)
+{
+ pCtx->AltPrivate.uA = UINT32_C(0x67452301);
+ pCtx->AltPrivate.uB = UINT32_C(0xefcdab89);
+ pCtx->AltPrivate.uC = UINT32_C(0x98badcfe);
+ pCtx->AltPrivate.uD = UINT32_C(0x10325476);
+ pCtx->AltPrivate.cTotalBits = 0;
+ RT_ZERO(pCtx->AltPrivate.u);
+}
+RT_EXPORT_SYMBOL(RTMd4Init);
+
+
+DECLINLINE(uint32_t) rtMd4FuncF(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+ return (uX & uY) | (~uX & uZ);
+}
+
+DECLINLINE(uint32_t) rtMd4FuncG(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+ return (uX & (uY | uZ)) | (uY & uZ);
+}
+
+DECLINLINE(uint32_t) rtMd4FuncH(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+ return uX ^ uY ^ uZ;
+}
+
+
+/**
+ * Process the current block.
+ *
+ * Requires one of the rtMD4BlockInit functions to be called first.
+ *
+ * @param pCtx The MD4 context.
+ */
+DECLINLINE(void) rtMD4BlockProcess(PRTMD4CONTEXT pCtx)
+{
+#ifdef RT_BIG_ENDIAN
+ /* Convert the X array to little endian. */
+ for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->AltPrivate.u.aX); i++)
+ pCtx->AltPrivate.u.aX[i] = RT_BSWAP_U32(pCtx->AltPrivate.u.aX[i]);
+#endif
+
+ /* Instead of saving A, B, C, D we copy them into variables and work on those. */
+ uint32_t A = pCtx->AltPrivate.uA;
+ uint32_t B = pCtx->AltPrivate.uB;
+ uint32_t C = pCtx->AltPrivate.uC;
+ uint32_t D = pCtx->AltPrivate.uD;
+
+ /* Round #1: */
+#define ABCD_K_S(a,b,c,d, k, s) ASMRotateLeftU32(a + rtMd4FuncF(b, c, d) + pCtx->AltPrivate.u.aX[k], s)
+ A = ABCD_K_S(A,B,C,D, 0, 3); D = ABCD_K_S(D,A,B,C, 1, 7); C = ABCD_K_S(C,D,A,B, 2, 11); B = ABCD_K_S(B,C,D,A, 3, 19);
+ A = ABCD_K_S(A,B,C,D, 4, 3); D = ABCD_K_S(D,A,B,C, 5, 7); C = ABCD_K_S(C,D,A,B, 6, 11); B = ABCD_K_S(B,C,D,A, 7, 19);
+ A = ABCD_K_S(A,B,C,D, 8, 3); D = ABCD_K_S(D,A,B,C, 9, 7); C = ABCD_K_S(C,D,A,B, 10, 11); B = ABCD_K_S(B,C,D,A, 11, 19);
+ A = ABCD_K_S(A,B,C,D, 12, 3); D = ABCD_K_S(D,A,B,C, 13, 7); C = ABCD_K_S(C,D,A,B, 14, 11); B = ABCD_K_S(B,C,D,A, 15, 19);
+#undef ABCD_K_S
+
+ /* Round #2: */
+#define ABCD_K_S(a,b,c,d, k, s) ASMRotateLeftU32(a + rtMd4FuncG(b, c, d) + pCtx->AltPrivate.u.aX[k] + UINT32_C(0x5a827999), s)
+ A = ABCD_K_S(A,B,C,D, 0, 3); D = ABCD_K_S(D,A,B,C, 4, 5); C = ABCD_K_S(C,D,A,B, 8, 9); B = ABCD_K_S(B,C,D,A, 12, 13);
+ A = ABCD_K_S(A,B,C,D, 1, 3); D = ABCD_K_S(D,A,B,C, 5, 5); C = ABCD_K_S(C,D,A,B, 9, 9); B = ABCD_K_S(B,C,D,A, 13, 13);
+ A = ABCD_K_S(A,B,C,D, 2, 3); D = ABCD_K_S(D,A,B,C, 6, 5); C = ABCD_K_S(C,D,A,B, 10, 9); B = ABCD_K_S(B,C,D,A, 14, 13);
+ A = ABCD_K_S(A,B,C,D, 3, 3); D = ABCD_K_S(D,A,B,C, 7, 5); C = ABCD_K_S(C,D,A,B, 11, 9); B = ABCD_K_S(B,C,D,A, 15, 13);
+#undef ABCD_K_S
+
+ /* Round #3: */
+#define ABCD_K_S(a,b,c,d, k, s) ASMRotateLeftU32(a + rtMd4FuncH(b, c, d) + pCtx->AltPrivate.u.aX[k] + UINT32_C(0x6ed9eba1), s)
+ A = ABCD_K_S(A,B,C,D, 0, 3); D = ABCD_K_S(D,A,B,C, 8, 9); C = ABCD_K_S(C,D,A,B, 4, 11); B = ABCD_K_S(B,C,D,A, 12, 15);
+ A = ABCD_K_S(A,B,C,D, 2, 3); D = ABCD_K_S(D,A,B,C, 10, 9); C = ABCD_K_S(C,D,A,B, 6, 11); B = ABCD_K_S(B,C,D,A, 14, 15);
+ A = ABCD_K_S(A,B,C,D, 1, 3); D = ABCD_K_S(D,A,B,C, 9, 9); C = ABCD_K_S(C,D,A,B, 5, 11); B = ABCD_K_S(B,C,D,A, 13, 15);
+ A = ABCD_K_S(A,B,C,D, 3, 3); D = ABCD_K_S(D,A,B,C, 11, 9); C = ABCD_K_S(C,D,A,B, 7, 11); B = ABCD_K_S(B,C,D,A, 15, 15);
+#undef ABCD_K_S
+
+ /* Perform the additions. */
+ pCtx->AltPrivate.uA += A;
+ pCtx->AltPrivate.uB += B;
+ pCtx->AltPrivate.uC += C;
+ pCtx->AltPrivate.uD += D;
+}
+
+
+RTDECL(void) RTMd4Update(PRTMD4CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ uint8_t const *pbBuf = (uint8_t const *)pvBuf;
+
+ /*
+ * Deal with buffered bytes first.
+ */
+ if (pCtx->AltPrivate.cTotalBits & (RTMD4_BLOCK_SIZE_IN_BITS - 1))
+ {
+ uint8_t cbBuffered = (pCtx->AltPrivate.cTotalBits >> 3) & (RTMD4_BLOCK_SIZE - 1);
+ uint8_t cbMissing = RTMD4_BLOCK_SIZE - cbBuffered;
+ if (cbBuf >= cbMissing)
+ {
+ memcpy(&pCtx->AltPrivate.u.abBuffer[cbBuffered], pbBuf, cbMissing);
+ pCtx->AltPrivate.cTotalBits += cbMissing << 3;
+ pbBuf += cbMissing;
+ cbBuf -= cbMissing;
+
+ rtMD4BlockProcess(pCtx);
+ }
+ else
+ {
+ memcpy(&pCtx->AltPrivate.u.abBuffer[cbBuffered], pbBuf, cbBuf);
+ pCtx->AltPrivate.cTotalBits += cbBuf << 3;
+ return;
+ }
+ }
+
+ /*
+ * Process full blocks directly from the input buffer.
+ */
+ while (cbBuf >= RTMD4_BLOCK_SIZE)
+ {
+ memcpy(&pCtx->AltPrivate.u.abBuffer[0], pbBuf, RTMD4_BLOCK_SIZE);
+ rtMD4BlockProcess(pCtx);
+
+ pbBuf += RTMD4_BLOCK_SIZE;
+ cbBuf -= RTMD4_BLOCK_SIZE;
+ pCtx->AltPrivate.cTotalBits += RTMD4_BLOCK_SIZE_IN_BITS;
+ }
+
+ /*
+ * Stash any remaining bytes into the context buffer.
+ */
+ if (cbBuf > 0)
+ {
+ memcpy(&pCtx->AltPrivate.u.abBuffer[0], pbBuf, cbBuf);
+ pCtx->AltPrivate.cTotalBits += cbBuf << 3;
+ }
+}
+RT_EXPORT_SYMBOL(RTMd4Update);
+
+
+RTDECL(void) RTMd4Final(PRTMD4CONTEXT pCtx, uint8_t pabDigest[RTMD4_HASH_SIZE])
+{
+ uint64_t const cTotalBits = pCtx->AltPrivate.cTotalBits;
+
+ /*
+ * Pad input to block size minus sizeof(cTotalBits).
+ */
+ uint8_t cbMissing = RTMD4_BLOCK_SIZE - ((cTotalBits >> 3) & (RTMD4_BLOCK_SIZE - 1));
+ uint8_t cbPadding = cbMissing + (cbMissing > 8 ? 0 : RTMD4_BLOCK_SIZE) - 8;
+ Assert(cbPadding > 0 && cbPadding <= sizeof(g_abMd4Padding));
+ RTMd4Update(pCtx, g_abMd4Padding, cbPadding);
+ Assert(((pCtx->AltPrivate.cTotalBits >> 3) & (RTMD4_BLOCK_SIZE - 1)) == RTMD4_BLOCK_SIZE - 8);
+
+ /*
+ * Encode the total bitcount at the end of the buffer and do the final round.
+ */
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 8] = (uint8_t)(cTotalBits );
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 7] = (uint8_t)(cTotalBits >> 8);
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 6] = (uint8_t)(cTotalBits >> 16);
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 5] = (uint8_t)(cTotalBits >> 24);
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 4] = (uint8_t)(cTotalBits >> 32);
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 3] = (uint8_t)(cTotalBits >> 40);
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 2] = (uint8_t)(cTotalBits >> 48);
+ pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 1] = (uint8_t)(cTotalBits >> 56);
+ rtMD4BlockProcess(pCtx);
+
+ /*
+ * Done. Just encode the digest.
+ */
+ pabDigest[ 0] = (uint8_t)(pCtx->AltPrivate.uA );
+ pabDigest[ 1] = (uint8_t)(pCtx->AltPrivate.uA >> 8);
+ pabDigest[ 2] = (uint8_t)(pCtx->AltPrivate.uA >> 16);
+ pabDigest[ 3] = (uint8_t)(pCtx->AltPrivate.uA >> 24);
+ pabDigest[ 4] = (uint8_t)(pCtx->AltPrivate.uB );
+ pabDigest[ 5] = (uint8_t)(pCtx->AltPrivate.uB >> 8);
+ pabDigest[ 6] = (uint8_t)(pCtx->AltPrivate.uB >> 16);
+ pabDigest[ 7] = (uint8_t)(pCtx->AltPrivate.uB >> 24);
+ pabDigest[ 8] = (uint8_t)(pCtx->AltPrivate.uC );
+ pabDigest[ 9] = (uint8_t)(pCtx->AltPrivate.uC >> 8);
+ pabDigest[10] = (uint8_t)(pCtx->AltPrivate.uC >> 16);
+ pabDigest[11] = (uint8_t)(pCtx->AltPrivate.uC >> 24);
+ pabDigest[12] = (uint8_t)(pCtx->AltPrivate.uD );
+ pabDigest[13] = (uint8_t)(pCtx->AltPrivate.uD >> 8);
+ pabDigest[14] = (uint8_t)(pCtx->AltPrivate.uD >> 16);
+ pabDigest[15] = (uint8_t)(pCtx->AltPrivate.uD >> 24);
+
+ /*
+ * Nuke the state.
+ */
+ RT_ZERO(pCtx->AltPrivate);
+}
+RT_EXPORT_SYMBOL(RTMd4Final);
+
+
+RTDECL(void) RTMd4(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD4_HASH_SIZE])
+{
+ RTMD4CONTEXT Ctx;
+ RTMd4Init(&Ctx);
+ RTMd4Update(&Ctx, pvBuf, cbBuf);
+ RTMd4Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTMd4);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-md5.cpp b/src/VBox/Runtime/common/checksum/alt-md5.cpp
new file mode 100644
index 00000000..b37ed13f
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-md5.cpp
@@ -0,0 +1,374 @@
+/* $Id: alt-md5.cpp $ */
+/** @file
+ * IPRT - MD5 message digest functions, alternative implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/* The code is virtually unchanged from the original version (see copyright
+ * notice below). Most changes are related to the function names and data
+ * types - in order to fit the code in the IPRT naming style. */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * RTMD5CONTEXT structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/md5.h>
+#include "internal/iprt.h"
+
+#include <iprt/string.h> /* for memcpy() */
+#if defined(RT_BIG_ENDIAN)
+# include <iprt/asm.h> /* RT_LE2H_U32 uses ASMByteSwapU32. */
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* The four core functions - F1 is optimized somewhat */
+#if 1
+/* #define F1(x, y, z) (x & y | ~x & z) */
+# define F1(x, y, z) (z ^ (x & (y ^ z)))
+# define F2(x, y, z) F1(z, x, y)
+# define F3(x, y, z) (x ^ y ^ z)
+# define F4(x, y, z) (y ^ (x | ~z))
+#else /* gcc 4.0.1 (x86) benefits from the explicitness of F1() here. */
+DECL_FORCE_INLINE(uint32_t) F1(uint32_t x, uint32_t y, uint32_t z)
+{
+ register uint32_t r = y ^ z;
+ r &= x;
+ r ^= z;
+ return r;
+}
+# define F2(x, y, z) F1(z, x, y)
+DECL_FORCE_INLINE(uint32_t) F3(uint32_t x, uint32_t y, uint32_t z)
+{
+ register uint32_t r = x ^ y;
+ r ^= z;
+ return r;
+}
+DECL_FORCE_INLINE(uint32_t) F4(uint32_t x, uint32_t y, uint32_t z)
+{
+ register uint32_t r = ~z;
+ r |= x;
+ r ^= y;
+ return r;
+}
+#endif
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+
+/**
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to reflect
+ * the addition of 16 longwords of new data. RTMd5Update blocks the data and
+ * converts bytes into longwords for this routine.
+ */
+static void rtMd5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+ uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ /* fn, w, x, y, z, data, s) */
+ MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+
+#ifdef RT_BIG_ENDIAN
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void rtMd5ByteReverse(uint32_t *buf, unsigned int longs)
+{
+ uint32_t t;
+ do
+ {
+ t = *buf;
+ t = RT_LE2H_U32(t);
+ *buf = t;
+ buf++;
+ } while (--longs);
+}
+#else /* little endian - do nothing */
+# define rtMd5ByteReverse(buf, len) do { /* Nothing */ } while (0)
+#endif
+
+
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+RTDECL(void) RTMd5Init(PRTMD5CONTEXT pCtx)
+{
+ pCtx->AltPrivate.buf[0] = 0x67452301;
+ pCtx->AltPrivate.buf[1] = 0xefcdab89;
+ pCtx->AltPrivate.buf[2] = 0x98badcfe;
+ pCtx->AltPrivate.buf[3] = 0x10325476;
+
+ pCtx->AltPrivate.bits[0] = 0;
+ pCtx->AltPrivate.bits[1] = 0;
+}
+RT_EXPORT_SYMBOL(RTMd5Init);
+
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+RTDECL(void) RTMd5Update(PRTMD5CONTEXT pCtx, const void *pvBuf, size_t len)
+{
+ const uint8_t *buf = (const uint8_t *)pvBuf;
+ uint32_t t;
+
+ /* Update bitcount */
+ t = pCtx->AltPrivate.bits[0];
+ if ((pCtx->AltPrivate.bits[0] = t + ((uint32_t) len << 3)) < t)
+ pCtx->AltPrivate.bits[1]++; /* Carry from low to high */
+ pCtx->AltPrivate.bits[1] += (uint32_t)(len >> 29);
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+ if (t)
+ {
+ uint8_t *p = (uint8_t *) pCtx->AltPrivate.in + t;
+
+ t = 64 - t;
+ if (len < t)
+ {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ rtMd5ByteReverse(pCtx->AltPrivate.in, 16);
+ rtMd5Transform(pCtx->AltPrivate.buf, pCtx->AltPrivate.in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+#ifndef RT_BIG_ENDIAN
+ if (!((uintptr_t)buf & 0x3))
+ {
+ while (len >= 64) {
+ rtMd5Transform(pCtx->AltPrivate.buf, (uint32_t const *)buf);
+ buf += 64;
+ len -= 64;
+ }
+ }
+ else
+#endif
+ {
+ while (len >= 64) {
+ memcpy(pCtx->AltPrivate.in, buf, 64);
+ rtMd5ByteReverse(pCtx->AltPrivate.in, 16);
+ rtMd5Transform(pCtx->AltPrivate.buf, pCtx->AltPrivate.in);
+ buf += 64;
+ len -= 64;
+ }
+ }
+
+ /* Handle any remaining bytes of data */
+ memcpy(pCtx->AltPrivate.in, buf, len);
+}
+RT_EXPORT_SYMBOL(RTMd5Update);
+
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+RTDECL(void) RTMd5Final(uint8_t digest[16], PRTMD5CONTEXT pCtx)
+{
+ unsigned int count;
+ uint8_t *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (pCtx->AltPrivate.bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = (uint8_t *)pCtx->AltPrivate.in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8)
+ {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ rtMd5ByteReverse(pCtx->AltPrivate.in, 16);
+ rtMd5Transform(pCtx->AltPrivate.buf, pCtx->AltPrivate.in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(pCtx->AltPrivate.in, 0, 56);
+ }
+ else
+ {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ rtMd5ByteReverse(pCtx->AltPrivate.in, 14);
+
+ /* Append length in bits and transform */
+ pCtx->AltPrivate.in[14] = pCtx->AltPrivate.bits[0];
+ pCtx->AltPrivate.in[15] = pCtx->AltPrivate.bits[1];
+
+ rtMd5Transform(pCtx->AltPrivate.buf, pCtx->AltPrivate.in);
+ rtMd5ByteReverse(pCtx->AltPrivate.buf, 4);
+ memcpy(digest, pCtx->AltPrivate.buf, 16);
+ memset(pCtx, 0, sizeof(*pCtx)); /* In case it's sensitive */
+}
+RT_EXPORT_SYMBOL(RTMd5Final);
+
+
+RTDECL(void) RTMd5(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD5HASHSIZE])
+{
+#if 0
+ RTMD5CONTEXT Ctx[2];
+ PRTMD5CONTEXT const pCtx = RT_ALIGN_PT(&Ctx[0], 64, PRTMD5CONTEXT);
+#else
+ RTMD5CONTEXT Ctx;
+ PRTMD5CONTEXT const pCtx = &Ctx;
+#endif
+
+ RTMd5Init(pCtx);
+ for (;;)
+ {
+ uint32_t cb = (uint32_t)RT_MIN(cbBuf, _2M);
+ RTMd5Update(pCtx, pvBuf, cb);
+ if (cb == cbBuf)
+ break;
+ cbBuf -= cb;
+ pvBuf = (uint8_t const *)pvBuf + cb;
+ }
+ RTMd5Final(pabDigest, pCtx);
+}
+RT_EXPORT_SYMBOL(RTMd5);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-sha1.cpp b/src/VBox/Runtime/common/checksum/alt-sha1.cpp
new file mode 100644
index 00000000..ff1fda3f
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-sha1.cpp
@@ -0,0 +1,535 @@
+/* $Id: alt-sha1.cpp $ */
+/** @file
+ * IPRT - SHA-1 hash functions, Alternative Implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The SHA-1 block size (in bytes). */
+#define RTSHA1_BLOCK_SIZE 64U
+
+/** Enables the unrolled code. */
+#define RTSHA1_UNROLLED 1
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+
+
+/** Our private context structure. */
+typedef struct RTSHA1ALTPRIVATECTX
+{
+ /** The W array.
+ * Buffering happens in the first 16 words, converted from big endian to host
+ * endian immediately before processing. The amount of buffered data is kept
+ * in the 6 least significant bits of cbMessage. */
+ uint32_t auW[80];
+ /** The message length (in bytes). */
+ uint64_t cbMessage;
+
+ /** The 5 hash values. */
+ uint32_t auH[5];
+} RTSHA1ALTPRIVATECTX;
+
+#define RT_SHA1_PRIVATE_ALT_CONTEXT
+#include <iprt/sha.h>
+
+
+AssertCompile(RT_SIZEOFMEMB(RTSHA1CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA1CONTEXT, AltPrivate));
+AssertCompileMemberSize(RTSHA1ALTPRIVATECTX, auH, RTSHA1_HASH_SIZE);
+
+
+
+
+RTDECL(void) RTSha1Init(PRTSHA1CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage = 0;
+ pCtx->AltPrivate.auH[0] = UINT32_C(0x67452301);
+ pCtx->AltPrivate.auH[1] = UINT32_C(0xefcdab89);
+ pCtx->AltPrivate.auH[2] = UINT32_C(0x98badcfe);
+ pCtx->AltPrivate.auH[3] = UINT32_C(0x10325476);
+ pCtx->AltPrivate.auH[4] = UINT32_C(0xc3d2e1f0);
+}
+RT_EXPORT_SYMBOL(RTSha1Init);
+
+
+/**
+ * Initializes the auW array from the specfied input block.
+ *
+ * @param pCtx The SHA1 context.
+ * @param pbBlock The block. Must be 32-bit aligned.
+ */
+DECLINLINE(void) rtSha1BlockInit(PRTSHA1CONTEXT pCtx, uint8_t const *pbBlock)
+{
+#ifdef RTSHA1_UNROLLED
+ uint32_t const *puSrc = (uint32_t const *)pbBlock;
+ uint32_t *puW = &pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puSrc & 3));
+ Assert(!((uintptr_t)puW & 3));
+
+ /* Copy and byte-swap the block. Initializing the rest of the Ws are done
+ in the processing loop. */
+# ifdef RT_LITTLE_ENDIAN
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+# else
+ memcpy(puW, puSrc, RTSHA1_BLOCK_SIZE);
+# endif
+
+#else /* !RTSHA1_UNROLLED */
+ uint32_t const *pu32Block = (uint32_t const *)pbBlock;
+ Assert(!((uintptr_t)pu32Block & 3));
+
+ unsigned iWord;
+ for (iWord = 0; iWord < 16; iWord++)
+ pCtx->AltPrivate.auW[iWord] = RT_BE2H_U32(pu32Block[iWord]);
+
+ for (; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint32_t u32 = pCtx->AltPrivate.auW[iWord - 16];
+ u32 ^= pCtx->AltPrivate.auW[iWord - 14];
+ u32 ^= pCtx->AltPrivate.auW[iWord - 8];
+ u32 ^= pCtx->AltPrivate.auW[iWord - 3];
+ pCtx->AltPrivate.auW[iWord] = ASMRotateLeftU32(u32, 1);
+ }
+#endif /* !RTSHA1_UNROLLED */
+}
+
+
+/**
+ * Initializes the auW array from data buffered in the first part of the array.
+ *
+ * @param pCtx The SHA1 context.
+ */
+DECLINLINE(void) rtSha1BlockInitBuffered(PRTSHA1CONTEXT pCtx)
+{
+#ifdef RTSHA1_UNROLLED
+ uint32_t *puW = &pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puW & 3));
+
+ /* Do the byte swap if necessary. Initializing the rest of the Ws are done
+ in the processing loop. */
+# ifdef RT_LITTLE_ENDIAN
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+# endif
+
+#else /* !RTSHA1_UNROLLED_INIT */
+ unsigned iWord;
+ for (iWord = 0; iWord < 16; iWord++)
+ pCtx->AltPrivate.auW[iWord] = RT_BE2H_U32(pCtx->AltPrivate.auW[iWord]);
+
+ for (; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint32_t u32 = pCtx->AltPrivate.auW[iWord - 16];
+ u32 ^= pCtx->AltPrivate.auW[iWord - 14];
+ u32 ^= pCtx->AltPrivate.auW[iWord - 8];
+ u32 ^= pCtx->AltPrivate.auW[iWord - 3];
+ pCtx->AltPrivate.auW[iWord] = ASMRotateLeftU32(u32, 1);
+ }
+#endif /* !RTSHA1_UNROLLED_INIT */
+}
+
+
+/** Function 4.1, Ch(x,y,z). */
+DECL_FORCE_INLINE(uint32_t) rtSha1Ch(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+#if 1
+ /* Optimization that saves one operation and probably a temporary variable. */
+ uint32_t uResult = uY;
+ uResult ^= uZ;
+ uResult &= uX;
+ uResult ^= uZ;
+ return uResult;
+#else
+ /* The original. */
+ uint32_t uResult = uX & uY;
+ uResult ^= ~uX & uZ;
+ return uResult;
+#endif
+}
+
+
+/** Function 4.1, Parity(x,y,z). */
+DECL_FORCE_INLINE(uint32_t) rtSha1Parity(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+ uint32_t uResult = uX;
+ uResult ^= uY;
+ uResult ^= uZ;
+ return uResult;
+}
+
+
+/** Function 4.1, Maj(x,y,z). */
+DECL_FORCE_INLINE(uint32_t) rtSha1Maj(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+#if 1
+ /* Optimization that save one operation and probably a temporary variable. */
+ uint32_t uResult = uY;
+ uResult ^= uZ;
+ uResult &= uX;
+ uResult ^= uY & uZ;
+ return uResult;
+#else
+ /* The original. */
+ uint32_t uResult = (uX & uY);
+ uResult |= (uX & uZ);
+ uResult |= (uY & uZ);
+ return uResult;
+#endif
+}
+
+
+/**
+ * Process the current block.
+ *
+ * Requires one of the rtSha1BlockInit functions to be called first.
+ *
+ * @param pCtx The SHA1 context.
+ */
+static void rtSha1BlockProcess(PRTSHA1CONTEXT pCtx)
+{
+ uint32_t uA = pCtx->AltPrivate.auH[0];
+ uint32_t uB = pCtx->AltPrivate.auH[1];
+ uint32_t uC = pCtx->AltPrivate.auH[2];
+ uint32_t uD = pCtx->AltPrivate.auH[3];
+ uint32_t uE = pCtx->AltPrivate.auH[4];
+
+#ifdef RTSHA1_UNROLLED
+ /* This fully unrolled version will avoid the variable rotation by
+ embedding it into the loop unrolling. */
+ uint32_t *puW = &pCtx->AltPrivate.auW[0];
+# define SHA1_BODY(a_iWord, a_uK, a_fnFt, a_uA, a_uB, a_uC, a_uD, a_uE) \
+ do { \
+ if (a_iWord < 16) \
+ a_uE += *puW++; \
+ else \
+ { \
+ uint32_t u32 = puW[-16]; \
+ u32 ^= puW[-14]; \
+ u32 ^= puW[-8]; \
+ u32 ^= puW[-3]; \
+ u32 = ASMRotateLeftU32(u32, 1); \
+ *puW++ = u32; \
+ a_uE += u32; \
+ } \
+ a_uE += (a_uK); \
+ a_uE += ASMRotateLeftU32(a_uA, 5); \
+ a_uE += a_fnFt(a_uB, a_uC, a_uD); \
+ a_uB = ASMRotateLeftU32(a_uB, 30); \
+ } while (0)
+# define FIVE_ITERATIONS(a_iFirst, a_uK, a_fnFt) \
+ do { \
+ SHA1_BODY(a_iFirst + 0, a_uK, a_fnFt, uA, uB, uC, uD, uE); \
+ SHA1_BODY(a_iFirst + 1, a_uK, a_fnFt, uE, uA, uB, uC, uD); \
+ SHA1_BODY(a_iFirst + 2, a_uK, a_fnFt, uD, uE, uA, uB, uC); \
+ SHA1_BODY(a_iFirst + 3, a_uK, a_fnFt, uC, uD, uE, uA, uB); \
+ SHA1_BODY(a_iFirst + 4, a_uK, a_fnFt, uB, uC, uD, uE, uA); \
+ } while (0)
+# define TWENTY_ITERATIONS(a_iStart, a_uK, a_fnFt) \
+ do { \
+ FIVE_ITERATIONS(a_iStart + 0, a_uK, a_fnFt); \
+ FIVE_ITERATIONS(a_iStart + 5, a_uK, a_fnFt); \
+ FIVE_ITERATIONS(a_iStart + 10, a_uK, a_fnFt); \
+ FIVE_ITERATIONS(a_iStart + 15, a_uK, a_fnFt); \
+ } while (0)
+
+ TWENTY_ITERATIONS( 0, UINT32_C(0x5a827999), rtSha1Ch);
+ TWENTY_ITERATIONS(20, UINT32_C(0x6ed9eba1), rtSha1Parity);
+ TWENTY_ITERATIONS(40, UINT32_C(0x8f1bbcdc), rtSha1Maj);
+ TWENTY_ITERATIONS(60, UINT32_C(0xca62c1d6), rtSha1Parity);
+
+#elif 1 /* Version avoiding the constant selection. */
+ unsigned iWord = 0;
+# define TWENTY_ITERATIONS(a_iWordStop, a_uK, a_uExprBCD) \
+ for (; iWord < a_iWordStop; iWord++) \
+ { \
+ uint32_t uTemp = ASMRotateLeftU32(uA, 5); \
+ uTemp += (a_uExprBCD); \
+ uTemp += uE; \
+ uTemp += pCtx->AltPrivate.auW[iWord]; \
+ uTemp += (a_uK); \
+ \
+ uE = uD; \
+ uD = uC; \
+ uC = ASMRotateLeftU32(uB, 30); \
+ uB = uA; \
+ uA = uTemp; \
+ } do { } while (0)
+ TWENTY_ITERATIONS(20, UINT32_C(0x5a827999), rtSha1Ch(uB, uC, uD));
+ TWENTY_ITERATIONS(40, UINT32_C(0x6ed9eba1), rtSha1Parity(uB, uC, uD));
+ TWENTY_ITERATIONS(60, UINT32_C(0x8f1bbcdc), rtSha1Maj(uB, uC, uD));
+ TWENTY_ITERATIONS(80, UINT32_C(0xca62c1d6), rtSha1Parity(uB, uC, uD));
+
+#else /* Dead simple implementation. */
+ for (unsigned iWord = 0; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint32_t uTemp = ASMRotateLeftU32(uA, 5);
+ uTemp += uE;
+ uTemp += pCtx->AltPrivate.auW[iWord];
+ if (iWord <= 19)
+ {
+ uTemp += (uB & uC) | (~uB & uD);
+ uTemp += UINT32_C(0x5a827999);
+ }
+ else if (iWord <= 39)
+ {
+ uTemp += uB ^ uC ^ uD;
+ uTemp += UINT32_C(0x6ed9eba1);
+ }
+ else if (iWord <= 59)
+ {
+ uTemp += (uB & uC) | (uB & uD) | (uC & uD);
+ uTemp += UINT32_C(0x8f1bbcdc);
+ }
+ else
+ {
+ uTemp += uB ^ uC ^ uD;
+ uTemp += UINT32_C(0xca62c1d6);
+ }
+
+ uE = uD;
+ uD = uC;
+ uC = ASMRotateLeftU32(uB, 30);
+ uB = uA;
+ uA = uTemp;
+ }
+#endif
+
+ pCtx->AltPrivate.auH[0] += uA;
+ pCtx->AltPrivate.auH[1] += uB;
+ pCtx->AltPrivate.auH[2] += uC;
+ pCtx->AltPrivate.auH[3] += uD;
+ pCtx->AltPrivate.auH[4] += uE;
+}
+
+
+RTDECL(void) RTSha1Update(PRTSHA1CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ Assert(pCtx->AltPrivate.cbMessage < UINT64_MAX / 2);
+ uint8_t const *pbBuf = (uint8_t const *)pvBuf;
+
+ /*
+ * Deal with buffered bytes first.
+ */
+ size_t cbBuffered = (size_t)pCtx->AltPrivate.cbMessage & (RTSHA1_BLOCK_SIZE - 1U);
+ if (cbBuffered)
+ {
+ size_t cbMissing = RTSHA1_BLOCK_SIZE - cbBuffered;
+ if (cbBuf >= cbMissing)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, pbBuf, cbMissing);
+ pCtx->AltPrivate.cbMessage += cbMissing;
+ pbBuf += cbMissing;
+ cbBuf -= cbMissing;
+
+ rtSha1BlockInitBuffered(pCtx);
+ rtSha1BlockProcess(pCtx);
+ }
+ else
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, pbBuf, cbBuf);
+ pCtx->AltPrivate.cbMessage += cbBuf;
+ return;
+ }
+ }
+
+ if (!((uintptr_t)pbBuf & 3))
+ {
+ /*
+ * Process full blocks directly from the input buffer.
+ */
+ while (cbBuf >= RTSHA1_BLOCK_SIZE)
+ {
+ rtSha1BlockInit(pCtx, pbBuf);
+ rtSha1BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbMessage += RTSHA1_BLOCK_SIZE;
+ pbBuf += RTSHA1_BLOCK_SIZE;
+ cbBuf -= RTSHA1_BLOCK_SIZE;
+ }
+ }
+ else
+ {
+ /*
+ * Unaligned input, so buffer it.
+ */
+ while (cbBuf >= RTSHA1_BLOCK_SIZE)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0], pbBuf, RTSHA1_BLOCK_SIZE);
+ rtSha1BlockInitBuffered(pCtx);
+ rtSha1BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbMessage += RTSHA1_BLOCK_SIZE;
+ pbBuf += RTSHA1_BLOCK_SIZE;
+ cbBuf -= RTSHA1_BLOCK_SIZE;
+ }
+ }
+
+ /*
+ * Stash any remaining bytes into the context buffer.
+ */
+ if (cbBuf > 0)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0], pbBuf, cbBuf);
+ pCtx->AltPrivate.cbMessage += cbBuf;
+ }
+}
+RT_EXPORT_SYMBOL(RTSha1Update);
+
+
+static void rtSha1FinalInternal(PRTSHA1CONTEXT pCtx)
+{
+ Assert(pCtx->AltPrivate.cbMessage < UINT64_MAX / 2);
+
+ /*
+ * Complete the message by adding a single bit (0x80), padding till
+ * the next 448-bit boundrary, the add the message length.
+ */
+ uint64_t const cMessageBits = pCtx->AltPrivate.cbMessage * 8;
+
+ unsigned cbMissing = RTSHA1_BLOCK_SIZE - ((unsigned)pCtx->AltPrivate.cbMessage & (RTSHA1_BLOCK_SIZE - 1U));
+ static uint8_t const s_abSingleBitAndSomePadding[12] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+ if (cbMissing < 1U + 8U)
+ /* Less than 64+8 bits left in the current block, force a new block. */
+ RTSha1Update(pCtx, &s_abSingleBitAndSomePadding, sizeof(s_abSingleBitAndSomePadding));
+ else
+ RTSha1Update(pCtx, &s_abSingleBitAndSomePadding, 1);
+
+ unsigned cbBuffered = (unsigned)pCtx->AltPrivate.cbMessage & (RTSHA1_BLOCK_SIZE - 1U);
+ cbMissing = RTSHA1_BLOCK_SIZE - cbBuffered;
+ Assert(cbMissing >= 8);
+ memset((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, 0, cbMissing - 8);
+
+ *(uint64_t *)&pCtx->AltPrivate.auW[14] = RT_H2BE_U64(cMessageBits);
+
+ /*
+ * Process the last buffered block constructed/completed above.
+ */
+ rtSha1BlockInitBuffered(pCtx);
+ rtSha1BlockProcess(pCtx);
+
+ /*
+ * Convert the byte order of the hash words and we're done.
+ */
+ pCtx->AltPrivate.auH[0] = RT_H2BE_U32(pCtx->AltPrivate.auH[0]);
+ pCtx->AltPrivate.auH[1] = RT_H2BE_U32(pCtx->AltPrivate.auH[1]);
+ pCtx->AltPrivate.auH[2] = RT_H2BE_U32(pCtx->AltPrivate.auH[2]);
+ pCtx->AltPrivate.auH[3] = RT_H2BE_U32(pCtx->AltPrivate.auH[3]);
+ pCtx->AltPrivate.auH[4] = RT_H2BE_U32(pCtx->AltPrivate.auH[4]);
+}
+
+
+DECLINLINE(void) rtSha1WipeCtx(PRTSHA1CONTEXT pCtx)
+{
+ RT_ZERO(pCtx->AltPrivate);
+ pCtx->AltPrivate.cbMessage = UINT64_MAX;
+}
+
+
+RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+{
+ rtSha1FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA1_HASH_SIZE);
+ rtSha1WipeCtx(pCtx);
+}
+RT_EXPORT_SYMBOL(RTSha1Final);
+
+
+RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+{
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+ RTSha1Update(&Ctx, pvBuf, cbBuf);
+ RTSha1Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha1);
+
+
+RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA1_HASH_SIZE])
+{
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+ RTSha1Update(&Ctx, pvBuf, cbBuf);
+ rtSha1FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA1_HASH_SIZE) == 0;
+
+ rtSha1WipeCtx(&Ctx);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha1Check);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-sha256.cpp b/src/VBox/Runtime/common/checksum/alt-sha256.cpp
new file mode 100644
index 00000000..28acca96
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-sha256.cpp
@@ -0,0 +1,693 @@
+/* $Id: alt-sha256.cpp $ */
+/** @file
+ * IPRT - SHA-256 and SHA-224 hash functions, Alternative Implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The SHA-256 block size (in bytes). */
+#define RTSHA256_BLOCK_SIZE 64U
+
+/** Enables the unrolled code. */
+#define RTSHA256_UNROLLED 1
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+
+
+/** Our private context structure. */
+typedef struct RTSHA256ALTPRIVATECTX
+{
+ /** The W array.
+ * Buffering happens in the first 16 words, converted from big endian to host
+ * endian immediately before processing. The amount of buffered data is kept
+ * in the 6 least significant bits of cbMessage. */
+ uint32_t auW[64];
+ /** The message length (in bytes). */
+ uint64_t cbMessage;
+ /** The 8 hash values. */
+ uint32_t auH[8];
+} RTSHA256ALTPRIVATECTX;
+
+#define RT_SHA256_PRIVATE_ALT_CONTEXT
+#include <iprt/sha.h>
+
+
+AssertCompile(RT_SIZEOFMEMB(RTSHA256CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA256CONTEXT, AltPrivate));
+AssertCompileMemberSize(RTSHA256ALTPRIVATECTX, auH, RTSHA256_HASH_SIZE);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifndef RTSHA256_UNROLLED
+/** The K constants */
+static uint32_t const g_auKs[] =
+{
+ UINT32_C(0x428a2f98), UINT32_C(0x71374491), UINT32_C(0xb5c0fbcf), UINT32_C(0xe9b5dba5),
+ UINT32_C(0x3956c25b), UINT32_C(0x59f111f1), UINT32_C(0x923f82a4), UINT32_C(0xab1c5ed5),
+ UINT32_C(0xd807aa98), UINT32_C(0x12835b01), UINT32_C(0x243185be), UINT32_C(0x550c7dc3),
+ UINT32_C(0x72be5d74), UINT32_C(0x80deb1fe), UINT32_C(0x9bdc06a7), UINT32_C(0xc19bf174),
+ UINT32_C(0xe49b69c1), UINT32_C(0xefbe4786), UINT32_C(0x0fc19dc6), UINT32_C(0x240ca1cc),
+ UINT32_C(0x2de92c6f), UINT32_C(0x4a7484aa), UINT32_C(0x5cb0a9dc), UINT32_C(0x76f988da),
+ UINT32_C(0x983e5152), UINT32_C(0xa831c66d), UINT32_C(0xb00327c8), UINT32_C(0xbf597fc7),
+ UINT32_C(0xc6e00bf3), UINT32_C(0xd5a79147), UINT32_C(0x06ca6351), UINT32_C(0x14292967),
+ UINT32_C(0x27b70a85), UINT32_C(0x2e1b2138), UINT32_C(0x4d2c6dfc), UINT32_C(0x53380d13),
+ UINT32_C(0x650a7354), UINT32_C(0x766a0abb), UINT32_C(0x81c2c92e), UINT32_C(0x92722c85),
+ UINT32_C(0xa2bfe8a1), UINT32_C(0xa81a664b), UINT32_C(0xc24b8b70), UINT32_C(0xc76c51a3),
+ UINT32_C(0xd192e819), UINT32_C(0xd6990624), UINT32_C(0xf40e3585), UINT32_C(0x106aa070),
+ UINT32_C(0x19a4c116), UINT32_C(0x1e376c08), UINT32_C(0x2748774c), UINT32_C(0x34b0bcb5),
+ UINT32_C(0x391c0cb3), UINT32_C(0x4ed8aa4a), UINT32_C(0x5b9cca4f), UINT32_C(0x682e6ff3),
+ UINT32_C(0x748f82ee), UINT32_C(0x78a5636f), UINT32_C(0x84c87814), UINT32_C(0x8cc70208),
+ UINT32_C(0x90befffa), UINT32_C(0xa4506ceb), UINT32_C(0xbef9a3f7), UINT32_C(0xc67178f2),
+};
+#endif /* !RTSHA256_UNROLLED */
+
+
+
+RTDECL(void) RTSha256Init(PRTSHA256CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage = 0;
+ pCtx->AltPrivate.auH[0] = UINT32_C(0x6a09e667);
+ pCtx->AltPrivate.auH[1] = UINT32_C(0xbb67ae85);
+ pCtx->AltPrivate.auH[2] = UINT32_C(0x3c6ef372);
+ pCtx->AltPrivate.auH[3] = UINT32_C(0xa54ff53a);
+ pCtx->AltPrivate.auH[4] = UINT32_C(0x510e527f);
+ pCtx->AltPrivate.auH[5] = UINT32_C(0x9b05688c);
+ pCtx->AltPrivate.auH[6] = UINT32_C(0x1f83d9ab);
+ pCtx->AltPrivate.auH[7] = UINT32_C(0x5be0cd19);
+}
+RT_EXPORT_SYMBOL(RTSha256Init);
+
+
+/** Function 4.2. */
+DECL_FORCE_INLINE(uint32_t) rtSha256Ch(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+#if 1
+ /* Optimization that saves one operation and probably a temporary variable. */
+ uint32_t uResult = uY;
+ uResult ^= uZ;
+ uResult &= uX;
+ uResult ^= uZ;
+ return uResult;
+#else
+ /* The original. */
+ uint32_t uResult = uX & uY;
+ uResult ^= ~uX & uZ;
+ return uResult;
+#endif
+}
+
+
+/** Function 4.3. */
+DECL_FORCE_INLINE(uint32_t) rtSha256Maj(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+#if 1
+ /* Optimization that save one operation and probably a temporary variable. */
+ uint32_t uResult = uY;
+ uResult ^= uZ;
+ uResult &= uX;
+ uResult ^= uY & uZ;
+ return uResult;
+#else
+ /* The original. */
+ uint32_t uResult = uX & uY;
+ uResult ^= uX & uZ;
+ uResult ^= uY & uZ;
+ return uResult;
+#endif
+}
+
+
+/** Function 4.4. */
+DECL_FORCE_INLINE(uint32_t) rtSha256CapitalSigma0(uint32_t uX)
+{
+ uint32_t uResult = uX = ASMRotateRightU32(uX, 2);
+ uX = ASMRotateRightU32(uX, 13 - 2);
+ uResult ^= uX;
+ uX = ASMRotateRightU32(uX, 22 - 13);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/** Function 4.5. */
+DECL_FORCE_INLINE(uint32_t) rtSha256CapitalSigma1(uint32_t uX)
+{
+ uint32_t uResult = uX = ASMRotateRightU32(uX, 6);
+ uX = ASMRotateRightU32(uX, 11 - 6);
+ uResult ^= uX;
+ uX = ASMRotateRightU32(uX, 25 - 11);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/** Function 4.6. */
+DECL_FORCE_INLINE(uint32_t) rtSha256SmallSigma0(uint32_t uX)
+{
+ uint32_t uResult = uX >> 3;
+ uX = ASMRotateRightU32(uX, 7);
+ uResult ^= uX;
+ uX = ASMRotateRightU32(uX, 18 - 7);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/** Function 4.7. */
+DECL_FORCE_INLINE(uint32_t) rtSha256SmallSigma1(uint32_t uX)
+{
+ uint32_t uResult = uX >> 10;
+ uX = ASMRotateRightU32(uX, 17);
+ uResult ^= uX;
+ uX = ASMRotateRightU32(uX, 19 - 17);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/**
+ * Initializes the auW array from the specfied input block.
+ *
+ * @param pCtx The SHA-256 context.
+ * @param pbBlock The block. Must be arch-bit-width aligned.
+ */
+DECLINLINE(void) rtSha256BlockInit(PRTSHA256CONTEXT pCtx, uint8_t const *pbBlock)
+{
+#ifdef RTSHA256_UNROLLED
+ /* Copy and byte-swap the block. Initializing the rest of the Ws are done
+ in the processing loop. */
+# ifdef RT_LITTLE_ENDIAN
+# if 0 /* Just an idea... very little gain as this isn't the expensive code. */
+ __m128i const uBSwapConst = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 };
+ __m128i const *puSrc = (__m128i const *)pbBlock;
+ __m128i *puDst = (__m128i *)&pCtx->AltPrivate.auW[0];
+
+ _mm_storeu_si128(puDst, _mm_shuffle_epi8(_mm_loadu_si128(puSrc), uBSwapConst)); puDst++; puSrc++;
+ _mm_storeu_si128(puDst, _mm_shuffle_epi8(_mm_loadu_si128(puSrc), uBSwapConst)); puDst++; puSrc++;
+ _mm_storeu_si128(puDst, _mm_shuffle_epi8(_mm_loadu_si128(puSrc), uBSwapConst)); puDst++; puSrc++;
+ _mm_storeu_si128(puDst, _mm_shuffle_epi8(_mm_loadu_si128(puSrc), uBSwapConst)); puDst++; puSrc++;
+
+# elif ARCH_BITS == 64
+ uint64_t const *puSrc = (uint64_t const *)pbBlock;
+ uint64_t *puW = (uint64_t *)&pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puSrc & 7));
+ Assert(!((uintptr_t)puW & 7));
+
+ /* b0 b1 b2 b3 b4 b5 b6 b7 --bwap--> b7 b6 b5 b4 b3 b2 b1 b0 --ror--> b3 b2 b1 b0 b7 b6 b5 b4; */
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+ *puW++ = ASMRotateRightU64(ASMByteSwapU64(*puSrc++), 32);
+
+# else
+ uint32_t const *puSrc = (uint32_t const *)pbBlock;
+ uint32_t *puW = &pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puSrc & 3));
+ Assert(!((uintptr_t)puW & 3));
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+ *puW++ = ASMByteSwapU32(*puSrc++);
+# endif
+# else /* RT_BIG_ENDIAN */
+ memcpy(&pCtx->AltPrivate.auW[0], pbBlock, RTSHA256_BLOCK_SIZE);
+# endif /* RT_BIG_ENDIAN */
+
+#else /* !RTSHA256_UNROLLED */
+ uint32_t const *pu32Block = (uint32_t const *)pbBlock;
+ Assert(!((uintptr_t)pu32Block & 3));
+
+ unsigned iWord;
+ for (iWord = 0; iWord < 16; iWord++)
+ pCtx->AltPrivate.auW[iWord] = RT_BE2H_U32(pu32Block[iWord]);
+
+ for (; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint32_t u32 = rtSha256SmallSigma1(pCtx->AltPrivate.auW[iWord - 2]);
+ u32 += rtSha256SmallSigma0(pCtx->AltPrivate.auW[iWord - 15]);
+ u32 += pCtx->AltPrivate.auW[iWord - 7];
+ u32 += pCtx->AltPrivate.auW[iWord - 16];
+ pCtx->AltPrivate.auW[iWord] = u32;
+ }
+#endif /* !RTSHA256_UNROLLED */
+}
+
+
+/**
+ * Initializes the auW array from data buffered in the first part of the array.
+ *
+ * @param pCtx The SHA-256 context.
+ */
+DECLINLINE(void) rtSha256BlockInitBuffered(PRTSHA256CONTEXT pCtx)
+{
+#ifdef RTSHA256_UNROLLED
+ /* Do the byte swap if necessary. Initializing the rest of the Ws are done
+ in the processing loop. */
+# ifdef RT_LITTLE_ENDIAN
+# if ARCH_BITS == 64
+ uint64_t *puW = (uint64_t *)&pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puW & 7));
+ /* b0 b1 b2 b3 b4 b5 b6 b7 --bwap--> b7 b6 b5 b4 b3 b2 b1 b0 --ror--> b3 b2 b1 b0 b7 b6 b5 b4; */
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+ *puW = ASMRotateRightU64(ASMByteSwapU64(*puW), 32); puW++;
+
+# else
+ uint32_t *puW = &pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puW & 3));
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+ *puW = ASMByteSwapU32(*puW); puW++;
+# endif
+# endif
+
+#else /* !RTSHA256_UNROLLED */
+ unsigned iWord;
+ for (iWord = 0; iWord < 16; iWord++)
+ pCtx->AltPrivate.auW[iWord] = RT_BE2H_U32(pCtx->AltPrivate.auW[iWord]);
+
+ for (; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint32_t u32 = rtSha256SmallSigma1(pCtx->AltPrivate.auW[iWord - 2]);
+ u32 += rtSha256SmallSigma0(pCtx->AltPrivate.auW[iWord - 15]);
+ u32 += pCtx->AltPrivate.auW[iWord - 7];
+ u32 += pCtx->AltPrivate.auW[iWord - 16];
+ pCtx->AltPrivate.auW[iWord] = u32;
+ }
+#endif /* !RTSHA256_UNROLLED */
+}
+
+
+/**
+ * Process the current block.
+ *
+ * Requires one of the rtSha256BlockInit functions to be called first.
+ *
+ * @param pCtx The SHA-256 context.
+ */
+static void rtSha256BlockProcess(PRTSHA256CONTEXT pCtx)
+{
+ uint32_t uA = pCtx->AltPrivate.auH[0];
+ uint32_t uB = pCtx->AltPrivate.auH[1];
+ uint32_t uC = pCtx->AltPrivate.auH[2];
+ uint32_t uD = pCtx->AltPrivate.auH[3];
+ uint32_t uE = pCtx->AltPrivate.auH[4];
+ uint32_t uF = pCtx->AltPrivate.auH[5];
+ uint32_t uG = pCtx->AltPrivate.auH[6];
+ uint32_t uH = pCtx->AltPrivate.auH[7];
+
+#ifdef RTSHA256_UNROLLED
+ uint32_t *puW = &pCtx->AltPrivate.auW[0];
+# define RTSHA256_BODY(a_iWord, a_uK, a_uA, a_uB, a_uC, a_uD, a_uE, a_uF, a_uG, a_uH) \
+ do { \
+ if ((a_iWord) < 16) \
+ a_uH += *puW++; \
+ else \
+ { \
+ uint32_t u32 = puW[-16]; \
+ u32 += rtSha256SmallSigma0(puW[-15]); \
+ u32 += puW[-7]; \
+ u32 += rtSha256SmallSigma1(puW[-2]); \
+ if (a_iWord < 64-2) *puW++ = u32; else puW++; \
+ a_uH += u32; \
+ } \
+ \
+ a_uH += rtSha256CapitalSigma1(a_uE); \
+ a_uH += a_uK; \
+ a_uH += rtSha256Ch(a_uE, a_uF, a_uG); \
+ a_uD += a_uH; \
+ \
+ a_uH += rtSha256CapitalSigma0(a_uA); \
+ a_uH += rtSha256Maj(a_uA, a_uB, a_uC); \
+ } while (0)
+# define RTSHA256_EIGHT(a_uK0, a_uK1, a_uK2, a_uK3, a_uK4, a_uK5, a_uK6, a_uK7, a_iFirst) \
+ do { \
+ RTSHA256_BODY(a_iFirst + 0, a_uK0, uA, uB, uC, uD, uE, uF, uG, uH); \
+ RTSHA256_BODY(a_iFirst + 1, a_uK1, uH, uA, uB, uC, uD, uE, uF, uG); \
+ RTSHA256_BODY(a_iFirst + 2, a_uK2, uG, uH, uA, uB, uC, uD, uE, uF); \
+ RTSHA256_BODY(a_iFirst + 3, a_uK3, uF, uG, uH, uA, uB, uC, uD, uE); \
+ RTSHA256_BODY(a_iFirst + 4, a_uK4, uE, uF, uG, uH, uA, uB, uC, uD); \
+ RTSHA256_BODY(a_iFirst + 5, a_uK5, uD, uE, uF, uG, uH, uA, uB, uC); \
+ RTSHA256_BODY(a_iFirst + 6, a_uK6, uC, uD, uE, uF, uG, uH, uA, uB); \
+ RTSHA256_BODY(a_iFirst + 7, a_uK7, uB, uC, uD, uE, uF, uG, uH, uA); \
+ } while (0)
+ RTSHA256_EIGHT(UINT32_C(0x428a2f98), UINT32_C(0x71374491), UINT32_C(0xb5c0fbcf), UINT32_C(0xe9b5dba5),
+ UINT32_C(0x3956c25b), UINT32_C(0x59f111f1), UINT32_C(0x923f82a4), UINT32_C(0xab1c5ed5), 0);
+ RTSHA256_EIGHT(UINT32_C(0xd807aa98), UINT32_C(0x12835b01), UINT32_C(0x243185be), UINT32_C(0x550c7dc3),
+ UINT32_C(0x72be5d74), UINT32_C(0x80deb1fe), UINT32_C(0x9bdc06a7), UINT32_C(0xc19bf174), 8);
+ RTSHA256_EIGHT(UINT32_C(0xe49b69c1), UINT32_C(0xefbe4786), UINT32_C(0x0fc19dc6), UINT32_C(0x240ca1cc),
+ UINT32_C(0x2de92c6f), UINT32_C(0x4a7484aa), UINT32_C(0x5cb0a9dc), UINT32_C(0x76f988da), 16);
+ RTSHA256_EIGHT(UINT32_C(0x983e5152), UINT32_C(0xa831c66d), UINT32_C(0xb00327c8), UINT32_C(0xbf597fc7),
+ UINT32_C(0xc6e00bf3), UINT32_C(0xd5a79147), UINT32_C(0x06ca6351), UINT32_C(0x14292967), 24);
+ RTSHA256_EIGHT(UINT32_C(0x27b70a85), UINT32_C(0x2e1b2138), UINT32_C(0x4d2c6dfc), UINT32_C(0x53380d13),
+ UINT32_C(0x650a7354), UINT32_C(0x766a0abb), UINT32_C(0x81c2c92e), UINT32_C(0x92722c85), 32);
+ RTSHA256_EIGHT(UINT32_C(0xa2bfe8a1), UINT32_C(0xa81a664b), UINT32_C(0xc24b8b70), UINT32_C(0xc76c51a3),
+ UINT32_C(0xd192e819), UINT32_C(0xd6990624), UINT32_C(0xf40e3585), UINT32_C(0x106aa070), 40);
+ RTSHA256_EIGHT(UINT32_C(0x19a4c116), UINT32_C(0x1e376c08), UINT32_C(0x2748774c), UINT32_C(0x34b0bcb5),
+ UINT32_C(0x391c0cb3), UINT32_C(0x4ed8aa4a), UINT32_C(0x5b9cca4f), UINT32_C(0x682e6ff3), 48);
+ RTSHA256_EIGHT(UINT32_C(0x748f82ee), UINT32_C(0x78a5636f), UINT32_C(0x84c87814), UINT32_C(0x8cc70208),
+ UINT32_C(0x90befffa), UINT32_C(0xa4506ceb), UINT32_C(0xbef9a3f7), UINT32_C(0xc67178f2), 56);
+
+#else /* !RTSHA256_UNROLLED */
+ for (unsigned iWord = 0; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint32_t uT1 = uH;
+ uT1 += rtSha256CapitalSigma1(uE);
+ uT1 += rtSha256Ch(uE, uF, uG);
+ uT1 += g_auKs[iWord];
+ uT1 += pCtx->AltPrivate.auW[iWord];
+
+ uint32_t uT2 = rtSha256CapitalSigma0(uA);
+ uT2 += rtSha256Maj(uA, uB, uC);
+
+ uH = uG;
+ uG = uF;
+ uF = uE;
+ uE = uD + uT1;
+ uD = uC;
+ uC = uB;
+ uB = uA;
+ uA = uT1 + uT2;
+ }
+#endif /* !RTSHA256_UNROLLED */
+
+ pCtx->AltPrivate.auH[0] += uA;
+ pCtx->AltPrivate.auH[1] += uB;
+ pCtx->AltPrivate.auH[2] += uC;
+ pCtx->AltPrivate.auH[3] += uD;
+ pCtx->AltPrivate.auH[4] += uE;
+ pCtx->AltPrivate.auH[5] += uF;
+ pCtx->AltPrivate.auH[6] += uG;
+ pCtx->AltPrivate.auH[7] += uH;
+}
+
+
+RTDECL(void) RTSha256Update(PRTSHA256CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ Assert(pCtx->AltPrivate.cbMessage < UINT64_MAX / 8);
+ uint8_t const *pbBuf = (uint8_t const *)pvBuf;
+
+ /*
+ * Deal with buffered bytes first.
+ */
+ size_t cbBuffered = (size_t)pCtx->AltPrivate.cbMessage & (RTSHA256_BLOCK_SIZE - 1U);
+ if (cbBuffered)
+ {
+ size_t cbMissing = RTSHA256_BLOCK_SIZE - cbBuffered;
+ if (cbBuf >= cbMissing)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, pbBuf, cbMissing);
+ pCtx->AltPrivate.cbMessage += cbMissing;
+ pbBuf += cbMissing;
+ cbBuf -= cbMissing;
+
+ rtSha256BlockInitBuffered(pCtx);
+ rtSha256BlockProcess(pCtx);
+ }
+ else
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, pbBuf, cbBuf);
+ pCtx->AltPrivate.cbMessage += cbBuf;
+ return;
+ }
+ }
+
+ if (!((uintptr_t)pbBuf & (sizeof(void *) - 1)))
+ {
+ /*
+ * Process full blocks directly from the input buffer.
+ */
+ while (cbBuf >= RTSHA256_BLOCK_SIZE)
+ {
+ rtSha256BlockInit(pCtx, pbBuf);
+ rtSha256BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbMessage += RTSHA256_BLOCK_SIZE;
+ pbBuf += RTSHA256_BLOCK_SIZE;
+ cbBuf -= RTSHA256_BLOCK_SIZE;
+ }
+ }
+ else
+ {
+ /*
+ * Unaligned input, so buffer it.
+ */
+ while (cbBuf >= RTSHA256_BLOCK_SIZE)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0], pbBuf, RTSHA256_BLOCK_SIZE);
+ rtSha256BlockInitBuffered(pCtx);
+ rtSha256BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbMessage += RTSHA256_BLOCK_SIZE;
+ pbBuf += RTSHA256_BLOCK_SIZE;
+ cbBuf -= RTSHA256_BLOCK_SIZE;
+ }
+ }
+
+ /*
+ * Stash any remaining bytes into the context buffer.
+ */
+ if (cbBuf > 0)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0], pbBuf, cbBuf);
+ pCtx->AltPrivate.cbMessage += cbBuf;
+ }
+}
+RT_EXPORT_SYMBOL(RTSha256Update);
+
+
+/**
+ * Internal worker for RTSha256Final and RTSha224Final that finalizes the
+ * computation but does not copy out the hash value.
+ *
+ * @param pCtx The SHA-256 context.
+ */
+static void rtSha256FinalInternal(PRTSHA256CONTEXT pCtx)
+{
+ Assert(pCtx->AltPrivate.cbMessage < UINT64_MAX / 8);
+
+ /*
+ * Complete the message by adding a single bit (0x80), padding till
+ * the next 448-bit boundrary, the add the message length.
+ */
+ uint64_t const cMessageBits = pCtx->AltPrivate.cbMessage * 8;
+
+ unsigned cbMissing = RTSHA256_BLOCK_SIZE - ((unsigned)pCtx->AltPrivate.cbMessage & (RTSHA256_BLOCK_SIZE - 1U));
+ static uint8_t const s_abSingleBitAndSomePadding[12] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+ if (cbMissing < 1U + 8U)
+ /* Less than 64+8 bits left in the current block, force a new block. */
+ RTSha256Update(pCtx, &s_abSingleBitAndSomePadding, sizeof(s_abSingleBitAndSomePadding));
+ else
+ RTSha256Update(pCtx, &s_abSingleBitAndSomePadding, 1);
+
+ unsigned cbBuffered = (unsigned)pCtx->AltPrivate.cbMessage & (RTSHA256_BLOCK_SIZE - 1U);
+ cbMissing = RTSHA256_BLOCK_SIZE - cbBuffered;
+ Assert(cbMissing >= 8);
+ memset((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, 0, cbMissing - 8);
+
+ *(uint64_t *)&pCtx->AltPrivate.auW[14] = RT_H2BE_U64(cMessageBits);
+
+ /*
+ * Process the last buffered block constructed/completed above.
+ */
+ rtSha256BlockInitBuffered(pCtx);
+ rtSha256BlockProcess(pCtx);
+
+ /*
+ * Convert the byte order of the hash words and we're done.
+ */
+ pCtx->AltPrivate.auH[0] = RT_H2BE_U32(pCtx->AltPrivate.auH[0]);
+ pCtx->AltPrivate.auH[1] = RT_H2BE_U32(pCtx->AltPrivate.auH[1]);
+ pCtx->AltPrivate.auH[2] = RT_H2BE_U32(pCtx->AltPrivate.auH[2]);
+ pCtx->AltPrivate.auH[3] = RT_H2BE_U32(pCtx->AltPrivate.auH[3]);
+ pCtx->AltPrivate.auH[4] = RT_H2BE_U32(pCtx->AltPrivate.auH[4]);
+ pCtx->AltPrivate.auH[5] = RT_H2BE_U32(pCtx->AltPrivate.auH[5]);
+ pCtx->AltPrivate.auH[6] = RT_H2BE_U32(pCtx->AltPrivate.auH[6]);
+ pCtx->AltPrivate.auH[7] = RT_H2BE_U32(pCtx->AltPrivate.auH[7]);
+
+ RT_ZERO(pCtx->AltPrivate.auW);
+ pCtx->AltPrivate.cbMessage = UINT64_MAX;
+}
+RT_EXPORT_SYMBOL(RTSha256Final);
+
+
+RTDECL(void) RTSha256Final(PRTSHA256CONTEXT pCtx, uint8_t pabDigest[RTSHA256_HASH_SIZE])
+{
+ rtSha256FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA256_HASH_SIZE);
+ RT_ZERO(pCtx->AltPrivate.auH);
+}
+RT_EXPORT_SYMBOL(RTSha256Final);
+
+
+RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA256_HASH_SIZE])
+{
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+ RTSha256Update(&Ctx, pvBuf, cbBuf);
+ RTSha256Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha256);
+
+
+RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA256_HASH_SIZE])
+{
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+ RTSha256Update(&Ctx, pvBuf, cbBuf);
+ rtSha256FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA256_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha256Check);
+
+
+
+/*
+ * SHA-224 is just SHA-256 with different initial values an a truncated result.
+ */
+
+RTDECL(void) RTSha224Init(PRTSHA224CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage = 0;
+ pCtx->AltPrivate.auH[0] = UINT32_C(0xc1059ed8);
+ pCtx->AltPrivate.auH[1] = UINT32_C(0x367cd507);
+ pCtx->AltPrivate.auH[2] = UINT32_C(0x3070dd17);
+ pCtx->AltPrivate.auH[3] = UINT32_C(0xf70e5939);
+ pCtx->AltPrivate.auH[4] = UINT32_C(0xffc00b31);
+ pCtx->AltPrivate.auH[5] = UINT32_C(0x68581511);
+ pCtx->AltPrivate.auH[6] = UINT32_C(0x64f98fa7);
+ pCtx->AltPrivate.auH[7] = UINT32_C(0xbefa4fa4);
+}
+RT_EXPORT_SYMBOL(RTSha224Init);
+
+
+RTDECL(void) RTSha224Update(PRTSHA224CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ RTSha256Update(pCtx, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha224Update);
+
+
+RTDECL(void) RTSha224Final(PRTSHA224CONTEXT pCtx, uint8_t pabDigest[RTSHA224_HASH_SIZE])
+{
+ rtSha256FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA224_HASH_SIZE);
+ RT_ZERO(pCtx->AltPrivate.auH);
+}
+RT_EXPORT_SYMBOL(RTSha224Final);
+
+
+RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA224_HASH_SIZE])
+{
+ RTSHA224CONTEXT Ctx;
+ RTSha224Init(&Ctx);
+ RTSha224Update(&Ctx, pvBuf, cbBuf);
+ RTSha224Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha224);
+
+
+RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA224_HASH_SIZE])
+{
+ RTSHA224CONTEXT Ctx;
+ RTSha224Init(&Ctx);
+ RTSha224Update(&Ctx, pvBuf, cbBuf);
+ rtSha256FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA224_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha224Check);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-sha3.cpp b/src/VBox/Runtime/common/checksum/alt-sha3.cpp
new file mode 100644
index 00000000..ef7c4959
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-sha3.cpp
@@ -0,0 +1,642 @@
+/* $Id: alt-sha3.cpp $ */
+/** @file
+ * IPRT - SHA-3 hash functions, Alternative Implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** Number of rounds [3.4]. */
+#define RTSHA3_ROUNDS 24
+
+/** @def RTSHA3_FULL_UNROLL
+ * Do full loop unrolling.
+ *
+ * With gcc 10.2.1 on a recent Intel system (10890XE), this results SHA3-512
+ * throughput (tstRTDigest-2) increasing from 83532 KiB/s to 194942 KiB/s
+ * against a text size jump from 5913 to 6929 bytes, i.e. +1016 bytes.
+ *
+ * With VS2019 on a half decent AMD system (3990X), this results in SHA3-512
+ * speedup from 147676 KiB/s to about 192770 KiB/s. The text cost is +612 bytes
+ * (4496 to 5108). When disabling the unrolling of Rho+Pi we get a little
+ * increase 196591 KiB/s (+3821) for some reason, saving 22 bytes of code.
+ *
+ * For comparison, openssl 1.1.1g assembly code (AMD64) achives 264915 KiB/s,
+ * which is only 36% more. Performance is more or less exactly the same as
+ * KECCAK_2X without ROL optimizations (they improve it to 203493 KiB/s).
+ */
+#if !defined(IN_SUP_HARDENED_R3) || defined(DOXYGEN_RUNNING)
+# define RTSHA3_FULL_UNROLL
+#endif
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/assert.h>
+#include <iprt/assertcompile.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+typedef struct RTSHA3ALTPRIVATECTX
+{
+ /** The KECCAK state (W=1600). */
+ union
+ {
+ uint64_t au64[/*1600/64 =*/ 25];
+ uint8_t ab[/*1600/8 =*/ 200];
+ };
+
+ /** Current input position. */
+ uint8_t offInput;
+ /** The number of bytes to xor into the state before doing KECCAK. */
+ uint8_t cbInput;
+ /** The digest size in bytes. */
+ uint8_t cbDigest;
+ /** Padding the size up to 208 bytes. */
+ uint8_t abPadding[4];
+ /** Set if we've finalized the digest. */
+ bool fFinal;
+} RTSHA3ALTPRIVATECTX;
+
+#define RT_SHA3_PRIVATE_ALT_CONTEXT
+#include <iprt/sha.h>
+
+
+
+static void rtSha3Keccak(RTSHA3ALTPRIVATECTX *pState)
+{
+#ifdef RT_BIG_ENDIAN
+ /* This sucks a performance wise on big endian systems, sorry. We just
+ needed something simple that works on AMD64 and x86. */
+ for (size_t i = 0; i < RT_ELEMENTS(pState->au64); i++)
+ pState->au64[i] = RT_LE2H_U64(pState->au64[i]);
+#endif
+
+ /*
+ * Rounds: Rnd(A,idxRound) = Iota(Chi(Pi(Rho(Theta(A)))), idxRount) [3.3]
+ */
+ for (uint32_t idxRound = 0; idxRound < RTSHA3_ROUNDS; idxRound++)
+ {
+ /*
+ * 3.2.1 Theta
+ */
+ {
+ /* Step 1: */
+ const uint64_t au64C[5] =
+ {
+ pState->au64[0] ^ pState->au64[5] ^ pState->au64[10] ^ pState->au64[15] ^ pState->au64[20],
+ pState->au64[1] ^ pState->au64[6] ^ pState->au64[11] ^ pState->au64[16] ^ pState->au64[21],
+ pState->au64[2] ^ pState->au64[7] ^ pState->au64[12] ^ pState->au64[17] ^ pState->au64[22],
+ pState->au64[3] ^ pState->au64[8] ^ pState->au64[13] ^ pState->au64[18] ^ pState->au64[23],
+ pState->au64[4] ^ pState->au64[9] ^ pState->au64[14] ^ pState->au64[19] ^ pState->au64[24],
+ };
+
+ /* Step 2 & 3: */
+#ifndef RTSHA3_FULL_UNROLL
+ for (size_t i = 0; i < RT_ELEMENTS(au64C); i++)
+ {
+ uint64_t const u64D = au64C[(i + 4) % RT_ELEMENTS(au64C)]
+ ^ ASMRotateLeftU64(au64C[(i + 1) % RT_ELEMENTS(au64C)], 1);
+ pState->au64[ 0 + i] ^= u64D;
+ pState->au64[ 5 + i] ^= u64D;
+ pState->au64[10 + i] ^= u64D;
+ pState->au64[15 + i] ^= u64D;
+ pState->au64[20 + i] ^= u64D;
+ }
+#else /* RTSHA3_FULL_UNROLL */
+# define THETA_STEP_2_3(a_i, a_idxCLeft, a_idxCRight) do { \
+ uint64_t const u64D = au64C[a_idxCLeft] ^ ASMRotateLeftU64(au64C[a_idxCRight], 1); \
+ pState->au64[ 0 + a_i] ^= u64D; \
+ pState->au64[ 5 + a_i] ^= u64D; \
+ pState->au64[10 + a_i] ^= u64D; \
+ pState->au64[15 + a_i] ^= u64D; \
+ pState->au64[20 + a_i] ^= u64D; \
+ } while (0)
+ THETA_STEP_2_3(0, 4, 1);
+ THETA_STEP_2_3(1, 0, 2);
+ THETA_STEP_2_3(2, 1, 3);
+ THETA_STEP_2_3(3, 2, 4);
+ THETA_STEP_2_3(4, 3, 0);
+#endif /* RTSHA3_FULL_UNROLL */
+ }
+
+ /*
+ * 3.2.2 Rho + 3.2.3 Pi
+ */
+ {
+#if !defined(RTSHA3_FULL_UNROLL) || defined(_MSC_VER) /* VS2019 is slightly slow with this section unrolled. go figure */
+ static uint8_t const s_aidxState[] = {10,7,11,17,18, 3, 5,16, 8,21, 24, 4,15,23,19, 13,12, 2,20,14, 22, 9, 6, 1};
+ static uint8_t const s_acRotate[] = { 1,3, 6,10,15, 21,28,36,45,55, 2,14,27,41,56, 8,25,43,62,18, 39,61,20,44};
+ AssertCompile(RT_ELEMENTS(s_aidxState) == 24); AssertCompile(RT_ELEMENTS(s_acRotate) == 24);
+ uint64_t u64 = pState->au64[1 /*s_aidxState[RT_ELEMENTS(s_aidxState) - 1]*/];
+# if !defined(_MSC_VER) /* This is slower with VS2019 but slightly faster with g++ (10.2.1). */
+ for (size_t i = 0; i <= 23 - 1; i++) /*i=t*/
+ {
+ uint64_t const u64Result = ASMRotateLeftU64(u64, s_acRotate[i]);
+ size_t const idxState = s_aidxState[i];
+ u64 = pState->au64[idxState];
+ pState->au64[idxState] = u64Result;
+ }
+ pState->au64[1 /*s_aidxState[23]*/] = ASMRotateLeftU64(u64, 44 /*s_acRotate[23]*/);
+# else
+ for (size_t i = 0; i <= 23; i++) /*i=t*/
+ {
+ uint64_t const u64Result = ASMRotateLeftU64(u64, s_acRotate[i]);
+ size_t const idxState = s_aidxState[i];
+ u64 = pState->au64[idxState];
+ pState->au64[idxState] = u64Result;
+ }
+# endif
+#else /* RTSHA3_FULL_UNROLL */
+# define RHO_AND_PI(a_idxState, a_cRotate) do { \
+ uint64_t const u64Result = ASMRotateLeftU64(u64, a_cRotate); \
+ u64 = pState->au64[a_idxState]; \
+ pState->au64[a_idxState] = u64Result; \
+ } while (0)
+
+ uint64_t u64 = pState->au64[1 /*s_aidxState[RT_ELEMENTS(s_aidxState) - 1]*/];
+ RHO_AND_PI(10, 1);
+ RHO_AND_PI( 7, 3);
+ RHO_AND_PI(11, 6);
+ RHO_AND_PI(17, 10);
+ RHO_AND_PI(18, 15);
+ RHO_AND_PI( 3, 21);
+ RHO_AND_PI( 5, 28);
+ RHO_AND_PI(16, 36);
+ RHO_AND_PI( 8, 45);
+ RHO_AND_PI(21, 55);
+ RHO_AND_PI(24, 2);
+ RHO_AND_PI( 4, 14);
+ RHO_AND_PI(15, 27);
+ RHO_AND_PI(23, 41);
+ RHO_AND_PI(19, 56);
+ RHO_AND_PI(13, 8);
+ RHO_AND_PI(12, 25);
+ RHO_AND_PI( 2, 43);
+ RHO_AND_PI(20, 62);
+ RHO_AND_PI(14, 18);
+ RHO_AND_PI(22, 39);
+ RHO_AND_PI( 9, 61);
+ RHO_AND_PI( 6, 20);
+ pState->au64[1 /*s_aidxState[23]*/] = ASMRotateLeftU64(u64, 44 /*s_acRotate[23]*/);
+
+#endif /* RTSHA3_FULL_UNROLL */
+ }
+
+ /*
+ * 3.2.4 Chi & 3.2.5 Iota.
+ */
+ /* Iota values xor constants (indexed by round). */
+ static uint64_t const s_au64RC[] =
+ {
+ UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082), UINT64_C(0x800000000000808a), UINT64_C(0x8000000080008000),
+ UINT64_C(0x000000000000808b), UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009),
+ UINT64_C(0x000000000000008a), UINT64_C(0x0000000000000088), UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000a),
+ UINT64_C(0x000000008000808b), UINT64_C(0x800000000000008b), UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003),
+ UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080), UINT64_C(0x000000000000800a), UINT64_C(0x800000008000000a),
+ UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080), UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008),
+ };
+ AssertCompile(RT_ELEMENTS(s_au64RC) == RTSHA3_ROUNDS);
+#ifndef RTSHA3_FULL_UNROLL
+ /* Chi */
+ for (size_t i = 0; i < 25; i += 5)
+ {
+# ifndef _MSC_VER /* This is typically slower with VS2019 - go figure. Makes not difference with g++. */
+ uint64_t const u0 = pState->au64[i + 0];
+ uint64_t const u1 = pState->au64[i + 1];
+ uint64_t const u2 = pState->au64[i + 2];
+ pState->au64[i + 0] = u0 ^ (~u1 & u2);
+ uint64_t const u3 = pState->au64[i + 3];
+ pState->au64[i + 1] = u1 ^ (~u2 & u3);
+ uint64_t const u4 = pState->au64[i + 4];
+ pState->au64[i + 2] = u2 ^ (~u3 & u4);
+ pState->au64[i + 3] = u3 ^ (~u4 & u0);
+ pState->au64[i + 4] = u4 ^ (~u0 & u1);
+# else
+ uint64_t const au64Tmp[] = { pState->au64[i + 0], pState->au64[i + 1], pState->au64[i + 2],
+ pState->au64[i + 3], pState->au64[i + 4] };
+ pState->au64[i + 0] ^= ~au64Tmp[1] & au64Tmp[2];
+ pState->au64[i + 1] ^= ~au64Tmp[2] & au64Tmp[3];
+ pState->au64[i + 2] ^= ~au64Tmp[3] & au64Tmp[4];
+ pState->au64[i + 3] ^= ~au64Tmp[4] & au64Tmp[0];
+ pState->au64[i + 4] ^= ~au64Tmp[0] & au64Tmp[1];
+# endif
+ }
+
+ /* Iota. */
+ pState->au64[0] ^= s_au64RC[idxRound];
+
+#else /* RTSHA3_FULL_UNROLL */
+# define CHI_AND_IOTA(a_i, a_IotaExpr) do { \
+ uint64_t const u0 = pState->au64[a_i + 0]; \
+ uint64_t const u1 = pState->au64[a_i + 1]; \
+ uint64_t const u2 = pState->au64[a_i + 2]; \
+ pState->au64[a_i + 0] = u0 ^ (~u1 & u2) a_IotaExpr; \
+ uint64_t const u3 = pState->au64[a_i + 3]; \
+ pState->au64[a_i + 1] = u1 ^ (~u2 & u3); \
+ uint64_t const u4 = pState->au64[a_i + 4]; \
+ pState->au64[a_i + 2] = u2 ^ (~u3 & u4); \
+ pState->au64[a_i + 3] = u3 ^ (~u4 & u0); \
+ pState->au64[a_i + 4] = u4 ^ (~u0 & u1); \
+ } while (0)
+ CHI_AND_IOTA( 0, ^ s_au64RC[idxRound]);
+ CHI_AND_IOTA( 5, RT_NOTHING);
+ CHI_AND_IOTA(10, RT_NOTHING);
+ CHI_AND_IOTA(15, RT_NOTHING);
+ CHI_AND_IOTA(20, RT_NOTHING);
+#endif /* RTSHA3_FULL_UNROLL */
+ }
+
+#ifdef RT_BIG_ENDIAN
+ for (size_t i = 0; i < RT_ELEMENTS(pState->au64); i++)
+ pState->au64[i] = RT_H2LE_U64(pState->au64[i]);
+#endif
+}
+
+
+static int rtSha3Init(RTSHA3ALTPRIVATECTX *pCtx, unsigned cBitsDigest)
+{
+ RT_ZERO(pCtx->au64);
+ pCtx->offInput = 0;
+ pCtx->cbInput = (uint8_t)(sizeof(pCtx->ab) - (2 * cBitsDigest / 8));
+ pCtx->cbDigest = cBitsDigest / 8;
+ pCtx->fFinal = false;
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3Update(RTSHA3ALTPRIVATECTX *pCtx, uint8_t const *pbData, size_t cbData)
+{
+ Assert(!pCtx->fFinal);
+ size_t const cbInput = pCtx->cbInput;
+ size_t offState = pCtx->offInput;
+ Assert(!(cbInput & 7));
+#if 1
+ if ( ((uintptr_t)pbData & 7) == 0
+ && (offState & 7) == 0
+ && (cbData & 7) == 0)
+ {
+ uint64_t const cQwordsInput = cbInput / sizeof(uint64_t);
+ uint64_t const *pu64Data = (uint64_t const *)pbData;
+ size_t cQwordsData = cbData / sizeof(uint64_t);
+ size_t offData = 0;
+ offState /= sizeof(uint64_t);
+
+ /*
+ * Any catching up to do?
+ */
+ if (offState == 0 || cQwordsData >= cQwordsInput - offState)
+ {
+ if (offState > 0)
+ {
+ while (offState < cQwordsInput)
+ pCtx->au64[offState++] ^= pu64Data[offData++];
+ rtSha3Keccak(pCtx);
+ offState = 0;
+ }
+ if (offData < cQwordsData)
+ {
+ /*
+ * Do full chunks.
+ */
+# if 1
+ switch (cQwordsInput)
+ {
+ case 18: /* ( 200 - (2 * 224/8) = 0x90 (144) ) / 8 = 0x12 (18) */
+ {
+ size_t cFullChunks = (cQwordsData - offData) / 18;
+ while (cFullChunks-- > 0)
+ {
+ pCtx->au64[ 0] ^= pu64Data[offData + 0];
+ pCtx->au64[ 1] ^= pu64Data[offData + 1];
+ pCtx->au64[ 2] ^= pu64Data[offData + 2];
+ pCtx->au64[ 3] ^= pu64Data[offData + 3];
+ pCtx->au64[ 4] ^= pu64Data[offData + 4];
+ pCtx->au64[ 5] ^= pu64Data[offData + 5];
+ pCtx->au64[ 6] ^= pu64Data[offData + 6];
+ pCtx->au64[ 7] ^= pu64Data[offData + 7];
+ pCtx->au64[ 8] ^= pu64Data[offData + 8];
+ pCtx->au64[ 9] ^= pu64Data[offData + 9];
+ pCtx->au64[10] ^= pu64Data[offData + 10];
+ pCtx->au64[11] ^= pu64Data[offData + 11];
+ pCtx->au64[12] ^= pu64Data[offData + 12];
+ pCtx->au64[13] ^= pu64Data[offData + 13];
+ pCtx->au64[14] ^= pu64Data[offData + 14];
+ pCtx->au64[15] ^= pu64Data[offData + 15];
+ pCtx->au64[16] ^= pu64Data[offData + 16];
+ pCtx->au64[17] ^= pu64Data[offData + 17];
+ offData += 18;
+ rtSha3Keccak(pCtx);
+ }
+ break;
+ }
+
+ case 17: /* ( 200 - (2 * 256/8) = 0x88 (136) ) / 8 = 0x11 (17) */
+ {
+ size_t cFullChunks = (cQwordsData - offData) / 17;
+ while (cFullChunks-- > 0)
+ {
+ pCtx->au64[ 0] ^= pu64Data[offData + 0];
+ pCtx->au64[ 1] ^= pu64Data[offData + 1];
+ pCtx->au64[ 2] ^= pu64Data[offData + 2];
+ pCtx->au64[ 3] ^= pu64Data[offData + 3];
+ pCtx->au64[ 4] ^= pu64Data[offData + 4];
+ pCtx->au64[ 5] ^= pu64Data[offData + 5];
+ pCtx->au64[ 6] ^= pu64Data[offData + 6];
+ pCtx->au64[ 7] ^= pu64Data[offData + 7];
+ pCtx->au64[ 8] ^= pu64Data[offData + 8];
+ pCtx->au64[ 9] ^= pu64Data[offData + 9];
+ pCtx->au64[10] ^= pu64Data[offData + 10];
+ pCtx->au64[11] ^= pu64Data[offData + 11];
+ pCtx->au64[12] ^= pu64Data[offData + 12];
+ pCtx->au64[13] ^= pu64Data[offData + 13];
+ pCtx->au64[14] ^= pu64Data[offData + 14];
+ pCtx->au64[15] ^= pu64Data[offData + 15];
+ pCtx->au64[16] ^= pu64Data[offData + 16];
+ offData += 17;
+ rtSha3Keccak(pCtx);
+ }
+ break;
+ }
+
+ case 13: /* ( 200 - (2 * 384/8) = 0x68 (104) ) / 8 = 0x0d (13) */
+ {
+ size_t cFullChunks = (cQwordsData - offData) / 13;
+ while (cFullChunks-- > 0)
+ {
+ pCtx->au64[ 0] ^= pu64Data[offData + 0];
+ pCtx->au64[ 1] ^= pu64Data[offData + 1];
+ pCtx->au64[ 2] ^= pu64Data[offData + 2];
+ pCtx->au64[ 3] ^= pu64Data[offData + 3];
+ pCtx->au64[ 4] ^= pu64Data[offData + 4];
+ pCtx->au64[ 5] ^= pu64Data[offData + 5];
+ pCtx->au64[ 6] ^= pu64Data[offData + 6];
+ pCtx->au64[ 7] ^= pu64Data[offData + 7];
+ pCtx->au64[ 8] ^= pu64Data[offData + 8];
+ pCtx->au64[ 9] ^= pu64Data[offData + 9];
+ pCtx->au64[10] ^= pu64Data[offData + 10];
+ pCtx->au64[11] ^= pu64Data[offData + 11];
+ pCtx->au64[12] ^= pu64Data[offData + 12];
+ offData += 13;
+ rtSha3Keccak(pCtx);
+ }
+ break;
+ }
+
+ case 9: /* ( 200 - (2 * 512/8) = 0x48 (72) ) / 8 = 0x09 (9) */
+ {
+ size_t cFullChunks = (cQwordsData - offData) / 9;
+ while (cFullChunks-- > 0)
+ {
+ pCtx->au64[ 0] ^= pu64Data[offData + 0];
+ pCtx->au64[ 1] ^= pu64Data[offData + 1];
+ pCtx->au64[ 2] ^= pu64Data[offData + 2];
+ pCtx->au64[ 3] ^= pu64Data[offData + 3];
+ pCtx->au64[ 4] ^= pu64Data[offData + 4];
+ pCtx->au64[ 5] ^= pu64Data[offData + 5];
+ pCtx->au64[ 6] ^= pu64Data[offData + 6];
+ pCtx->au64[ 7] ^= pu64Data[offData + 7];
+ pCtx->au64[ 8] ^= pu64Data[offData + 8];
+ offData += 9;
+ rtSha3Keccak(pCtx);
+ }
+ break;
+ }
+
+ default:
+ {
+ AssertFailed();
+# endif
+ size_t cFullChunks = (cQwordsData - offData) / cQwordsInput;
+ while (cFullChunks-- > 0)
+ {
+ offState = cQwordsInput;
+ while (offState-- > 0)
+ pCtx->au64[offState] ^= pu64Data[offData + offState];
+ offData += cQwordsInput;
+ rtSha3Keccak(pCtx);
+ }
+# if 1
+ break;
+ }
+ }
+# endif
+ offState = 0;
+
+ /*
+ * Partial last chunk?
+ */
+ if (offData < cQwordsData)
+ {
+ Assert(cQwordsData - offData < cQwordsInput);
+ while (offData < cQwordsData)
+ pCtx->au64[offState++] ^= pu64Data[offData++];
+ offState *= sizeof(uint64_t);
+ }
+ }
+ }
+ else
+ {
+ while (offData < cQwordsData)
+ pCtx->au64[offState++] ^= pu64Data[offData++];
+ offState *= sizeof(uint64_t);
+ }
+ Assert(offData == cQwordsData);
+ }
+ else
+#endif
+ {
+ /*
+ * Misaligned input/state, so just do simpe byte by byte processing.
+ */
+ for (size_t offData = 0; offData < cbData; offData++)
+ {
+ pCtx->ab[offState] ^= pbData[offData];
+ offState++;
+ if (offState < cbInput)
+ { /* likely */ }
+ else
+ {
+ rtSha3Keccak(pCtx);
+ offState = 0;
+ }
+ }
+ }
+ pCtx->offInput = (uint8_t)offState;
+ return VINF_SUCCESS;
+}
+
+
+static void rtSha3FinalInternal(RTSHA3ALTPRIVATECTX *pCtx)
+{
+ Assert(!pCtx->fFinal);
+
+ pCtx->ab[pCtx->offInput] ^= 0x06;
+ pCtx->ab[pCtx->cbInput - 1] ^= 0x80;
+ rtSha3Keccak(pCtx);
+}
+
+
+static int rtSha3Final(RTSHA3ALTPRIVATECTX *pCtx, uint8_t *pbDigest)
+{
+ Assert(!pCtx->fFinal);
+
+ rtSha3FinalInternal(pCtx);
+
+ memcpy(pbDigest, pCtx->ab, pCtx->cbDigest);
+
+ /* Wipe non-hash state. */
+ RT_BZERO(&pCtx->ab[pCtx->cbDigest], sizeof(pCtx->ab) - pCtx->cbDigest);
+ pCtx->fFinal = true;
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3(const void *pvData, size_t cbData, unsigned cBitsDigest, uint8_t *pabHash)
+{
+ RTSHA3ALTPRIVATECTX Ctx;
+ rtSha3Init(&Ctx, cBitsDigest);
+ rtSha3Update(&Ctx, (uint8_t const *)pvData, cbData);
+ rtSha3Final(&Ctx, pabHash);
+ return VINF_SUCCESS;
+}
+
+
+static bool rtSha3Check(const void *pvData, size_t cbData, unsigned cBitsDigest, const uint8_t *pabHash)
+{
+ RTSHA3ALTPRIVATECTX Ctx;
+ rtSha3Init(&Ctx, cBitsDigest);
+ rtSha3Update(&Ctx, (uint8_t const *)pvData, cbData);
+ rtSha3FinalInternal(&Ctx);
+ bool fRet = memcmp(pabHash, &Ctx.ab, cBitsDigest / 8) == 0;
+ RT_ZERO(Ctx);
+ return fRet;
+}
+
+
+/** Macro for declaring the interface for a SHA3 variation.
+ * @internal */
+#define RTSHA3_DEFINE_VARIANT(a_cBits) \
+AssertCompile((a_cBits / 8) == RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)); \
+AssertCompile(sizeof(RT_CONCAT3(RTSHA3T,a_cBits,CONTEXT)) >= sizeof(RTSHA3ALTPRIVATECTX)); \
+\
+RTDECL(int) RT_CONCAT(RTSha3t,a_cBits)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ return rtSha3(pvBuf, cbBuf, a_cBits, pabHash); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT(RTSha3t,a_cBits)); \
+\
+\
+RTDECL(bool) RT_CONCAT3(RTSha3t,a_cBits,Check)(const void *pvBuf, size_t cbBuf, \
+ uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ return rtSha3Check(pvBuf, cbBuf, a_cBits, pabHash); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Check)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Init)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx) \
+{ \
+ AssertCompile(sizeof(pCtx->Sha3.a64Padding) >= sizeof(pCtx->Sha3.AltPrivate)); \
+ AssertCompile(sizeof(pCtx->Sha3.a64Padding) == sizeof(pCtx->Sha3.abPadding)); \
+ return rtSha3Init(&pCtx->Sha3.AltPrivate, a_cBits); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Init)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Update)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf) \
+{ \
+ Assert(pCtx->Sha3.AltPrivate.cbDigest == (a_cBits) / 8); \
+ return rtSha3Update(&pCtx->Sha3.AltPrivate, (uint8_t const *)pvBuf, cbBuf); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Update)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Final)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, \
+ uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ Assert(pCtx->Sha3.AltPrivate.cbDigest == (a_cBits) / 8); \
+ return rtSha3Final(&pCtx->Sha3.AltPrivate, pabHash); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Final)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Cleanup)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx) \
+{ \
+ if (pCtx) \
+ { \
+ Assert(pCtx->Sha3.AltPrivate.cbDigest == (a_cBits) / 8); \
+ RT_ZERO(*pCtx); \
+ } \
+ return VINF_SUCCESS; \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Cleanup)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Clone)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, \
+ RT_CONCAT3(RTSHA3T,a_cBits,CONTEXT) const *pCtxSrc) \
+{ \
+ memcpy(pCtx, pCtxSrc, sizeof(*pCtx)); \
+ return VINF_SUCCESS; \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Clone)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)], \
+ char *pszDigest, size_t cchDigest) \
+{ \
+ return RTStrPrintHexBytes(pszDigest, cchDigest, pabHash, (a_cBits) / 8, 0 /*fFlags*/); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,ToString)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabHash[0], (a_cBits) / 8, 0 /*fFlags*/); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,FromString))
+
+
+RTSHA3_DEFINE_VARIANT(224);
+RTSHA3_DEFINE_VARIANT(256);
+RTSHA3_DEFINE_VARIANT(384);
+RTSHA3_DEFINE_VARIANT(512);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-sha512.cpp b/src/VBox/Runtime/common/checksum/alt-sha512.cpp
new file mode 100644
index 00000000..18d91d6a
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/alt-sha512.cpp
@@ -0,0 +1,805 @@
+/* $Id: alt-sha512.cpp $ */
+/** @file
+ * IPRT - SHA-512 and SHA-384 hash functions, Alternative Implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The SHA-512 block size (in bytes). */
+#define RTSHA512_BLOCK_SIZE 128U
+
+/** Enables the unrolled code. */
+#define RTSHA512_UNROLLED 1
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+
+
+/** Our private context structure. */
+typedef struct RTSHA512ALTPRIVATECTX
+{
+ /** The W array.
+ * Buffering happens in the first 16 words, converted from big endian to host
+ * endian immediately before processing. The amount of buffered data is kept
+ * in the 6 least significant bits of cbMessage. */
+ uint64_t auW[80];
+ /** The message length (in bytes). */
+ RTUINT128U cbMessage;
+ /** The 8 hash values. */
+ uint64_t auH[8];
+} RTSHA512ALTPRIVATECTX;
+
+#define RT_SHA512_PRIVATE_ALT_CONTEXT
+#include <iprt/sha.h>
+
+
+AssertCompile(RT_SIZEOFMEMB(RTSHA512CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA512CONTEXT, AltPrivate));
+AssertCompileMemberSize(RTSHA512ALTPRIVATECTX, auH, RTSHA512_HASH_SIZE);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifndef RTSHA512_UNROLLED
+/** The K constants. */
+static uint64_t const g_auKs[] =
+{
+ UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
+ UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
+ UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
+ UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
+ UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
+ UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
+ UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
+ UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
+ UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
+ UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
+ UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
+ UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
+ UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
+ UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
+ UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
+ UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
+ UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
+ UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
+ UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
+ UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817),
+};
+#endif /* !RTSHA512_UNROLLED */
+
+
+
+RTDECL(void) RTSha512Init(PRTSHA512CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage.s.Lo = 0;
+ pCtx->AltPrivate.cbMessage.s.Hi = 0;
+ pCtx->AltPrivate.auH[0] = UINT64_C(0x6a09e667f3bcc908);
+ pCtx->AltPrivate.auH[1] = UINT64_C(0xbb67ae8584caa73b);
+ pCtx->AltPrivate.auH[2] = UINT64_C(0x3c6ef372fe94f82b);
+ pCtx->AltPrivate.auH[3] = UINT64_C(0xa54ff53a5f1d36f1);
+ pCtx->AltPrivate.auH[4] = UINT64_C(0x510e527fade682d1);
+ pCtx->AltPrivate.auH[5] = UINT64_C(0x9b05688c2b3e6c1f);
+ pCtx->AltPrivate.auH[6] = UINT64_C(0x1f83d9abfb41bd6b);
+ pCtx->AltPrivate.auH[7] = UINT64_C(0x5be0cd19137e2179);
+}
+RT_EXPORT_SYMBOL(RTSha512Init);
+
+
+/** Function 4.8. */
+DECL_FORCE_INLINE(uint64_t) rtSha512Ch(uint64_t uX, uint64_t uY, uint64_t uZ)
+{
+#if 1
+ /* Optimization that saves one operation and probably a temporary variable. */
+ uint64_t uResult = uY;
+ uResult ^= uZ;
+ uResult &= uX;
+ uResult ^= uZ;
+ return uResult;
+#else
+ /* The original. */
+ uint64_t uResult = uX & uY;
+ uResult ^= ~uX & uZ;
+ return uResult;
+#endif
+}
+
+
+/** Function 4.9. */
+DECL_FORCE_INLINE(uint64_t) rtSha512Maj(uint64_t uX, uint64_t uY, uint64_t uZ)
+{
+#if 1
+ /* Optimization that save one operation and probably a temporary variable. */
+ uint64_t uResult = uY;
+ uResult ^= uZ;
+ uResult &= uX;
+ uResult ^= uY & uZ;
+ return uResult;
+#else
+ /* The original. */
+ uint64_t uResult = uX & uY;
+ uResult ^= uX & uZ;
+ uResult ^= uY & uZ;
+ return uResult;
+#endif
+}
+
+
+/** Function 4.10. */
+DECL_FORCE_INLINE(uint64_t) rtSha512CapitalSigma0(uint64_t uX)
+{
+ uint64_t uResult = uX = ASMRotateRightU64(uX, 28);
+ uX = ASMRotateRightU64(uX, 34 - 28);
+ uResult ^= uX;
+ uX = ASMRotateRightU64(uX, 39 - 34);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/** Function 4.11. */
+DECL_FORCE_INLINE(uint64_t) rtSha512CapitalSigma1(uint64_t uX)
+{
+ uint64_t uResult = uX = ASMRotateRightU64(uX, 14);
+ uX = ASMRotateRightU64(uX, 18 - 14);
+ uResult ^= uX;
+ uX = ASMRotateRightU64(uX, 41 - 18);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/** Function 4.12. */
+DECL_FORCE_INLINE(uint64_t) rtSha512SmallSigma0(uint64_t uX)
+{
+ uint64_t uResult = uX >> 7;
+ uX = ASMRotateRightU64(uX, 1);
+ uResult ^= uX;
+ uX = ASMRotateRightU64(uX, 8 - 1);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/** Function 4.13. */
+DECL_FORCE_INLINE(uint64_t) rtSha512SmallSigma1(uint64_t uX)
+{
+ uint64_t uResult = uX >> 6;
+ uX = ASMRotateRightU64(uX, 19);
+ uResult ^= uX;
+ uX = ASMRotateRightU64(uX, 61 - 19);
+ uResult ^= uX;
+ return uResult;
+}
+
+
+/**
+ * Initializes the auW array from the specfied input block.
+ *
+ * @param pCtx The SHA-512 context.
+ * @param pbBlock The block. Must be 64-bit aligned.
+ */
+DECLINLINE(void) rtSha512BlockInit(PRTSHA512CONTEXT pCtx, uint8_t const *pbBlock)
+{
+#ifdef RTSHA512_UNROLLED
+ uint64_t const *puSrc = (uint64_t const *)pbBlock;
+ uint64_t *puW = &pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puSrc & 7));
+ Assert(!((uintptr_t)puW & 7));
+
+ /* Copy and byte-swap the block. Initializing the rest of the Ws are done
+ in the processing loop. */
+# ifdef RT_LITTLE_ENDIAN
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+ *puW++ = ASMByteSwapU64(*puSrc++);
+# else
+ memcpy(puW, puSrc, RTSHA512_BLOCK_SIZE);
+# endif
+
+#else /* !RTSHA512_UNROLLED */
+
+ uint64_t const *pu32Block = (uint64_t const *)pbBlock;
+ Assert(!((uintptr_t)pu32Block & 3));
+
+ unsigned iWord;
+ for (iWord = 0; iWord < 16; iWord++)
+ pCtx->AltPrivate.auW[iWord] = RT_BE2H_U64(pu32Block[iWord]);
+
+ for (; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint64_t u64 = rtSha512SmallSigma1(pCtx->AltPrivate.auW[iWord - 2]);
+ u64 += rtSha512SmallSigma0(pCtx->AltPrivate.auW[iWord - 15]);
+ u64 += pCtx->AltPrivate.auW[iWord - 7];
+ u64 += pCtx->AltPrivate.auW[iWord - 16];
+ pCtx->AltPrivate.auW[iWord] = u64;
+ }
+#endif /* !RTSHA512_UNROLLED */
+}
+
+
+/**
+ * Initializes the auW array from data buffered in the first part of the array.
+ *
+ * @param pCtx The SHA-512 context.
+ */
+DECLINLINE(void) rtSha512BlockInitBuffered(PRTSHA512CONTEXT pCtx)
+{
+#ifdef RTSHA512_UNROLLED
+ uint64_t *puW = &pCtx->AltPrivate.auW[0];
+ Assert(!((uintptr_t)puW & 7));
+
+ /* Do the byte swap if necessary. Initializing the rest of the Ws are done
+ in the processing loop. */
+# ifdef RT_LITTLE_ENDIAN
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+ *puW = ASMByteSwapU64(*puW); puW++;
+# endif
+
+#else /* !RTSHA512_UNROLLED */
+
+ unsigned iWord;
+ for (iWord = 0; iWord < 16; iWord++)
+ pCtx->AltPrivate.auW[iWord] = RT_BE2H_U64(pCtx->AltPrivate.auW[iWord]);
+
+ for (; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint64_t u64 = rtSha512SmallSigma1(pCtx->AltPrivate.auW[iWord - 2]);
+ u64 += rtSha512SmallSigma0(pCtx->AltPrivate.auW[iWord - 15]);
+ u64 += pCtx->AltPrivate.auW[iWord - 7];
+ u64 += pCtx->AltPrivate.auW[iWord - 16];
+ pCtx->AltPrivate.auW[iWord] = u64;
+ }
+#endif /* !RTSHA512_UNROLLED */
+}
+
+
+/**
+ * Process the current block.
+ *
+ * Requires one of the rtSha512BlockInit functions to be called first.
+ *
+ * @param pCtx The SHA-512 context.
+ */
+static void rtSha512BlockProcess(PRTSHA512CONTEXT pCtx)
+{
+ uint64_t uA = pCtx->AltPrivate.auH[0];
+ uint64_t uB = pCtx->AltPrivate.auH[1];
+ uint64_t uC = pCtx->AltPrivate.auH[2];
+ uint64_t uD = pCtx->AltPrivate.auH[3];
+ uint64_t uE = pCtx->AltPrivate.auH[4];
+ uint64_t uF = pCtx->AltPrivate.auH[5];
+ uint64_t uG = pCtx->AltPrivate.auH[6];
+ uint64_t uH = pCtx->AltPrivate.auH[7];
+
+#ifdef RTSHA512_UNROLLED
+ uint64_t *puW = &pCtx->AltPrivate.auW[0];
+# define RTSHA512_BODY(a_iWord, a_uK, a_uA, a_uB, a_uC, a_uD, a_uE, a_uF, a_uG, a_uH) \
+ do { \
+ if ((a_iWord) < 16) \
+ a_uH += *puW++; \
+ else \
+ { \
+ uint64_t u64 = puW[-16]; \
+ u64 += rtSha512SmallSigma0(puW[-15]); \
+ u64 += puW[-7]; \
+ u64 += rtSha512SmallSigma1(puW[-2]); \
+ if (a_iWord < 80-2) *puW++ = u64; else puW++; \
+ a_uH += u64; \
+ } \
+ \
+ a_uH += rtSha512CapitalSigma1(a_uE); \
+ a_uH += a_uK; \
+ a_uH += rtSha512Ch(a_uE, a_uF, a_uG); \
+ a_uD += a_uH; \
+ \
+ a_uH += rtSha512CapitalSigma0(a_uA); \
+ a_uH += rtSha512Maj(a_uA, a_uB, a_uC); \
+ } while (0)
+# define RTSHA512_EIGHT(a_uK0, a_uK1, a_uK2, a_uK3, a_uK4, a_uK5, a_uK6, a_uK7, a_iFirst) \
+ do { \
+ RTSHA512_BODY(a_iFirst + 0, a_uK0, uA, uB, uC, uD, uE, uF, uG, uH); \
+ RTSHA512_BODY(a_iFirst + 1, a_uK1, uH, uA, uB, uC, uD, uE, uF, uG); \
+ RTSHA512_BODY(a_iFirst + 2, a_uK2, uG, uH, uA, uB, uC, uD, uE, uF); \
+ RTSHA512_BODY(a_iFirst + 3, a_uK3, uF, uG, uH, uA, uB, uC, uD, uE); \
+ RTSHA512_BODY(a_iFirst + 4, a_uK4, uE, uF, uG, uH, uA, uB, uC, uD); \
+ RTSHA512_BODY(a_iFirst + 5, a_uK5, uD, uE, uF, uG, uH, uA, uB, uC); \
+ RTSHA512_BODY(a_iFirst + 6, a_uK6, uC, uD, uE, uF, uG, uH, uA, uB); \
+ RTSHA512_BODY(a_iFirst + 7, a_uK7, uB, uC, uD, uE, uF, uG, uH, uA); \
+ } while (0)
+ RTSHA512_EIGHT(UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
+ UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
+ 0);
+ RTSHA512_EIGHT(UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
+ UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
+ 8);
+ RTSHA512_EIGHT(UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
+ UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
+ 16);
+ RTSHA512_EIGHT(UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
+ UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
+ 24);
+ RTSHA512_EIGHT(UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
+ UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
+ 32);
+ RTSHA512_EIGHT(UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
+ UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
+ 40);
+ RTSHA512_EIGHT(UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
+ UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
+ 48);
+ RTSHA512_EIGHT(UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
+ UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
+ 56);
+ RTSHA512_EIGHT(UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
+ UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
+ 64);
+ RTSHA512_EIGHT(UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
+ UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817),
+ 72);
+#else
+ for (unsigned iWord = 0; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
+ {
+ uint64_t uT1 = uH;
+ uT1 += rtSha512CapitalSigma1(uE);
+ uT1 += rtSha512Ch(uE, uF, uG);
+ uT1 += g_auKs[iWord];
+ uT1 += pCtx->AltPrivate.auW[iWord];
+
+ uint64_t uT2 = rtSha512CapitalSigma0(uA);
+ uT2 += rtSha512Maj(uA, uB, uC);
+
+ uH = uG;
+ uG = uF;
+ uF = uE;
+ uE = uD + uT1;
+ uD = uC;
+ uC = uB;
+ uB = uA;
+ uA = uT1 + uT2;
+ }
+#endif
+
+ pCtx->AltPrivate.auH[0] += uA;
+ pCtx->AltPrivate.auH[1] += uB;
+ pCtx->AltPrivate.auH[2] += uC;
+ pCtx->AltPrivate.auH[3] += uD;
+ pCtx->AltPrivate.auH[4] += uE;
+ pCtx->AltPrivate.auH[5] += uF;
+ pCtx->AltPrivate.auH[6] += uG;
+ pCtx->AltPrivate.auH[7] += uH;
+}
+
+
+RTDECL(void) RTSha512Update(PRTSHA512CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ Assert(pCtx->AltPrivate.cbMessage.s.Hi < UINT64_MAX / 8);
+ uint8_t const *pbBuf = (uint8_t const *)pvBuf;
+
+ /*
+ * Deal with buffered bytes first.
+ */
+ size_t cbBuffered = (size_t)pCtx->AltPrivate.cbMessage.s.Lo & (RTSHA512_BLOCK_SIZE - 1U);
+ if (cbBuffered)
+ {
+ size_t cbMissing = RTSHA512_BLOCK_SIZE - cbBuffered;
+ if (cbBuf >= cbMissing)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, pbBuf, cbMissing);
+ pCtx->AltPrivate.cbMessage.s.Lo += cbMissing;
+ if (!pCtx->AltPrivate.cbMessage.s.Lo)
+ pCtx->AltPrivate.cbMessage.s.Hi++;
+ pbBuf += cbMissing;
+ cbBuf -= cbMissing;
+
+ rtSha512BlockInitBuffered(pCtx);
+ rtSha512BlockProcess(pCtx);
+ }
+ else
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, pbBuf, cbBuf);
+ pCtx->AltPrivate.cbMessage.s.Lo += cbBuf;
+ return;
+ }
+ }
+
+ if (!((uintptr_t)pbBuf & 7))
+ {
+ /*
+ * Process full blocks directly from the input buffer.
+ */
+ while (cbBuf >= RTSHA512_BLOCK_SIZE)
+ {
+ rtSha512BlockInit(pCtx, pbBuf);
+ rtSha512BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbMessage.s.Lo += RTSHA512_BLOCK_SIZE;
+ if (!pCtx->AltPrivate.cbMessage.s.Lo)
+ pCtx->AltPrivate.cbMessage.s.Hi++;
+ pbBuf += RTSHA512_BLOCK_SIZE;
+ cbBuf -= RTSHA512_BLOCK_SIZE;
+ }
+ }
+ else
+ {
+ /*
+ * Unaligned input, so buffer it.
+ */
+ while (cbBuf >= RTSHA512_BLOCK_SIZE)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0], pbBuf, RTSHA512_BLOCK_SIZE);
+ rtSha512BlockInitBuffered(pCtx);
+ rtSha512BlockProcess(pCtx);
+
+ pCtx->AltPrivate.cbMessage.s.Lo += RTSHA512_BLOCK_SIZE;
+ if (!pCtx->AltPrivate.cbMessage.s.Lo)
+ pCtx->AltPrivate.cbMessage.s.Hi++;
+ pbBuf += RTSHA512_BLOCK_SIZE;
+ cbBuf -= RTSHA512_BLOCK_SIZE;
+ }
+ }
+
+ /*
+ * Stash any remaining bytes into the context buffer.
+ */
+ if (cbBuf > 0)
+ {
+ memcpy((uint8_t *)&pCtx->AltPrivate.auW[0], pbBuf, cbBuf);
+ pCtx->AltPrivate.cbMessage.s.Lo += cbBuf;
+ if (!pCtx->AltPrivate.cbMessage.s.Lo)
+ pCtx->AltPrivate.cbMessage.s.Hi++;
+ }
+}
+RT_EXPORT_SYMBOL(RTSha512Update);
+
+
+/**
+ * Internal worker for RTSha512Final and RTSha384Final that finalizes the
+ * computation but does not copy out the hash value.
+ *
+ * @param pCtx The SHA-512 context.
+ */
+static void rtSha512FinalInternal(PRTSHA512CONTEXT pCtx)
+{
+ Assert(pCtx->AltPrivate.cbMessage.s.Hi < UINT64_MAX / 8);
+
+ /*
+ * Complete the message by adding a single bit (0x80), padding till
+ * the next 448-bit boundrary, the add the message length.
+ */
+ RTUINT128U cMessageBits = pCtx->AltPrivate.cbMessage;
+ cMessageBits.s.Hi <<= 3;
+ cMessageBits.s.Hi |= cMessageBits.s.Lo >> 61;
+ cMessageBits.s.Lo <<= 3;
+
+ unsigned cbMissing = RTSHA512_BLOCK_SIZE - ((unsigned)pCtx->AltPrivate.cbMessage.s.Lo & (RTSHA512_BLOCK_SIZE - 1U));
+ static uint8_t const s_abSingleBitAndSomePadding[20] =
+ { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
+ if (cbMissing < 1U + 16U)
+ /* Less than 64+16 bits left in the current block, force a new block. */
+ RTSha512Update(pCtx, &s_abSingleBitAndSomePadding, sizeof(s_abSingleBitAndSomePadding));
+ else
+ RTSha512Update(pCtx, &s_abSingleBitAndSomePadding, 1);
+
+ unsigned cbBuffered = (unsigned)pCtx->AltPrivate.cbMessage.s.Lo & (RTSHA512_BLOCK_SIZE - 1U);
+ cbMissing = RTSHA512_BLOCK_SIZE - cbBuffered;
+ Assert(cbMissing >= 16);
+ memset((uint8_t *)&pCtx->AltPrivate.auW[0] + cbBuffered, 0, cbMissing - 16);
+
+ pCtx->AltPrivate.auW[14] = RT_H2BE_U64(cMessageBits.s.Hi);
+ pCtx->AltPrivate.auW[15] = RT_H2BE_U64(cMessageBits.s.Lo);
+
+ /*
+ * Process the last buffered block constructed/completed above.
+ */
+ rtSha512BlockInitBuffered(pCtx);
+ rtSha512BlockProcess(pCtx);
+
+ /*
+ * Convert the byte order of the hash words and we're done.
+ */
+ pCtx->AltPrivate.auH[0] = RT_H2BE_U64(pCtx->AltPrivate.auH[0]);
+ pCtx->AltPrivate.auH[1] = RT_H2BE_U64(pCtx->AltPrivate.auH[1]);
+ pCtx->AltPrivate.auH[2] = RT_H2BE_U64(pCtx->AltPrivate.auH[2]);
+ pCtx->AltPrivate.auH[3] = RT_H2BE_U64(pCtx->AltPrivate.auH[3]);
+ pCtx->AltPrivate.auH[4] = RT_H2BE_U64(pCtx->AltPrivate.auH[4]);
+ pCtx->AltPrivate.auH[5] = RT_H2BE_U64(pCtx->AltPrivate.auH[5]);
+ pCtx->AltPrivate.auH[6] = RT_H2BE_U64(pCtx->AltPrivate.auH[6]);
+ pCtx->AltPrivate.auH[7] = RT_H2BE_U64(pCtx->AltPrivate.auH[7]);
+
+ RT_ZERO(pCtx->AltPrivate.auW);
+ pCtx->AltPrivate.cbMessage.s.Lo = UINT64_MAX;
+ pCtx->AltPrivate.cbMessage.s.Hi = UINT64_MAX;
+}
+RT_EXPORT_SYMBOL(RTSha512Final);
+
+
+RTDECL(void) RTSha512Final(PRTSHA512CONTEXT pCtx, uint8_t pabDigest[RTSHA512_HASH_SIZE])
+{
+ rtSha512FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA512_HASH_SIZE);
+ RT_ZERO(pCtx->AltPrivate.auH);
+}
+RT_EXPORT_SYMBOL(RTSha512Final);
+
+
+RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA512_HASH_SIZE])
+{
+ RTSHA512CONTEXT Ctx;
+ RTSha512Init(&Ctx);
+ RTSha512Update(&Ctx, pvBuf, cbBuf);
+ RTSha512Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha512);
+
+
+RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512_HASH_SIZE])
+{
+ RTSHA512CONTEXT Ctx;
+ RTSha512Init(&Ctx);
+ RTSha512Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA512_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512Check);
+
+
+
+/*
+ * SHA-384 is just SHA-512 with different initial values an a truncated result.
+ */
+
+RTDECL(void) RTSha384Init(PRTSHA384CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage.s.Lo = 0;
+ pCtx->AltPrivate.cbMessage.s.Hi = 0;
+ pCtx->AltPrivate.auH[0] = UINT64_C(0xcbbb9d5dc1059ed8);
+ pCtx->AltPrivate.auH[1] = UINT64_C(0x629a292a367cd507);
+ pCtx->AltPrivate.auH[2] = UINT64_C(0x9159015a3070dd17);
+ pCtx->AltPrivate.auH[3] = UINT64_C(0x152fecd8f70e5939);
+ pCtx->AltPrivate.auH[4] = UINT64_C(0x67332667ffc00b31);
+ pCtx->AltPrivate.auH[5] = UINT64_C(0x8eb44a8768581511);
+ pCtx->AltPrivate.auH[6] = UINT64_C(0xdb0c2e0d64f98fa7);
+ pCtx->AltPrivate.auH[7] = UINT64_C(0x47b5481dbefa4fa4);
+}
+RT_EXPORT_SYMBOL(RTSha384Init);
+
+
+RTDECL(void) RTSha384Update(PRTSHA384CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ RTSha512Update(pCtx, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha384Update);
+
+
+RTDECL(void) RTSha384Final(PRTSHA384CONTEXT pCtx, uint8_t pabDigest[RTSHA384_HASH_SIZE])
+{
+ rtSha512FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA384_HASH_SIZE);
+ RT_ZERO(pCtx->AltPrivate.auH);
+}
+RT_EXPORT_SYMBOL(RTSha384Final);
+
+
+RTDECL(void) RTSha384(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA384_HASH_SIZE])
+{
+ RTSHA384CONTEXT Ctx;
+ RTSha384Init(&Ctx);
+ RTSha384Update(&Ctx, pvBuf, cbBuf);
+ RTSha384Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha384);
+
+
+RTDECL(bool) RTSha384Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA384_HASH_SIZE])
+{
+ RTSHA384CONTEXT Ctx;
+ RTSha384Init(&Ctx);
+ RTSha384Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA384_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha384Check);
+
+
+/*
+ * SHA-512/224 is just SHA-512 with different initial values an a truncated result.
+ */
+
+RTDECL(void) RTSha512t224Init(PRTSHA512T224CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage.s.Lo = 0;
+ pCtx->AltPrivate.cbMessage.s.Hi = 0;
+ pCtx->AltPrivate.auH[0] = UINT64_C(0x8c3d37c819544da2);
+ pCtx->AltPrivate.auH[1] = UINT64_C(0x73e1996689dcd4d6);
+ pCtx->AltPrivate.auH[2] = UINT64_C(0x1dfab7ae32ff9c82);
+ pCtx->AltPrivate.auH[3] = UINT64_C(0x679dd514582f9fcf);
+ pCtx->AltPrivate.auH[4] = UINT64_C(0x0f6d2b697bd44da8);
+ pCtx->AltPrivate.auH[5] = UINT64_C(0x77e36f7304c48942);
+ pCtx->AltPrivate.auH[6] = UINT64_C(0x3f9d85a86a1d36c8);
+ pCtx->AltPrivate.auH[7] = UINT64_C(0x1112e6ad91d692a1);
+}
+RT_EXPORT_SYMBOL(RTSha512t224Init);
+
+
+RTDECL(void) RTSha512t224Update(PRTSHA512T224CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ RTSha512Update(pCtx, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha512t224Update);
+
+
+RTDECL(void) RTSha512t224Final(PRTSHA512T224CONTEXT pCtx, uint8_t pabDigest[RTSHA512T224_HASH_SIZE])
+{
+ rtSha512FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA512T224_HASH_SIZE);
+ RT_ZERO(pCtx->AltPrivate.auH);
+}
+RT_EXPORT_SYMBOL(RTSha512t224Final);
+
+
+RTDECL(void) RTSha512t224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA512T224_HASH_SIZE])
+{
+ RTSHA512T224CONTEXT Ctx;
+ RTSha512t224Init(&Ctx);
+ RTSha512t224Update(&Ctx, pvBuf, cbBuf);
+ RTSha512t224Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha512t224);
+
+
+RTDECL(bool) RTSha512t224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512T224_HASH_SIZE])
+{
+ RTSHA512T224CONTEXT Ctx;
+ RTSha512t224Init(&Ctx);
+ RTSha512t224Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA512T224_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512t224Check);
+
+
+/*
+ * SHA-512/256 is just SHA-512 with different initial values an a truncated result.
+ */
+
+RTDECL(void) RTSha512t256Init(PRTSHA512T256CONTEXT pCtx)
+{
+ pCtx->AltPrivate.cbMessage.s.Lo = 0;
+ pCtx->AltPrivate.cbMessage.s.Hi = 0;
+ pCtx->AltPrivate.auH[0] = UINT64_C(0x22312194fc2bf72c);
+ pCtx->AltPrivate.auH[1] = UINT64_C(0x9f555fa3c84c64c2);
+ pCtx->AltPrivate.auH[2] = UINT64_C(0x2393b86b6f53b151);
+ pCtx->AltPrivate.auH[3] = UINT64_C(0x963877195940eabd);
+ pCtx->AltPrivate.auH[4] = UINT64_C(0x96283ee2a88effe3);
+ pCtx->AltPrivate.auH[5] = UINT64_C(0xbe5e1e2553863992);
+ pCtx->AltPrivate.auH[6] = UINT64_C(0x2b0199fc2c85b8aa);
+ pCtx->AltPrivate.auH[7] = UINT64_C(0x0eb72ddc81c52ca2);
+}
+RT_EXPORT_SYMBOL(RTSha512t256Init);
+
+
+RTDECL(void) RTSha512t256Update(PRTSHA512T256CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ RTSha512Update(pCtx, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha512t256Update);
+
+
+RTDECL(void) RTSha512t256Final(PRTSHA512T256CONTEXT pCtx, uint8_t pabDigest[RTSHA512T256_HASH_SIZE])
+{
+ rtSha512FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA512T256_HASH_SIZE);
+ RT_ZERO(pCtx->AltPrivate.auH);
+}
+RT_EXPORT_SYMBOL(RTSha512t256Final);
+
+
+RTDECL(void) RTSha512t256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA512T256_HASH_SIZE])
+{
+ RTSHA512T256CONTEXT Ctx;
+ RTSha512t256Init(&Ctx);
+ RTSha512t256Update(&Ctx, pvBuf, cbBuf);
+ RTSha512t256Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha512t256);
+
+
+RTDECL(bool) RTSha512t256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512T256_HASH_SIZE])
+{
+ RTSHA512T256CONTEXT Ctx;
+ RTSha512t256Init(&Ctx);
+ RTSha512t256Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA512T256_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512t256Check);
+
diff --git a/src/VBox/Runtime/common/checksum/crc16ccitt.cpp b/src/VBox/Runtime/common/checksum/crc16ccitt.cpp
new file mode 100644
index 00000000..6ca03ed0
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/crc16ccitt.cpp
@@ -0,0 +1,118 @@
+/* $Id: crc16ccitt.cpp $ */
+/** @file
+ * IPRT - CRC-16-CCITT.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crc.h>
+#include "internal/iprt.h"
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+/**
+ * CRC-16-CCTII / CRC-CCTII / CRC 010041 table.
+ */
+static uint16_t const g_au16Crc16Cctii[0x100] =
+{
+ UINT16_C(0x0000), UINT16_C(0x1021), UINT16_C(0x2042), UINT16_C(0x3063), UINT16_C(0x4084), UINT16_C(0x50a5), UINT16_C(0x60c6), UINT16_C(0x70e7),
+ UINT16_C(0x8108), UINT16_C(0x9129), UINT16_C(0xa14a), UINT16_C(0xb16b), UINT16_C(0xc18c), UINT16_C(0xd1ad), UINT16_C(0xe1ce), UINT16_C(0xf1ef),
+ UINT16_C(0x1231), UINT16_C(0x0210), UINT16_C(0x3273), UINT16_C(0x2252), UINT16_C(0x52b5), UINT16_C(0x4294), UINT16_C(0x72f7), UINT16_C(0x62d6),
+ UINT16_C(0x9339), UINT16_C(0x8318), UINT16_C(0xb37b), UINT16_C(0xa35a), UINT16_C(0xd3bd), UINT16_C(0xc39c), UINT16_C(0xf3ff), UINT16_C(0xe3de),
+ UINT16_C(0x2462), UINT16_C(0x3443), UINT16_C(0x0420), UINT16_C(0x1401), UINT16_C(0x64e6), UINT16_C(0x74c7), UINT16_C(0x44a4), UINT16_C(0x5485),
+ UINT16_C(0xa56a), UINT16_C(0xb54b), UINT16_C(0x8528), UINT16_C(0x9509), UINT16_C(0xe5ee), UINT16_C(0xf5cf), UINT16_C(0xc5ac), UINT16_C(0xd58d),
+ UINT16_C(0x3653), UINT16_C(0x2672), UINT16_C(0x1611), UINT16_C(0x0630), UINT16_C(0x76d7), UINT16_C(0x66f6), UINT16_C(0x5695), UINT16_C(0x46b4),
+ UINT16_C(0xb75b), UINT16_C(0xa77a), UINT16_C(0x9719), UINT16_C(0x8738), UINT16_C(0xf7df), UINT16_C(0xe7fe), UINT16_C(0xd79d), UINT16_C(0xc7bc),
+ UINT16_C(0x48c4), UINT16_C(0x58e5), UINT16_C(0x6886), UINT16_C(0x78a7), UINT16_C(0x0840), UINT16_C(0x1861), UINT16_C(0x2802), UINT16_C(0x3823),
+ UINT16_C(0xc9cc), UINT16_C(0xd9ed), UINT16_C(0xe98e), UINT16_C(0xf9af), UINT16_C(0x8948), UINT16_C(0x9969), UINT16_C(0xa90a), UINT16_C(0xb92b),
+ UINT16_C(0x5af5), UINT16_C(0x4ad4), UINT16_C(0x7ab7), UINT16_C(0x6a96), UINT16_C(0x1a71), UINT16_C(0x0a50), UINT16_C(0x3a33), UINT16_C(0x2a12),
+ UINT16_C(0xdbfd), UINT16_C(0xcbdc), UINT16_C(0xfbbf), UINT16_C(0xeb9e), UINT16_C(0x9b79), UINT16_C(0x8b58), UINT16_C(0xbb3b), UINT16_C(0xab1a),
+ UINT16_C(0x6ca6), UINT16_C(0x7c87), UINT16_C(0x4ce4), UINT16_C(0x5cc5), UINT16_C(0x2c22), UINT16_C(0x3c03), UINT16_C(0x0c60), UINT16_C(0x1c41),
+ UINT16_C(0xedae), UINT16_C(0xfd8f), UINT16_C(0xcdec), UINT16_C(0xddcd), UINT16_C(0xad2a), UINT16_C(0xbd0b), UINT16_C(0x8d68), UINT16_C(0x9d49),
+ UINT16_C(0x7e97), UINT16_C(0x6eb6), UINT16_C(0x5ed5), UINT16_C(0x4ef4), UINT16_C(0x3e13), UINT16_C(0x2e32), UINT16_C(0x1e51), UINT16_C(0x0e70),
+ UINT16_C(0xff9f), UINT16_C(0xefbe), UINT16_C(0xdfdd), UINT16_C(0xcffc), UINT16_C(0xbf1b), UINT16_C(0xaf3a), UINT16_C(0x9f59), UINT16_C(0x8f78),
+ UINT16_C(0x9188), UINT16_C(0x81a9), UINT16_C(0xb1ca), UINT16_C(0xa1eb), UINT16_C(0xd10c), UINT16_C(0xc12d), UINT16_C(0xf14e), UINT16_C(0xe16f),
+ UINT16_C(0x1080), UINT16_C(0x00a1), UINT16_C(0x30c2), UINT16_C(0x20e3), UINT16_C(0x5004), UINT16_C(0x4025), UINT16_C(0x7046), UINT16_C(0x6067),
+ UINT16_C(0x83b9), UINT16_C(0x9398), UINT16_C(0xa3fb), UINT16_C(0xb3da), UINT16_C(0xc33d), UINT16_C(0xd31c), UINT16_C(0xe37f), UINT16_C(0xf35e),
+ UINT16_C(0x02b1), UINT16_C(0x1290), UINT16_C(0x22f3), UINT16_C(0x32d2), UINT16_C(0x4235), UINT16_C(0x5214), UINT16_C(0x6277), UINT16_C(0x7256),
+ UINT16_C(0xb5ea), UINT16_C(0xa5cb), UINT16_C(0x95a8), UINT16_C(0x8589), UINT16_C(0xf56e), UINT16_C(0xe54f), UINT16_C(0xd52c), UINT16_C(0xc50d),
+ UINT16_C(0x34e2), UINT16_C(0x24c3), UINT16_C(0x14a0), UINT16_C(0x0481), UINT16_C(0x7466), UINT16_C(0x6447), UINT16_C(0x5424), UINT16_C(0x4405),
+ UINT16_C(0xa7db), UINT16_C(0xb7fa), UINT16_C(0x8799), UINT16_C(0x97b8), UINT16_C(0xe75f), UINT16_C(0xf77e), UINT16_C(0xc71d), UINT16_C(0xd73c),
+ UINT16_C(0x26d3), UINT16_C(0x36f2), UINT16_C(0x0691), UINT16_C(0x16b0), UINT16_C(0x6657), UINT16_C(0x7676), UINT16_C(0x4615), UINT16_C(0x5634),
+ UINT16_C(0xd94c), UINT16_C(0xc96d), UINT16_C(0xf90e), UINT16_C(0xe92f), UINT16_C(0x99c8), UINT16_C(0x89e9), UINT16_C(0xb98a), UINT16_C(0xa9ab),
+ UINT16_C(0x5844), UINT16_C(0x4865), UINT16_C(0x7806), UINT16_C(0x6827), UINT16_C(0x18c0), UINT16_C(0x08e1), UINT16_C(0x3882), UINT16_C(0x28a3),
+ UINT16_C(0xcb7d), UINT16_C(0xdb5c), UINT16_C(0xeb3f), UINT16_C(0xfb1e), UINT16_C(0x8bf9), UINT16_C(0x9bd8), UINT16_C(0xabbb), UINT16_C(0xbb9a),
+ UINT16_C(0x4a75), UINT16_C(0x5a54), UINT16_C(0x6a37), UINT16_C(0x7a16), UINT16_C(0x0af1), UINT16_C(0x1ad0), UINT16_C(0x2ab3), UINT16_C(0x3a92),
+ UINT16_C(0xfd2e), UINT16_C(0xed0f), UINT16_C(0xdd6c), UINT16_C(0xcd4d), UINT16_C(0xbdaa), UINT16_C(0xad8b), UINT16_C(0x9de8), UINT16_C(0x8dc9),
+ UINT16_C(0x7c26), UINT16_C(0x6c07), UINT16_C(0x5c64), UINT16_C(0x4c45), UINT16_C(0x3ca2), UINT16_C(0x2c83), UINT16_C(0x1ce0), UINT16_C(0x0cc1),
+ UINT16_C(0xef1f), UINT16_C(0xff3e), UINT16_C(0xcf5d), UINT16_C(0xdf7c), UINT16_C(0xaf9b), UINT16_C(0xbfba), UINT16_C(0x8fd9), UINT16_C(0x9ff8),
+ UINT16_C(0x6e17), UINT16_C(0x7e36), UINT16_C(0x4e55), UINT16_C(0x5e74), UINT16_C(0x2e93), UINT16_C(0x3eb2), UINT16_C(0x0ed1), UINT16_C(0x1ef0),
+};
+
+
+
+RTDECL(uint16_t) RTCrc16Ccitt(const void *pv, size_t cb)
+{
+ uint16_t uCrc = 0;
+ const uint8_t *pb = (const uint8_t *)pv;
+ while (cb-- > 0)
+ uCrc = g_au16Crc16Cctii[(uint8_t)(uCrc >> 8) ^ *pb++] ^ (uCrc << 8);
+ return uCrc;
+}
+
+
+RTDECL(uint16_t) RTCrc16CcittStart(void)
+{
+ return 0;
+}
+
+
+RTDECL(uint16_t) RTCrc16CcittProcess(uint16_t uCrc, const void *pv, size_t cb)
+{
+ const uint8_t *pb = (const uint8_t *)pv;
+ while (cb-- > 0)
+ uCrc = g_au16Crc16Cctii[(uint8_t)(uCrc >> 8) ^ *pb++] ^ (uCrc << 8);
+ return uCrc;
+}
+
+
+RTDECL(uint16_t) RTCrc16CcittFinish(uint16_t uCrc)
+{
+ return uCrc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/crc32-zlib.cpp b/src/VBox/Runtime/common/checksum/crc32-zlib.cpp
new file mode 100644
index 00000000..0b41b28d
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/crc32-zlib.cpp
@@ -0,0 +1,99 @@
+/* $Id: crc32-zlib.cpp $ */
+/** @file
+ * IPRT - CRC-32 on top of zlib (very fast).
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/crc.h>
+
+#include <zlib.h>
+
+/** @todo Check if we can't just use the zlib code directly here. */
+
+/**
+ * Deal with blocks that are too big for the uInt type.
+ */
+static uint32_t rtCrc32ProcessTooBig(uint32_t uCRC32, const void *pv, size_t cb)
+{
+ const Bytef *pb = (const Bytef *)pv;
+ do
+ {
+ uInt const cbChunk = cb <= ~(uInt)0 ? (uInt)cb : ~(uInt)0;
+ uCRC32 = crc32(uCRC32, pb, cbChunk);
+ pb += cbChunk;
+ cb -= cbChunk;
+ } while (!cb);
+ return uCRC32;
+}
+
+RTDECL(uint32_t) RTCrc32(const void *pv, size_t cb)
+{
+ uint32_t uCrc = crc32(0, NULL, 0);
+ if (RT_UNLIKELY((uInt)cb == cb))
+ uCrc = crc32(uCrc, (const Bytef *)pv, (uInt)cb);
+ else
+ uCrc = rtCrc32ProcessTooBig(uCrc, pv, cb);
+ return uCrc;
+}
+RT_EXPORT_SYMBOL(RTCrc32);
+
+
+RTDECL(uint32_t) RTCrc32Start(void)
+{
+ return crc32(0, NULL, 0);
+}
+RT_EXPORT_SYMBOL(RTCrc32Start);
+
+
+RTDECL(uint32_t) RTCrc32Process(uint32_t uCRC32, const void *pv, size_t cb)
+{
+ if (RT_UNLIKELY((uInt)cb == cb))
+ uCRC32 = crc32(uCRC32, (const Bytef *)pv, (uInt)cb);
+ else
+ uCRC32 = rtCrc32ProcessTooBig(uCRC32, pv, cb);
+ return uCRC32;
+}
+RT_EXPORT_SYMBOL(RTCrc32Process);
+
+
+RTDECL(uint32_t) RTCrc32Finish(uint32_t uCRC32)
+{
+ return uCRC32;
+}
+RT_EXPORT_SYMBOL(RTCrc32Finish);
+
diff --git a/src/VBox/Runtime/common/checksum/crc32.cpp b/src/VBox/Runtime/common/checksum/crc32.cpp
new file mode 100644
index 00000000..4d29782f
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/crc32.cpp
@@ -0,0 +1,196 @@
+/* $Id: crc32.cpp $ */
+/** @file
+ * IPRT - CRC32.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ *
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to height-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ *
+ */
+
+#if 0
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/libkern/crc32.c,v 1.2 2003/06/11 05:23:04 obrien Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#else
+# include <iprt/crc.h>
+# include "internal/iprt.h"
+#endif
+
+#if 0
+uint32_t crc32_tab[] = {
+#else
+/** CRC32 feedback table. */
+static uint32_t const g_au32CRC32[] =
+{
+#endif
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#if 0
+uint32_t
+crc32(const void *buf, size_t size)
+{
+ const uint8_t *p;
+ uint32_t crc;
+
+ p = buf;
+ crc = ~0U;
+
+ while (size--)
+ crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+ return crc ^ ~0U;
+}
+#endif
+
+
+
+
+RTDECL(uint32_t) RTCrc32(const void *pv, size_t cb)
+{
+ const uint8_t *pu8 = (const uint8_t *)pv;
+ uint32_t uCRC32 = ~0U;
+ while (cb--)
+ uCRC32 = g_au32CRC32[(uCRC32 ^ *pu8++) & 0xff] ^ (uCRC32 >> 8);
+ return uCRC32 ^ ~0U;
+}
+RT_EXPORT_SYMBOL(RTCrc32);
+
+
+RTDECL(uint32_t) RTCrc32Start(void)
+{
+ return ~0U;
+}
+RT_EXPORT_SYMBOL(RTCrc32Start);
+
+
+RTDECL(uint32_t) RTCrc32Process(uint32_t uCRC32, const void *pv, size_t cb)
+{
+ const uint8_t *pu8 = (const uint8_t *)pv;
+ while (cb--)
+ uCRC32 = g_au32CRC32[(uCRC32 ^ *pu8++) & 0xff] ^ (uCRC32 >> 8);
+ return uCRC32;
+}
+RT_EXPORT_SYMBOL(RTCrc32Process);
+
+
+RTDECL(uint32_t) RTCrc32Finish(uint32_t uCRC32)
+{
+ return uCRC32 ^ ~0U;
+}
+RT_EXPORT_SYMBOL(RTCrc32Finish);
+
diff --git a/src/VBox/Runtime/common/checksum/crc32c.cpp b/src/VBox/Runtime/common/checksum/crc32c.cpp
new file mode 100644
index 00000000..184c8166
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/crc32c.cpp
@@ -0,0 +1,132 @@
+/* $Id: crc32c.cpp $ */
+/** @file
+ * IPRT - CRC32C.
+ */
+
+/*
+ * Copyright (C) 2014-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include <iprt/crc.h>
+#include "internal/iprt.h"
+
+/**
+ * Generated using the pycrc tool using model crc-32c.
+ */
+static uint32_t const g_au32Crc32C[] =
+{
+ 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,
+ 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
+ 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,
+ 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
+ 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,
+ 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
+ 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,
+ 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
+ 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,
+ 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
+ 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,
+ 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
+ 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,
+ 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
+ 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,
+ 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
+ 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,
+ 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
+ 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,
+ 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
+ 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,
+ 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
+ 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,
+ 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
+ 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,
+ 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
+ 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,
+ 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
+ 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,
+ 0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
+ 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,
+ 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
+ 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,
+ 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
+ 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,
+ 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
+ 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,
+ 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
+ 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,
+ 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
+ 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,
+ 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
+ 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
+};
+
+
+DECLINLINE(uint32_t) rtCrc32CProcessWithTable(const uint32_t *pau32Crc32,
+ uint32_t uCrc32, const void *pv, size_t cb)
+{
+ const uint8_t *pu8 = (const uint8_t *)pv;
+
+ while (cb--)
+ uCrc32 = pau32Crc32[(uCrc32 ^ *pu8++) & 0xff] ^ (uCrc32 >> 8);
+
+ return uCrc32;
+}
+
+
+RTDECL(uint32_t) RTCrc32CStart(void)
+{
+ return ~0U;
+}
+RT_EXPORT_SYMBOL(RTCrc32CStart);
+
+
+RTDECL(uint32_t) RTCrc32CFinish(uint32_t uCRC32)
+{
+ return uCRC32 ^ ~0U;
+}
+RT_EXPORT_SYMBOL(RTCrc32CFinish);
+
+
+RTDECL(uint32_t) RTCrc32C(const void *pv, size_t cb)
+{
+ uint32_t uCrc32C = RTCrc32CStart();
+
+ uCrc32C = rtCrc32CProcessWithTable(g_au32Crc32C, uCrc32C, pv, cb);
+ return RTCrc32CFinish(uCrc32C);
+}
+RT_EXPORT_SYMBOL(RTCrc32C);
+
+
+RTDECL(uint32_t) RTCrc32CProcess(uint32_t uCrc32C, const void *pv, size_t cb)
+{
+ return rtCrc32CProcessWithTable(g_au32Crc32C, uCrc32C, pv, cb);;
+}
+RT_EXPORT_SYMBOL(RTCrc32CProcess);
+
diff --git a/src/VBox/Runtime/common/checksum/crc64.cpp b/src/VBox/Runtime/common/checksum/crc64.cpp
new file mode 100644
index 00000000..008bdd1d
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/crc64.cpp
@@ -0,0 +1,196 @@
+/* $Id: crc64.cpp $ */
+/** @file
+ * IPRT - CRC64.
+ *
+ * The method to compute the CRC64 is referred to as CRC-64-ISO:
+ * http://en.wikipedia.org/wiki/Cyclic_redundancy_check
+ * The generator polynomial is x^64 + x^4 + x^3 + x + 1.
+ * Reverse polynom: 0xd800000000000000ULL
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crc.h>
+#include "internal/iprt.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/**
+ * Lookup table (precomputed CRC64 values for each 8 bit string) computation
+ * takes into account the fact that the reverse polynom has zeros in lower 8 bits:
+ *
+ * @code
+ * for (i = 0; i < 256; i++)
+ * {
+ * shiftRegister = i;
+ * for (j = 0; j < 8; j++)
+ * {
+ * if (shiftRegister & 1)
+ * shiftRegister = (shiftRegister >> 1) ^ Reverse_polynom;
+ * else
+ * shiftRegister >>= 1;
+ * }
+ * CRCTable[i] = shiftRegister;
+ * }
+ * @endcode
+ *
+ * Generic code would look as follows:
+ *
+ * @code
+ * for (i = 0; i < 256; i++)
+ * {
+ * shiftRegister = 0;
+ * bitString = i;
+ * for (j = 0; j < 8; j++)
+ * {
+ * if ((shiftRegister ^ (bitString >> j)) & 1)
+ * shiftRegister = (shiftRegister >> 1) ^ Reverse_polynom;
+ * else
+ * shiftRegister >>= 1;
+ * }
+ * CRCTable[i] = shiftRegister;
+ * }
+ * @endcode
+ *
+ * @remark Since the lookup table elements have 0 in the lower 32 bit word,
+ * the 32 bit assembler implementation of CRC64Process can be optimized,
+ * avoiding at least one 'xor' operation.
+ */
+static const uint64_t g_au64CRC64[] =
+{
+ 0x0000000000000000ULL, 0x01B0000000000000ULL, 0x0360000000000000ULL, 0x02D0000000000000ULL,
+ 0x06C0000000000000ULL, 0x0770000000000000ULL, 0x05A0000000000000ULL, 0x0410000000000000ULL,
+ 0x0D80000000000000ULL, 0x0C30000000000000ULL, 0x0EE0000000000000ULL, 0x0F50000000000000ULL,
+ 0x0B40000000000000ULL, 0x0AF0000000000000ULL, 0x0820000000000000ULL, 0x0990000000000000ULL,
+ 0x1B00000000000000ULL, 0x1AB0000000000000ULL, 0x1860000000000000ULL, 0x19D0000000000000ULL,
+ 0x1DC0000000000000ULL, 0x1C70000000000000ULL, 0x1EA0000000000000ULL, 0x1F10000000000000ULL,
+ 0x1680000000000000ULL, 0x1730000000000000ULL, 0x15E0000000000000ULL, 0x1450000000000000ULL,
+ 0x1040000000000000ULL, 0x11F0000000000000ULL, 0x1320000000000000ULL, 0x1290000000000000ULL,
+ 0x3600000000000000ULL, 0x37B0000000000000ULL, 0x3560000000000000ULL, 0x34D0000000000000ULL,
+ 0x30C0000000000000ULL, 0x3170000000000000ULL, 0x33A0000000000000ULL, 0x3210000000000000ULL,
+ 0x3B80000000000000ULL, 0x3A30000000000000ULL, 0x38E0000000000000ULL, 0x3950000000000000ULL,
+ 0x3D40000000000000ULL, 0x3CF0000000000000ULL, 0x3E20000000000000ULL, 0x3F90000000000000ULL,
+ 0x2D00000000000000ULL, 0x2CB0000000000000ULL, 0x2E60000000000000ULL, 0x2FD0000000000000ULL,
+ 0x2BC0000000000000ULL, 0x2A70000000000000ULL, 0x28A0000000000000ULL, 0x2910000000000000ULL,
+ 0x2080000000000000ULL, 0x2130000000000000ULL, 0x23E0000000000000ULL, 0x2250000000000000ULL,
+ 0x2640000000000000ULL, 0x27F0000000000000ULL, 0x2520000000000000ULL, 0x2490000000000000ULL,
+ 0x6C00000000000000ULL, 0x6DB0000000000000ULL, 0x6F60000000000000ULL, 0x6ED0000000000000ULL,
+ 0x6AC0000000000000ULL, 0x6B70000000000000ULL, 0x69A0000000000000ULL, 0x6810000000000000ULL,
+ 0x6180000000000000ULL, 0x6030000000000000ULL, 0x62E0000000000000ULL, 0x6350000000000000ULL,
+ 0x6740000000000000ULL, 0x66F0000000000000ULL, 0x6420000000000000ULL, 0x6590000000000000ULL,
+ 0x7700000000000000ULL, 0x76B0000000000000ULL, 0x7460000000000000ULL, 0x75D0000000000000ULL,
+ 0x71C0000000000000ULL, 0x7070000000000000ULL, 0x72A0000000000000ULL, 0x7310000000000000ULL,
+ 0x7A80000000000000ULL, 0x7B30000000000000ULL, 0x79E0000000000000ULL, 0x7850000000000000ULL,
+ 0x7C40000000000000ULL, 0x7DF0000000000000ULL, 0x7F20000000000000ULL, 0x7E90000000000000ULL,
+ 0x5A00000000000000ULL, 0x5BB0000000000000ULL, 0x5960000000000000ULL, 0x58D0000000000000ULL,
+ 0x5CC0000000000000ULL, 0x5D70000000000000ULL, 0x5FA0000000000000ULL, 0x5E10000000000000ULL,
+ 0x5780000000000000ULL, 0x5630000000000000ULL, 0x54E0000000000000ULL, 0x5550000000000000ULL,
+ 0x5140000000000000ULL, 0x50F0000000000000ULL, 0x5220000000000000ULL, 0x5390000000000000ULL,
+ 0x4100000000000000ULL, 0x40B0000000000000ULL, 0x4260000000000000ULL, 0x43D0000000000000ULL,
+ 0x47C0000000000000ULL, 0x4670000000000000ULL, 0x44A0000000000000ULL, 0x4510000000000000ULL,
+ 0x4C80000000000000ULL, 0x4D30000000000000ULL, 0x4FE0000000000000ULL, 0x4E50000000000000ULL,
+ 0x4A40000000000000ULL, 0x4BF0000000000000ULL, 0x4920000000000000ULL, 0x4890000000000000ULL,
+ 0xD800000000000000ULL, 0xD9B0000000000000ULL, 0xDB60000000000000ULL, 0xDAD0000000000000ULL,
+ 0xDEC0000000000000ULL, 0xDF70000000000000ULL, 0xDDA0000000000000ULL, 0xDC10000000000000ULL,
+ 0xD580000000000000ULL, 0xD430000000000000ULL, 0xD6E0000000000000ULL, 0xD750000000000000ULL,
+ 0xD340000000000000ULL, 0xD2F0000000000000ULL, 0xD020000000000000ULL, 0xD190000000000000ULL,
+ 0xC300000000000000ULL, 0xC2B0000000000000ULL, 0xC060000000000000ULL, 0xC1D0000000000000ULL,
+ 0xC5C0000000000000ULL, 0xC470000000000000ULL, 0xC6A0000000000000ULL, 0xC710000000000000ULL,
+ 0xCE80000000000000ULL, 0xCF30000000000000ULL, 0xCDE0000000000000ULL, 0xCC50000000000000ULL,
+ 0xC840000000000000ULL, 0xC9F0000000000000ULL, 0xCB20000000000000ULL, 0xCA90000000000000ULL,
+ 0xEE00000000000000ULL, 0xEFB0000000000000ULL, 0xED60000000000000ULL, 0xECD0000000000000ULL,
+ 0xE8C0000000000000ULL, 0xE970000000000000ULL, 0xEBA0000000000000ULL, 0xEA10000000000000ULL,
+ 0xE380000000000000ULL, 0xE230000000000000ULL, 0xE0E0000000000000ULL, 0xE150000000000000ULL,
+ 0xE540000000000000ULL, 0xE4F0000000000000ULL, 0xE620000000000000ULL, 0xE790000000000000ULL,
+ 0xF500000000000000ULL, 0xF4B0000000000000ULL, 0xF660000000000000ULL, 0xF7D0000000000000ULL,
+ 0xF3C0000000000000ULL, 0xF270000000000000ULL, 0xF0A0000000000000ULL, 0xF110000000000000ULL,
+ 0xF880000000000000ULL, 0xF930000000000000ULL, 0xFBE0000000000000ULL, 0xFA50000000000000ULL,
+ 0xFE40000000000000ULL, 0xFFF0000000000000ULL, 0xFD20000000000000ULL, 0xFC90000000000000ULL,
+ 0xB400000000000000ULL, 0xB5B0000000000000ULL, 0xB760000000000000ULL, 0xB6D0000000000000ULL,
+ 0xB2C0000000000000ULL, 0xB370000000000000ULL, 0xB1A0000000000000ULL, 0xB010000000000000ULL,
+ 0xB980000000000000ULL, 0xB830000000000000ULL, 0xBAE0000000000000ULL, 0xBB50000000000000ULL,
+ 0xBF40000000000000ULL, 0xBEF0000000000000ULL, 0xBC20000000000000ULL, 0xBD90000000000000ULL,
+ 0xAF00000000000000ULL, 0xAEB0000000000000ULL, 0xAC60000000000000ULL, 0xADD0000000000000ULL,
+ 0xA9C0000000000000ULL, 0xA870000000000000ULL, 0xAAA0000000000000ULL, 0xAB10000000000000ULL,
+ 0xA280000000000000ULL, 0xA330000000000000ULL, 0xA1E0000000000000ULL, 0xA050000000000000ULL,
+ 0xA440000000000000ULL, 0xA5F0000000000000ULL, 0xA720000000000000ULL, 0xA690000000000000ULL,
+ 0x8200000000000000ULL, 0x83B0000000000000ULL, 0x8160000000000000ULL, 0x80D0000000000000ULL,
+ 0x84C0000000000000ULL, 0x8570000000000000ULL, 0x87A0000000000000ULL, 0x8610000000000000ULL,
+ 0x8F80000000000000ULL, 0x8E30000000000000ULL, 0x8CE0000000000000ULL, 0x8D50000000000000ULL,
+ 0x8940000000000000ULL, 0x88F0000000000000ULL, 0x8A20000000000000ULL, 0x8B90000000000000ULL,
+ 0x9900000000000000ULL, 0x98B0000000000000ULL, 0x9A60000000000000ULL, 0x9BD0000000000000ULL,
+ 0x9FC0000000000000ULL, 0x9E70000000000000ULL, 0x9CA0000000000000ULL, 0x9D10000000000000ULL,
+ 0x9480000000000000ULL, 0x9530000000000000ULL, 0x97E0000000000000ULL, 0x9650000000000000ULL,
+ 0x9240000000000000ULL, 0x93F0000000000000ULL, 0x9120000000000000ULL, 0x9090000000000000ULL
+};
+
+
+RTDECL(uint64_t) RTCrc64(const void *pv, size_t cb)
+{
+ const uint8_t *pu8 = (const uint8_t *)pv;
+ uint64_t uCRC64 = 0ULL;
+ while (cb--)
+ uCRC64 = g_au64CRC64[(uCRC64 ^ *pu8++) & 0xff] ^ (uCRC64 >> 8);
+ return uCRC64;
+}
+RT_EXPORT_SYMBOL(RTCrc64);
+
+
+RTDECL(uint64_t) RTCrc64Start(void)
+{
+ return 0ULL;
+}
+RT_EXPORT_SYMBOL(RTCrc64Start);
+
+
+RTDECL(uint64_t) RTCrc64Process(uint64_t uCRC64, const void *pv, size_t cb)
+{
+ const uint8_t *pu8 = (const uint8_t *)pv;
+ while (cb--)
+ uCRC64 = g_au64CRC64[(uCRC64 ^ *pu8++) & 0xff] ^ (uCRC64 >> 8);
+ return uCRC64;
+}
+RT_EXPORT_SYMBOL(RTCrc64Process);
+
+
+RTDECL(uint64_t) RTCrc64Finish(uint64_t uCRC64)
+{
+ return uCRC64;
+}
+RT_EXPORT_SYMBOL(RTCrc64Finish);
+
diff --git a/src/VBox/Runtime/common/checksum/ipv4.cpp b/src/VBox/Runtime/common/checksum/ipv4.cpp
new file mode 100644
index 00000000..2d75b989
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/ipv4.cpp
@@ -0,0 +1,774 @@
+/* $Id: ipv4.cpp $ */
+/** @file
+ * IPRT - IPv4 Checksum calculation and validation.
+ */
+
+/*
+ * Copyright (C) 2008-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/net.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+
+
+/**
+ * Calculates the checksum of the IPv4 header.
+ *
+ * @returns Checksum (network endian).
+ * @param pIpHdr Pointer to the IPv4 header to checksum, network endian (big).
+ * Assumes the caller already checked the minimum size requirement.
+ */
+RTDECL(uint16_t) RTNetIPv4HdrChecksum(PCRTNETIPV4 pIpHdr)
+{
+ uint16_t const *paw = (uint16_t const *)pIpHdr;
+ uint32_t u32Sum = paw[0] /* ip_hl */
+ + paw[1] /* ip_len */
+ + paw[2] /* ip_id */
+ + paw[3] /* ip_off */
+ + paw[4] /* ip_ttl */
+ /*+ paw[5] == 0 */ /* ip_sum */
+ + paw[6] /* ip_src */
+ + paw[7] /* ip_src:16 */
+ + paw[8] /* ip_dst */
+ + paw[9]; /* ip_dst:16 */
+ /* any options */
+ if (pIpHdr->ip_hl > 20 / 4)
+ {
+ /* this is a bit insane... (identical to the TCP header) */
+ switch (pIpHdr->ip_hl)
+ {
+ case 6: u32Sum += paw[10] + paw[11]; break;
+ case 7: u32Sum += paw[10] + paw[11] + paw[12] + paw[13]; break;
+ case 8: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15]; break;
+ case 9: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17]; break;
+ case 10: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19]; break;
+ case 11: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21]; break;
+ case 12: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23]; break;
+ case 13: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25]; break;
+ case 14: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25] + paw[26] + paw[27]; break;
+ case 15: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25] + paw[26] + paw[27] + paw[28] + paw[29]; break;
+ default:
+ AssertFailed();
+ }
+ }
+
+ /* 16-bit one complement fun */
+ u32Sum = (u32Sum >> 16) + (u32Sum & 0xffff); /* hi + low words */
+ u32Sum += u32Sum >> 16; /* carry */
+ return (uint16_t)~u32Sum;
+}
+RT_EXPORT_SYMBOL(RTNetIPv4HdrChecksum);
+
+
+/**
+ * Verifies the header version, header size, packet size, and header checksum
+ * of the specified IPv4 header.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header to validate. Network endian (big).
+ * @param cbHdrMax The max header size, or the max size of what pIpHdr points
+ * to if you like. Note that an IPv4 header can be up to 60 bytes.
+ * @param cbPktMax The max IP packet size, IP header and payload. This doesn't have
+ * to be mapped following pIpHdr.
+ * @param fChecksum Whether to validate the checksum (GSO).
+ */
+RTDECL(bool) RTNetIPv4IsHdrValid(PCRTNETIPV4 pIpHdr, size_t cbHdrMax, size_t cbPktMax, bool fChecksum)
+{
+ /*
+ * The header fields.
+ */
+ Assert(cbPktMax >= cbHdrMax);
+ if (RT_UNLIKELY(cbHdrMax < RTNETIPV4_MIN_LEN))
+ return false;
+ if (RT_UNLIKELY(pIpHdr->ip_hl * 4 < RTNETIPV4_MIN_LEN))
+ return false;
+ if (RT_UNLIKELY((size_t)pIpHdr->ip_hl * 4 > cbHdrMax))
+ {
+ Assert((size_t)pIpHdr->ip_hl * 4 > cbPktMax); /* You'll hit this if you mapped/copy too little of the header! */
+ return false;
+ }
+ if (RT_UNLIKELY(pIpHdr->ip_v != 4))
+ return false;
+ if (RT_UNLIKELY(RT_BE2H_U16(pIpHdr->ip_len) > cbPktMax))
+ return false;
+
+ /*
+ * The header checksum if requested.
+ */
+ if (fChecksum)
+ {
+ uint16_t u16Sum = RTNetIPv4HdrChecksum(pIpHdr);
+ if (RT_UNLIKELY(pIpHdr->ip_sum != u16Sum))
+ return false;
+ }
+ return true;
+}
+RT_EXPORT_SYMBOL(RTNetIPv4IsHdrValid);
+
+
+/**
+ * Calculates the checksum of a pseudo header given an IPv4 header [inlined].
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pIpHdr The IP header (network endian (big)).
+ */
+DECLINLINE(uint32_t) rtNetIPv4PseudoChecksum(PCRTNETIPV4 pIpHdr)
+{
+ uint16_t cbPayload = RT_BE2H_U16(pIpHdr->ip_len) - pIpHdr->ip_hl * 4;
+ uint32_t u32Sum = pIpHdr->ip_src.au16[0]
+ + pIpHdr->ip_src.au16[1]
+ + pIpHdr->ip_dst.au16[0]
+ + pIpHdr->ip_dst.au16[1]
+#ifdef RT_BIG_ENDIAN
+ + pIpHdr->ip_p
+#else
+ + ((uint32_t)pIpHdr->ip_p << 8)
+#endif
+ + RT_H2BE_U16(cbPayload);
+ return u32Sum;
+}
+
+
+/**
+ * Calculates the checksum of a pseudo header given an IPv4 header.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pIpHdr The IP header (network endian (big)).
+ */
+RTDECL(uint32_t) RTNetIPv4PseudoChecksum(PCRTNETIPV4 pIpHdr)
+{
+ return rtNetIPv4PseudoChecksum(pIpHdr);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4PseudoChecksum);
+
+
+/**
+ * Calculates the checksum of a pseudo header given the individual components.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param SrcAddr The source address in host endian.
+ * @param DstAddr The destination address in host endian.
+ * @param bProtocol The protocol number.
+ * @param cbPkt The packet size (host endian of course) (no IPv4 header).
+ */
+RTDECL(uint32_t) RTNetIPv4PseudoChecksumBits(RTNETADDRIPV4 SrcAddr, RTNETADDRIPV4 DstAddr, uint8_t bProtocol, uint16_t cbPkt)
+{
+ uint32_t u32Sum = RT_H2BE_U16(SrcAddr.au16[0])
+ + RT_H2BE_U16(SrcAddr.au16[1])
+ + RT_H2BE_U16(DstAddr.au16[0])
+ + RT_H2BE_U16(DstAddr.au16[1])
+#ifdef RT_BIG_ENDIAN
+ + bProtocol
+#else
+ + ((uint32_t)bProtocol << 8)
+#endif
+ + RT_H2BE_U16(cbPkt);
+ return u32Sum;
+}
+RT_EXPORT_SYMBOL(RTNetIPv4PseudoChecksumBits);
+
+
+/**
+ * Adds the checksum of the UDP header to the intermediate checksum value [inlined].
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pUdpHdr Pointer to the UDP header to checksum, network endian (big).
+ * @param u32Sum The 32-bit intermediate checksum value.
+ */
+DECLINLINE(uint32_t) rtNetIPv4AddUDPChecksum(PCRTNETUDP pUdpHdr, uint32_t u32Sum)
+{
+ u32Sum += pUdpHdr->uh_sport
+ + pUdpHdr->uh_dport
+ /*+ pUdpHdr->uh_sum = 0 */
+ + pUdpHdr->uh_ulen;
+ return u32Sum;
+}
+
+
+/**
+ * Adds the checksum of the UDP header to the intermediate checksum value.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pUdpHdr Pointer to the UDP header to checksum, network endian (big).
+ * @param u32Sum The 32-bit intermediate checksum value.
+ */
+RTDECL(uint32_t) RTNetIPv4AddUDPChecksum(PCRTNETUDP pUdpHdr, uint32_t u32Sum)
+{
+ return rtNetIPv4AddUDPChecksum(pUdpHdr, u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4AddUDPChecksum);
+
+
+/**
+ * Adds the checksum of the TCP header to the intermediate checksum value [inlined].
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pTcpHdr Pointer to the TCP header to checksum, network
+ * endian (big). Assumes the caller has already validate
+ * it and made sure the entire header is present.
+ * @param u32Sum The 32-bit intermediate checksum value.
+ */
+DECLINLINE(uint32_t) rtNetIPv4AddTCPChecksum(PCRTNETTCP pTcpHdr, uint32_t u32Sum)
+{
+ uint16_t const *paw = (uint16_t const *)pTcpHdr;
+ u32Sum += paw[0] /* th_sport */
+ + paw[1] /* th_dport */
+ + paw[2] /* th_seq */
+ + paw[3] /* th_seq:16 */
+ + paw[4] /* th_ack */
+ + paw[5] /* th_ack:16 */
+ + paw[6] /* th_off, th_x2, th_flags */
+ + paw[7] /* th_win */
+ /*+ paw[8] == 0 */ /* th_sum */
+ + paw[9]; /* th_urp */
+ if (pTcpHdr->th_off > RTNETTCP_MIN_LEN / 4)
+ {
+ /* this is a bit insane... (identical to the IPv4 header) */
+ switch (pTcpHdr->th_off)
+ {
+ case 6: u32Sum += paw[10] + paw[11]; break;
+ case 7: u32Sum += paw[10] + paw[11] + paw[12] + paw[13]; break;
+ case 8: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15]; break;
+ case 9: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17]; break;
+ case 10: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19]; break;
+ case 11: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21]; break;
+ case 12: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23]; break;
+ case 13: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25]; break;
+ case 14: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25] + paw[26] + paw[27]; break;
+ case 15: u32Sum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25] + paw[26] + paw[27] + paw[28] + paw[29]; break;
+ default:
+ AssertFailed();
+ }
+ }
+
+ return u32Sum;
+}
+
+
+/**
+ * Adds the checksum of the TCP header to the intermediate checksum value.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pTcpHdr Pointer to the TCP header to checksum, network
+ * endian (big). Assumes the caller has already validate
+ * it and made sure the entire header is present.
+ * @param u32Sum The 32-bit intermediate checksum value.
+ */
+RTDECL(uint32_t) RTNetIPv4AddTCPChecksum(PCRTNETTCP pTcpHdr, uint32_t u32Sum)
+{
+ return rtNetIPv4AddTCPChecksum(pTcpHdr, u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4AddTCPChecksum);
+
+
+/**
+ * Adds the checksum of the specified data segment to the intermediate checksum value [inlined].
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pvData Pointer to the data that should be checksummed.
+ * @param cbData The number of bytes to checksum.
+ * @param u32Sum The 32-bit intermediate checksum value.
+ * @param pfOdd This is used to keep track of odd bits, initialize to false
+ * when starting to checksum the data (aka text) after a TCP
+ * or UDP header (data never start at an odd offset).
+ */
+DECLINLINE(uint32_t) rtNetIPv4AddDataChecksum(void const *pvData, size_t cbData, uint32_t u32Sum, bool *pfOdd)
+{
+ if (*pfOdd)
+ {
+#ifdef RT_BIG_ENDIAN
+ /* there was an odd byte in the previous chunk, add the lower byte. */
+ u32Sum += *(uint8_t *)pvData;
+#else
+ /* there was an odd byte in the previous chunk, add the upper byte. */
+ u32Sum += (uint32_t)*(uint8_t *)pvData << 8;
+#endif
+ /* skip the byte. */
+ cbData--;
+ if (!cbData)
+ return u32Sum;
+ pvData = (uint8_t const *)pvData + 1;
+ }
+
+ /* iterate the data. */
+ uint16_t const *pw = (uint16_t const *)pvData;
+ while (cbData > 1)
+ {
+ u32Sum += *pw;
+ pw++;
+ cbData -= 2;
+ }
+
+ /* handle odd byte. */
+ if (cbData)
+ {
+#ifdef RT_BIG_ENDIAN
+ u32Sum += (uint32_t)*(uint8_t *)pw << 8;
+#else
+ u32Sum += *(uint8_t *)pw;
+#endif
+ *pfOdd = true;
+ }
+ else
+ *pfOdd = false;
+ return u32Sum;
+}
+
+/**
+ * Adds the checksum of the specified data segment to the intermediate checksum value.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pvData The data bits to checksum.
+ * @param cbData The number of bytes to checksum.
+ * @param u32Sum The 32-bit intermediate checksum value.
+ * @param pfOdd This is used to keep track of odd bits, initialize to false
+ * when starting to checksum the data (aka text) after a TCP
+ * or UDP header (data never start at an odd offset).
+ */
+RTDECL(uint32_t) RTNetIPv4AddDataChecksum(void const *pvData, size_t cbData, uint32_t u32Sum, bool *pfOdd)
+{
+ return rtNetIPv4AddDataChecksum(pvData, cbData, u32Sum, pfOdd);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4AddDataChecksum);
+
+
+/**
+ * Finalizes a IPv4 checksum [inlined].
+ *
+ * @returns The checksum (network endian).
+ * @param u32Sum The 32-bit intermediate checksum value.
+ */
+DECLINLINE(uint16_t) rtNetIPv4FinalizeChecksum(uint32_t u32Sum)
+{
+ /* 16-bit one complement fun */
+ u32Sum = (u32Sum >> 16) + (u32Sum & 0xffff); /* hi + low words */
+ u32Sum += u32Sum >> 16; /* carry */
+ return (uint16_t)~u32Sum;
+}
+
+
+/**
+ * Finalizes a IPv4 checksum.
+ *
+ * @returns The checksum (network endian).
+ * @param u32Sum The 32-bit intermediate checksum value.
+ */
+RTDECL(uint16_t) RTNetIPv4FinalizeChecksum(uint32_t u32Sum)
+{
+ return rtNetIPv4FinalizeChecksum(u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4FinalizeChecksum);
+
+
+/**
+ * Calculates the checksum for the UDP header given the UDP header w/ payload
+ * and the checksum of the pseudo header.
+ *
+ * @returns The checksum (network endian).
+ * @param u32Sum The checksum of the pseudo header. See
+ * RTNetIPv4PseudoChecksum and RTNetIPv6PseudoChecksum.
+ * @param pUdpHdr Pointer to the UDP header and the payload, in
+ * network endian (big). We use the uh_ulen field to
+ * figure out how much to checksum.
+ */
+RTDECL(uint16_t) RTNetUDPChecksum(uint32_t u32Sum, PCRTNETUDP pUdpHdr)
+{
+ bool fOdd;
+ u32Sum = rtNetIPv4AddUDPChecksum(pUdpHdr, u32Sum);
+ fOdd = false;
+ u32Sum = rtNetIPv4AddDataChecksum(pUdpHdr + 1, RT_BE2H_U16(pUdpHdr->uh_ulen) - sizeof(*pUdpHdr), u32Sum, &fOdd);
+ return rtNetIPv4FinalizeChecksum(u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetUDPChecksum);
+
+
+/**
+ * Calculates the checksum for the UDP header given the IP header,
+ * UDP header and payload.
+ *
+ * @returns The checksum (network endian).
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * @param pUdpHdr Pointer to the UDP header, in network endian (big).
+ * @param pvData Pointer to the UDP payload. The size is taken from the
+ * UDP header and the caller is supposed to have validated
+ * this before calling.
+ */
+RTDECL(uint16_t) RTNetIPv4UDPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData)
+{
+ bool fOdd;
+ uint32_t u32Sum = rtNetIPv4PseudoChecksum(pIpHdr);
+ u32Sum = rtNetIPv4AddUDPChecksum(pUdpHdr, u32Sum);
+ fOdd = false;
+ u32Sum = rtNetIPv4AddDataChecksum(pvData, RT_BE2H_U16(pUdpHdr->uh_ulen) - sizeof(*pUdpHdr), u32Sum, &fOdd);
+ return rtNetIPv4FinalizeChecksum(u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4UDPChecksum);
+
+
+/**
+ * Simple verification of an UDP packet size.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * This is assumed to be valid and the minimum size being mapped.
+ * @param pUdpHdr Pointer to the UDP header, in network endian (big).
+ * @param cbPktMax The max UDP packet size, UDP header and payload (data).
+ */
+DECLINLINE(bool) rtNetIPv4IsUDPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, size_t cbPktMax)
+{
+ /*
+ * Size validation.
+ */
+ size_t cb;
+ if (RT_UNLIKELY(cbPktMax < RTNETUDP_MIN_LEN))
+ return false;
+ cb = RT_BE2H_U16(pUdpHdr->uh_ulen);
+ if (RT_UNLIKELY(cb > cbPktMax))
+ return false;
+ if (RT_UNLIKELY(cb > (size_t)(RT_BE2H_U16(pIpHdr->ip_len) - pIpHdr->ip_hl * 4)))
+ return false;
+ return true;
+}
+
+
+/**
+ * Simple verification of an UDP packet size.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * This is assumed to be valid and the minimum size being mapped.
+ * @param pUdpHdr Pointer to the UDP header, in network endian (big).
+ * @param cbPktMax The max UDP packet size, UDP header and payload (data).
+ */
+RTDECL(bool) RTNetIPv4IsUDPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, size_t cbPktMax)
+{
+ return rtNetIPv4IsUDPSizeValid(pIpHdr, pUdpHdr, cbPktMax);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4IsUDPSizeValid);
+
+
+/**
+ * Simple verification of an UDP packet (size + checksum).
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * This is assumed to be valid and the minimum size being mapped.
+ * @param pUdpHdr Pointer to the UDP header, in network endian (big).
+ * @param pvData Pointer to the data, assuming it's one single segment
+ * and that cbPktMax - sizeof(RTNETUDP) is mapped here.
+ * @param cbPktMax The max UDP packet size, UDP header and payload (data).
+ * @param fChecksum Whether to validate the checksum (GSO).
+ */
+RTDECL(bool) RTNetIPv4IsUDPValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData, size_t cbPktMax, bool fChecksum)
+{
+ if (RT_UNLIKELY(!rtNetIPv4IsUDPSizeValid(pIpHdr, pUdpHdr, cbPktMax)))
+ return false;
+ if (fChecksum && pUdpHdr->uh_sum)
+ {
+ uint16_t u16Sum = RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pvData);
+ if (RT_UNLIKELY(pUdpHdr->uh_sum != u16Sum))
+ return false;
+ }
+ return true;
+}
+RT_EXPORT_SYMBOL(RTNetIPv4IsUDPValid);
+
+
+/**
+ * Calculates the checksum for the TCP header given the IP header,
+ * TCP header and payload.
+ *
+ * @returns The checksum (network endian).
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * @param pTcpHdr Pointer to the TCP header, in network endian (big).
+ * @param pvData Pointer to the TCP payload. The size is derived from
+ * the two headers and the caller is supposed to have
+ * validated this before calling. If NULL, we assume
+ * the data follows immediately after the TCP header.
+ */
+RTDECL(uint16_t) RTNetIPv4TCPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, void const *pvData)
+{
+ bool fOdd;
+ size_t cbData;
+ uint32_t u32Sum = rtNetIPv4PseudoChecksum(pIpHdr);
+ u32Sum = rtNetIPv4AddTCPChecksum(pTcpHdr, u32Sum);
+ fOdd = false;
+ cbData = RT_BE2H_U16(pIpHdr->ip_len) - pIpHdr->ip_hl * 4 - pTcpHdr->th_off * 4;
+ u32Sum = rtNetIPv4AddDataChecksum(pvData ? pvData : (uint8_t const *)pTcpHdr + pTcpHdr->th_off * 4,
+ cbData, u32Sum, &fOdd);
+ return rtNetIPv4FinalizeChecksum(u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4TCPChecksum);
+
+
+/**
+ * Calculates the checksum for the TCP header given the TCP header, payload and
+ * the checksum of the pseudo header.
+ *
+ * This is not specific to IPv4.
+ *
+ * @returns The checksum (network endian).
+ * @param u32Sum The checksum of the pseudo header. See
+ * RTNetIPv4PseudoChecksum and RTNetIPv6PseudoChecksum.
+ * @param pTcpHdr Pointer to the TCP header, in network endian (big).
+ * @param pvData Pointer to the TCP payload.
+ * @param cbData The size of the TCP payload.
+ */
+RTDECL(uint16_t) RTNetTCPChecksum(uint32_t u32Sum, PCRTNETTCP pTcpHdr, void const *pvData, size_t cbData)
+{
+ bool fOdd;
+ u32Sum = rtNetIPv4AddTCPChecksum(pTcpHdr, u32Sum);
+ fOdd = false;
+ u32Sum = rtNetIPv4AddDataChecksum(pvData, cbData, u32Sum, &fOdd);
+ return rtNetIPv4FinalizeChecksum(u32Sum);
+}
+RT_EXPORT_SYMBOL(RTNetTCPChecksum);
+
+
+/**
+ * Verification of a TCP header.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * This is assumed to be valid and the minimum size being mapped.
+ * @param pTcpHdr Pointer to the TCP header, in network endian (big).
+ * @param cbHdrMax The max TCP header size (what pTcpHdr points to).
+ * @param cbPktMax The max TCP packet size, TCP header and payload (data).
+ */
+DECLINLINE(bool) rtNetIPv4IsTCPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, size_t cbPktMax)
+{
+ size_t cbTcpHdr;
+ size_t cbTcp;
+
+ Assert(cbPktMax >= cbHdrMax);
+
+ /*
+ * Size validations.
+ */
+ if (RT_UNLIKELY(cbPktMax < RTNETTCP_MIN_LEN))
+ return false;
+ cbTcpHdr = pTcpHdr->th_off * 4;
+ if (RT_UNLIKELY(cbTcpHdr > cbHdrMax))
+ return false;
+ cbTcp = RT_BE2H_U16(pIpHdr->ip_len) - pIpHdr->ip_hl * 4;
+ if (RT_UNLIKELY(cbTcp > cbPktMax))
+ return false;
+ return true;
+}
+
+
+/**
+ * Simple verification of an TCP packet size.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * This is assumed to be valid and the minimum size being mapped.
+ * @param pTcpHdr Pointer to the TCP header, in network endian (big).
+ * @param cbHdrMax The max TCP header size (what pTcpHdr points to).
+ * @param cbPktMax The max TCP packet size, TCP header and payload (data).
+ */
+RTDECL(bool) RTNetIPv4IsTCPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, size_t cbPktMax)
+{
+ return rtNetIPv4IsTCPSizeValid(pIpHdr, pTcpHdr, cbHdrMax, cbPktMax);
+}
+RT_EXPORT_SYMBOL(RTNetIPv4IsTCPSizeValid);
+
+
+/**
+ * Simple verification of an TCP packet (size + checksum).
+ *
+ * @returns true if valid, false if invalid.
+ * @param pIpHdr Pointer to the IPv4 header, in network endian (big).
+ * This is assumed to be valid and the minimum size being mapped.
+ * @param pTcpHdr Pointer to the TCP header, in network endian (big).
+ * @param cbHdrMax The max TCP header size (what pTcpHdr points to).
+ * @param pvData Pointer to the data, assuming it's one single segment
+ * and that cbPktMax - sizeof(RTNETTCP) is mapped here.
+ * If NULL then we assume the data follows immediately after
+ * the TCP header.
+ * @param cbPktMax The max TCP packet size, TCP header and payload (data).
+ * @param fChecksum Whether to validate the checksum (GSO).
+ */
+RTDECL(bool) RTNetIPv4IsTCPValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, void const *pvData, size_t cbPktMax,
+ bool fChecksum)
+{
+ if (RT_UNLIKELY(!rtNetIPv4IsTCPSizeValid(pIpHdr, pTcpHdr, cbHdrMax, cbPktMax)))
+ return false;
+ if (fChecksum)
+ {
+ uint16_t u16Sum = RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, pvData);
+ if (RT_UNLIKELY(pTcpHdr->th_sum != u16Sum))
+ return false;
+ }
+ return true;
+}
+RT_EXPORT_SYMBOL(RTNetIPv4IsTCPValid);
+
+
+/**
+ * Minimal validation of a DHCP packet.
+ *
+ * This will fail on BOOTP packets (if sufficient data is supplied).
+ * It will not verify the source and destination ports, that's the
+ * caller's responsibility.
+ *
+ * This function will ASSUME that the hardware type is ethernet
+ * and use that for htype/hlen validation.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pUdpHdr Pointer to the UDP header, in network endian (big).
+ * This is assumed to be valid and fully mapped.
+ * @param pDhcp Pointer to the DHCP packet.
+ * This might not be the entire thing, see cbDhcp.
+ * @param cbDhcp The number of valid bytes that pDhcp points to.
+ * @param pMsgType Where to store the message type (if found).
+ * This will be set to 0 if not found and on failure.
+ */
+RTDECL(bool) RTNetIPv4IsDHCPValid(PCRTNETUDP pUdpHdr, PCRTNETBOOTP pDhcp, size_t cbDhcp, uint8_t *pMsgType)
+{
+ ssize_t cbLeft;
+ uint8_t MsgType;
+ PCRTNETDHCPOPT pOpt;
+ NOREF(pUdpHdr); /** @todo rainy-day: Why isn't the UDP header used? */
+
+ AssertPtrNull(pMsgType);
+ if (pMsgType)
+ *pMsgType = 0;
+
+ /*
+ * Validate all the header fields we're able to...
+ */
+ if (cbDhcp < RT_UOFFSETOF(RTNETBOOTP, bp_op) + sizeof(pDhcp->bp_op))
+ return true;
+ if (RT_UNLIKELY( pDhcp->bp_op != RTNETBOOTP_OP_REQUEST
+ && pDhcp->bp_op != RTNETBOOTP_OP_REPLY))
+ return false;
+
+ if (cbDhcp < RT_UOFFSETOF(RTNETBOOTP, bp_htype) + sizeof(pDhcp->bp_htype))
+ return true;
+ if (RT_UNLIKELY(pDhcp->bp_htype != RTNET_ARP_ETHER))
+ return false;
+
+ if (cbDhcp < RT_UOFFSETOF(RTNETBOOTP, bp_hlen) + sizeof(pDhcp->bp_hlen))
+ return true;
+ if (RT_UNLIKELY(pDhcp->bp_hlen != sizeof(RTMAC)))
+ return false;
+
+ if (cbDhcp < RT_UOFFSETOF(RTNETBOOTP, bp_flags) + sizeof(pDhcp->bp_flags))
+ return true;
+ if (RT_UNLIKELY(RT_BE2H_U16(pDhcp->bp_flags) & ~(RTNET_DHCP_FLAGS_NO_BROADCAST)))
+ return false;
+
+ /*
+ * Check the DHCP cookie and make sure it isn't followed by an END option
+ * (because that seems to be indicating that it's BOOTP and not DHCP).
+ */
+ cbLeft = (ssize_t)cbDhcp - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_cookie) + sizeof(pDhcp->bp_vend.Dhcp.dhcp_cookie);
+ if (cbLeft < 0)
+ return true;
+ if (RT_UNLIKELY(RT_BE2H_U32(pDhcp->bp_vend.Dhcp.dhcp_cookie) != RTNET_DHCP_COOKIE))
+ return false;
+ if (cbLeft < 1)
+ return true;
+ pOpt = (PCRTNETDHCPOPT)&pDhcp->bp_vend.Dhcp.dhcp_opts[0];
+ if (pOpt->dhcp_opt == RTNET_DHCP_OPT_END)
+ return false;
+
+ /*
+ * Scan the options until we find the message type or run out of message.
+ *
+ * We're not strict about termination (END) for many reasons, however,
+ * we don't accept END without MSG_TYPE.
+ */
+ MsgType = 0;
+ while (cbLeft > 0)
+ {
+ if (pOpt->dhcp_opt == RTNET_DHCP_OPT_END)
+ {
+ /* Fail if no MSG_TYPE. */
+ if (!MsgType)
+ return false;
+ break;
+ }
+ if (pOpt->dhcp_opt == RTNET_DHCP_OPT_PAD)
+ {
+ pOpt = (PCRTNETDHCPOPT)((uint8_t const *)pOpt + 1);
+ cbLeft--;
+ }
+ else
+ {
+ switch (pOpt->dhcp_opt)
+ {
+ case RTNET_DHCP_OPT_MSG_TYPE:
+ {
+ if (cbLeft < 3)
+ return true;
+ MsgType = *(const uint8_t *)(pOpt + 1);
+ switch (MsgType)
+ {
+ case RTNET_DHCP_MT_DISCOVER:
+ case RTNET_DHCP_MT_OFFER:
+ case RTNET_DHCP_MT_REQUEST:
+ case RTNET_DHCP_MT_DECLINE:
+ case RTNET_DHCP_MT_ACK:
+ case RTNET_DHCP_MT_NAC:
+ case RTNET_DHCP_MT_RELEASE:
+ case RTNET_DHCP_MT_INFORM:
+ break;
+
+ default:
+ /* we don't know this message type, fail. */
+ return false;
+ }
+
+ /* Found a known message type, consider the job done. */
+ if (pMsgType)
+ *pMsgType = MsgType;
+ return true;
+ }
+ }
+
+ /* Skip the option. */
+ cbLeft -= pOpt->dhcp_len + sizeof(*pOpt);
+ pOpt = (PCRTNETDHCPOPT)((uint8_t const *)pOpt + pOpt->dhcp_len + sizeof(*pOpt));
+ }
+ }
+
+ return true;
+}
+RT_EXPORT_SYMBOL(RTNetIPv4IsDHCPValid);
+
diff --git a/src/VBox/Runtime/common/checksum/ipv6.cpp b/src/VBox/Runtime/common/checksum/ipv6.cpp
new file mode 100644
index 00000000..6c248b07
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/ipv6.cpp
@@ -0,0 +1,136 @@
+/* $Id: ipv6.cpp $ */
+/** @file
+ * IPRT - IPv6 Checksum calculation and validation.
+ */
+
+/*
+ * Copyright (C) 2008-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/net.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+
+
+/**
+ * @copydoc RTNetIPv6PseudoChecksumBits
+ */
+DECLINLINE(uint32_t) rtNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTNETADDRIPV6 pDstAddr,
+ uint8_t bProtocol, uint32_t cbPkt)
+{
+ uint32_t u32Sum = pSrcAddr->au16[0]
+ + pSrcAddr->au16[1]
+ + pSrcAddr->au16[2]
+ + pSrcAddr->au16[3]
+ + pSrcAddr->au16[4]
+ + pSrcAddr->au16[5]
+ + pSrcAddr->au16[6]
+ + pSrcAddr->au16[7]
+ + pDstAddr->au16[0]
+ + pDstAddr->au16[1]
+ + pDstAddr->au16[2]
+ + pDstAddr->au16[3]
+ + pDstAddr->au16[4]
+ + pDstAddr->au16[5]
+ + pDstAddr->au16[6]
+ + pDstAddr->au16[7]
+ + RT_H2BE_U16(RT_HIWORD(cbPkt))
+ + RT_H2BE_U16(RT_LOWORD(cbPkt))
+ + 0
+ + RT_H2BE_U16(RT_MAKE_U16(bProtocol, 0));
+ return u32Sum;
+}
+
+
+/**
+ * Calculates the checksum of a pseudo header given an IPv6 header, ASSUMING
+ * that there are no headers between the IPv6 header and the upper layer header.
+ *
+ * Use this method with create care! In most cases you should be using
+ * RTNetIPv6PseudoChecksumEx.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pIpHdr The IPv6 header (network endian (big)).
+ */
+RTDECL(uint32_t) RTNetIPv6PseudoChecksum(PCRTNETIPV6 pIpHdr)
+{
+ return rtNetIPv6PseudoChecksumBits(&pIpHdr->ip6_src, &pIpHdr->ip6_dst,
+ pIpHdr->ip6_nxt, RT_N2H_U16(pIpHdr->ip6_plen));
+}
+RT_EXPORT_SYMBOL(RTNetIPv6PseudoChecksum);
+
+
+/**
+ * Calculates the checksum of a pseudo header given an IPv6 header.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pIpHdr The IPv6 header (network endian (big)).
+ * @param bProtocol The protocol number. This can be the same as the
+ * ip6_nxt field, but doesn't need to be.
+ * @param cbPkt The packet size (host endian of course). This can
+ * be the same as the ip6_plen field, but as with @a
+ * bProtocol it won't be when extension headers are
+ * present. For UDP this will be uh_ulen converted to
+ * host endian.
+ */
+RTDECL(uint32_t) RTNetIPv6PseudoChecksumEx(PCRTNETIPV6 pIpHdr, uint8_t bProtocol, uint16_t cbPkt)
+{
+ return rtNetIPv6PseudoChecksumBits(&pIpHdr->ip6_src, &pIpHdr->ip6_dst, bProtocol, cbPkt);
+}
+RT_EXPORT_SYMBOL(RTNetIPv6PseudoChecksumEx);
+
+
+/**
+ * Calculates the checksum of a pseudo header given the individual components.
+ *
+ * @returns 32-bit intermediary checksum value.
+ * @param pSrcAddr Pointer to the source address in network endian.
+ * @param pDstAddr Pointer to the destination address in network endian.
+ * @param bProtocol The protocol number. This can be the same as the
+ * ip6_nxt field, but doesn't need to be.
+ * @param cbPkt The packet size (host endian of course). This can
+ * be the same as the ip6_plen field, but as with @a
+ * bProtocol it won't be when extension headers are
+ * present. For UDP this will be uh_ulen converted to
+ * host endian.
+ */
+RTDECL(uint32_t) RTNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTNETADDRIPV6 pDstAddr,
+ uint8_t bProtocol, uint16_t cbPkt)
+{
+ return rtNetIPv6PseudoChecksumBits(pSrcAddr, pDstAddr, bProtocol, cbPkt);
+}
+RT_EXPORT_SYMBOL(RTNetIPv6PseudoChecksumBits);
+
diff --git a/src/VBox/Runtime/common/checksum/manifest-file.cpp b/src/VBox/Runtime/common/checksum/manifest-file.cpp
new file mode 100644
index 00000000..2f6c269a
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/manifest-file.cpp
@@ -0,0 +1,94 @@
+/* $Id: manifest-file.cpp $ */
+/** @file
+ * IPRT - Manifest, the bits with file dependencies
+ */
+
+/*
+ * Copyright (C) 2010-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/manifest.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/vfs.h>
+
+#include "internal/magics.h"
+
+
+
+RTDECL(int) RTManifestReadStandardFromFile(RTMANIFEST hManifest, const char *pszFilename)
+{
+ RTFILE hFile;
+ uint32_t fFlags = RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN;
+ int rc = RTFileOpen(&hFile, pszFilename, fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIos;
+ rc = RTVfsIoStrmFromRTFile(hFile, fFlags, true /*fLeaveOpen*/, &hVfsIos);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTManifestReadStandard(hManifest, hVfsIos);
+ RTVfsIoStrmRelease(hVfsIos);
+ }
+ RTFileClose(hFile);
+ }
+ return rc;
+}
+
+
+RTDECL(int) RTManifestWriteStandardToFile(RTMANIFEST hManifest, const char *pszFilename)
+{
+ RTFILE hFile;
+ uint32_t fFlags = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE;
+ int rc = RTFileOpen(&hFile, pszFilename, fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ RTVFSIOSTREAM hVfsIos;
+ rc = RTVfsIoStrmFromRTFile(hFile, fFlags, true /*fLeaveOpen*/, &hVfsIos);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTManifestWriteStandard(hManifest, hVfsIos);
+ RTVfsIoStrmRelease(hVfsIos);
+ }
+ RTFileClose(hFile);
+ }
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/manifest.cpp b/src/VBox/Runtime/common/checksum/manifest.cpp
new file mode 100644
index 00000000..74bcc05d
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/manifest.cpp
@@ -0,0 +1,593 @@
+/* $Id: manifest.cpp $ */
+/** @file
+ * IPRT - Manifest file handling, old style - deprecated.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/manifest.h>
+
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/sha.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Internal per file structure used by RTManifestVerify
+ */
+typedef struct RTMANIFESTFILEENTRY
+{
+ char *pszManifestFile;
+ char *pszManifestDigest;
+ PRTMANIFESTTEST pTestPattern;
+} RTMANIFESTFILEENTRY;
+typedef RTMANIFESTFILEENTRY* PRTMANIFESTFILEENTRY;
+
+/**
+ * Internal structure used for the progress callback
+ */
+typedef struct RTMANIFESTCALLBACKDATA
+{
+ PFNRTPROGRESS pfnProgressCallback;
+ void *pvUser;
+ size_t cMaxFiles;
+ size_t cCurrentFile;
+} RTMANIFESTCALLBACKDATA;
+typedef RTMANIFESTCALLBACKDATA* PRTMANIFESTCALLBACKDATA;
+
+
+/*******************************************************************************
+* Private functions
+*******************************************************************************/
+
+DECLINLINE(char *) rtManifestPosOfCharInBuf(char const *pv, size_t cb, char c)
+{
+ char *pb = (char *)pv;
+ for (; cb; --cb, ++pb)
+ if (RT_UNLIKELY(*pb == c))
+ return pb;
+ return NULL;
+}
+
+DECLINLINE(size_t) rtManifestIndexOfCharInBuf(char const *pv, size_t cb, char c)
+{
+ char const *pb = (char const *)pv;
+ for (size_t i=0; i < cb; ++i, ++pb)
+ if (RT_UNLIKELY(*pb == c))
+ return i;
+ return cb;
+}
+
+static DECLCALLBACK(int) rtSHAProgressCallback(unsigned uPercent, void *pvUser)
+{
+ PRTMANIFESTCALLBACKDATA pData = (PRTMANIFESTCALLBACKDATA)pvUser;
+ return pData->pfnProgressCallback((unsigned)( (uPercent + (float)pData->cCurrentFile * 100.0)
+ / (float)pData->cMaxFiles),
+ pData->pvUser);
+}
+
+
+/*******************************************************************************
+* Public functions
+*******************************************************************************/
+
+RTR3DECL(int) RTManifestVerify(const char *pszManifestFile, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
+{
+ /* Validate input */
+ AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
+
+ /* Open the manifest file */
+ RTFILE file;
+ int rc = RTFileOpen(&file, pszManifestFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ void *pvBuf = 0;
+ do
+ {
+ uint64_t cbSize;
+ rc = RTFileQuerySize(file, &cbSize);
+ if (RT_FAILURE(rc))
+ break;
+
+ /* Cast down for the case size_t < uint64_t. This isn't really correct,
+ but we consider manifest files bigger than size_t as not supported
+ by now. */
+ size_t cbToRead = (size_t)cbSize;
+ pvBuf = RTMemAlloc(cbToRead);
+ if (!pvBuf)
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+
+ size_t cbRead = 0;
+ rc = RTFileRead(file, pvBuf, cbToRead, &cbRead);
+ if (RT_FAILURE(rc))
+ break;
+
+ rc = RTManifestVerifyFilesBuf(pvBuf, cbRead, paTests, cTests, piFailed);
+ }while (0);
+
+ /* Cleanup */
+ if (pvBuf)
+ RTMemFree(pvBuf);
+
+ RTFileClose(file);
+
+ return rc;
+}
+
+RTR3DECL(int) RTManifestVerifyFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles, size_t *piFailed,
+ PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
+ AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ /* Create our compare list */
+ PRTMANIFESTTEST paFiles = (PRTMANIFESTTEST)RTMemTmpAllocZ(sizeof(RTMANIFESTTEST) * cFiles);
+ if (!paFiles)
+ return VERR_NO_MEMORY;
+
+ RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
+ /* Fill our compare list */
+ for (size_t i = 0; i < cFiles; ++i)
+ {
+ char *pszDigest;
+ if (pfnProgressCallback)
+ {
+ callback.cCurrentFile = i;
+ rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, rtSHAProgressCallback, &callback);
+ }
+ else
+ rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, NULL, NULL);
+ if (RT_FAILURE(rc))
+ break;
+ paFiles[i].pszTestFile = (char*)papszFiles[i];
+ paFiles[i].pszTestDigest = pszDigest;
+ }
+
+ /* Do the verification */
+ if (RT_SUCCESS(rc))
+ rc = RTManifestVerify(pszManifestFile, paFiles, cFiles, piFailed);
+
+ /* Cleanup */
+ for (size_t i = 0; i < cFiles; ++i)
+ {
+ if (paFiles[i].pszTestDigest)
+ RTStrFree((char*)paFiles[i].pszTestDigest);
+ }
+ RTMemTmpFree(paFiles);
+
+ return rc;
+}
+
+RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, RTDIGESTTYPE enmDigestType,
+ const char * const *papszFiles, size_t cFiles,
+ PFNRTPROGRESS pfnProgressCallback, void *pvUser)
+{
+ /* Validate input */
+ AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
+ AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
+
+ RTFILE file;
+ int rc = RTFileOpen(&file, pszManifestFile, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ PRTMANIFESTTEST paFiles = 0;
+ void *pvBuf = 0;
+ do
+ {
+ paFiles = (PRTMANIFESTTEST)RTMemAllocZ(sizeof(RTMANIFESTTEST) * cFiles);
+ if (!paFiles)
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+
+ RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
+ for (size_t i = 0; i < cFiles; ++i)
+ {
+ paFiles[i].pszTestFile = papszFiles[i];
+ /* Calculate the SHA1 digest of every file */
+ if (pfnProgressCallback)
+ {
+ callback.cCurrentFile = i;
+ rc = RTSha1DigestFromFile(paFiles[i].pszTestFile, (char**)&paFiles[i].pszTestDigest, rtSHAProgressCallback, &callback);
+ }
+ else
+ rc = RTSha1DigestFromFile(paFiles[i].pszTestFile, (char**)&paFiles[i].pszTestDigest, NULL, NULL);
+ if (RT_FAILURE(rc))
+ break;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ size_t cbSize = 0;
+ rc = RTManifestWriteFilesBuf(&pvBuf, &cbSize, enmDigestType, paFiles, cFiles);
+ if (RT_FAILURE(rc))
+ break;
+
+ rc = RTFileWrite(file, pvBuf, cbSize, 0);
+ }
+ }while (0);
+
+ RTFileClose(file);
+
+ /* Cleanup */
+ if (pvBuf)
+ RTMemFree(pvBuf);
+ if (paFiles)
+ {
+ for (size_t i = 0; i < cFiles; ++i)
+ if (paFiles[i].pszTestDigest)
+ RTStrFree((char*)paFiles[i].pszTestDigest);
+ RTMemFree(paFiles);
+ }
+
+ /* Delete the manifest file on failure */
+ if (RT_FAILURE(rc))
+ RTFileDelete(pszManifestFile);
+
+ return rc;
+}
+
+
+RTR3DECL(int) RTManifestVerifyDigestType(void const *pvBuf, size_t cbSize, RTDIGESTTYPE *penmDigestType)
+{
+ /* Validate input */
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(penmDigestType, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ char const *pcBuf = (char *)pvBuf;
+ size_t cbRead = 0;
+ /* Parse the manifest file line by line */
+ for (;;)
+ {
+ if (cbRead >= cbSize)
+ return VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
+
+ size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;
+
+ /* Skip empty lines (UNIX/DOS format) */
+ if ( ( cch == 1
+ && pcBuf[0] == '\n')
+ || ( cch == 2
+ && pcBuf[0] == '\r'
+ && pcBuf[1] == '\n'))
+ {
+ pcBuf += cch;
+ cbRead += cch;
+ continue;
+ }
+
+/** @todo r=bird: Missing space check here. */
+ /* Check for the digest algorithm */
+ if ( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '1')
+ {
+ *penmDigestType = RTDIGESTTYPE_SHA1;
+ break;
+ }
+ if ( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '2'
+ && pcBuf[4] == '5'
+ && pcBuf[5] == '6')
+ {
+ *penmDigestType = RTDIGESTTYPE_SHA256;
+ break;
+ }
+
+ pcBuf += cch;
+ cbRead += cch;
+ }
+
+ return rc;
+}
+
+
+RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
+{
+ /* Validate input */
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(paTests, VERR_INVALID_POINTER);
+ AssertReturn(cTests > 0, VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(piFailed, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests);
+ if (!paFiles)
+ return VERR_NO_MEMORY;
+
+ /* Fill our compare list */
+ for (size_t i = 0; i < cTests; ++i)
+ paFiles[i].pTestPattern = &paTests[i];
+
+ char *pcBuf = (char*)pvBuf;
+ size_t cbRead = 0;
+ /* Parse the manifest file line by line */
+ for (;;)
+ {
+ if (cbRead >= cbSize)
+ break;
+
+ size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;
+
+ /* Skip empty lines (UNIX/DOS format) */
+ if ( ( cch == 1
+ && pcBuf[0] == '\n')
+ || ( cch == 2
+ && pcBuf[0] == '\r'
+ && pcBuf[1] == '\n'))
+ {
+ pcBuf += cch;
+ cbRead += cch;
+ continue;
+ }
+
+ /** @todo r=bird:
+ * -# Better deal with this EOF line platform dependency
+ * -# The SHA1 and SHA256 tests should probably include a blank space check.
+ * -# If there is a specific order to the elements in the string, it would be
+ * good if the delimiter searching checked for it.
+ * -# Deal with filenames containing delimiter characters.
+ */
+
+ /* Check for the digest algorithm */
+ if ( cch < 4
+ || ( !( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '1')
+ &&
+ !( pcBuf[0] == 'S'
+ && pcBuf[1] == 'H'
+ && pcBuf[2] == 'A'
+ && pcBuf[3] == '2'
+ && pcBuf[4] == '5'
+ && pcBuf[5] == '6')
+ )
+ )
+ {
+ /* Digest unsupported */
+ rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
+ break;
+ }
+
+ /* Try to find the filename */
+ char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '(');
+ if (!pszNameStart)
+ {
+ rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
+ break;
+ }
+ char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')');
+ if (!pszNameEnd)
+ {
+ rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
+ break;
+ }
+
+ /* Copy the filename part */
+ size_t cchName = pszNameEnd - pszNameStart - 1;
+ char *pszName = (char *)RTMemTmpAlloc(cchName + 1);
+ if (!pszName)
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ memcpy(pszName, pszNameStart + 1, cchName);
+ pszName[cchName] = '\0';
+
+ /* Try to find the digest sum */
+ char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1;
+ if (!pszDigestStart)
+ {
+ RTMemTmpFree(pszName);
+ rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
+ break;
+ }
+ char *pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\r');
+ if (!pszDigestEnd)
+ pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n');
+ if (!pszDigestEnd)
+ {
+ RTMemTmpFree(pszName);
+ rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
+ break;
+ }
+ /* Copy the digest part */
+ size_t cchDigest = pszDigestEnd - pszDigestStart - 1;
+ char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1);
+ if (!pszDigest)
+ {
+ RTMemTmpFree(pszName);
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ memcpy(pszDigest, pszDigestStart + 1, cchDigest);
+ pszDigest[cchDigest] = '\0';
+
+ /* Check our file list against the extracted data */
+ bool fFound = false;
+ for (size_t i = 0; i < cTests; ++i)
+ {
+ /** @todo r=bird: Using RTStrStr here looks bogus. */
+ if (RTStrStr(paFiles[i].pTestPattern->pszTestFile, RTStrStrip(pszName)) != NULL)
+ {
+ /* Add the data of the manifest file to the file list */
+ paFiles[i].pszManifestFile = RTStrDup(RTStrStrip(pszName));
+ paFiles[i].pszManifestDigest = RTStrDup(RTStrStrip(pszDigest));
+ fFound = true;
+ break;
+ }
+ }
+ RTMemTmpFree(pszName);
+ RTMemTmpFree(pszDigest);
+ if (!fFound)
+ {
+ /* There have to be an entry in the file list */
+ rc = VERR_MANIFEST_FILE_MISMATCH;
+ break;
+ }
+
+ pcBuf += cch;
+ cbRead += cch;
+ }
+
+ if ( rc == VINF_SUCCESS
+ || rc == VERR_EOF)
+ {
+ rc = VINF_SUCCESS;
+ for (size_t i = 0; i < cTests; ++i)
+ {
+ /* If there is an entry in the file list, which hasn't an
+ * equivalent in the manifest file, its an error. */
+ if ( !paFiles[i].pszManifestFile
+ || !paFiles[i].pszManifestDigest)
+ {
+ rc = VERR_MANIFEST_FILE_MISMATCH;
+ break;
+ }
+
+ /* Do the manifest SHA digest match against the actual digest? */
+ if (RTStrICmp(paFiles[i].pszManifestDigest, paFiles[i].pTestPattern->pszTestDigest))
+ {
+ if (piFailed)
+ *piFailed = i;
+ rc = VERR_MANIFEST_DIGEST_MISMATCH;
+ break;
+ }
+ }
+ }
+
+ /* Cleanup */
+ for (size_t i = 0; i < cTests; ++i)
+ {
+ if (paFiles[i].pszManifestFile)
+ RTStrFree(paFiles[i].pszManifestFile);
+ if (paFiles[i].pszManifestDigest)
+ RTStrFree(paFiles[i].pszManifestDigest);
+ }
+ RTMemTmpFree(paFiles);
+
+ return rc;
+}
+
+RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, RTDIGESTTYPE enmDigestType, PRTMANIFESTTEST paFiles, size_t cFiles)
+{
+ /* Validate input */
+ AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
+ AssertPtrReturn(paFiles, VERR_INVALID_POINTER);
+ AssertReturn(cFiles > 0, VERR_INVALID_PARAMETER);
+
+ const char *pcszDigestType;
+ switch (enmDigestType)
+ {
+ case RTDIGESTTYPE_CRC32: pcszDigestType = "CRC32"; break;
+ case RTDIGESTTYPE_CRC64: pcszDigestType = "CRC64"; break;
+ case RTDIGESTTYPE_MD5: pcszDigestType = "MD5"; break;
+ case RTDIGESTTYPE_SHA1: pcszDigestType = "SHA1"; break;
+ case RTDIGESTTYPE_SHA256: pcszDigestType = "SHA256"; break;
+ default: return VERR_INVALID_PARAMETER;
+ }
+
+ /* Calculate the size necessary for the memory buffer. */
+ size_t cbSize = 0;
+ size_t cbMaxSize = 0;
+ for (size_t i = 0; i < cFiles; ++i)
+ {
+ size_t cbTmp = strlen(RTPathFilename(paFiles[i].pszTestFile))
+ + strlen(paFiles[i].pszTestDigest)
+ + strlen(pcszDigestType)
+ + 6;
+ cbMaxSize = RT_MAX(cbMaxSize, cbTmp);
+ cbSize += cbTmp;
+ }
+
+ /* Create the memory buffer */
+ void *pvBuf = RTMemAlloc(cbSize);
+ if (!pvBuf)
+ return VERR_NO_MEMORY;
+
+ /* Allocate a temporary string buffer. */
+ char *pszTmp = RTStrAlloc(cbMaxSize + 1);
+ if (!pszTmp)
+ {
+ RTMemFree(pvBuf);
+ return VERR_NO_MEMORY;
+ }
+ size_t cbPos = 0;
+
+ for (size_t i = 0; i < cFiles; ++i)
+ {
+ size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "%s (%s)= %s\n", pcszDigestType, RTPathFilename(paFiles[i].pszTestFile), paFiles[i].pszTestDigest);
+ memcpy(&((char*)pvBuf)[cbPos], pszTmp, cch);
+ cbPos += cch;
+ }
+ RTStrFree(pszTmp);
+
+ /* Results */
+ *ppvBuf = pvBuf;
+ *pcbSize = cbSize;
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/manifest2.cpp b/src/VBox/Runtime/common/checksum/manifest2.cpp
new file mode 100644
index 00000000..0e961977
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/manifest2.cpp
@@ -0,0 +1,1477 @@
+/* $Id: manifest2.cpp $ */
+/** @file
+ * IPRT - Manifest, the core.
+ */
+
+/*
+ * Copyright (C) 2010-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/manifest.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/param.h>
+#include <iprt/md5.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
+#include <iprt/vfs.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Manifest attribute.
+ *
+ * Used both for entries and manifest attributes.
+ */
+typedef struct RTMANIFESTATTR
+{
+ /** The string space core (szName). */
+ RTSTRSPACECORE StrCore;
+ /** The property value. */
+ char *pszValue;
+ /** The attribute type if applicable, RTMANIFEST_ATTR_UNKNOWN if not. */
+ uint32_t fType;
+ /** Whether it was visited by the equals operation or not. */
+ bool fVisited;
+ /** The normalized property name that StrCore::pszString points at. */
+ RT_FLEXIBLE_ARRAY_EXTENSION
+ char szName[RT_FLEXIBLE_ARRAY];
+} RTMANIFESTATTR;
+/** Pointer to a manifest attribute. */
+typedef RTMANIFESTATTR *PRTMANIFESTATTR;
+
+
+/**
+ * Manifest entry.
+ */
+typedef struct RTMANIFESTENTRY
+{
+ /** The string space core (szName). */
+ RTSTRSPACECORE StrCore;
+ /** The entry attributes (hashes, checksums, size, etc) -
+ * RTMANIFESTATTR. */
+ RTSTRSPACE Attributes;
+ /** The number of attributes. */
+ uint32_t cAttributes;
+ /** Whether it was visited by the equals operation or not. */
+ bool fVisited;
+ /** The normalized entry name that StrCore::pszString points at. */
+ char szName[RT_FLEXIBLE_ARRAY_NESTED];
+} RTMANIFESTENTRY;
+/** Pointer to a manifest entry. */
+typedef RTMANIFESTENTRY *PRTMANIFESTENTRY;
+
+
+/**
+ * Manifest handle data.
+ */
+typedef struct RTMANIFESTINT
+{
+ /** Magic value (RTMANIFEST_MAGIC). */
+ uint32_t u32Magic;
+ /** The number of references to this manifest. */
+ uint32_t volatile cRefs;
+ /** String space of the entries covered by this manifest -
+ * RTMANIFESTENTRY. */
+ RTSTRSPACE Entries;
+ /** The number of entries. */
+ uint32_t cEntries;
+ /** The entry for the manifest itself. */
+ RTMANIFESTENTRY SelfEntry;
+} RTMANIFESTINT;
+
+/** The value of RTMANIFESTINT::u32Magic. */
+#define RTMANIFEST_MAGIC UINT32_C(0x99998866)
+
+/**
+ * Argument package passed to rtManifestWriteStdAttr by rtManifestWriteStdEntry
+ * and RTManifestWriteStandard.
+ */
+typedef struct RTMANIFESTWRITESTDATTR
+{
+ /** The entry name. */
+ const char *pszEntry;
+ /** The output I/O stream. */
+ RTVFSIOSTREAM hVfsIos;
+} RTMANIFESTWRITESTDATTR;
+
+
+/**
+ * Argument package used by RTManifestEqualsEx to pass its arguments to the
+ * enumeration callback functions.
+ */
+typedef struct RTMANIFESTEQUALS
+{
+ /** Name of entries to ignore. */
+ const char * const *papszIgnoreEntries;
+ /** Name of attributes to ignore. */
+ const char * const *papszIgnoreAttrs;
+ /** Flags governing the comparision. */
+ uint32_t fFlags;
+ /** Where to return an error message (++) on failure. Can be NULL. */
+ char *pszError;
+ /** The size of the buffer pszError points to. Can be 0. */
+ size_t cbError;
+
+ /** Pointer to the 2nd manifest. */
+ RTMANIFESTINT *pThis2;
+
+ /** The number of ignored entries from the 1st manifest. */
+ uint32_t cIgnoredEntries2;
+ /** The number of entries processed from the 2nd manifest. */
+ uint32_t cEntries2;
+
+ /** The number of ignored attributes from the 1st manifest. */
+ uint32_t cIgnoredAttributes1;
+ /** The number of ignored attributes from the 1st manifest. */
+ uint32_t cIgnoredAttributes2;
+ /** The number of attributes processed from the 2nd manifest. */
+ uint32_t cAttributes2;
+ /** Pointer to the string space to get matching attributes from. */
+ PRTSTRSPACE pAttributes2;
+ /** The name of the current entry.
+ * Points to an empty string it's the manifest attributes. */
+ const char *pszCurEntry;
+} RTMANIFESTEQUALS;
+/** Pointer to an RTManifestEqualEx argument packet. */
+typedef RTMANIFESTEQUALS *PRTMANIFESTEQUALS;
+
+/**
+ * Argument package used by rtManifestQueryAttrWorker to pass its search
+ * criteria to rtManifestQueryAttrEnumCallback and get a result back.
+ */
+typedef struct RTMANIFESTQUERYATTRARGS
+{
+ /** The attribute types we're hunting for. */
+ uint32_t fType;
+ /** What we've found. */
+ PRTMANIFESTATTR pAttr;
+} RTMANIFESTQUERYATTRARGS;
+/** Pointer to a rtManifestQueryAttrEnumCallback argument packet. */
+typedef RTMANIFESTQUERYATTRARGS *PRTMANIFESTQUERYATTRARGS;
+
+
+RTDECL(int) RTManifestCreate(uint32_t fFlags, PRTMANIFEST phManifest)
+{
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+ AssertPtr(phManifest);
+
+ RTMANIFESTINT *pThis = (RTMANIFESTINT *)RTMemAlloc(RT_UOFFSETOF(RTMANIFESTINT, SelfEntry.szName[1]));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTMANIFEST_MAGIC;
+ pThis->cRefs = 1;
+ pThis->Entries = NULL;
+ pThis->cEntries = 0;
+ pThis->SelfEntry.StrCore.pszString = "main";
+ pThis->SelfEntry.StrCore.cchString = 4;
+ pThis->SelfEntry.Attributes = NULL;
+ pThis->SelfEntry.cAttributes = 0;
+ pThis->SelfEntry.fVisited = false;
+ pThis->SelfEntry.szName[0] = '\0';
+
+ *phManifest = pThis;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(uint32_t) RTManifestRetain(RTMANIFEST hManifest)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs > 1 && cRefs < _1M);
+
+ return cRefs;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Destroys RTMANIFESTATTR.}
+ */
+static DECLCALLBACK(int) rtManifestDestroyAttribute(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
+ RTStrFree(pAttr->pszValue);
+ pAttr->pszValue = NULL;
+ RTMemFree(pAttr);
+ NOREF(pvUser);
+ return 0;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Destroys RTMANIFESTENTRY.}
+ */
+static DECLCALLBACK(int) rtManifestDestroyEntry(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
+ RTStrSpaceDestroy(&pEntry->Attributes, rtManifestDestroyAttribute, pvUser);
+ RTMemFree(pEntry);
+ return 0;
+}
+
+
+RTDECL(uint32_t) RTManifestRelease(RTMANIFEST hManifest)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ if (pThis == NIL_RTMANIFEST)
+ return 0;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ Assert(cRefs < _1M);
+ if (!cRefs)
+ {
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTMANIFEST_MAGIC);
+ RTStrSpaceDestroy(&pThis->Entries, rtManifestDestroyEntry,pThis);
+ RTStrSpaceDestroy(&pThis->SelfEntry.Attributes, rtManifestDestroyAttribute, pThis);
+ RTMemFree(pThis);
+ }
+
+ return cRefs;
+}
+
+
+RTDECL(int) RTManifestDup(RTMANIFEST hManifestSrc, PRTMANIFEST phManifestDst)
+{
+ RTMANIFESTINT *pThis = hManifestSrc;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(phManifestDst);
+
+ RT_NOREF_PV(phManifestDst); /** @todo implement cloning. */
+
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation}
+ */
+static DECLCALLBACK(int) rtManifestAttributeClearVisited(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
+ pAttr->fVisited = false;
+ NOREF(pvUser);
+ return 0;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation}
+ */
+static DECLCALLBACK(int) rtManifestEntryClearVisited(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
+ RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestAttributeClearVisited, NULL);
+ pEntry->fVisited = false;
+ NOREF(pvUser);
+ return 0;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Finds the first missing}
+ */
+static DECLCALLBACK(int) rtManifestAttributeFindMissing2(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
+ PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
+
+ /*
+ * Already visited?
+ */
+ if (pAttr->fVisited)
+ return 0;
+
+ /*
+ * Ignore this entry?
+ */
+ char const * const *ppsz = pEquals->papszIgnoreAttrs;
+ if (ppsz)
+ {
+ while (*ppsz)
+ {
+ if (!strcmp(*ppsz, pAttr->szName))
+ return 0;
+ ppsz++;
+ }
+ }
+
+ /*
+ * Gotcha!
+ */
+ if (*pEquals->pszCurEntry)
+ RTStrPrintf(pEquals->pszError, pEquals->cbError,
+ "Attribute '%s' on '%s' was not found in the 1st manifest",
+ pAttr->szName, pEquals->pszCurEntry);
+ else
+ RTStrPrintf(pEquals->pszError, pEquals->cbError, "Attribute '%s' was not found in the 1st manifest", pAttr->szName);
+ return VERR_NOT_EQUAL;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Finds the first missing}
+ */
+static DECLCALLBACK(int) rtManifestEntryFindMissing2(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
+ PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
+
+ /*
+ * Already visited?
+ */
+ if (pEntry->fVisited)
+ return 0;
+
+ /*
+ * Ignore this entry?
+ */
+ char const * const *ppsz = pEquals->papszIgnoreEntries;
+ if (ppsz)
+ {
+ while (*ppsz)
+ {
+ if (!strcmp(*ppsz, pEntry->StrCore.pszString))
+ return 0;
+ ppsz++;
+ }
+ }
+
+ /*
+ * Gotcha!
+ */
+ RTStrPrintf(pEquals->pszError, pEquals->cbError, "'%s' was not found in the 1st manifest", pEntry->StrCore.pszString);
+ return VERR_NOT_EQUAL;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Compares attributes}
+ */
+static DECLCALLBACK(int) rtManifestAttributeCompare(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
+ PRTMANIFESTATTR pAttr1 = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
+ PRTMANIFESTATTR pAttr2;
+
+ Assert(!pAttr1->fVisited);
+ pAttr1->fVisited = true;
+
+ /*
+ * Ignore this entry?
+ */
+ char const * const *ppsz = pEquals->papszIgnoreAttrs;
+ if (ppsz)
+ {
+ while (*ppsz)
+ {
+ if (!strcmp(*ppsz, pAttr1->szName))
+ {
+ pAttr2 = (PRTMANIFESTATTR)RTStrSpaceGet(pEquals->pAttributes2, pAttr1->szName);
+ if (pAttr2)
+ {
+ Assert(!pAttr2->fVisited);
+ pAttr2->fVisited = true;
+ pEquals->cIgnoredAttributes2++;
+ }
+ pEquals->cIgnoredAttributes1++;
+ return 0;
+ }
+ ppsz++;
+ }
+ }
+
+ /*
+ * Find the matching attribute.
+ */
+ pAttr2 = (PRTMANIFESTATTR)RTStrSpaceGet(pEquals->pAttributes2, pAttr1->szName);
+ if (!pAttr2)
+ {
+ if (pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)
+ return 0;
+
+ if (*pEquals->pszCurEntry)
+ RTStrPrintf(pEquals->pszError, pEquals->cbError,
+ "Attribute '%s' on '%s' was not found in the 2nd manifest",
+ pAttr1->szName, pEquals->pszCurEntry);
+ else
+ RTStrPrintf(pEquals->pszError, pEquals->cbError, "Attribute '%s' was not found in the 2nd manifest", pAttr1->szName);
+ return VERR_NOT_EQUAL;
+ }
+
+ Assert(!pAttr2->fVisited);
+ pAttr2->fVisited = true;
+ pEquals->cAttributes2++;
+
+ /*
+ * Compare them.
+ */
+ if (RTStrICmp(pAttr1->pszValue, pAttr2->pszValue))
+ {
+ if (*pEquals->pszCurEntry)
+ RTStrPrintf(pEquals->pszError, pEquals->cbError,
+ "Attribute '%s' on '%s' does not match ('%s' vs. '%s')",
+ pAttr1->szName, pEquals->pszCurEntry, pAttr1->pszValue, pAttr2->pszValue);
+ else
+ RTStrPrintf(pEquals->pszError, pEquals->cbError,
+ "Attribute '%s' does not match ('%s' vs. '%s')",
+ pAttr1->szName, pAttr1->pszValue, pAttr2->pszValue);
+ return VERR_NOT_EQUAL;
+ }
+
+ return 0;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation}
+ */
+DECLINLINE (int) rtManifestEntryCompare2(PRTMANIFESTEQUALS pEquals, PRTMANIFESTENTRY pEntry1, PRTMANIFESTENTRY pEntry2)
+{
+ /*
+ * Compare the attributes. It's a bit ugly with all this counting, but
+ * how else to efficiently implement RTMANIFEST_EQUALS_IGN_MISSING_ATTRS?
+ */
+ pEquals->cIgnoredAttributes1 = 0;
+ pEquals->cIgnoredAttributes2 = 0;
+ pEquals->cAttributes2 = 0;
+ pEquals->pszCurEntry = &pEntry2->szName[0];
+ pEquals->pAttributes2 = &pEntry2->Attributes;
+ int rc = RTStrSpaceEnumerate(&pEntry1->Attributes, rtManifestAttributeCompare, pEquals);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Check that we matched all that is required.
+ */
+ if ( pEquals->cAttributes2 + pEquals->cIgnoredAttributes2 != pEntry2->cAttributes
+ && ( !(pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)
+ || pEquals->cIgnoredAttributes1 == pEntry1->cAttributes))
+ rc = RTStrSpaceEnumerate(&pEntry2->Attributes, rtManifestAttributeFindMissing2, pEquals);
+ }
+ return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation}
+ */
+static DECLCALLBACK(int) rtManifestEntryCompare(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
+ PRTMANIFESTENTRY pEntry1 = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
+ PRTMANIFESTENTRY pEntry2;
+
+ /*
+ * Ignore this entry?
+ */
+ char const * const *ppsz = pEquals->papszIgnoreEntries;
+ if (ppsz)
+ {
+ while (*ppsz)
+ {
+ if (!strcmp(*ppsz, pStr->pszString))
+ {
+ pEntry2 = (PRTMANIFESTENTRY)RTStrSpaceGet(&pEquals->pThis2->Entries, pStr->pszString);
+ if (pEntry2)
+ {
+ pEntry2->fVisited = true;
+ pEquals->cIgnoredEntries2++;
+ }
+ pEntry1->fVisited = true;
+ return 0;
+ }
+ ppsz++;
+ }
+ }
+
+ /*
+ * Try find the entry in the other manifest.
+ */
+ pEntry2 = (PRTMANIFESTENTRY)RTStrSpaceGet(&pEquals->pThis2->Entries, pEntry1->StrCore.pszString);
+ if (!pEntry2)
+ {
+ if (!(pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ENTRIES_2ND))
+ {
+ RTStrPrintf(pEquals->pszError, pEquals->cbError, "'%s' not found in the 2nd manifest", pEntry1->StrCore.pszString);
+ return VERR_NOT_EQUAL;
+ }
+ pEntry1->fVisited = true;
+ return VINF_SUCCESS;
+ }
+
+ Assert(!pEntry1->fVisited);
+ Assert(!pEntry2->fVisited);
+ pEntry1->fVisited = true;
+ pEntry2->fVisited = true;
+ pEquals->cEntries2++;
+
+ return rtManifestEntryCompare2(pEquals, pEntry1, pEntry2);
+}
+
+
+
+RTDECL(int) RTManifestEqualsEx(RTMANIFEST hManifest1, RTMANIFEST hManifest2, const char * const *papszIgnoreEntries,
+ const char * const *papszIgnoreAttrs, uint32_t fFlags, char *pszError, size_t cbError)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrNullReturn(pszError, VERR_INVALID_POINTER);
+ if (pszError && cbError)
+ *pszError = '\0';
+ RTMANIFESTINT *pThis1 = hManifest1;
+ RTMANIFESTINT *pThis2 = hManifest2;
+ if (pThis1 != NIL_RTMANIFEST)
+ {
+ AssertPtrReturn(pThis1, VERR_INVALID_HANDLE);
+ AssertReturn(pThis1->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ }
+ if (pThis2 != NIL_RTMANIFEST)
+ {
+ AssertPtrReturn(pThis2, VERR_INVALID_HANDLE);
+ AssertReturn(pThis2->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ }
+ AssertReturn(!(fFlags & ~RTMANIFEST_EQUALS_VALID_MASK), VERR_INVALID_PARAMETER);
+
+ /*
+ * The simple cases.
+ */
+ if (pThis1 == pThis2)
+ return VINF_SUCCESS;
+ if (pThis1 == NIL_RTMANIFEST || pThis2 == NIL_RTMANIFEST)
+ return VERR_NOT_EQUAL;
+
+ /*
+ * Since we have to use callback style enumeration, we have to mark the
+ * entries and attributes to make sure we've covered them all.
+ */
+ RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryClearVisited, NULL);
+ RTStrSpaceEnumerate(&pThis2->Entries, rtManifestEntryClearVisited, NULL);
+ RTStrSpaceEnumerate(&pThis1->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL);
+ RTStrSpaceEnumerate(&pThis2->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL);
+
+ RTMANIFESTEQUALS Equals;
+ Equals.pThis2 = pThis2;
+ Equals.fFlags = fFlags;
+ Equals.papszIgnoreEntries = papszIgnoreEntries;
+ Equals.papszIgnoreAttrs = papszIgnoreAttrs;
+ Equals.pszError = pszError;
+ Equals.cbError = cbError;
+
+ Equals.cIgnoredEntries2 = 0;
+ Equals.cEntries2 = 0;
+ Equals.cIgnoredAttributes1 = 0;
+ Equals.cIgnoredAttributes2 = 0;
+ Equals.cAttributes2 = 0;
+ Equals.pAttributes2 = NULL;
+ Equals.pszCurEntry = NULL;
+
+ int rc = rtManifestEntryCompare2(&Equals, &pThis1->SelfEntry, &pThis2->SelfEntry);
+ if (RT_SUCCESS(rc))
+ rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryCompare, &Equals);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Did we cover all entries of the 2nd manifest?
+ */
+ if (Equals.cEntries2 + Equals.cIgnoredEntries2 != pThis2->cEntries)
+ rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryFindMissing2, &Equals);
+ }
+
+ return rc;
+}
+
+
+RTDECL(int) RTManifestEquals(RTMANIFEST hManifest1, RTMANIFEST hManifest2)
+{
+ return RTManifestEqualsEx(hManifest1, hManifest2,
+ NULL /*papszIgnoreEntries*/, NULL /*papszIgnoreAttrs*/,
+ 0 /*fFlags*/, NULL, 0);
+}
+
+
+/**
+ * Translates a attribyte type to a attribute name.
+ *
+ * @returns Attribute name for fFlags, NULL if not translatable.
+ * @param fType The type flags. Only one bit should be set.
+ */
+static const char *rtManifestTypeToAttrName(uint32_t fType)
+{
+ switch (fType)
+ {
+ case RTMANIFEST_ATTR_SIZE: return "SIZE";
+ case RTMANIFEST_ATTR_MD5: return "MD5";
+ case RTMANIFEST_ATTR_SHA1: return "SHA1";
+ case RTMANIFEST_ATTR_SHA256: return "SHA256";
+ case RTMANIFEST_ATTR_SHA512: return "SHA512";
+ default: return NULL;
+ }
+}
+
+
+/**
+ * Worker common to RTManifestSetAttr and RTManifestEntrySetAttr.
+ *
+ * @returns IPRT status code.
+ * @param pEntry Pointer to the entry.
+ * @param pszAttr The name of the attribute to add.
+ * @param pszValue The value string.
+ * @param fType The attribute type type.
+ */
+static int rtManifestSetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr, const char *pszValue, uint32_t fType)
+{
+ char *pszValueCopy;
+ int rc = RTStrDupEx(&pszValueCopy, pszValue);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Does the attribute exist already?
+ */
+ AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0);
+ PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(&pEntry->Attributes, pszAttr);
+ if (pAttr)
+ {
+ RTStrFree(pAttr->pszValue);
+ pAttr->pszValue = pszValueCopy;
+ pAttr->fType = fType;
+ }
+ else
+ {
+ size_t const cbName = strlen(pszAttr) + 1;
+ pAttr = (PRTMANIFESTATTR)RTMemAllocVar(RT_UOFFSETOF_DYN(RTMANIFESTATTR, szName[cbName]));
+ if (!pAttr)
+ {
+ RTStrFree(pszValueCopy);
+ return VERR_NO_MEMORY;
+ }
+ memcpy(pAttr->szName, pszAttr, cbName);
+ pAttr->StrCore.pszString = pAttr->szName;
+ pAttr->StrCore.cchString = cbName - 1;
+ pAttr->pszValue = pszValueCopy;
+ pAttr->fType = fType;
+ if (RT_UNLIKELY(!RTStrSpaceInsert(&pEntry->Attributes, &pAttr->StrCore)))
+ {
+ AssertFailed();
+ RTStrFree(pszValueCopy);
+ RTMemFree(pAttr);
+ return VERR_INTERNAL_ERROR_4;
+ }
+ pEntry->cAttributes++;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTManifestSetAttr(RTMANIFEST hManifest, const char *pszAttr, const char *pszValue, uint32_t fType)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszValue);
+ AssertReturn(RT_IS_POWER_OF_TWO(fType) && fType < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
+ if (!pszAttr)
+ pszAttr = rtManifestTypeToAttrName(fType);
+ AssertPtr(pszAttr);
+
+ return rtManifestSetAttrWorker(&pThis->SelfEntry, pszAttr, pszValue, fType);
+}
+
+
+/**
+ * Worker common to RTManifestUnsetAttr and RTManifestEntryUnsetAttr.
+ *
+ * @returns IPRT status code.
+ * @param pEntry Pointer to the entry.
+ * @param pszAttr The name of the attribute to remove.
+ */
+static int rtManifestUnsetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr)
+{
+ PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&pEntry->Attributes, pszAttr);
+ if (!pStrCore)
+ return VWRN_NOT_FOUND;
+ pEntry->cAttributes--;
+ rtManifestDestroyAttribute(pStrCore, NULL);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTManifestUnsetAttr(RTMANIFEST hManifest, const char *pszAttr)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszAttr);
+
+ return rtManifestUnsetAttrWorker(&pThis->SelfEntry, pszAttr);
+}
+
+
+/**
+ * Callback employed by rtManifestQueryAttrWorker to search by attribute type.
+ *
+ * @returns VINF_SUCCESS or VINF_CALLBACK_RETURN.
+ * @param pStr The attribute string node.
+ * @param pvUser The argument package.
+ */
+static DECLCALLBACK(int) rtManifestQueryAttrEnumCallback(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)pStr;
+ PRTMANIFESTQUERYATTRARGS pArgs = (PRTMANIFESTQUERYATTRARGS)pvUser;
+
+ if (pAttr->fType & pArgs->fType)
+ {
+ pArgs->pAttr = pAttr;
+ return VINF_CALLBACK_RETURN;
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker common to RTManifestQueryAttr and RTManifestEntryQueryAttr.
+ *
+ * @returns IPRT status code.
+ * @param pEntry The entry.
+ * @param pszAttr The attribute name. If NULL, it will be
+ * selected by @a fType alone.
+ * @param fType The attribute types the entry should match. Pass
+ * Pass RTMANIFEST_ATTR_ANY match any. If more
+ * than one is given, the first matching one is
+ * returned.
+ * @param pszValue Where to return value.
+ * @param cbValue The size of the buffer @a pszValue points to.
+ * @param pfType Where to return the attribute type value.
+ */
+static int rtManifestQueryAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr, uint32_t fType,
+ char *pszValue, size_t cbValue, uint32_t *pfType)
+{
+ /*
+ * Find the requested attribute.
+ */
+ PRTMANIFESTATTR pAttr;
+ if (pszAttr)
+ {
+ /* By name. */
+ pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(&pEntry->Attributes, pszAttr);
+ if (!pAttr)
+ return VERR_MANIFEST_ATTR_NOT_FOUND;
+ if (!(pAttr->fType & fType))
+ return VERR_MANIFEST_ATTR_TYPE_MISMATCH;
+ }
+ else
+ {
+ /* By type. */
+ RTMANIFESTQUERYATTRARGS Args;
+ Args.fType = fType;
+ Args.pAttr = NULL;
+ int rc = RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestQueryAttrEnumCallback, &Args);
+ AssertRCReturn(rc, rc);
+ pAttr = Args.pAttr;
+ if (!pAttr)
+ return VERR_MANIFEST_ATTR_TYPE_NOT_FOUND;
+ }
+
+ /*
+ * Set the return values.
+ */
+ if (cbValue || pszValue)
+ {
+ size_t cbNeeded = strlen(pAttr->pszValue) + 1;
+ if (cbNeeded > cbValue)
+ return VERR_BUFFER_OVERFLOW;
+ memcpy(pszValue, pAttr->pszValue, cbNeeded);
+ }
+
+ if (pfType)
+ *pfType = pAttr->fType;
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTManifestQueryAttr(RTMANIFEST hManifest, const char *pszAttr, uint32_t fType,
+ char *pszValue, size_t cbValue, uint32_t *pfType)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtrNull(pszAttr);
+ AssertPtr(pszValue);
+
+ return rtManifestQueryAttrWorker(&pThis->SelfEntry, pszAttr, fType, pszValue, cbValue, pfType);
+}
+
+
+/**
+ * Callback employed by RTManifestQueryAllAttrTypes to collect attribute types.
+ *
+ * @returns VINF_SUCCESS.
+ * @param pStr The attribute string node.
+ * @param pvUser Pointer to type flags (uint32_t).
+ */
+static DECLCALLBACK(int) rtManifestQueryAllAttrTypesEnumAttrCallback(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)pStr;
+ uint32_t *pfTypes = (uint32_t *)pvUser;
+ *pfTypes |= pAttr->fType;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Callback employed by RTManifestQueryAllAttrTypes to collect attribute types
+ * for an entry.
+ *
+ * @returns VINF_SUCCESS.
+ * @param pStr The attribute string node.
+ * @param pvUser Pointer to type flags (uint32_t).
+ */
+static DECLCALLBACK(int) rtManifestQueryAllAttrTypesEnumEntryCallback(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
+ return RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestQueryAllAttrTypesEnumAttrCallback, pvUser);
+}
+
+
+RTDECL(int) RTManifestQueryAllAttrTypes(RTMANIFEST hManifest, bool fEntriesOnly, uint32_t *pfTypes)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pfTypes);
+
+ *pfTypes = 0;
+ int rc = RTStrSpaceEnumerate(&pThis->Entries, rtManifestQueryAllAttrTypesEnumEntryCallback, pfTypes);
+ if (RT_SUCCESS(rc) && fEntriesOnly)
+ rc = rtManifestQueryAllAttrTypesEnumAttrCallback(&pThis->SelfEntry.StrCore, pfTypes);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Validates the name entry.
+ *
+ * @returns IPRT status code.
+ * @param pszEntry The entry name to validate.
+ * @param pfNeedNormalization Where to return whether it needs normalization
+ * or not. Optional.
+ * @param pcchEntry Where to return the length. Optional.
+ */
+static int rtManifestValidateNameEntry(const char *pszEntry, bool *pfNeedNormalization, size_t *pcchEntry)
+{
+ int rc;
+ bool fNeedNormalization = false;
+ const char *pszCur = pszEntry;
+
+ for (;;)
+ {
+ RTUNICP uc;
+ rc = RTStrGetCpEx(&pszCur, &uc);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (!uc)
+ break;
+ if (uc == '\\')
+ fNeedNormalization = true;
+ else if (uc < 32 || uc == ':' || uc == '(' || uc == ')')
+ return VERR_INVALID_NAME;
+ }
+
+ if (pfNeedNormalization)
+ *pfNeedNormalization = fNeedNormalization;
+
+ size_t cchEntry = pszCur - pszEntry - 1;
+ if (!cchEntry)
+ rc = VERR_INVALID_NAME;
+ if (pcchEntry)
+ *pcchEntry = cchEntry;
+
+ return rc;
+}
+
+
+/**
+ * Normalizes a entry name.
+ *
+ * @param pszEntry The entry name to normalize.
+ */
+static void rtManifestNormalizeEntry(char *pszEntry)
+{
+ char ch;
+ while ((ch = *pszEntry))
+ {
+ if (ch == '\\')
+ *pszEntry = '/';
+ pszEntry++;
+ }
+}
+
+
+/**
+ * Gets an entry.
+ *
+ * @returns IPRT status code.
+ * @param pThis The manifest to work with.
+ * @param pszEntry The entry name.
+ * @param fNeedNormalization Whether rtManifestValidateNameEntry said it
+ * needed normalization.
+ * @param cchEntry The length of the name.
+ * @param ppEntry Where to return the entry pointer on success.
+ */
+static int rtManifestGetEntry(RTMANIFESTINT *pThis, const char *pszEntry, bool fNeedNormalization, size_t cchEntry,
+ PRTMANIFESTENTRY *ppEntry)
+{
+ PRTMANIFESTENTRY pEntry;
+
+ AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0);
+ if (!fNeedNormalization)
+ pEntry = (PRTMANIFESTENTRY)RTStrSpaceGet(&pThis->Entries, pszEntry);
+ else
+ {
+ char *pszCopy = (char *)RTMemTmpAlloc(cchEntry + 1);
+ if (RT_UNLIKELY(!pszCopy))
+ return VERR_NO_TMP_MEMORY;
+ memcpy(pszCopy, pszEntry, cchEntry + 1);
+ rtManifestNormalizeEntry(pszCopy);
+
+ pEntry = (PRTMANIFESTENTRY)RTStrSpaceGet(&pThis->Entries, pszCopy);
+ RTMemTmpFree(pszCopy);
+ }
+
+ *ppEntry = pEntry;
+ return pEntry ? VINF_SUCCESS : VERR_NOT_FOUND;
+}
+
+
+RTDECL(int) RTManifestEntrySetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr,
+ const char *pszValue, uint32_t fType)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszEntry);
+ AssertPtr(pszValue);
+ AssertReturn(RT_IS_POWER_OF_TWO(fType) && fType < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
+ if (!pszAttr)
+ pszAttr = rtManifestTypeToAttrName(fType);
+ AssertPtr(pszAttr);
+
+ bool fNeedNormalization;
+ size_t cchEntry;
+ int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Resolve the entry, adding one if necessary.
+ */
+ PRTMANIFESTENTRY pEntry;
+ rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
+ if (rc == VERR_NOT_FOUND)
+ {
+ pEntry = (PRTMANIFESTENTRY)RTMemAlloc(RT_UOFFSETOF_DYN(RTMANIFESTENTRY, szName[cchEntry + 1]));
+ if (!pEntry)
+ return VERR_NO_MEMORY;
+
+ pEntry->StrCore.cchString = cchEntry;
+ pEntry->StrCore.pszString = pEntry->szName;
+ pEntry->Attributes = NULL;
+ pEntry->cAttributes = 0;
+ memcpy(pEntry->szName, pszEntry, cchEntry + 1);
+ if (fNeedNormalization)
+ rtManifestNormalizeEntry(pEntry->szName);
+
+ if (!RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore))
+ {
+ RTMemFree(pEntry);
+ return VERR_INTERNAL_ERROR_4;
+ }
+ pThis->cEntries++;
+ }
+ else if (RT_FAILURE(rc))
+ return rc;
+
+ return rtManifestSetAttrWorker(pEntry, pszAttr, pszValue, fType);
+}
+
+
+RTDECL(int) RTManifestEntryUnsetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszEntry);
+ AssertPtr(pszAttr);
+
+ bool fNeedNormalization;
+ size_t cchEntry;
+ int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Resolve the entry and hand it over to the worker.
+ */
+ PRTMANIFESTENTRY pEntry;
+ rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
+ if (RT_SUCCESS(rc))
+ rc = rtManifestUnsetAttrWorker(pEntry, pszAttr);
+ return rc;
+}
+
+
+RTDECL(int) RTManifestEntryQueryAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr, uint32_t fType,
+ char *pszValue, size_t cbValue, uint32_t *pfType)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszEntry);
+ AssertPtrNull(pszAttr);
+ AssertPtr(pszValue);
+
+ /*
+ * Look up the entry.
+ */
+ bool fNeedNormalization;
+ size_t cchEntry;
+ int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
+ AssertRCReturn(rc, rc);
+
+ PRTMANIFESTENTRY pEntry;
+ rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
+ if (RT_SUCCESS(rc))
+ rc = rtManifestQueryAttrWorker(pEntry, pszAttr, fType, pszValue, cbValue, pfType);
+ return rc;
+}
+
+
+RTDECL(int) RTManifestEntryAdd(RTMANIFEST hManifest, const char *pszEntry)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszEntry);
+
+ bool fNeedNormalization;
+ size_t cchEntry;
+ int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Only add one if it does not already exist.
+ */
+ PRTMANIFESTENTRY pEntry;
+ rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
+ if (rc == VERR_NOT_FOUND)
+ {
+ pEntry = (PRTMANIFESTENTRY)RTMemAlloc(RT_UOFFSETOF_DYN(RTMANIFESTENTRY, szName[cchEntry + 1]));
+ if (pEntry)
+ {
+ pEntry->StrCore.cchString = cchEntry;
+ pEntry->StrCore.pszString = pEntry->szName;
+ pEntry->Attributes = NULL;
+ pEntry->cAttributes = 0;
+ memcpy(pEntry->szName, pszEntry, cchEntry + 1);
+ if (fNeedNormalization)
+ rtManifestNormalizeEntry(pEntry->szName);
+
+ if (RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore))
+ {
+ pThis->cEntries++;
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ RTMemFree(pEntry);
+ rc = VERR_INTERNAL_ERROR_4;
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else if (RT_SUCCESS(rc))
+ rc = VWRN_ALREADY_EXISTS;
+
+ return rc;
+}
+
+
+RTDECL(int) RTManifestEntryRemove(RTMANIFEST hManifest, const char *pszEntry)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+ AssertPtr(pszEntry);
+
+ bool fNeedNormalization;
+ size_t cchEntry;
+ int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Look it up before removing it.
+ */
+ PRTMANIFESTENTRY pEntry;
+ rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&pThis->Entries, pEntry->StrCore.pszString);
+ AssertReturn(pStrCore, VERR_INTERNAL_ERROR_3);
+ pThis->cEntries--;
+ rtManifestDestroyEntry(pStrCore, pThis);
+ }
+
+ return rc;
+}
+
+
+RTDECL(bool) RTManifestEntryExists(RTMANIFEST hManifest, const char *pszEntry)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, false);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, false);
+ AssertPtr(pszEntry);
+
+ bool fNeedNormalization;
+ size_t cchEntry;
+ int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
+ AssertRCReturn(rc, false);
+
+ /*
+ * Check if it exists.
+ */
+ PRTMANIFESTENTRY pEntry;
+ rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
+ return RT_SUCCESS_NP(rc);
+}
+
+
+/**
+ * Reads a line from a VFS I/O stream.
+ *
+ * @todo Replace this with a buffered I/O stream layer.
+ *
+ * @returns IPRT status code. VERR_EOF when trying to read beyond the stream
+ * end.
+ * @param hVfsIos The I/O stream to read from.
+ * @param pszLine Where to store what we've read.
+ * @param cbLine The number of bytes to read.
+ */
+static int rtManifestReadLine(RTVFSIOSTREAM hVfsIos, char *pszLine, size_t cbLine)
+{
+ /* This is horribly slow right now, but it's not a biggy as the input is
+ usually cached in memory somewhere... */
+ *pszLine = '\0';
+ while (cbLine > 1)
+ {
+ char ch;
+ int rc = RTVfsIoStrmRead(hVfsIos, &ch, 1, true /*fBLocking*/, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* \r\n */
+ if (ch == '\r')
+ {
+ if (cbLine <= 2)
+ {
+ pszLine[0] = ch;
+ pszLine[1] = '\0';
+ return VINF_BUFFER_OVERFLOW;
+ }
+
+ rc = RTVfsIoStrmRead(hVfsIos, &ch, 1, true /*fBLocking*/, NULL);
+ if (RT_SUCCESS(rc) && ch == '\n')
+ return VINF_SUCCESS;
+ pszLine[0] = '\r';
+ pszLine[1] = ch;
+ pszLine[2] = '\0';
+ if (RT_FAILURE(rc))
+ return rc == VERR_EOF ? VINF_EOF : rc;
+ }
+
+ /* \n */
+ if (ch == '\n')
+ return VINF_SUCCESS;
+
+ /* add character. */
+ pszLine[0] = ch;
+ pszLine[1] = '\0';
+
+ /* advance */
+ pszLine++;
+ cbLine--;
+ }
+
+ return VINF_BUFFER_OVERFLOW;
+}
+
+
+RTDECL(int) RTManifestReadStandardEx(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, char *pszErr, size_t cbErr)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrNull(pszErr);
+ if (pszErr && cbErr)
+ *pszErr = '\0';
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+
+ /*
+ * Process the stream line by line.
+ */
+ uint32_t iLine = 0;
+ for (;;)
+ {
+ /*
+ * Read a line from the input stream.
+ */
+ iLine++;
+ char szLine[RTPATH_MAX + RTSHA512_DIGEST_LEN + 32];
+ int rc = rtManifestReadLine(hVfsIos, szLine, sizeof(szLine));
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_EOF)
+ return VINF_SUCCESS;
+ RTStrPrintf(pszErr, cbErr, "Error reading line #%u: %Rrc", iLine, rc);
+ return rc;
+ }
+ if (rc != VINF_SUCCESS)
+ {
+ RTStrPrintf(pszErr, cbErr, "Line number %u is too long", iLine);
+ return VERR_OUT_OF_RANGE;
+ }
+
+ /*
+ * Strip it and skip if empty.
+ */
+ char *psz = RTStrStrip(szLine);
+ if (!*psz)
+ continue;
+
+ /*
+ * Read the attribute name.
+ */
+ char ch;
+ const char * const pszAttr = psz;
+ do
+ psz++;
+ while (!RT_C_IS_BLANK((ch = *psz)) && ch && ch != '(');
+ if (ch)
+ *psz++ = '\0';
+
+ /*
+ * The entry name is enclosed in parenthesis and followed by a '='.
+ */
+ if (ch != '(')
+ {
+ psz = RTStrStripL(psz);
+ ch = *psz++;
+ if (ch != '(')
+ {
+ RTStrPrintf(pszErr, cbErr, "Expected '(' after %zu on line %u", psz - szLine - 1, iLine);
+ return VERR_PARSE_ERROR;
+ }
+ }
+ const char * const pszName = psz;
+ while ((ch = *psz) != '\0')
+ {
+ if (ch == ')')
+ {
+ char *psz2 = RTStrStripL(psz + 1);
+ if (*psz2 == '=')
+ {
+ *psz = '\0';
+ psz = psz2;
+ break;
+ }
+ }
+ psz++;
+ }
+
+ if (*psz != '=')
+ {
+ RTStrPrintf(pszErr, cbErr, "Expected ')=' at %zu on line %u", psz - szLine, iLine);
+ return VERR_PARSE_ERROR;
+ }
+
+ /*
+ * The value.
+ */
+ psz = RTStrStrip(psz + 1);
+ const char * const pszValue = psz;
+ if (!*psz)
+ {
+ RTStrPrintf(pszErr, cbErr, "Expected value at %zu on line %u", psz - szLine, iLine);
+ return VERR_PARSE_ERROR;
+ }
+
+ /*
+ * Detect attribute type and sanity check the value.
+ */
+ uint32_t fType = RTMANIFEST_ATTR_UNKNOWN;
+ static const struct
+ {
+ const char *pszAttr;
+ uint32_t fType;
+ unsigned cBits;
+ unsigned uBase;
+ } s_aDecAttrs[] =
+ {
+ { "SIZE", RTMANIFEST_ATTR_SIZE, 64, 10}
+ };
+ for (unsigned i = 0; i < RT_ELEMENTS(s_aDecAttrs); i++)
+ if (!strcmp(s_aDecAttrs[i].pszAttr, pszAttr))
+ {
+ fType = s_aDecAttrs[i].fType;
+ rc = RTStrToUInt64Full(pszValue, s_aDecAttrs[i].uBase, NULL);
+ if (rc != VINF_SUCCESS)
+ {
+ RTStrPrintf(pszErr, cbErr, "Malformed value ('%s') at %zu on line %u: %Rrc", pszValue, psz - szLine, iLine, rc);
+ return VERR_PARSE_ERROR;
+ }
+ break;
+ }
+
+ if (fType == RTMANIFEST_ATTR_UNKNOWN)
+ {
+ static const struct
+ {
+ const char *pszAttr;
+ uint32_t fType;
+ unsigned cchHex;
+ } s_aHexAttrs[] =
+ {
+ { "MD5", RTMANIFEST_ATTR_MD5, RTMD5_DIGEST_LEN },
+ { "SHA1", RTMANIFEST_ATTR_SHA1, RTSHA1_DIGEST_LEN },
+ { "SHA256", RTMANIFEST_ATTR_SHA256, RTSHA256_DIGEST_LEN },
+ { "SHA512", RTMANIFEST_ATTR_SHA512, RTSHA512_DIGEST_LEN }
+ };
+ for (unsigned i = 0; i < RT_ELEMENTS(s_aHexAttrs); i++)
+ if (!strcmp(s_aHexAttrs[i].pszAttr, pszAttr))
+ {
+ fType = s_aHexAttrs[i].fType;
+ for (unsigned off = 0; off < s_aHexAttrs[i].cchHex; off++)
+ if (!RT_C_IS_XDIGIT(pszValue[off]))
+ {
+ RTStrPrintf(pszErr, cbErr, "Expected hex digit at %zu on line %u (value '%s', pos %u)",
+ pszValue - szLine + off, iLine, pszValue, off);
+ return VERR_PARSE_ERROR;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Finally, add it.
+ */
+ rc = RTManifestEntrySetAttr(hManifest, pszName, pszAttr, pszValue, fType);
+ if (RT_FAILURE(rc))
+ {
+ RTStrPrintf(pszErr, cbErr, "RTManifestEntrySetAttr(,'%s','%s', '%s', %#x) failed on line %u: %Rrc",
+ pszName, pszAttr, pszValue, fType, iLine, rc);
+ return rc;
+ }
+ }
+}
+
+RTDECL(int) RTManifestReadStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos)
+{
+ return RTManifestReadStandardEx(hManifest, hVfsIos, NULL, 0);
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Writes RTMANIFESTATTR.}
+ */
+static DECLCALLBACK(int) rtManifestWriteStdAttr(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
+ RTMANIFESTWRITESTDATTR *pArgs = (RTMANIFESTWRITESTDATTR *)pvUser;
+ char szLine[RTPATH_MAX + RTSHA512_DIGEST_LEN + 32];
+ size_t cchLine = RTStrPrintf(szLine, sizeof(szLine), "%s (%s) = %s\n", pAttr->szName, pArgs->pszEntry, pAttr->pszValue);
+ if (cchLine >= sizeof(szLine) - 1)
+ return VERR_BUFFER_OVERFLOW;
+ return RTVfsIoStrmWrite(pArgs->hVfsIos, szLine, cchLine, true /*fBlocking*/, NULL);
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Writes RTMANIFESTENTRY.}
+ */
+static DECLCALLBACK(int) rtManifestWriteStdEntry(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
+
+ RTMANIFESTWRITESTDATTR Args;
+ Args.hVfsIos = (RTVFSIOSTREAM)pvUser;
+ Args.pszEntry = pStr->pszString;
+ return RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestWriteStdAttr, &Args);
+}
+
+
+RTDECL(int) RTManifestWriteStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos)
+{
+ RTMANIFESTINT *pThis = hManifest;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
+
+ RTMANIFESTWRITESTDATTR Args;
+ Args.hVfsIos = hVfsIos;
+ Args.pszEntry = "main";
+ int rc = RTStrSpaceEnumerate(&pThis->SelfEntry.Attributes, rtManifestWriteStdAttr, &Args);
+ if (RT_SUCCESS(rc))
+ rc = RTStrSpaceEnumerate(&pThis->Entries, rtManifestWriteStdEntry, hVfsIos);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/manifest3.cpp b/src/VBox/Runtime/common/checksum/manifest3.cpp
new file mode 100644
index 00000000..8309d637
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/manifest3.cpp
@@ -0,0 +1,667 @@
+/* $Id: manifest3.cpp $ */
+/** @file
+ * IPRT - Manifest, the bits with the most dependencies.
+ */
+
+/*
+ * Copyright (C) 2010-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/manifest.h>
+
+#include <iprt/alloca.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/md5.h>
+#include <iprt/mem.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
+#include <iprt/vfs.h>
+#include <iprt/vfslowlevel.h>
+#include <iprt/zero.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Hashes data.
+ *
+ * Used when hashing a file, stream or similar.
+ */
+typedef struct RTMANIFESTHASHES
+{
+ /** The desired attribute types.
+ * Only the hashes indicated by this will be calculated. */
+ uint32_t fAttrs;
+ /** The size. */
+ RTFOFF cbStream;
+
+ /** The MD5 context. */
+ RTMD5CONTEXT Md5Ctx;
+ /** The SHA-1 context. */
+ RTSHA1CONTEXT Sha1Ctx;
+ /** The SHA-256 context. */
+ RTSHA256CONTEXT Sha256Ctx;
+ /** The SHA-512 context. */
+ RTSHA512CONTEXT Sha512Ctx;
+
+ /** The MD5 digest. */
+ uint8_t abMd5Digest[RTMD5_HASH_SIZE];
+ /** The SHA-1 digest. */
+ uint8_t abSha1Digest[RTSHA1_HASH_SIZE];
+ /** The SHA-256 digest. */
+ uint8_t abSha256Digest[RTSHA256_HASH_SIZE];
+ /** The SHA-512 digest. */
+ uint8_t abSha512Digest[RTSHA512_HASH_SIZE];
+} RTMANIFESTHASHES;
+/** Pointer to a the hashes for a stream. */
+typedef RTMANIFESTHASHES *PRTMANIFESTHASHES;
+
+
+/**
+ * The internal data of a manifest passthru I/O stream.
+ */
+typedef struct RTMANIFESTPTIOS
+{
+ /** The stream we're reading from or writing to. */
+ RTVFSIOSTREAM hVfsIos;
+ /** The hashes. */
+ PRTMANIFESTHASHES pHashes;
+ /** The current hash position. */
+ RTFOFF offCurPos;
+ /** Whether we're reading or writing. */
+ bool fReadOrWrite;
+ /** Whether we've already added the entry to the manifest. */
+ bool fAddedEntry;
+ /** The entry name. */
+ char *pszEntry;
+ /** The manifest to add the entry to. */
+ RTMANIFEST hManifest;
+} RTMANIFESTPTIOS;
+/** Pointer to a the internal data of a manifest passthru I/O stream. */
+typedef RTMANIFESTPTIOS *PRTMANIFESTPTIOS;
+
+
+
+/**
+ * Creates a hashes structure.
+ *
+ * @returns Pointer to a hashes structure.
+ * @param fAttrs The desired hashes, RTMANIFEST_ATTR_XXX.
+ */
+static PRTMANIFESTHASHES rtManifestHashesCreate(uint32_t fAttrs)
+{
+ PRTMANIFESTHASHES pHashes = (PRTMANIFESTHASHES)RTMemTmpAllocZ(sizeof(*pHashes));
+ if (pHashes)
+ {
+ pHashes->fAttrs = fAttrs;
+ /*pHashes->cbStream = 0;*/
+ if (fAttrs & RTMANIFEST_ATTR_MD5)
+ RTMd5Init(&pHashes->Md5Ctx);
+ if (fAttrs & RTMANIFEST_ATTR_SHA1)
+ RTSha1Init(&pHashes->Sha1Ctx);
+ if (fAttrs & RTMANIFEST_ATTR_SHA256)
+ RTSha256Init(&pHashes->Sha256Ctx);
+ if (fAttrs & RTMANIFEST_ATTR_SHA512)
+ RTSha512Init(&pHashes->Sha512Ctx);
+ }
+ return pHashes;
+}
+
+
+/**
+ * Updates the hashes with a block of data.
+ *
+ * @param pHashes The hashes structure.
+ * @param pvBuf The data block.
+ * @param cbBuf The size of the data block.
+ */
+static void rtManifestHashesUpdate(PRTMANIFESTHASHES pHashes, void const *pvBuf, size_t cbBuf)
+{
+ pHashes->cbStream += cbBuf;
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
+ RTMd5Update(&pHashes->Md5Ctx, pvBuf, cbBuf);
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
+ RTSha1Update(&pHashes->Sha1Ctx, pvBuf, cbBuf);
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
+ RTSha256Update(&pHashes->Sha256Ctx, pvBuf, cbBuf);
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
+ RTSha512Update(&pHashes->Sha512Ctx, pvBuf, cbBuf);
+}
+
+
+/**
+ * Finalizes all the hashes.
+ *
+ * @param pHashes The hashes structure.
+ */
+static void rtManifestHashesFinal(PRTMANIFESTHASHES pHashes)
+{
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
+ RTMd5Final(pHashes->abMd5Digest, &pHashes->Md5Ctx);
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
+ RTSha1Final(&pHashes->Sha1Ctx, pHashes->abSha1Digest);
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
+ RTSha256Final(&pHashes->Sha256Ctx, pHashes->abSha256Digest);
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
+ RTSha512Final(&pHashes->Sha512Ctx, pHashes->abSha512Digest);
+}
+
+
+/**
+ * Adds the hashes to a manifest entry.
+ *
+ * @returns IPRT status code.
+ * @param pHashes The hashes structure.
+ * @param hManifest The manifest to add them to.
+ * @param pszEntry The entry name.
+ */
+static int rtManifestHashesSetAttrs(PRTMANIFESTHASHES pHashes, RTMANIFEST hManifest, const char *pszEntry)
+{
+ char szValue[RTSHA512_DIGEST_LEN + 8];
+ int rc = VINF_SUCCESS;
+ int rc2;
+
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SIZE)
+ {
+ RTStrPrintf(szValue, sizeof(szValue), "%RU64", (uint64_t)pHashes->cbStream);
+ rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SIZE", szValue, RTMANIFEST_ATTR_SIZE);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
+ {
+ rc2 = RTMd5ToString(pHashes->abMd5Digest, szValue, sizeof(szValue));
+ if (RT_SUCCESS(rc2))
+ rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "MD5", szValue, RTMANIFEST_ATTR_MD5);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
+ {
+ rc2 = RTSha1ToString(pHashes->abSha1Digest, szValue, sizeof(szValue));
+ if (RT_SUCCESS(rc2))
+ rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA1", szValue, RTMANIFEST_ATTR_SHA1);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
+ {
+ rc2 = RTSha256ToString(pHashes->abSha256Digest, szValue, sizeof(szValue));
+ if (RT_SUCCESS(rc2))
+ rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA256", szValue, RTMANIFEST_ATTR_SHA256);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
+ {
+ rc2 = RTSha512ToString(pHashes->abSha512Digest, szValue, sizeof(szValue));
+ if (RT_SUCCESS(rc2))
+ rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA512", szValue, RTMANIFEST_ATTR_SHA512);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ return rc;
+}
+
+
+/**
+ * Destroys the hashes.
+ *
+ * @param pHashes The hashes structure. NULL is ignored.
+ */
+static void rtManifestHashesDestroy(PRTMANIFESTHASHES pHashes)
+{
+ RTMemTmpFree(pHashes);
+}
+
+
+
+/*
+ *
+ * M a n i f e s t p a s s t h r u I / O s t r e a m
+ * M a n i f e s t p a s s t h r u I / O s t r e a m
+ * M a n i f e s t p a s s t h r u I / O s t r e a m
+ *
+ */
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnClose}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_Close(void *pvThis)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+
+ int rc = VINF_SUCCESS;
+ if (!pThis->fAddedEntry)
+ {
+ rtManifestHashesFinal(pThis->pHashes);
+ rc = rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
+ }
+
+ RTVfsIoStrmRelease(pThis->hVfsIos);
+ pThis->hVfsIos = NIL_RTVFSIOSTREAM;
+ rtManifestHashesDestroy(pThis->pHashes);
+ pThis->pHashes = NULL;
+ RTStrFree(pThis->pszEntry);
+ pThis->pszEntry = NULL;
+ RTManifestRelease(pThis->hManifest);
+ pThis->hManifest = NIL_RTMANIFEST;
+
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+ return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
+}
+
+/**
+ * Updates the hashes with a scather/gather buffer.
+ *
+ * @param pThis The passthru I/O stream instance data.
+ * @param pSgBuf The scather/gather buffer.
+ * @param cbLeft The number of bytes to take from the buffer.
+ */
+static void rtManifestPtIos_UpdateHashes(PRTMANIFESTPTIOS pThis, PCRTSGBUF pSgBuf, size_t cbLeft)
+{
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ {
+ size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
+ if (cbSeg > cbLeft)
+ cbSeg = cbLeft;
+ rtManifestHashesUpdate(pThis->pHashes, pSgBuf->paSegs[iSeg].pvSeg, cbSeg);
+ cbLeft -= cbSeg;
+ if (!cbLeft)
+ break;
+ }
+}
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+ int rc;
+
+ /*
+ * To make sure we're continuing where we left off, we must have the exact
+ * stream position since a previous read using 'off' may change it.
+ */
+ RTFOFF offActual = off == -1 ? RTVfsIoStrmTell(pThis->hVfsIos) : off;
+ if (offActual == pThis->offCurPos)
+ {
+ rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
+ if (RT_SUCCESS(rc))
+ {
+ rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbRead ? *pcbRead : ~(size_t)0);
+ if (!pcbRead)
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ pThis->offCurPos += pSgBuf->paSegs[iSeg].cbSeg;
+ else
+ pThis->offCurPos += *pcbRead;
+ }
+ Assert(RTVfsIoStrmTell(pThis->hVfsIos) == pThis->offCurPos);
+ }
+ else
+ {
+ /*
+ * If we're skipping over stuff, we need to read the gap and hash it.
+ */
+ if (pThis->offCurPos < offActual)
+ {
+ size_t cbBuf = _8K;
+ void *pvBuf = alloca(cbBuf);
+ do
+ {
+ RTFOFF cbGap = off - pThis->offCurPos;
+ size_t cbThisRead = cbGap >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbGap;
+ size_t cbActual;
+ rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offCurPos, pvBuf, cbThisRead, fBlocking, &cbActual);
+ if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN)
+ return rc;
+
+ rtManifestHashesUpdate(pThis->pHashes, pvBuf, cbActual);
+ pThis->offCurPos += cbActual;
+
+ if (rc == VINF_EOF)
+ {
+ if (pcbRead)
+ *pcbRead = 0;
+ else
+ rc = VERR_EOF;
+ return rc;
+ }
+ } while (pThis->offCurPos < offActual);
+ Assert(RTVfsIoStrmTell(pThis->hVfsIos) == offActual);
+ }
+
+ /*
+ * At this point we've eliminated any gap and can execute the requested read.
+ */
+ rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
+ if (RT_SUCCESS(rc))
+ {
+ /* See if there is anything to update the hash with. */
+ size_t cbLeft = pcbRead ? *pcbRead : ~(size_t)0;
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ {
+ size_t cbThis = pSgBuf->paSegs[iSeg].cbSeg;
+ if (cbThis > cbLeft)
+ cbThis = cbLeft;
+
+ if ( offActual >= pThis->offCurPos
+ && pThis->offCurPos < offActual + (ssize_t)cbThis)
+ {
+ size_t offSeg = (size_t)(offActual - pThis->offCurPos);
+ rtManifestHashesUpdate(pThis->pHashes, (uint8_t *)pSgBuf->paSegs[iSeg].pvSeg + offSeg, cbThis - offSeg);
+ pThis->offCurPos += cbThis - offSeg;
+ }
+
+ cbLeft -= cbThis;
+ if (!cbLeft)
+ break;
+ offActual += cbThis;
+ }
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+ Assert(RTVfsIoStrmTell(pThis->hVfsIos) == pThis->offCurPos);
+
+ /*
+ * Validate the offset.
+ */
+ if (off < 0 || off == pThis->offCurPos)
+ { /* likely */ }
+ else
+ {
+ /* We cannot go back and rewrite stuff. Sorry. */
+ AssertReturn(off > pThis->offCurPos, VERR_WRONG_ORDER);
+
+ /*
+ * We've got a gap between the current and new position.
+ * Fill it with zeros and hope for the best.
+ */
+ uint64_t cbZeroGap = off - pThis->offCurPos;
+ do
+ {
+ size_t cbToZero = cbZeroGap >= sizeof(g_abRTZero64K) ? sizeof(g_abRTZero64K) : (size_t)cbZeroGap;
+ size_t cbZeroed = 0;
+ int rc = RTVfsIoStrmWrite(pThis->hVfsIos, g_abRTZero64K, cbToZero, true /*fBlocking*/, &cbZeroed);
+ if (RT_FAILURE(rc))
+ return rc;
+ pThis->offCurPos += cbZeroed;
+ rtManifestHashesUpdate(pThis->pHashes, g_abRTZero64K, cbZeroed);
+ cbZeroGap -= cbZeroed;
+ } while (cbZeroGap > 0);
+ Assert(off == pThis->offCurPos);
+ }
+
+ /*
+ * Do the writing.
+ */
+ int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
+ if (RT_SUCCESS(rc))
+ {
+ rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbWritten ? *pcbWritten : ~(size_t)0);
+ if (!pcbWritten)
+ for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
+ pThis->offCurPos += pSgBuf->paSegs[iSeg].cbSeg;
+ else
+ pThis->offCurPos += *pcbWritten;
+ }
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_Flush(void *pvThis)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+ return RTVfsIoStrmFlush(pThis->hVfsIos);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
+ uint32_t *pfRetEvents)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+ return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
+}
+
+
+/**
+ * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
+ */
+static DECLCALLBACK(int) rtManifestPtIos_Tell(void *pvThis, PRTFOFF poffActual)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
+ RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos);
+ if (off < 0)
+ return (int)off;
+ *poffActual = off;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * The manifest passthru I/O stream vtable.
+ */
+static RTVFSIOSTREAMOPS g_rtManifestPassthruIosOps =
+{
+ { /* Obj */
+ RTVFSOBJOPS_VERSION,
+ RTVFSOBJTYPE_IO_STREAM,
+ "manifest passthru I/O stream",
+ rtManifestPtIos_Close,
+ rtManifestPtIos_QueryInfo,
+ NULL,
+ RTVFSOBJOPS_VERSION
+ },
+ RTVFSIOSTREAMOPS_VERSION,
+ 0,
+ rtManifestPtIos_Read,
+ rtManifestPtIos_Write,
+ rtManifestPtIos_Flush,
+ rtManifestPtIos_PollOne,
+ rtManifestPtIos_Tell,
+ NULL /* Skip */,
+ NULL /* ZeroFill */,
+ RTVFSIOSTREAMOPS_VERSION,
+};
+
+
+
+RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry,
+ uint32_t fAttrs, bool fReadOrWrite, PRTVFSIOSTREAM phVfsIosPassthru)
+{
+ /*
+ * Validate input.
+ */
+ AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
+ AssertPtr(pszEntry);
+ AssertPtr(phVfsIosPassthru);
+
+ RTFOFF const offCurPos = RTVfsIoStrmTell(hVfsIos);
+ AssertReturn(offCurPos >= 0, (int)offCurPos);
+
+ uint32_t cRefs = RTManifestRetain(hManifest);
+ AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
+
+ cRefs = RTVfsIoStrmRetain(hVfsIos);
+ AssertReturnStmt(cRefs != UINT32_MAX, RTManifestRelease(hManifest), VERR_INVALID_HANDLE);
+
+ /*
+ * Create an instace of the passthru I/O stream.
+ */
+ PRTMANIFESTPTIOS pThis;
+ RTVFSIOSTREAM hVfsPtIos;
+ int rc = RTVfsNewIoStream(&g_rtManifestPassthruIosOps, sizeof(*pThis), fReadOrWrite ? RTFILE_O_READ : RTFILE_O_WRITE,
+ NIL_RTVFS, NIL_RTVFSLOCK, &hVfsPtIos, (void **)&pThis);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->hVfsIos = hVfsIos;
+ pThis->pHashes = rtManifestHashesCreate(fAttrs);
+ pThis->offCurPos = offCurPos;
+ pThis->hManifest = hManifest;
+ pThis->fReadOrWrite = fReadOrWrite;
+ pThis->fAddedEntry = false;
+ pThis->pszEntry = RTStrDup(pszEntry);
+ if (pThis->pszEntry && pThis->pHashes)
+ {
+ *phVfsIosPassthru = hVfsPtIos;
+ return VINF_SUCCESS;
+ }
+
+ RTVfsIoStrmRelease(hVfsPtIos);
+ }
+ else
+ {
+ RTVfsIoStrmRelease(hVfsIos);
+ RTManifestRelease(hManifest);
+ }
+ return rc;
+}
+
+
+RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos)
+{
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
+ AssertReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(!pThis->fAddedEntry, VERR_WRONG_ORDER);
+
+ pThis->fAddedEntry = true;
+ rtManifestHashesFinal(pThis->pHashes);
+ return rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
+}
+
+
+RTDECL(bool) RTManifestPtIosIsInstanceOf(RTVFSIOSTREAM hVfsPtIos)
+{
+ if (hVfsPtIos != NIL_RTVFSIOSTREAM)
+ {
+ PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
+ if (pThis)
+ return true;
+ }
+ return false;
+}
+
+
+RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs)
+{
+ /*
+ * Note! This is a convenicence function, so just use the available public
+ * methods to get the job done.
+ */
+ AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
+ AssertPtr(pszEntry);
+
+ /*
+ * Allocate and initialize the hash contexts, hash digests and I/O buffer.
+ */
+ PRTMANIFESTHASHES pHashes = rtManifestHashesCreate(fAttrs);
+ if (!pHashes)
+ return VERR_NO_TMP_MEMORY;
+
+ int rc;
+ size_t cbBuf = _1M;
+ void *pvBuf = RTMemTmpAlloc(cbBuf);
+ if (RT_UNLIKELY(!pvBuf))
+ {
+ cbBuf = _4K;
+ pvBuf = RTMemTmpAlloc(cbBuf);
+ }
+ if (RT_LIKELY(pvBuf))
+ {
+ /*
+ * Process the stream data.
+ */
+ for (;;)
+ {
+ size_t cbRead;
+ rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
+ if ( (rc == VINF_EOF && cbRead == 0)
+ || RT_FAILURE(rc))
+ break;
+ rtManifestHashesUpdate(pHashes, pvBuf, cbRead);
+ }
+ RTMemTmpFree(pvBuf);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Add the entry with the finalized hashes.
+ */
+ rtManifestHashesFinal(pHashes);
+ rc = RTManifestEntryAdd(hManifest, pszEntry);
+ if (RT_SUCCESS(rc))
+ rc = rtManifestHashesSetAttrs(pHashes, hManifest, pszEntry);
+ }
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+
+ rtManifestHashesDestroy(pHashes);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/checksum/md2str.cpp b/src/VBox/Runtime/common/checksum/md2str.cpp
new file mode 100644
index 00000000..7c1e42d6
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/md2str.cpp
@@ -0,0 +1,59 @@
+/* $Id: md2str.cpp $ */
+/** @file
+ * IPRT - MD2 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/md2.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTMd2ToString(uint8_t const pabDigest[RTMD2_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTMD2_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTMd2FromString(char const *pszDigest, uint8_t pabDigest[RTMD2_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTMD2_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/md4str.cpp b/src/VBox/Runtime/common/checksum/md4str.cpp
new file mode 100644
index 00000000..615a718b
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/md4str.cpp
@@ -0,0 +1,59 @@
+/* $Id: md4str.cpp $ */
+/** @file
+ * IPRT - MD4 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/md4.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTMd4ToString(uint8_t const pabDigest[RTMD4_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTMD4_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTMd4FromString(char const *pszDigest, uint8_t pabDigest[RTMD4_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTMD4_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/md5str.cpp b/src/VBox/Runtime/common/checksum/md5str.cpp
new file mode 100644
index 00000000..08068c96
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/md5str.cpp
@@ -0,0 +1,59 @@
+/* $Id: md5str.cpp $ */
+/** @file
+ * IPRT - MD5 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/md5.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTMd5ToString(uint8_t const pabDigest[RTMD5_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTMD5_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTMd5FromString(char const *pszDigest, uint8_t pabDigest[RTMD5_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTMD5_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-md2.cpp b/src/VBox/Runtime/common/checksum/openssl-md2.cpp
new file mode 100644
index 00000000..cce35588
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-md2.cpp
@@ -0,0 +1,96 @@
+/* $Id: openssl-md2.cpp $ */
+/** @file
+ * IPRT - Message-Digest Algorithm 2.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+
+#include "internal/openssl-pre.h"
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_MD2
+# include <openssl/md2.h>
+#endif
+#include "internal/openssl-post.h"
+
+#ifndef OPENSSL_NO_MD2
+# define RT_MD2_PRIVATE_CONTEXT
+# include <iprt/md2.h>
+
+# include <iprt/assert.h>
+
+AssertCompile(RT_SIZEOFMEMB(RTMD2CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTMD2CONTEXT, Private));
+
+
+RTDECL(void) RTMd2(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD2_HASH_SIZE])
+{
+ RTMD2CONTEXT Ctx;
+ RTMd2Init(&Ctx);
+ RTMd2Update(&Ctx, pvBuf, cbBuf);
+ RTMd2Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTMd2);
+
+
+RTDECL(void) RTMd2Init(PRTMD2CONTEXT pCtx)
+{
+ MD2_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTMd2Init);
+
+
+RTDECL(void) RTMd2Update(PRTMD2CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ MD2_Update(&pCtx->Private, (const unsigned char *)pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTMd2Update);
+
+
+RTDECL(void) RTMd2Final(PRTMD2CONTEXT pCtx, uint8_t pabDigest[RTMD2_HASH_SIZE])
+{
+ MD2_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTMd2Final);
+
+
+#else /* OPENSSL_NO_MD2 */
+/*
+ * If the OpenSSL build doesn't have MD2, use the IPRT implementation.
+ */
+# include "alt-md2.cpp"
+#endif /* OPENSSL_NO_MD2 */
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-md4.cpp b/src/VBox/Runtime/common/checksum/openssl-md4.cpp
new file mode 100644
index 00000000..f670801e
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-md4.cpp
@@ -0,0 +1,94 @@
+/* $Id: openssl-md4.cpp $ */
+/** @file
+ * IPRT - Message-Digest Algorithm 4.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+
+#include "internal/openssl-pre.h"
+#include <openssl/opensslconf.h>
+#include "internal/openssl-post.h"
+#if 0 //ndef OPENSSL_NO_MD4
+# include <openssl/md4.h>
+
+# define RT_MD4_PRIVATE_CONTEXT
+# include <iprt/md4.h>
+
+# include <iprt/assert.h>
+
+AssertCompile(RT_SIZEOFMEMB(RTMD4CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTMD4CONTEXT, Private));
+
+
+RTDECL(void) RTMd4(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD4_HASH_SIZE])
+{
+ RTMD4CONTEXT Ctx;
+ RTMd4Init(&Ctx);
+ RTMd4Update(&Ctx, pvBuf, cbBuf);
+ RTMd4Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTMd4);
+
+
+RTDECL(void) RTMd4Init(PRTMD4CONTEXT pCtx)
+{
+ MD4_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTMd4Init);
+
+
+RTDECL(void) RTMd4Update(PRTMD4CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ MD4_Update(&pCtx->Private, (const unsigned char *)pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTMd4Update);
+
+
+RTDECL(void) RTMd4Final(PRTMD4CONTEXT pCtx, uint8_t pabDigest[RTMD4_HASH_SIZE])
+{
+ MD4_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTMd4Final);
+
+
+#else /* OPENSSL_NO_MD4 */
+/*
+ * If the OpenSSL build doesn't have MD4, use the IPRT implementation.
+ */
+# include "alt-md4.cpp"
+#endif /* OPENSSL_NO_MD4 */
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-md5.cpp b/src/VBox/Runtime/common/checksum/openssl-md5.cpp
new file mode 100644
index 00000000..57f7b5a6
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-md5.cpp
@@ -0,0 +1,84 @@
+/* $Id: openssl-md5.cpp $ */
+/** @file
+ * IPRT - MD5 message digest functions, implemented using OpenSSL.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+
+#include "internal/openssl-pre.h"
+#include <openssl/md5.h>
+#include "internal/openssl-post.h"
+
+#define RT_MD5_OPENSSL_PRIVATE_CONTEXT
+#include <iprt/md5.h>
+
+#include <iprt/assert.h>
+
+AssertCompile(RT_SIZEOFMEMB(RTMD5CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTMD5CONTEXT, OsslPrivate));
+
+
+RTDECL(void) RTMd5(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD5_HASH_SIZE])
+{
+ RTMD5CONTEXT Ctx;
+ RTMd5Init(&Ctx);
+ RTMd5Update(&Ctx, pvBuf, cbBuf);
+ RTMd5Final(pabDigest, &Ctx);
+}
+RT_EXPORT_SYMBOL(RTMd5);
+
+
+RTDECL(void) RTMd5Init(PRTMD5CONTEXT pCtx)
+{
+ MD5_Init(&pCtx->OsslPrivate);
+}
+RT_EXPORT_SYMBOL(RTMd5Init);
+
+
+RTDECL(void) RTMd5Update(PRTMD5CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ MD5_Update(&pCtx->OsslPrivate, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTMd5Update);
+
+
+RTDECL(void) RTMd5Final(uint8_t pabDigest[32], PRTMD5CONTEXT pCtx)
+{
+ MD5_Final((unsigned char *)&pabDigest[0], &pCtx->OsslPrivate);
+}
+RT_EXPORT_SYMBOL(RTMd5Final);
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha1.cpp b/src/VBox/Runtime/common/checksum/openssl-sha1.cpp
new file mode 100644
index 00000000..7caad607
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-sha1.cpp
@@ -0,0 +1,100 @@
+/* $Id: openssl-sha1.cpp $ */
+/** @file
+ * IPRT - SHA-1 hash functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+
+#include "internal/openssl-pre.h"
+#include <openssl/sha.h>
+#include "internal/openssl-post.h"
+
+#define RT_SHA1_PRIVATE_CONTEXT
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+AssertCompile(RT_SIZEOFMEMB(RTSHA1CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA1CONTEXT, Private));
+
+
+RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+{
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+ RTSha1Update(&Ctx, pvBuf, cbBuf);
+ RTSha1Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha1);
+
+
+RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA1_HASH_SIZE])
+{
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+ RTSha1Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA1_HASH_SIZE];
+ RTSha1Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA1_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha1Check);
+
+
+RTDECL(void) RTSha1Init(PRTSHA1CONTEXT pCtx)
+{
+ SHA1_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha1Init);
+
+
+RTDECL(void) RTSha1Update(PRTSHA1CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ SHA1_Update(&pCtx->Private, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha1Update);
+
+
+RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+{
+ SHA1_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha1Final);
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha256.cpp b/src/VBox/Runtime/common/checksum/openssl-sha256.cpp
new file mode 100644
index 00000000..81659680
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-sha256.cpp
@@ -0,0 +1,150 @@
+/* $Id: openssl-sha256.cpp $ */
+/** @file
+ * IPRT - SHA-256 hash functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+
+#include "internal/openssl-pre.h"
+#include <openssl/sha.h>
+#include "internal/openssl-post.h"
+
+#define RT_SHA256_PRIVATE_CONTEXT
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+AssertCompile(RT_SIZEOFMEMB(RTSHA256CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA256CONTEXT, Private));
+
+
+RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA256_HASH_SIZE])
+{
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+ RTSha256Update(&Ctx, pvBuf, cbBuf);
+ RTSha256Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha256);
+
+
+RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA256_HASH_SIZE])
+{
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+ RTSha256Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA256_HASH_SIZE];
+ RTSha256Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA256_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha256Check);
+
+
+RTDECL(void) RTSha256Init(PRTSHA256CONTEXT pCtx)
+{
+ SHA256_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha256Init);
+
+
+RTDECL(void) RTSha256Update(PRTSHA256CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ SHA256_Update(&pCtx->Private, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha256Update);
+
+
+RTDECL(void) RTSha256Final(PRTSHA256CONTEXT pCtx, uint8_t pabDigest[32])
+{
+ SHA256_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha256Final);
+
+
+/*
+ * We have to expose the same API as alt-sha256.cpp, so the SHA-224
+ * implementation also lives here. (SHA-224 is just a truncated SHA-256 with
+ * different initial values.)
+ */
+RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA224_HASH_SIZE])
+{
+ RTSHA224CONTEXT Ctx;
+ RTSha224Init(&Ctx);
+ RTSha224Update(&Ctx, pvBuf, cbBuf);
+ RTSha224Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha224);
+
+
+RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA224_HASH_SIZE])
+{
+ RTSHA224CONTEXT Ctx;
+ RTSha224Init(&Ctx);
+ RTSha224Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA224_HASH_SIZE];
+ RTSha224Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA224_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha224Check);
+
+
+RTDECL(void) RTSha224Init(PRTSHA224CONTEXT pCtx)
+{
+ SHA224_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha224Init);
+
+
+RTDECL(void) RTSha224Update(PRTSHA224CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ SHA224_Update(&pCtx->Private, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha224Update);
+
+
+RTDECL(void) RTSha224Final(PRTSHA224CONTEXT pCtx, uint8_t pabDigest[32])
+{
+ SHA224_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha224Final);
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha3.cpp b/src/VBox/Runtime/common/checksum/openssl-sha3.cpp
new file mode 100644
index 00000000..9302b53f
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-sha3.cpp
@@ -0,0 +1,270 @@
+/* $Id: openssl-sha3.cpp $ */
+/** @file
+ * IPRT - SHA-3 hash functions, OpenSSL based implementation.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#if 1 /* For now: */
+# include "alt-sha3.cpp"
+
+#else
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+#include "internal/openssl-pre.h"
+#include <openssl/evp.h>
+#include "internal/openssl-post.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define RTSHA3PRIVATECTX_MAGIC UINT64_C(0xb6362d323c56b758)
+#define RTSHA3PRIVATECTX_MAGIC_FINAL UINT64_C(0x40890fe0e474215d)
+#define RTSHA3PRIVATECTX_MAGIC_DEAD UINT64_C(0xdead7a05081cbeef)
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/* Internal EVP structure that we fake here to avoid lots of casting. */
+struct evp_md_ctx_st
+{
+ void *apvWhatever[10];
+};
+
+/** The OpenSSL private context structure. */
+typedef struct RTSHA3PRIVATECTX
+{
+ /** RTSHA3PRIVATECTX_MAGIC / RTSHA3PRIVATECTX_MAGIC_FINAL / RTSHA3PRIVATECTX_MAGIC_DEAD */
+ uint64_t u64Magic;
+ /** The OpenSSL context. We cheat to avoid EVP_MD_CTX_new/free. */
+ struct evp_md_ctx_st MdCtx;
+} RTSHA3PRIVATECTX;
+
+#define RT_SHA3_PRIVATE_CONTEXT
+#include <iprt/sha.h>
+AssertCompile(RT_SIZEOFMEMB(RTSHA3CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA3CONTEXT, Private));
+
+
+
+static int rtSha3Init(PRTSHA3CONTEXT pCtx, const EVP_MD *pMdType)
+{
+ RT_ZERO(*pCtx); /* This is what EVP_MD_CTX_new does. */
+ pCtx->Private.u64Magic = RTSHA3PRIVATECTX_MAGIC;
+
+ AssertReturnStmt(EVP_DigestInit_ex(&pCtx->Private.MdCtx, pMdType, NULL /*engine*/),
+ pCtx->Private.u64Magic = RTSHA3PRIVATECTX_MAGIC_DEAD,
+ VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR);
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3Update(PRTSHA3CONTEXT pCtx, uint8_t const *pbData, size_t cbData)
+{
+ AssertMsgReturn(pCtx->Private.u64Magic == RTSHA3PRIVATECTX_MAGIC, ("u64Magic=%RX64\n", pCtx->Private.u64Magic),
+ VERR_INVALID_CONTEXT);
+ AssertReturn(EVP_DigestUpdate(&pCtx->Private.MdCtx, pbData, cbData), VERR_GENERAL_FAILURE);
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3Final(PRTSHA3CONTEXT pCtx, uint8_t *pbDigest, size_t cbDigest)
+{
+ RT_BZERO(pbDigest, cbDigest);
+ AssertMsgReturn(pCtx->Private.u64Magic == RTSHA3PRIVATECTX_MAGIC, ("u64Magic=%RX64\n", pCtx->Private.u64Magic),
+ VERR_INVALID_CONTEXT);
+ AssertReturn(EVP_DigestFinal_ex(&pCtx->Private.MdCtx, pbDigest, NULL), VERR_GENERAL_FAILURE);
+
+ /* Implicit cleanup. */
+ EVP_MD_CTX_reset(&pCtx->Private.MdCtx);
+ pCtx->Private.u64Magic = RTSHA3PRIVATECTX_MAGIC_FINAL;
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3Cleanup(PRTSHA3CONTEXT pCtx)
+{
+ if (pCtx)
+ {
+ if (pCtx->Private.u64Magic == RTSHA3PRIVATECTX_MAGIC_FINAL)
+ { /* likely */ }
+ else if (pCtx->Private.u64Magic == RTSHA3PRIVATECTX_MAGIC)
+ EVP_MD_CTX_reset(&pCtx->Private.MdCtx);
+ else
+ AssertMsgFailedReturn(("u64Magic=%RX64\n", pCtx->Private.u64Magic), VERR_INVALID_CONTEXT);
+ pCtx->Private.u64Magic = RTSHA3PRIVATECTX_MAGIC_DEAD;
+ }
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3Clone(PRTSHA3CONTEXT pCtx, RTSHA3CONTEXT const *pCtxSrc)
+{
+ Assert(pCtx->Private.u64Magic != RTSHA3PRIVATECTX_MAGIC);
+ RT_ZERO(*pCtx); /* This is what EVP_MD_CTX_new does. */
+
+ AssertReturn(pCtxSrc->Private.u64Magic == RTSHA3PRIVATECTX_MAGIC, VERR_INVALID_CONTEXT);
+
+ pCtx->Private.u64Magic = RTSHA3PRIVATECTX_MAGIC;
+ AssertReturnStmt(EVP_MD_CTX_copy_ex(&pCtx->Private.MdCtx, &pCtxSrc->Private.MdCtx),
+ pCtx->Private.u64Magic = RTSHA3PRIVATECTX_MAGIC_DEAD,
+ VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR);
+ return VINF_SUCCESS;
+}
+
+
+static int rtSha3(const void *pvData, size_t cbData, const EVP_MD *pMdType, uint8_t *pabHash, size_t cbHash)
+{
+ RT_BZERO(pabHash, cbHash);
+
+ int rc;
+ EVP_MD_CTX *pCtx = EVP_MD_CTX_new();
+ if (pCtx)
+ {
+ if (EVP_DigestInit_ex(pCtx, pMdType, NULL /*engine*/))
+ {
+ if (EVP_DigestUpdate(pCtx, pvData, cbData))
+ {
+ if (EVP_DigestFinal_ex(pCtx, pabHash, NULL))
+ rc = VINF_SUCCESS;
+ else
+ AssertFailedStmt(rc = VERR_GENERAL_FAILURE);
+ }
+ else
+ AssertFailedStmt(rc = VERR_GENERAL_FAILURE);
+ }
+ else
+ AssertFailedStmt(rc = VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR);
+ EVP_MD_CTX_free(pCtx);
+ }
+ else
+ AssertFailedStmt(rc = VERR_NO_MEMORY);
+ return rc;
+}
+
+
+static bool rtSha3Check(const void *pvData, size_t cbData, const EVP_MD *pMdType,
+ const uint8_t *pabHash, uint8_t *pabHashTmp, size_t cbHash)
+{
+ int rc = rtSha3(pvData, cbData, pMdType, pabHashTmp, cbHash);
+ return RT_SUCCESS(rc) && memcmp(pabHash, pabHashTmp, cbHash) == 0;
+}
+
+
+/** Macro for declaring the interface for a SHA3 variation.
+ * @internal */
+#define RTSHA3_DEFINE_VARIANT(a_cBits, a_pMdType) \
+AssertCompile((a_cBits / 8) == RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)); \
+\
+RTDECL(int) RT_CONCAT(RTSha3t,a_cBits)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ return rtSha3(pvBuf, cbBuf, a_pMdType, pabHash, (a_cBits) / 8); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT(RTSha3t,a_cBits)); \
+\
+\
+RTDECL(bool) RT_CONCAT3(RTSha3t,a_cBits,Check)(const void *pvBuf, size_t cbBuf, \
+ uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ uint8_t abHashTmp[(a_cBits) / 8]; \
+ return rtSha3Check(pvBuf, cbBuf, a_pMdType, pabHash, abHashTmp, (a_cBits) / 8); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Check)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Init)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx) \
+{ \
+ return rtSha3Init(&pCtx->Sha3, a_pMdType); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Init)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Update)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf) \
+{ \
+ return rtSha3Update(&pCtx->Sha3, (uint8_t const *)pvBuf, cbBuf); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Update)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Final)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, \
+ uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ return rtSha3Final(&pCtx->Sha3, pabHash, (a_cBits) / 8); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Final)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Cleanup)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx) \
+{ \
+ return rtSha3Cleanup(&pCtx->Sha3); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Cleanup)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Clone)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, \
+ RT_CONCAT3(RTSHA3T,a_cBits,CONTEXT) const *pCtxSrc) \
+{ \
+ return rtSha3Clone(&pCtx->Sha3, &pCtxSrc->Sha3); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Clone)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)], \
+ char *pszDigest, size_t cchDigest) \
+{ \
+ return RTStrPrintHexBytes(pszDigest, cchDigest, pabHash, (a_cBits) / 8, 0 /*fFlags*/); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,ToString)); \
+\
+\
+RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
+{ \
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabHash[0], (a_cBits) / 8, 0 /*fFlags*/); \
+} \
+RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,FromString))
+
+
+RTSHA3_DEFINE_VARIANT(224, EVP_sha3_224());
+RTSHA3_DEFINE_VARIANT(256, EVP_sha3_256());
+RTSHA3_DEFINE_VARIANT(384, EVP_sha3_384());
+RTSHA3_DEFINE_VARIANT(512, EVP_sha3_512());
+
+#endif /* !alt-sha3.cpp */
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha512.cpp b/src/VBox/Runtime/common/checksum/openssl-sha512.cpp
new file mode 100644
index 00000000..37a80bec
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/openssl-sha512.cpp
@@ -0,0 +1,151 @@
+/* $Id: openssl-sha512.cpp $ */
+/** @file
+ * IPRT - SHA-512 hash functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+
+#include "internal/openssl-pre.h"
+#include <openssl/sha.h>
+#include "internal/openssl-post.h"
+
+#define RT_SHA512_PRIVATE_CONTEXT
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+AssertCompile(RT_SIZEOFMEMB(RTSHA512CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA512CONTEXT, Private));
+
+
+RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA512_HASH_SIZE])
+{
+ RTSHA512CONTEXT Ctx;
+ RTSha512Init(&Ctx);
+ RTSha512Update(&Ctx, pvBuf, cbBuf);
+ RTSha512Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha512);
+
+
+RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA512_HASH_SIZE])
+{
+ RTSHA512CONTEXT Ctx;
+ RTSha512Init(&Ctx);
+ RTSha512Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA512_HASH_SIZE];
+ RTSha512Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA512_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512Check);
+
+
+RTDECL(void) RTSha512Init(PRTSHA512CONTEXT pCtx)
+{
+ SHA512_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha512Init);
+
+
+RTDECL(void) RTSha512Update(PRTSHA512CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ SHA512_Update(&pCtx->Private, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha512Update);
+
+
+RTDECL(void) RTSha512Final(PRTSHA512CONTEXT pCtx, uint8_t pabDigest[32])
+{
+ SHA512_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha512Final);
+
+
+/*
+ * We have to expose the same API as alt-sha512.cpp, so the SHA-384,
+ * SHA-512/224 and SHA-512/256 implementations also live here. (They are all
+ * just truncted SHA-512 with different initial values.)
+ */
+
+RTDECL(void) RTSha384(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA384_HASH_SIZE])
+{
+ RTSHA384CONTEXT Ctx;
+ RTSha384Init(&Ctx);
+ RTSha384Update(&Ctx, pvBuf, cbBuf);
+ RTSha384Final(&Ctx, pabDigest);
+}
+RT_EXPORT_SYMBOL(RTSha384);
+
+
+RTDECL(bool) RTSha384Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA384_HASH_SIZE])
+{
+ RTSHA384CONTEXT Ctx;
+ RTSha384Init(&Ctx);
+ RTSha384Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA384_HASH_SIZE];
+ RTSha384Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA384_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha384Check);
+
+
+RTDECL(void) RTSha384Init(PRTSHA384CONTEXT pCtx)
+{
+ SHA384_Init(&pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha384Init);
+
+
+RTDECL(void) RTSha384Update(PRTSHA384CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
+{
+ SHA384_Update(&pCtx->Private, pvBuf, cbBuf);
+}
+RT_EXPORT_SYMBOL(RTSha384Update);
+
+
+RTDECL(void) RTSha384Final(PRTSHA384CONTEXT pCtx, uint8_t pabDigest[32])
+{
+ SHA384_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
+}
+RT_EXPORT_SYMBOL(RTSha384Final);
+
diff --git a/src/VBox/Runtime/common/checksum/sha1str.cpp b/src/VBox/Runtime/common/checksum/sha1str.cpp
new file mode 100644
index 00000000..39574cde
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha1str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha1str.cpp $ */
+/** @file
+ * IPRT - SHA-1 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha1ToString(uint8_t const pabDigest[RTSHA1_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA1_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha1FromString(char const *pszDigest, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA1_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/sha224str.cpp b/src/VBox/Runtime/common/checksum/sha224str.cpp
new file mode 100644
index 00000000..0c5bdc04
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha224str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha224str.cpp $ */
+/** @file
+ * IPRT - SHA-224 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha224ToString(uint8_t const pabDigest[RTSHA224_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA224_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha224FromString(char const *pszDigest, uint8_t pabDigest[RTSHA224_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA224_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/sha256str.cpp b/src/VBox/Runtime/common/checksum/sha256str.cpp
new file mode 100644
index 00000000..bcd4284d
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha256str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha256str.cpp $ */
+/** @file
+ * IPRT - SHA-256 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha256ToString(uint8_t const pabDigest[RTSHA256_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA256_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha256FromString(char const *pszDigest, uint8_t pabDigest[RTSHA256_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA256_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/sha384str.cpp b/src/VBox/Runtime/common/checksum/sha384str.cpp
new file mode 100644
index 00000000..29fe4b5e
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha384str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha384str.cpp $ */
+/** @file
+ * IPRT - SHA-384 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha384ToString(uint8_t const pabDigest[RTSHA384_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA384_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha384FromString(char const *pszDigest, uint8_t pabDigest[RTSHA384_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA384_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/sha512str.cpp b/src/VBox/Runtime/common/checksum/sha512str.cpp
new file mode 100644
index 00000000..35b1d5ea
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha512str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha512str.cpp $ */
+/** @file
+ * IPRT - SHA-512 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha512ToString(uint8_t const pabDigest[RTSHA512_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA512_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha512FromString(char const *pszDigest, uint8_t pabDigest[RTSHA512_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA512_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/sha512t224str.cpp b/src/VBox/Runtime/common/checksum/sha512t224str.cpp
new file mode 100644
index 00000000..eb237588
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha512t224str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha512t224str.cpp $ */
+/** @file
+ * IPRT - SHA-512/224 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha512t224ToString(uint8_t const pabDigest[RTSHA512T224_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA512T224_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha512t224FromString(char const *pszDigest, uint8_t pabDigest[RTSHA512T224_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA512T224_HASH_SIZE, 0 /*fFlags*/);
+}
+
diff --git a/src/VBox/Runtime/common/checksum/sha512t256str.cpp b/src/VBox/Runtime/common/checksum/sha512t256str.cpp
new file mode 100644
index 00000000..c95cf752
--- /dev/null
+++ b/src/VBox/Runtime/common/checksum/sha512t256str.cpp
@@ -0,0 +1,59 @@
+/* $Id: sha512t256str.cpp $ */
+/** @file
+ * IPRT - SHA-512/256 string functions.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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 a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/sha.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTSha512t256ToString(uint8_t const pabDigest[RTSHA512T256_HASH_SIZE], char *pszDigest, size_t cchDigest)
+{
+ return RTStrPrintHexBytes(pszDigest, cchDigest, &pabDigest[0], RTSHA512T256_HASH_SIZE, 0 /*fFlags*/);
+}
+
+
+RTDECL(int) RTSha512t256FromString(char const *pszDigest, uint8_t pabDigest[RTSHA512T256_HASH_SIZE])
+{
+ return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA512T256_HASH_SIZE, 0 /*fFlags*/);
+}
+