From e1f9e8beb478e1a6c268fdea01487ec6164fc0ca Mon Sep 17 00:00:00 2001 From: Xisco Fauli Date: Thu, 20 Aug 2026 13:31:33 +0200 Subject: [PATCH] Revert "sal: remove MD2, SHA, HMAC_MD5 digests" it breaks the published API This reverts commit e4892750c35b28153130c3516ab4f67166c58d76. Change-Id: Id072882efc432cdbc3c20a6bcece1369f9a78bf4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209385 Tested-by: Jenkins Reviewed-by: Xisco Fauli --- include/rtl/digest.h | 207 ++++++++++ sal/qa/rtl/digest/rtl_digest.cxx | 64 ++-- sal/rtl/digest.cxx | 631 +++++++++++++++++++++++++++++++ 3 files changed, 876 insertions(+), 26 deletions(-) diff --git a/include/rtl/digest.h b/include/rtl/digest.h index 72cd61c2c72a..f649d8b594be 100644 --- a/include/rtl/digest.h +++ b/include/rtl/digest.h @@ -43,9 +43,12 @@ typedef void* rtlDigest; */ enum __rtl_DigestAlgorithm { + rtl_Digest_AlgorithmMD2, rtl_Digest_AlgorithmMD5, + rtl_Digest_AlgorithmSHA, rtl_Digest_AlgorithmSHA1, + rtl_Digest_AlgorithmHMAC_MD5, rtl_Digest_AlgorithmHMAC_SHA1, rtl_Digest_AlgorithmInvalid, @@ -156,6 +159,62 @@ SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_get ( sal_uInt8 *pBuffer, sal_uInt32 nBufLen ) SAL_THROW_EXTERN_C(); +#define RTL_DIGEST_LENGTH_MD2 16 + +/** Create a MD2 digest handle. + + The MD2 digest algorithm is specified in + RFC 1319 (Informational) + The MD2 Message-Digest Algorithm + + @see rtl_digest_create() + */ +SAL_DLLPUBLIC rtlDigest SAL_CALL rtl_digest_createMD2 (void) SAL_THROW_EXTERN_C(); + + +/** Destroy a MD2 digest handle. + @see rtl_digest_destroy() + */ +SAL_DLLPUBLIC void SAL_CALL rtl_digest_destroyMD2 ( + rtlDigest Digest +) SAL_THROW_EXTERN_C(); + +/** Update a MD2 digest with given data. + @see rtl_digest_update() + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_updateMD2 ( + rtlDigest Digest, + const void *pData, sal_uInt32 nDatLen +) SAL_THROW_EXTERN_C(); + +/** Finalize a MD2 digest and retrieve the digest value. + @see rtl_digest_get() + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_getMD2 ( + rtlDigest Digest, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen +) SAL_THROW_EXTERN_C(); + +/** Evaluate a MD2 digest value from given data. + + This function performs an optimized call sequence on a + single data buffer, avoiding digest creation and destruction. + + @see rtl_digest_updateMD2() + @see rtl_digest_getMD2() + + @param[in] pData data buffer. + @param[in] nDatLen data length. + @param[in] pBuffer digest value buffer. + @param[in] nBufLen digest value length. + + @retval rtl_Digest_E_None upon success. + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_MD2 ( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen +) SAL_THROW_EXTERN_C(); + #define RTL_DIGEST_LENGTH_MD5 16 /** Create a MD5 digest handle. @@ -224,6 +283,80 @@ SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_MD5 ( sal_uInt8 *pBuffer, sal_uInt32 nBufLen ) SAL_THROW_EXTERN_C(); +#define RTL_DIGEST_LENGTH_SHA 20 + +/** Create a SHA digest handle. + + The SHA digest algorithm is specified in + FIPS PUB 180 (Superseded by FIPS PUB 180-1) + Secure Hash Standard + + @deprecated The implementation is buggy and generates incorrect results + for 52 <= (len % 64) <= 55; use only for bug-compatibility. + + @see rtl_digest_create() + */ +SAL_DLLPUBLIC rtlDigest SAL_CALL rtl_digest_createSHA (void) SAL_THROW_EXTERN_C(); + +/** Destroy a SHA digest handle. + + @deprecated The implementation is buggy and generates incorrect results + for 52 <= (len % 64) <= 55; use only for bug-compatibility. + + @see rtl_digest_destroy() + */ +SAL_DLLPUBLIC void SAL_CALL rtl_digest_destroySHA ( + rtlDigest Digest +) SAL_THROW_EXTERN_C(); + + +/** Update a SHA digest with given data. + + @deprecated The implementation is buggy and generates incorrect results + for 52 <= (len % 64) <= 55; use only for bug-compatibility. + + @see rtl_digest_update() + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_updateSHA ( + rtlDigest Digest, + const void *pData, sal_uInt32 nDatLen +) SAL_THROW_EXTERN_C(); + +/** Finalize a SHA digest and retrieve the digest value. + + @deprecated The implementation is buggy and generates incorrect results + for 52 <= (len % 64) <= 55; use only for bug-compatibility. + + @see rtl_digest_get() + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_getSHA ( + rtlDigest Digest, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen +) SAL_THROW_EXTERN_C(); + +/** Evaluate a SHA digest value from given data. + + This function performs an optimized call sequence on a + single data buffer, avoiding digest creation and destruction. + + @deprecated The implementation is buggy and generates incorrect results + for 52 <= (len % 64) <= 55; use only for bug-compatibility. + + @see rtl_digest_updateSHA() + @see rtl_digest_getSHA() + + @param[in] pData data buffer. + @param[in] nDatLen data length. + @param[in] pBuffer digest value buffer. + @param[in] nBufLen digest value length. + + @retval rtl_Digest_E_None upon success. + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_SHA ( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen +) SAL_THROW_EXTERN_C(); + /*======================================================================== * * rtl_digest_SHA1 interface. @@ -302,6 +435,80 @@ SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_SHA1 ( sal_uInt8 *pBuffer, sal_uInt32 nBufLen ) SAL_THROW_EXTERN_C(); +#define RTL_DIGEST_LENGTH_HMAC_MD5 RTL_DIGEST_LENGTH_MD5 + +/** Create a HMAC_MD5 digest handle. + + The HMAC_MD5 digest algorithm is specified in + + RFC 2104 (Informational) + HMAC: Keyed-Hashing for Message Authentication + + @see rtl_digest_create() + */ +SAL_DLLPUBLIC rtlDigest SAL_CALL rtl_digest_createHMAC_MD5 (void) SAL_THROW_EXTERN_C(); + +/** Destroy a HMAC_MD5 digest handle. + @see rtl_digest_destroy() + */ +SAL_DLLPUBLIC void SAL_CALL rtl_digest_destroyHMAC_MD5 ( + rtlDigest Digest +) SAL_THROW_EXTERN_C(); + +/** Initialize a HMAC_MD5 digest. + @see rtl_digest_init() + + @param[in] Digest digest handle. + @param[in] pKeyData key material buffer. + @param[in] nKeyLen key material length. + + @retval rtl_Digest_E_None upon success. + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_initHMAC_MD5 ( + rtlDigest Digest, + const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen +) SAL_THROW_EXTERN_C(); + +/** Update a HMAC_MD5 digest with given data. + @see rtl_digest_update() + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_updateHMAC_MD5 ( + rtlDigest Digest, + const void *pData, sal_uInt32 nDatLen +) SAL_THROW_EXTERN_C(); + +/** Finalize a HMAC_MD5 digest and retrieve the digest value. + @see rtl_digest_get() + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_getHMAC_MD5 ( + rtlDigest Digest, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen +) SAL_THROW_EXTERN_C(); + +/** Evaluate a HMAC_MD5 digest value from given data. + + This function performs an optimized call sequence on a + single data buffer, avoiding digest creation and destruction. + + @see rtl_digest_initHMAC_MD5() + @see rtl_digest_updateHMAC_MD5() + @see rtl_digest_getHMAC_MD5() + + @param[in] pKeyData key material buffer. + @param[in] nKeyLen key material length. + @param[in] pData data buffer. + @param[in] nDatLen data length. + @param[in] pBuffer digest value buffer. + @param[in] nBufLen digest value length. + + @retval rtl_Digest_E_None upon success. + */ +SAL_DLLPUBLIC rtlDigestError SAL_CALL rtl_digest_HMAC_MD5 ( + const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen, + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen +) SAL_THROW_EXTERN_C(); + #define RTL_DIGEST_LENGTH_HMAC_SHA1 RTL_DIGEST_LENGTH_SHA1 /** Create a HMAC_SHA1 digest handle. diff --git a/sal/qa/rtl/digest/rtl_digest.cxx b/sal/qa/rtl/digest/rtl_digest.cxx index d1e888b22dbd..2244d98e3cc7 100644 --- a/sal/qa/rtl/digest/rtl_digest.cxx +++ b/sal/qa/rtl/digest/rtl_digest.cxx @@ -41,22 +41,31 @@ constexpr OStringLiteral sSampleString_only_one_diff ("This is a sample sentence const rtlDigestAlgorithm constDigestAlgorithms[] = { + rtl_Digest_AlgorithmMD2, rtl_Digest_AlgorithmMD5, + rtl_Digest_AlgorithmSHA, rtl_Digest_AlgorithmSHA1, + rtl_Digest_AlgorithmHMAC_MD5, rtl_Digest_AlgorithmHMAC_SHA1, }; const sal_uInt32 constDigestAlgorithmLengths[] = { + RTL_DIGEST_LENGTH_MD2, RTL_DIGEST_LENGTH_MD5, + RTL_DIGEST_LENGTH_SHA, RTL_DIGEST_LENGTH_SHA1, + RTL_DIGEST_LENGTH_HMAC_MD5, RTL_DIGEST_LENGTH_HMAC_SHA1, }; const std::string_view constSampleStringSums[] = { + std::string_view("647ee6c9d4aa5fdd374ed9d7a156acbf"), std::string_view("b16b903e6fc0b62ae389013ed93fe531"), + std::string_view("eab2814429b2613301c8a077b806af3680548914"), std::string_view("2bc5bdb7506a2cdc2fd27fc8b9889343012d5008"), + std::string_view("0b1b0e1a6f2e4420326354b031063605"), std::string_view("1998c6a556915be76451bfb587fa7c34d849936e") }; @@ -271,42 +280,45 @@ public: CPPUNIT_ASSERT_EQUAL_MESSAGE("does not handle wrong parameter", rtl_Digest_E_Argument, aError); aHandle = nullptr; - aError = rtl_digest_updateSHA1(aHandle, nullptr, 0); + aError = rtl_digest_updateMD2(aHandle, nullptr, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("does not handle wrong parameter", rtl_Digest_E_Argument, aError); - aHandle = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); - CPPUNIT_ASSERT(aHandle != nullptr); + aError = rtl_digest_updateMD5(aHandle, nullptr, 0); + CPPUNIT_ASSERT_EQUAL_MESSAGE("does not handle wrong parameter", rtl_Digest_E_Argument, aError); + + aHandle = rtl_digest_create( rtl_Digest_AlgorithmMD2 ); + CPPUNIT_ASSERT_MESSAGE("create with rtl_Digest_AlgorithmMD2", aHandle != nullptr); const sal_uInt8* pData = reinterpret_cast(sSampleString.getStr()); sal_uInt32 nSize = sSampleString.getLength(); - aError = rtl_digest_updateSHA1(aHandle, nullptr, 0); + aError = rtl_digest_updateMD2(aHandle, nullptr, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'pData' wrong", rtl_Digest_E_Argument, aError); - aError = rtl_digest_updateSHA1(aHandle, pData, 0); + aError = rtl_digest_updateMD2(aHandle, pData, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'nSize' wrong", rtl_Digest_E_None, aError); - rtl_digest_destroySHA1(aHandle); + rtl_digest_destroyMD2(aHandle); // use wrong Algorithm!!! This is volitional! - aHandle = rtl_digest_create(rtl_Digest_AlgorithmHMAC_SHA1); - CPPUNIT_ASSERT(aHandle != nullptr); + aHandle = rtl_digest_create(rtl_Digest_AlgorithmMD2); + CPPUNIT_ASSERT_MESSAGE("create with rtl_Digest_AlgorithmMD2", aHandle != nullptr); - aError = rtl_digest_updateSHA1(aHandle, pData, nSize); + aError = rtl_digest_updateMD5(aHandle, pData, nSize); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'handle' wrong", rtl_Digest_E_Algorithm, aError); - rtl_digest_destroyHMAC_SHA1(aHandle); + rtl_digest_destroyMD5(aHandle); - aHandle = rtl_digest_create( rtl_Digest_AlgorithmHMAC_SHA1 ); - CPPUNIT_ASSERT(aHandle != nullptr); + aHandle = rtl_digest_create( rtl_Digest_AlgorithmMD5 ); + CPPUNIT_ASSERT_MESSAGE("create with rtl_Digest_AlgorithmMD5", aHandle != nullptr); - aError = rtl_digest_updateHMAC_SHA1(aHandle, nullptr, 0); + aError = rtl_digest_updateMD5(aHandle, nullptr, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'pData' wrong", rtl_Digest_E_Argument, aError); - aError = rtl_digest_updateHMAC_SHA1(aHandle, pData, 0); + aError = rtl_digest_updateMD5(aHandle, pData, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'nSize' wrong", rtl_Digest_E_None, aError); - rtl_digest_destroyHMAC_SHA1(aHandle); + rtl_digest_destroyMD5(aHandle); } void testGet() @@ -319,34 +331,34 @@ public: CPPUNIT_ASSERT_EQUAL_MESSAGE("does not handle wrong parameter", rtl_Digest_E_Argument, aError); aHandle = nullptr; - aError = rtl_digest_getSHA1(aHandle, nullptr, 0); + aError = rtl_digest_getMD5(aHandle, nullptr, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("does not handle wrong parameter", rtl_Digest_E_Argument, aError); // test with wrong algorithm - aHandle = rtl_digest_create(rtl_Digest_AlgorithmHMAC_SHA1); - CPPUNIT_ASSERT(aHandle != nullptr); + aHandle = rtl_digest_create(rtl_Digest_AlgorithmMD2); + CPPUNIT_ASSERT_MESSAGE("create with rtl_Digest_AlgorithmMD2", aHandle != nullptr); sal_uInt32 nKeyLen = rtl_digest_queryLength(aHandle); std::unique_ptr pKeyBuffer(new sal_uInt8[nKeyLen]); - aError = rtl_digest_getSHA1(aHandle, nullptr, 0); + aError = rtl_digest_getMD5(aHandle, nullptr, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle 2. parameter wrong", rtl_Digest_E_Argument, aError); - aError = rtl_digest_getSHA1(aHandle, pKeyBuffer.get(), 0); + aError = rtl_digest_getMD5(aHandle, pKeyBuffer.get(), 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'handle' wrong", rtl_Digest_E_Algorithm, aError); - rtl_digest_destroyHMAC_SHA1(aHandle); + rtl_digest_destroyMD2(aHandle); - aHandle = rtl_digest_create(rtl_Digest_AlgorithmSHA1); - CPPUNIT_ASSERT(aHandle != nullptr); + aHandle = rtl_digest_create(rtl_Digest_AlgorithmMD5); + CPPUNIT_ASSERT_MESSAGE("create with rtl_Digest_AlgorithmMD5", aHandle != nullptr); - aError = rtl_digest_getSHA1(aHandle, nullptr, nKeyLen); + aError = rtl_digest_getMD5(aHandle, nullptr, nKeyLen); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'pData' wrong", rtl_Digest_E_Argument, aError); - aError = rtl_digest_getSHA1(aHandle, pKeyBuffer.get(), 0); + aError = rtl_digest_getMD5(aHandle, pKeyBuffer.get(), 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("handle parameter 'nSize' wrong", rtl_Digest_E_BufferSize, aError); - rtl_digest_destroySHA1(aHandle); + rtl_digest_destroyMD5(aHandle); } void testSHA1SumForBiggerInputData() diff --git a/sal/rtl/digest.cxx b/sal/rtl/digest.cxx index 8dc495e930cc..a87570b32b86 100644 --- a/sal/rtl/digest.cxx +++ b/sal/rtl/digest.cxx @@ -86,14 +86,26 @@ rtlDigest SAL_CALL rtl_digest_create(rtlDigestAlgorithm Algorithm) noexcept rtlDigest Digest = nullptr; switch (Algorithm) { + case rtl_Digest_AlgorithmMD2: + Digest = rtl_digest_createMD2(); + break; + case rtl_Digest_AlgorithmMD5: Digest = rtl_digest_createMD5(); break; + case rtl_Digest_AlgorithmSHA: + Digest = rtl_digest_createSHA(); + break; + case rtl_Digest_AlgorithmSHA1: Digest = rtl_digest_createSHA1(); break; + case rtl_Digest_AlgorithmHMAC_MD5: + Digest = rtl_digest_createHMAC_MD5(); + break; + case rtl_Digest_AlgorithmHMAC_SHA1: Digest = rtl_digest_createHMAC_SHA1(); break; @@ -158,6 +170,270 @@ void SAL_CALL rtl_digest_destroy(rtlDigest Digest) noexcept pImpl->m_delete(Digest); } +constexpr auto DIGEST_CBLOCK_MD2 = 16; +constexpr auto DIGEST_LBLOCK_MD2 = 16; + +namespace { + +struct DigestContextMD2 +{ + sal_uInt32 m_nDatLen; + sal_uInt8 m_pData[DIGEST_CBLOCK_MD2]; + sal_uInt32 m_state[DIGEST_LBLOCK_MD2]; + sal_uInt32 m_chksum[DIGEST_LBLOCK_MD2]; +}; + +struct DigestMD2_Impl +{ + Digest_Impl m_digest; + DigestContextMD2 m_context; +}; + +} + +static void initMD2 (DigestContextMD2 *ctx); +static void updateMD2 (DigestContextMD2 *ctx); +static void endMD2 (DigestContextMD2 *ctx); + +const sal_uInt32 S[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, + 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, + 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, + 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, + 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, + 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, + 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, + 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, + 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, + 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, + 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, + 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, + 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, + 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, + 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, + 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, + 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, + 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, + 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, + 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, + 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, + 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, +}; + +const Digest_Impl MD2 = +{ + rtl_Digest_AlgorithmMD2, + RTL_DIGEST_LENGTH_MD2, + nullptr, + rtl_digest_destroyMD2, + rtl_digest_updateMD2, + rtl_digest_getMD2 +}; + +static void initMD2(DigestContextMD2 *ctx) +{ + memset(ctx, 0, sizeof(DigestContextMD2)); +} + +static void updateMD2(DigestContextMD2 *ctx) +{ + sal_uInt8 *X; + sal_uInt32 *sp1, *sp2; + sal_uInt32 i, k, t; + + sal_uInt32 state[48]; + + X = ctx->m_pData; + sp1 = ctx->m_state; + sp2 = ctx->m_chksum; + + k = sp2[DIGEST_LBLOCK_MD2 - 1]; + for (i = 0; i < 16; i++) + { + state[i + 0] = sp1[i]; + state[i + 16] = t = X[i]; + state[i + 32] = t ^ sp1[i]; + k = sp2[i] ^= S[t^k]; + } + + t = 0; + for (i = 0; i < 18; i++) + { + for (k = 0; k < 48; k += 8) + { + t = state[k + 0] ^= S[t]; + t = state[k + 1] ^= S[t]; + t = state[k + 2] ^= S[t]; + t = state[k + 3] ^= S[t]; + t = state[k + 4] ^= S[t]; + t = state[k + 5] ^= S[t]; + t = state[k + 6] ^= S[t]; + t = state[k + 7] ^= S[t]; + } + t = ((t + i) & 0xff); + } + + memcpy(sp1, state, 16 * sizeof(sal_uInt32)); + rtl_secureZeroMemory(state, 48 * sizeof(sal_uInt32)); +} + +static void endMD2(DigestContextMD2 *ctx) +{ + sal_uInt8 *X; + sal_uInt32 *C; + sal_uInt32 i, n; + + X = ctx->m_pData; + C = ctx->m_chksum; + n = DIGEST_CBLOCK_MD2 - ctx->m_nDatLen; + + for (i = ctx->m_nDatLen; i < DIGEST_CBLOCK_MD2; i++) + X[i] = static_cast(n & 0xff); + + updateMD2(ctx); + + for (i = 0; i < DIGEST_CBLOCK_MD2; i++) + X[i] = static_cast(C[i] & 0xff); + updateMD2(ctx); +} + +rtlDigestError SAL_CALL rtl_digest_MD2( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) noexcept +{ + DigestMD2_Impl digest; + rtlDigestError result; + + digest.m_digest = MD2; + initMD2(&(digest.m_context)); + + result = rtl_digest_updateMD2(&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getMD2(&digest, pBuffer, nBufLen); + + rtl_secureZeroMemory(&digest, sizeof(digest)); + return result; +} + +rtlDigest SAL_CALL rtl_digest_createMD2() noexcept +{ + DigestMD2_Impl *pImpl = RTL_DIGEST_CREATE(DigestMD2_Impl); + if (pImpl) + { + pImpl->m_digest = MD2; + initMD2(&(pImpl->m_context)); + } + return static_cast(pImpl); +} + +rtlDigestError SAL_CALL rtl_digest_updateMD2( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) noexcept +{ + DigestMD2_Impl *pImpl = static_cast(Digest); + const sal_uInt8 *d = static_cast(pData); + + DigestContextMD2 *ctx; + + if (!pImpl || !pData) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmMD2) + return rtl_Digest_E_Algorithm; + + if (nDatLen == 0) + return rtl_Digest_E_None; + + ctx = &(pImpl->m_context); + + if (ctx->m_nDatLen) + { + sal_uInt8 *p = ctx->m_pData + ctx->m_nDatLen; + sal_uInt32 n = DIGEST_CBLOCK_MD2 - ctx->m_nDatLen; + + if (nDatLen < n) + { + memcpy(p, d, nDatLen); + ctx->m_nDatLen += nDatLen; + + return rtl_Digest_E_None; + } + + memcpy(p, d, n); + d += n; + nDatLen -= n; + + updateMD2(ctx); + ctx->m_nDatLen = 0; + } + + while (nDatLen >= DIGEST_CBLOCK_MD2) + { + memcpy(ctx->m_pData, d, DIGEST_CBLOCK_MD2); + d += DIGEST_CBLOCK_MD2; + nDatLen -= DIGEST_CBLOCK_MD2; + + updateMD2(ctx); + } + + memcpy(ctx->m_pData, d, nDatLen); + ctx->m_nDatLen = nDatLen; + + return rtl_Digest_E_None; +} + +rtlDigestError SAL_CALL rtl_digest_getMD2( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) noexcept +{ + DigestMD2_Impl *pImpl = static_cast(Digest); + sal_uInt32 i; + + DigestContextMD2 *ctx; + + if (!pImpl || !pBuffer) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmMD2) + return rtl_Digest_E_Algorithm; + + if (pImpl->m_digest.m_length > nBufLen) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + endMD2(ctx); + for (i = 0; i < DIGEST_CBLOCK_MD2; i++) + { + pBuffer[i] = static_cast(ctx->m_state[i] & 0xff); + } + + initMD2(ctx); + + return rtl_Digest_E_None; +} + +void SAL_CALL rtl_digest_destroyMD2(rtlDigest Digest) noexcept +{ + DigestMD2_Impl *pImpl = static_cast(Digest); + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD2) + rtl_freeZeroMemory(pImpl, sizeof(DigestMD2_Impl)); + else + free(pImpl); + } +} + #define DIGEST_CBLOCK_MD5 64 #define DIGEST_LBLOCK_MD5 16 @@ -546,6 +822,7 @@ void SAL_CALL rtl_digest_destroyMD5(rtlDigest Digest) noexcept typedef sal_uInt32 DigestSHA_update_t(sal_uInt32 x); +static sal_uInt32 updateSHA_0(sal_uInt32 x); static sal_uInt32 updateSHA_1(sal_uInt32 x); namespace { @@ -798,6 +1075,163 @@ static void endSHA(DigestContextSHA *ctx) updateSHA(ctx); } +const Digest_Impl SHA_0 = +{ + rtl_Digest_AlgorithmSHA, + RTL_DIGEST_LENGTH_SHA, + nullptr, + rtl_digest_destroySHA, + rtl_digest_updateSHA, + rtl_digest_getSHA +}; + +static sal_uInt32 updateSHA_0(sal_uInt32 x) +{ + return x; +} + +rtlDigestError SAL_CALL rtl_digest_SHA( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) noexcept +{ + DigestSHA_Impl digest; + rtlDigestError result; + + digest.m_digest = SHA_0; + initSHA(&(digest.m_context), updateSHA_0); + + result = rtl_digest_updateSHA(&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getSHA(&digest, pBuffer, nBufLen); + + rtl_secureZeroMemory(&digest, sizeof(digest)); + return result; +} + +rtlDigest SAL_CALL rtl_digest_createSHA() noexcept +{ + DigestSHA_Impl *pImpl = RTL_DIGEST_CREATE(DigestSHA_Impl); + if (pImpl) + { + pImpl->m_digest = SHA_0; + initSHA(&(pImpl->m_context), updateSHA_0); + } + return static_cast(pImpl); +} + +rtlDigestError SAL_CALL rtl_digest_updateSHA( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) noexcept +{ + DigestSHA_Impl *pImpl = static_cast(Digest); + const sal_uInt8 *d = static_cast(pData); + + DigestContextSHA *ctx; + sal_uInt32 len; + + if (!pImpl || !pData) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmSHA) + return rtl_Digest_E_Algorithm; + + if (nDatLen == 0) + return rtl_Digest_E_None; + + ctx = &(pImpl->m_context); + + len = ctx->m_nL + (nDatLen << 3); + if (len < ctx->m_nL) + ctx->m_nH += 1; + + ctx->m_nH += (nDatLen >> 29); + ctx->m_nL = len; + + if (ctx->m_nDatLen) + { + sal_uInt8 *p = reinterpret_cast(ctx->m_pData) + ctx->m_nDatLen; + sal_uInt32 n = DIGEST_CBLOCK_SHA - ctx->m_nDatLen; + + if (nDatLen < n) + { + memcpy(p, d, nDatLen); + ctx->m_nDatLen += nDatLen; + + return rtl_Digest_E_None; + } + + memcpy(p, d, n); + d += n; + nDatLen -= n; + +#ifndef OSL_BIGENDIAN + swapLong(ctx->m_pData, DIGEST_LBLOCK_SHA); +#endif /* OSL_BIGENDIAN */ + + updateSHA(ctx); + ctx->m_nDatLen = 0; + } + + while (nDatLen >= DIGEST_CBLOCK_SHA) + { + memcpy(ctx->m_pData, d, DIGEST_CBLOCK_SHA); + d += DIGEST_CBLOCK_SHA; + nDatLen -= DIGEST_CBLOCK_SHA; + +#ifndef OSL_BIGENDIAN + swapLong(ctx->m_pData, DIGEST_LBLOCK_SHA); +#endif /* OSL_BIGENDIAN */ + + updateSHA(ctx); + } + + memcpy(ctx->m_pData, d, nDatLen); + ctx->m_nDatLen = nDatLen; + + return rtl_Digest_E_None; +} + +rtlDigestError SAL_CALL rtl_digest_getSHA( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) noexcept +{ + DigestSHA_Impl *pImpl = static_cast(Digest); + sal_uInt8 *p = pBuffer; + + DigestContextSHA *ctx; + + if (!pImpl || !pBuffer) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmSHA) + return rtl_Digest_E_Algorithm; + + if (pImpl->m_digest.m_length > nBufLen) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + endSHA(ctx); + RTL_DIGEST_HTONL(ctx->m_nA, p); + RTL_DIGEST_HTONL(ctx->m_nB, p); + RTL_DIGEST_HTONL(ctx->m_nC, p); + RTL_DIGEST_HTONL(ctx->m_nD, p); + RTL_DIGEST_HTONL(ctx->m_nE, p); + initSHA(ctx, updateSHA_0); + + return rtl_Digest_E_None; +} + +void SAL_CALL rtl_digest_destroySHA(rtlDigest Digest) noexcept +{ + DigestSHA_Impl *pImpl = static_cast< DigestSHA_Impl * >(Digest); + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA) + rtl_freeZeroMemory(pImpl, sizeof(DigestSHA_Impl)); + else + free(pImpl); + } +} + const Digest_Impl SHA_1 = { rtl_Digest_AlgorithmSHA1, @@ -955,6 +1389,203 @@ void SAL_CALL rtl_digest_destroySHA1(rtlDigest Digest) noexcept } } +#define DIGEST_CBLOCK_HMAC_MD5 64 + +namespace { + +struct ContextHMAC_MD5 +{ + DigestMD5_Impl m_hash; + sal_uInt8 m_opad[DIGEST_CBLOCK_HMAC_MD5]; +}; + +struct DigestHMAC_MD5_Impl +{ + Digest_Impl m_digest; + ContextHMAC_MD5 m_context; +}; + +} + +static void initHMAC_MD5(ContextHMAC_MD5 * ctx); +static void ipadHMAC_MD5(ContextHMAC_MD5 * ctx); +static void opadHMAC_MD5(ContextHMAC_MD5 * ctx); + +const Digest_Impl HMAC_MD5 = +{ + rtl_Digest_AlgorithmHMAC_MD5, + RTL_DIGEST_LENGTH_MD5, + + rtl_digest_initHMAC_MD5, + rtl_digest_destroyHMAC_MD5, + rtl_digest_updateHMAC_MD5, + rtl_digest_getHMAC_MD5 +}; + +static void initHMAC_MD5(ContextHMAC_MD5 * ctx) +{ + DigestMD5_Impl *pImpl = &(ctx->m_hash); + + pImpl->m_digest = MD5; + initMD5(&(pImpl->m_context)); + + memset(ctx->m_opad, 0, DIGEST_CBLOCK_HMAC_MD5); +} + +static void ipadHMAC_MD5(ContextHMAC_MD5 * ctx) +{ + sal_uInt32 i; + + for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++) + { + ctx->m_opad[i] ^= 0x36; + } + + rtl_digest_updateMD5(&(ctx->m_hash), ctx->m_opad, DIGEST_CBLOCK_HMAC_MD5); + + for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++) + { + ctx->m_opad[i] ^= 0x36; + } +} + +static void opadHMAC_MD5(ContextHMAC_MD5 * ctx) +{ + sal_uInt32 i; + + for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++) + { + ctx->m_opad[i] ^= 0x5c; + } +} + +rtlDigestError SAL_CALL rtl_digest_HMAC_MD5( + const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen, + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) noexcept +{ + DigestHMAC_MD5_Impl digest; + rtlDigestError result; + + digest.m_digest = HMAC_MD5; + + result = rtl_digest_initHMAC_MD5(&digest, pKeyData, nKeyLen); + if (result == rtl_Digest_E_None) + { + result = rtl_digest_updateHMAC_MD5(&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getHMAC_MD5(&digest, pBuffer, nBufLen); + } + + rtl_secureZeroMemory(&digest, sizeof(digest)); + return result; +} + +rtlDigest SAL_CALL rtl_digest_createHMAC_MD5() noexcept +{ + DigestHMAC_MD5_Impl *pImpl = RTL_DIGEST_CREATE(DigestHMAC_MD5_Impl); + if (pImpl) + { + pImpl->m_digest = HMAC_MD5; + initHMAC_MD5(&(pImpl->m_context)); + } + return static_cast< rtlDigest >(pImpl); +} + +rtlDigestError SAL_CALL rtl_digest_initHMAC_MD5( + rtlDigest Digest, const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen) noexcept +{ + DigestHMAC_MD5_Impl *pImpl = static_cast< DigestHMAC_MD5_Impl* >(Digest); + ContextHMAC_MD5 *ctx; + + if (!pImpl || !pKeyData) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmHMAC_MD5) + return rtl_Digest_E_Algorithm; + + ctx = &(pImpl->m_context); + initHMAC_MD5(ctx); + + if (nKeyLen > DIGEST_CBLOCK_HMAC_MD5) + { + /* Initialize 'opad' with hashed 'KeyData' */ + rtl_digest_updateMD5(&(ctx->m_hash), pKeyData, nKeyLen); + rtl_digest_getMD5(&(ctx->m_hash), ctx->m_opad, RTL_DIGEST_LENGTH_MD5); + } + else + { + /* Initialize 'opad' with plain 'KeyData' */ + memcpy(ctx->m_opad, pKeyData, nKeyLen); + } + + ipadHMAC_MD5(ctx); + opadHMAC_MD5(ctx); + + return rtl_Digest_E_None; +} + +rtlDigestError SAL_CALL rtl_digest_updateHMAC_MD5( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) noexcept +{ + DigestHMAC_MD5_Impl *pImpl = static_cast< DigestHMAC_MD5_Impl* >(Digest); + ContextHMAC_MD5 *ctx; + + if (!pImpl || !pData) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmHMAC_MD5) + return rtl_Digest_E_Algorithm; + + ctx = &(pImpl->m_context); + rtl_digest_updateMD5(&(ctx->m_hash), pData, nDatLen); + + return rtl_Digest_E_None; +} + +rtlDigestError SAL_CALL rtl_digest_getHMAC_MD5( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) noexcept +{ + DigestHMAC_MD5_Impl *pImpl = static_cast(Digest); + ContextHMAC_MD5 *ctx; + + if (!pImpl || !pBuffer) + return rtl_Digest_E_Argument; + + if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmHMAC_MD5) + return rtl_Digest_E_Algorithm; + + if (pImpl->m_digest.m_length > nBufLen) + return rtl_Digest_E_BufferSize; + + nBufLen = pImpl->m_digest.m_length; + + ctx = &(pImpl->m_context); + rtl_digest_getMD5(&(ctx->m_hash), pBuffer, nBufLen); + + rtl_digest_updateMD5(&(ctx->m_hash), ctx->m_opad, 64); + rtl_digest_updateMD5(&(ctx->m_hash), pBuffer, nBufLen); + rtl_digest_getMD5(&(ctx->m_hash), pBuffer, nBufLen); + + opadHMAC_MD5(ctx); + ipadHMAC_MD5(ctx); + opadHMAC_MD5(ctx); + + return rtl_Digest_E_None; +} + +void SAL_CALL rtl_digest_destroyHMAC_MD5(rtlDigest Digest) noexcept +{ + DigestHMAC_MD5_Impl *pImpl = static_cast< DigestHMAC_MD5_Impl* >(Digest); + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_MD5) + rtl_freeZeroMemory(pImpl, sizeof(DigestHMAC_MD5_Impl)); + else + free(pImpl); + } +} + #define DIGEST_CBLOCK_HMAC_SHA1 64 namespace {