diff options
Diffstat (limited to 'src/VBox/Runtime/common/checksum')
37 files changed, 9105 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..eaf4081c --- /dev/null +++ b/src/VBox/Runtime/common/checksum/RTSha1Digest.cpp @@ -0,0 +1,191 @@ +/* $Id: RTSha1Digest.cpp $ */ +/** @file + * IPRT - SHA1 digest creation + * + * @todo Replace this with generic RTCrDigest based implementation. Too much + * stupid code duplication. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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 ? 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); + RTSha1Update(&Ctx, pvTmp, cbRead); + cbReadTotal += cbRead; + pvTmp += cbRead; + + /* Call the progress callback if one is defined */ + if (pfnProgressCallback) + { + rc = pfnProgressCallback((unsigned)(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; + if (pfnProgressCallback) + { + uint64_t cbFile; + rc = RTFileGetSize(hFile, &cbFile); + if (RT_FAILURE(rc)) + { + RTFileClose(hFile); + return rc; + } + rdMulti = 100.0 / (cbFile ? cbFile : 1); + } + + /* 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)(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..cc4c13dd --- /dev/null +++ b/src/VBox/Runtime/common/checksum/RTSha256Digest.cpp @@ -0,0 +1,191 @@ +/* $Id: RTSha256Digest.cpp $ */ +/** @file + * IPRT - SHA256 digest creation + * + * @todo Replace this with generic RTCrDigest based implementation. Too much + * stupid code duplication. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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 ? 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)(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; + if (pfnProgressCallback) + { + uint64_t cbFile; + rc = RTFileGetSize(hFile, &cbFile); + if (RT_FAILURE(rc)) + { + RTFileClose(hFile); + return rc; + } + rdMulti = 100.0 / (cbFile ? cbFile : 1); + } + + /* 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)(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..2908e17f --- /dev/null +++ b/src/VBox/Runtime/common/checksum/adler32.cpp @@ -0,0 +1,171 @@ +/* $Id: adler32.cpp $ */ +/** @file + * IPRT - Adler-32 + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..53801dd4 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/alt-md2.cpp @@ -0,0 +1,272 @@ +/* $Id: alt-md2.cpp $ */ +/** @file + * IPRT - Message-Digest Algorithm 2, Alternative Implementation. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..e40d7d92 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/alt-md4.cpp @@ -0,0 +1,283 @@ +/* $Id: alt-md4.cpp $ */ +/** @file + * IPRT - Message-Digest Algorithm 4, Alternative Implementation. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..d4e3fa45 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/alt-md5.cpp @@ -0,0 +1,364 @@ +/* $Id: alt-md5.cpp $ */ +/** @file + * IPRT - MD5 message digest functions, alternative implementation. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + +/* 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..7e3a97e1 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/alt-sha1.cpp @@ -0,0 +1,525 @@ +/* $Id: alt-sha1.cpp $ */ +/** @file + * IPRT - SHA-1 hash functions, Alternative Implementation. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..2b9c2a70 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/alt-sha256.cpp @@ -0,0 +1,683 @@ +/* $Id: alt-sha256.cpp $ */ +/** @file + * IPRT - SHA-256 and SHA-224 hash functions, Alternative Implementation. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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-sha512.cpp b/src/VBox/Runtime/common/checksum/alt-sha512.cpp new file mode 100644 index 00000000..166889eb --- /dev/null +++ b/src/VBox/Runtime/common/checksum/alt-sha512.cpp @@ -0,0 +1,795 @@ +/* $Id: alt-sha512.cpp $ */ +/** @file + * IPRT - SHA-512 and SHA-384 hash functions, Alternative Implementation. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..e2162c45 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/crc16ccitt.cpp @@ -0,0 +1,108 @@ +/* $Id: crc16ccitt.cpp $ */ +/** @file + * IPRT - CRC-16-CCITT. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..f961b5dd --- /dev/null +++ b/src/VBox/Runtime/common/checksum/crc32-zlib.cpp @@ -0,0 +1,89 @@ +/* $Id: crc32-zlib.cpp $ */ +/** @file + * IPRT - CRC-32 on top of zlib (very fast). + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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, register 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..ef4fc326 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/crc32.cpp @@ -0,0 +1,186 @@ +/* $Id: crc32.cpp $ */ +/** @file + * IPRT - CRC32. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + * -------------------------------------------------------------------- + * + * 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..8e925090 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/crc32c.cpp @@ -0,0 +1,122 @@ +/* $Id: crc32c.cpp $ */ +/** @file + * IPRT - CRC32C. + */ + +/* + * Copyright (C) 2014-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + +#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..e544433e --- /dev/null +++ b/src/VBox/Runtime/common/checksum/crc64.cpp @@ -0,0 +1,212 @@ +/* $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-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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 +}; + + +/** + * Calculate CRC64 for a memory block. + * + * @returns CRC64 for the memory block. + * @param pv Pointer to the memory block. + * @param cb Size of the memory block in bytes. + */ +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); + + +/** + * Start a multiblock CRC64 calculation. + * + * @returns Start CRC64. + */ +RTDECL(uint64_t) RTCrc64Start(void) +{ + return 0ULL; +} +RT_EXPORT_SYMBOL(RTCrc64Start); + + +/** + * Processes a multiblock of a CRC64 calculation. + * + * @returns Intermediate CRC64 value. + * @param uCRC64 Current CRC64 intermediate value. + * @param pv The data block to process. + * @param cb The size of the data block in bytes. + */ +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); + + +/** + * Complete a multiblock CRC64 calculation. + * + * @returns CRC64 value. + * @param uCRC64 Current CRC64 intermediate value. + */ +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..3b8606ae --- /dev/null +++ b/src/VBox/Runtime/common/checksum/ipv4.cpp @@ -0,0 +1,764 @@ +/* $Id: ipv4.cpp $ */ +/** @file + * IPRT - IPv4 Checksum calculation and validation. + */ + +/* + * Copyright (C) 2008-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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) +{ + uint16_t const *pw = (uint16_t const *)pvData; + 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. */ + 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..597813ec --- /dev/null +++ b/src/VBox/Runtime/common/checksum/ipv6.cpp @@ -0,0 +1,126 @@ +/* $Id: ipv6.cpp $ */ +/** @file + * IPRT - IPv6 Checksum calculation and validation. + */ + +/* + * Copyright (C) 2008-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..c35c9b6e --- /dev/null +++ b/src/VBox/Runtime/common/checksum/manifest-file.cpp @@ -0,0 +1,84 @@ +/* $Id: manifest-file.cpp $ */ +/** @file + * IPRT - Manifest, the bits with file dependencies + */ + +/* + * Copyright (C) 2010-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..498365fa --- /dev/null +++ b/src/VBox/Runtime/common/checksum/manifest.cpp @@ -0,0 +1,583 @@ +/* $Id: manifest.cpp $ */ +/** @file + * IPRT - Manifest file handling, old style - deprecated. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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 = RTFileGetSize(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..c14b469c --- /dev/null +++ b/src/VBox/Runtime/common/checksum/manifest2.cpp @@ -0,0 +1,1566 @@ +/* $Id: manifest2.cpp $ */ +/** @file + * IPRT - Manifest, the core. + */ + +/* + * Copyright (C) 2010-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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. */ + 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; + + +/** + * Creates an empty manifest. + * + * @returns IPRT status code. + * @param fFlags Flags, MBZ. + * @param phManifest Where to return the handle to the manifest. + */ +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; +} + +/** + * Retains a reference to the manifest handle. + * + * @returns The new reference count, UINT32_MAX if the handle is invalid. + * @param hManifest The handle to retain. + */ +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; +} + + +/** + * Releases a reference to the manifest handle. + * + * @returns The new reference count, 0 if free. UINT32_MAX is returned if the + * handle is invalid. + * @param hManifest The handle to release. + * NIL is quietly ignored (returns 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; +} + + +/** + * Creates a duplicate of the specified manifest. + * + * @returns IPRT status code + * @param hManifestSrc The manifest to clone. + * @param phManifestDst Where to store the handle to the duplicate. + */ +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; +} + + +/** + * Sets a manifest attribute. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszAttr The attribute name. If this already exists, + * its value will be replaced. + * @param pszValue The value string. + * @param fType The attribute type, pass + * RTMANIFEST_ATTR_UNKNOWN if not known. + */ +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; +} + + +/** + * Unsets (removes) a manifest attribute if it exists. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if not found. + * + * @param hManifest The manifest handle. + * @param pszAttr The attribute name. + */ +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; +} + + +/** + * Sets an attribute of a manifest entry. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. This will automatically be + * added if there was no previous call to + * RTManifestEntryAdd for this name. See + * RTManifestEntryAdd for the entry name rules. + * @param pszAttr The attribute name. If this already exists, + * its value will be replaced. + * @param pszValue The value string. + * @param fType The attribute type, pass + * RTMANIFEST_ATTR_UNKNOWN if not known. + */ +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); +} + + +/** + * Unsets (removes) an attribute of a manifest entry if they both exist. + * + * @returns IPRT status code. + * @retval VWRN_NOT_FOUND if not found. + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + * @param pszAttr The attribute name. + */ +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; +} + + +/** + * Adds a new entry to a manifest. + * + * The entry name rules: + * - The entry name can contain any character defined by unicode, except + * control characters, ':', '(' and ')'. The exceptions are mainly there + * because of uncertainty around how various formats handles these. + * - It is considered case sensitive. + * - Forward (unix) and backward (dos) slashes are considered path + * separators and converted to forward slashes. + * + * @returns IPRT status code. + * @retval VWRN_ALREADY_EXISTS if the entry already exists. + * + * @param hManifest The manifest handle. + * @param pszEntry The entry name (UTF-8). + * + * @remarks Some manifest formats will not be able to store an entry without + * any attributes. So, this is just here in case it comes in handy + * when dealing with formats which can. + */ +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; +} + + +/** + * Removes an entry. + * + * @returns IPRT status code. + * @param hManifest The manifest handle. + * @param pszEntry The entry name. + */ +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..eb73c0c1 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/manifest3.cpp @@ -0,0 +1,699 @@ +/* $Id: manifest3.cpp $ */ +/** @file + * IPRT - Manifest, the bits with the most dependencies. + */ + +/* + * Copyright (C) 2010-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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, + RTVFSOBJOPS_VERSION + }, + RTVFSIOSTREAMOPS_VERSION, + 0, + rtManifestPtIos_Read, + rtManifestPtIos_Write, + rtManifestPtIos_Flush, + rtManifestPtIos_PollOne, + rtManifestPtIos_Tell, + NULL /* Skip */, + NULL /* ZeroFill */, + RTVFSIOSTREAMOPS_VERSION, +}; + + + +/** + * Add an entry for an I/O stream using a passthru stream. + * + * The passthru I/O stream will hash all the data read from or written to the + * stream and automatically add an entry to the manifest with the desired + * attributes when it is released. Alternatively one can call + * RTManifestPtIosAddEntryNow() to have more control over exactly when this + * action is performed and which status it yields. + * + * @returns IPRT status code. + * @param hManifest The manifest to add the entry to. + * @param hVfsIos The I/O stream to pass thru to/from. + * @param pszEntry The entry name. + * @param fAttrs The attributes to create for this stream. + * @param fReadOrWrite Whether it's a read or write I/O stream. + * @param phVfsIosPassthru Where to return the new handle. + */ +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; +} + + +/** + * Adds the entry to the manifest right now. + * + * @returns IPRT status code. + * @param hVfsPtIos The manifest passthru I/O stream returned by + * RTManifestEntryAddPassthruIoStream(). + */ +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); +} + + +/** + * Checks if the give I/O stream is a manifest passthru instance or not. + * + * @returns true if it's a manifest passthru I/O stream, false if not. + * @param hVfsPtIos Possible the manifest passthru I/O stream handle. + */ +RTDECL(bool) RTManifestPtIosIsInstanceOf(RTVFSIOSTREAM hVfsPtIos) +{ + if (hVfsPtIos != NIL_RTVFSIOSTREAM) + { + PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps); + if (pThis) + return true; + } + return false; +} + + +/** + * Adds an entry for a file with the specified set of attributes. + * + * @returns IPRT status code. + * + * @param hManifest The manifest handle. + * @param hVfsIos The I/O stream handle of the entry. This will + * be processed to its end on successful return. + * (Must be positioned at the start to get + * the expected results.) + * @param pszEntry The entry name. + * @param fAttrs The attributes to create for this stream. + */ +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..3cf879b8 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/md2str.cpp @@ -0,0 +1,49 @@ +/* $Id: md2str.cpp $ */ +/** @file + * IPRT - MD2 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..50048641 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/md4str.cpp @@ -0,0 +1,49 @@ +/* $Id: md4str.cpp $ */ +/** @file + * IPRT - MD4 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..415adc83 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/md5str.cpp @@ -0,0 +1,49 @@ +/* $Id: md5str.cpp $ */ +/** @file + * IPRT - MD5 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..10e09164 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/openssl-md2.cpp @@ -0,0 +1,82 @@ +/* $Id: openssl-md2.cpp $ */ +/** @file + * IPRT - Message-Digest Algorithm 2. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" + +#include <openssl/opensslconf.h> +#ifndef OPENSSL_NO_MD2 +# include <openssl/md2.h> + +# 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..6b9e761f --- /dev/null +++ b/src/VBox/Runtime/common/checksum/openssl-md4.cpp @@ -0,0 +1,82 @@ +/* $Id: openssl-md4.cpp $ */ +/** @file + * IPRT - Message-Digest Algorithm 4. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" + +#include <openssl/opensslconf.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..c556d75c --- /dev/null +++ b/src/VBox/Runtime/common/checksum/openssl-md5.cpp @@ -0,0 +1,72 @@ +/* $Id: openssl-md5.cpp $ */ +/** @file + * IPRT - MD5 message digest functions, implemented using OpenSSL. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" + +#include <openssl/md5.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..4bf3bd0f --- /dev/null +++ b/src/VBox/Runtime/common/checksum/openssl-sha1.cpp @@ -0,0 +1,88 @@ +/* $Id: openssl-sha1.cpp $ */ +/** @file + * IPRT - SHA-1 hash functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" + +#include <openssl/sha.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..738f3997 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/openssl-sha256.cpp @@ -0,0 +1,138 @@ +/* $Id: openssl-sha256.cpp $ */ +/** @file + * IPRT - SHA-256 hash functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" + +#include <openssl/sha.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-sha512.cpp b/src/VBox/Runtime/common/checksum/openssl-sha512.cpp new file mode 100644 index 00000000..99b391c2 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/openssl-sha512.cpp @@ -0,0 +1,139 @@ +/* $Id: openssl-sha512.cpp $ */ +/** @file + * IPRT - SHA-512 hash functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" + +#include <openssl/sha.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..b19bc81c --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha1str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha1str.cpp $ */ +/** @file + * IPRT - SHA-1 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..2570e347 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha224str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha224str.cpp $ */ +/** @file + * IPRT - SHA-224 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..4aa421ed --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha256str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha256str.cpp $ */ +/** @file + * IPRT - SHA-256 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..fe2e7115 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha384str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha384str.cpp $ */ +/** @file + * IPRT - SHA-384 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..1c22ecc8 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha512str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha512str.cpp $ */ +/** @file + * IPRT - SHA-512 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..bbc5df05 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha512t224str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha512t224str.cpp $ */ +/** @file + * IPRT - SHA-512/224 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..55524670 --- /dev/null +++ b/src/VBox/Runtime/common/checksum/sha512t256str.cpp @@ -0,0 +1,49 @@ +/* $Id: sha512t256str.cpp $ */ +/** @file + * IPRT - SHA-512/256 string functions. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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*/); +} + |