diff --git a/tests/api/test_sha512.c b/tests/api/test_sha512.c index e44aac331d9..17bb329f392 100644 --- a/tests/api/test_sha512.c +++ b/tests/api/test_sha512.c @@ -274,6 +274,32 @@ int test_wc_Sha512Transform(void) "\x68\x75\xde\x70\x09\x4d\xcd\xfe" "\xbe\x11\x20\xd6\xe7\x7c\x49\xd3" "\x5b\xd7\x07\x75\x19\xc9\x8a\xfa"); +#if !defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0) + /* Transform must not modify the caller's block (v5/v6 modules do). */ + ExpectBufEQ(abcData, abcSha512Data, WC_SHA512_BLOCK_SIZE); + /* Transform must keep input pending from an earlier Update. */ + { + wc_Sha512 shaA; + wc_Sha512 shaB; + byte hashA[WC_SHA512_DIGEST_SIZE]; + byte hashB[WC_SHA512_DIGEST_SIZE]; + + XMEMSET(&shaA, 0, sizeof(shaA)); + XMEMSET(&shaB, 0, sizeof(shaB)); + ExpectIntEQ(wc_InitSha512(&shaA), 0); + ExpectIntEQ(wc_Sha512Update(&shaA, (const byte*)"ab", 2), 0); + ExpectIntEQ(wc_Sha512Transform(&shaA, abcData), 0); + ExpectIntEQ(wc_Sha512Update(&shaA, (const byte*)"c", 1), 0); + ExpectIntEQ(wc_Sha512Final(&shaA, hashA), 0); + ExpectIntEQ(wc_InitSha512(&shaB), 0); + ExpectIntEQ(wc_Sha512Transform(&shaB, abcData), 0); + ExpectIntEQ(wc_Sha512Update(&shaB, (const byte*)"abc", 3), 0); + ExpectIntEQ(wc_Sha512Final(&shaB, hashB), 0); + ExpectBufEQ(hashA, hashB, WC_SHA512_DIGEST_SIZE); + wc_Sha512Free(&shaA); + wc_Sha512Free(&shaB); + } +#endif #endif return EXPECT_RESULT(); } @@ -342,6 +368,24 @@ int test_wc_Sha512_224FinalRaw(void) "\x73\xe1\x99\x66\x89\xdc\xd4\xd6" "\x1d\xfa\xb7\xae\x32\xff\x9c\x82" "\x67\x9d\xd5\x14"); + { + /* Hashing continues after FinalRaw: "ab", raw read, "c" is "abc". */ + wc_Sha512 raw; + byte rawHash[WC_SHA512_224_DIGEST_SIZE]; + + XMEMSET(&raw, 0, sizeof(raw)); + ExpectIntEQ(wc_InitSha512_224(&raw), 0); + ExpectIntEQ(wc_Sha512_224Update(&raw, (const byte*)"ab", 2), 0); + ExpectIntEQ(wc_Sha512_224FinalRaw(&raw, rawHash), 0); + ExpectIntEQ(wc_Sha512_224Update(&raw, (const byte*)"c", 1), 0); + ExpectIntEQ(wc_Sha512_224Final(&raw, rawHash), 0); + ExpectBufEQ(rawHash, + "\x46\x34\x27\x0f\x70\x7b\x6a\x54" + "\xda\xae\x75\x30\x46\x08\x42\xe2" + "\x0e\x37\xed\x26\x5c\xee\xe9\xa4" + "\x3e\x89\x24\xaa", WC_SHA512_224_DIGEST_SIZE); + wc_Sha512_224Free(&raw); + } #endif return EXPECT_RESULT(); } /* END test_wc_Sha512_224Final */ diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index 2e048f0e72a..eddb1caeff6 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -2716,9 +2716,12 @@ static int Sha512FinalRaw(wc_Sha512* sha512, byte* hash, word32 digestSz) if ((digestSz & 0x7) == 0) ByteReverseWords64((word64 *)hash, sha512->digest, digestSz); else { + /* Reverse for the copy, then reverse back to keep the state. */ ByteReverseWords64(sha512->digest, sha512->digest, WC_SHA512_DIGEST_SIZE); XMEMCPY(hash, sha512->digest, digestSz); + ByteReverseWords64(sha512->digest, sha512->digest, + WC_SHA512_DIGEST_SIZE); } #else XMEMCPY(hash, sha512->digest, digestSz); @@ -2877,7 +2880,7 @@ void wc_Sha512Free(wc_Sha512* sha512) int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data) { int ret; - /* back up buffer */ + /* aligned copy of data, or backup of sha->buffer */ WC_DECLARE_VAR(buffer, word64, WC_SHA512_BLOCK_SIZE / sizeof(word64), 0); @@ -2907,28 +2910,34 @@ int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data) wc_MemZero_Add("wc_Sha512Transform buffer", buffer, WC_SHA512_BLOCK_SIZE); #endif + /* data is const: never modify the caller's block. */ +#if (defined(WOLFSSL_ARMASM) && defined(WOLFSSL_ARM_ARCH) && \ + (WOLFSSL_ARM_ARCH < 6)) || \ + (defined(WOLFSSL_RISCV_ASM) && defined(WOLFSSL_RISCV_VECTOR_CRYPTO_ASM)) + /* ARMv5 LDR and RISC-V vl8re64.v loads need an aligned copy. */ + XMEMCPY(buffer, data, WC_SHA512_BLOCK_SIZE); + ret = Transform_Sha512(sha, (const byte*)buffer); +#elif defined(WOLFSSL_ARMASM) && defined(__aarch64__) + /* The C CPU step writes sha->buffer, which may hold pending input. */ + XMEMCPY(buffer, sha->buffer, WC_SHA512_BLOCK_SIZE); + ret = Transform_Sha512(sha, data); + XMEMCPY(sha->buffer, buffer, WC_SHA512_BLOCK_SIZE); +#elif defined(WOLFSSL_ARMASM) || defined(WOLFSSL_RISCV_ASM) || \ + defined(WOLFSSL_PPC64_ASM) || defined(WOLFSSL_PPC32_ASM) + /* The asm reads data as Sha512Update passes it: unreversed. */ + ret = Transform_Sha512(sha, data); +#else + XMEMCPY(buffer, sha->buffer, WC_SHA512_BLOCK_SIZE); + XMEMCPY(sha->buffer, data, WC_SHA512_BLOCK_SIZE); #if defined(LITTLE_ENDIAN_ORDER) && !defined(WC_SHA512_RAW_BE_BUFFER) #if defined(WOLFSSL_X86_64_BUILD) && defined(USE_INTEL_SPEEDUP) && \ (defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2)) if (!IS_INTEL_AVX1(intel_flags) && !IS_INTEL_AVX2(intel_flags)) #endif { - ByteReverseWords64((word64*)data, (word64*)data, - WC_SHA512_BLOCK_SIZE); + ByteReverseWords64(sha->buffer, sha->buffer, WC_SHA512_BLOCK_SIZE); } -#endif /* LITTLE_ENDIAN_ORDER && !WC_SHA512_RAW_BE_BUFFER */ - -#if defined(WOLFSSL_ARMASM) || defined(WOLFSSL_RISCV_ASM) - ByteReverseWords64(buffer, (word64*)data, WC_SHA512_BLOCK_SIZE); - ret = Transform_Sha512(sha, (const byte*)buffer); -#elif defined(WOLFSSL_PPC64_ASM) || defined(WOLFSSL_PPC32_ASM) - /* PPC assembly uses the (sha, data) form and reads the block directly - * (big-endian native - any little-endian reversal was done above). */ - (void)buffer; - ret = Transform_Sha512(sha, data); -#else - XMEMCPY(buffer, sha->buffer, WC_SHA512_BLOCK_SIZE); - XMEMCPY(sha->buffer, data, WC_SHA512_BLOCK_SIZE); +#endif ret = Transform_Sha512(sha);