Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions tests/api/test_sha512.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ 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);
#endif
#endif
return EXPECT_RESULT();
}
Expand Down Expand Up @@ -342,6 +346,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 */
Expand Down
38 changes: 23 additions & 15 deletions wolfcrypt/src/sha512.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -2907,28 +2910,33 @@ 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)
/* ARMv5 asm loads words with LDR, so it needs 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);
Comment thread
kaleb-himes marked this conversation as resolved.
Resolved
Comment on lines +2924 to +2927

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 (optional) RISC-V vector-crypto builds can now fault in wc_Sha512Transform on a misaligned caller block. The base code gave the asm an aligned word64 copy. The shared branch at sha512.c:2924-2927 passes data straight to Transform_Sha512_Len_riscv_vector. That routine loads it with vl8re64.v, which RVV allows to raise an address-misaligned exception. Fix: when WOLFSSL_RISCV_VECTOR_CRYPTO_ASM is set, copy data into the local aligned buffer first, as the ARMv5 branch at 2916-2918 does. That keeps the caller's block unmodified and every load aligned.

Why this was flagged

The trigger is a build with --enable-riscv-asm and WOLFSSL_RISCV_VECTOR_CRYPTO_ASM, running on a core or kernel that does not handle misaligned vector element accesses. The caller passes a block at an address that is not 8-byte aligned, through wc_Sha512Transform or wolfSSL_SHA512_Transform. The new branch at sha512.c:2924-2927 calls Transform_Sha512(sha, data). Under WOLFSSL_RISCV_VECTOR_CRYPTO_ASM, sha512.c:1915-1918 sends that to Transform_Sha512_Len_riscv_vector, which loads the block with vl8re64.v v0, (t1) (riscv-64-sha512-asm.S:117). Under the RVV spec a misaligned 64-bit element may raise an address-misaligned exception, so the process can get SIGBUS. The base always ran ByteReverseWords64(buffer, ...) into the word64-aligned local buffer and passed that, so the vector load was always aligned. The PR's own ARMv5 branch (sha512.c:2916) already makes an aligned copy for this kind of hazard, but nothing does the same for RISC-V vector.

Verification: In the base, the RISC-V branch ran ByteReverseWords64(buffer, ...), so the asm always got the aligned local word64 buffer. The new shared branch passes the caller's pointer straight through. Transform_Sha512 (sha512.c ~1915-1918) calls Transform_Sha512_Len_riscv_vector(sha512, data, WC_SHA512_BLOCK_SIZE). That routine does vl8re64.v v0, (t1) (riscv-64-sha512-asm.S:116-117).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed, and fixed in b6111e438d. The vector-crypto lane loads the block with vl8re64.v (riscv-64-sha512-asm.S:117), and RVV 1.0 §7.9 lets whole-register loads raise an address-misaligned exception when the base is not aligned to the element size (8 bytes here). Transform now copies the block into the aligned local buffer first for WOLFSSL_RISCV_VECTOR_CRYPTO_ASM, the same as ARMv5. The base and scalar-crypto RISC-V lanes still pass data through: they load with lbu, or with ld on Zbb builds, which have their own WOLFSSL_RISCV_ASM_NO_UNALIGNED opt-out. Tested under qemu-riscv64 -cpu max with --enable-riscv-asm=zv,zvkb,zvkned: the SHA-512 tests pass, and an aligned and a misaligned Transform of the same block give the same digest. qemu does not fault on misaligned vector loads, so the trap itself was not reproduced. Thanks!

#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);

Expand Down
Loading