Skip to content

Commit 3a36f93

Browse files
Translate SHA-2 intermediate state for cross-endian peers
1 parent 62eea4e commit 3a36f93

6 files changed

Lines changed: 514 additions & 44 deletions

File tree

docs/draft/async-crypto.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ is:
128128
| Sha256Request / Sha512Request | resumeState + control fields
129129
| resumeState.hiLen (4 bytes) |
130130
| resumeState.loLen (4 bytes) |
131-
| resumeState.hash (32 or 64 bytes) | intermediate digest
131+
| resumeState.hash (32 or 64 bytes) | intermediate digest (see below)
132132
| [resumeState.hashType (4 bytes)] | SHA-512 family only
133133
| isLastBlock (4 bytes) |
134134
| inSz (4 bytes) |
@@ -346,6 +346,22 @@ reaches the server:
346346
The hash state (`resumeState`) always travels **inline**, not via DMA, for
347347
cross-architecture concerns (endian translation, etc.)
348348

349+
### Endianness of `resumeState.hash`
350+
351+
`resumeState.hash` is not an opaque byte array. wolfCrypt keeps the SHA-2
352+
chaining variables in `wc_Sha256.digest` / `wc_Sha512.digest` as **host-order**
353+
`word32` / `word64`, and the client copies them to the wire verbatim, so the
354+
field carries eight chaining words in the *client's* byte order. The server
355+
byte-swaps each word when the client's `magic` reports the opposite endianness,
356+
exactly as it does for the SHA-3 Keccak state (`whMessageCrypto_Sha3State`).
357+
358+
The response field is context-dependent: on a non-final update it carries the
359+
same host-order chaining words, but on `isLastBlock` it carries the finalized
360+
digest, which wolfCrypt has already emitted in canonical big-endian byte order
361+
and which must not be swapped. The response translation helpers therefore take
362+
the chaining word size (4, 8, or 0 for a finalized digest) from the caller —
363+
see `wh_MessageCrypto_TranslateSha2Response_ex()`.
364+
349365
DMA async functions require the client to stash the translated DMA address
350366
across the Request/Response boundary for POST cleanup. This context is stored
351367
in `whClientContext.dma.asyncCtx.sha`:

src/wh_message_crypto.c

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,43 @@ int wh_MessageCrypto_TranslateEd25519VerifyResponse(
639639
return 0;
640640
}
641641

642+
/* Number of chaining words in a SHA-2 intermediate state, for every variant */
643+
#define WH_MESSAGE_CRYPTO_SHA2_STATE_WORDS 8
644+
645+
/* Swap the host-order chaining words of a serialized SHA-2 state, as the SHA3
646+
* Keccak state does. wordSize is 4 (SHA224/256) or 8 (SHA384/512); any other
647+
* value, including 0 for a finalized digest, copies the array verbatim. */
648+
static void _TranslateSha2State(uint16_t magic, uint8_t* dest,
649+
const uint8_t* src, uint32_t hashSz,
650+
uint32_t wordSize)
651+
{
652+
uint32_t i;
653+
uint32_t stateSz = WH_MESSAGE_CRYPTO_SHA2_STATE_WORDS * wordSize;
654+
uint32_t w32;
655+
uint64_t w64;
656+
657+
if (dest != src) {
658+
memcpy(dest, src, hashSz);
659+
}
660+
if (stateSz > hashSz) {
661+
return;
662+
}
663+
if (wordSize == sizeof(uint32_t)) {
664+
for (i = 0; i < stateSz; i += wordSize) {
665+
memcpy(&w32, dest + i, sizeof(w32));
666+
w32 = wh_Translate32(magic, w32);
667+
memcpy(dest + i, &w32, sizeof(w32));
668+
}
669+
}
670+
else if (wordSize == sizeof(uint64_t)) {
671+
for (i = 0; i < stateSz; i += wordSize) {
672+
memcpy(&w64, dest + i, sizeof(w64));
673+
w64 = wh_Translate64(magic, w64);
674+
memcpy(dest + i, &w64, sizeof(w64));
675+
}
676+
}
677+
}
678+
642679
/* SHA256 Request translation. Only the fixed-size header is translated; any
643680
* trailing variable-length input bytes (uint8_t in[inSz]) are raw bytes that
644681
* do not need endian translation. */
@@ -651,11 +688,10 @@ int wh_MessageCrypto_TranslateSha256Request(
651688
}
652689
WH_T32(magic, dest, src, resumeState.hiLen);
653690
WH_T32(magic, dest, src, resumeState.loLen);
654-
/* Hash value is just a byte array, no translation needed */
655-
if (src != dest) {
656-
memcpy(dest->resumeState.hash, src->resumeState.hash,
657-
sizeof(src->resumeState.hash));
658-
}
691+
/* A request always carries intermediate state, even on the last block */
692+
_TranslateSha2State(magic, dest->resumeState.hash, src->resumeState.hash,
693+
(uint32_t)sizeof(src->resumeState.hash),
694+
(uint32_t)sizeof(uint32_t));
659695
WH_T32(magic, dest, src, isLastBlock);
660696
WH_T32(magic, dest, src, inSz);
661697
return 0;
@@ -675,32 +711,38 @@ int wh_MessageCrypto_TranslateSha512Request(
675711
WH_T32(magic, dest, src, resumeState.hiLen);
676712
WH_T32(magic, dest, src, resumeState.loLen);
677713
WH_T32(magic, dest, src, resumeState.hashType);
678-
/* Hash value is just a byte array, no translation needed */
679-
if (src != dest) {
680-
memcpy(dest->resumeState.hash, src->resumeState.hash,
681-
sizeof(src->resumeState.hash));
682-
}
714+
/* A request always carries intermediate state, even on the last block */
715+
_TranslateSha2State(magic, dest->resumeState.hash, src->resumeState.hash,
716+
(uint32_t)sizeof(src->resumeState.hash),
717+
(uint32_t)sizeof(uint64_t));
683718
WH_T32(magic, dest, src, isLastBlock);
684719
WH_T32(magic, dest, src, inSz);
685720
return 0;
686721
}
687722
#endif /* WOLFSSL_SHA512 || WOLFSSL_SHA384 */
688723

689-
/* SHA2 Response translation */
724+
/* SHA2 Response translation, treating hash as a finalized digest */
690725
int wh_MessageCrypto_TranslateSha2Response(
691726
uint16_t magic, const whMessageCrypto_Sha2Response* src,
692727
whMessageCrypto_Sha2Response* dest)
728+
{
729+
return wh_MessageCrypto_TranslateSha2Response_ex(magic, src, dest, 0);
730+
}
731+
732+
/* SHA2 Response translation. stateWordSize is the chaining word size when hash
733+
* carries intermediate state, or 0 when it carries a finalized digest. */
734+
int wh_MessageCrypto_TranslateSha2Response_ex(
735+
uint16_t magic, const whMessageCrypto_Sha2Response* src,
736+
whMessageCrypto_Sha2Response* dest, uint32_t stateWordSize)
693737
{
694738
if ((src == NULL) || (dest == NULL)) {
695739
return WH_ERROR_BADARGS;
696740
}
697741
WH_T32(magic, dest, src, hiLen);
698742
WH_T32(magic, dest, src, loLen);
699743
WH_T32(magic, dest, src, hashType);
700-
/* Hash value is just a byte array, no translation needed */
701-
if (src != dest) {
702-
memcpy(dest->hash, src->hash, sizeof(src->hash));
703-
}
744+
_TranslateSha2State(magic, dest->hash, src->hash,
745+
(uint32_t)sizeof(src->hash), stateWordSize);
704746
return 0;
705747
}
706748

@@ -1024,10 +1066,9 @@ int wh_MessageCrypto_TranslateSha256DmaRequest(
10241066

10251067
WH_T32(magic, dest, src, resumeState.hiLen);
10261068
WH_T32(magic, dest, src, resumeState.loLen);
1027-
if (src != dest) {
1028-
memcpy(dest->resumeState.hash, src->resumeState.hash,
1029-
sizeof(src->resumeState.hash));
1030-
}
1069+
_TranslateSha2State(magic, dest->resumeState.hash, src->resumeState.hash,
1070+
(uint32_t)sizeof(src->resumeState.hash),
1071+
(uint32_t)sizeof(uint32_t));
10311072

10321073
ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->input, &dest->input);
10331074
if (ret != 0) {
@@ -1053,10 +1094,9 @@ int wh_MessageCrypto_TranslateSha512DmaRequest(
10531094

10541095
WH_T32(magic, dest, src, resumeState.hiLen);
10551096
WH_T32(magic, dest, src, resumeState.loLen);
1056-
if (src != dest) {
1057-
memcpy(dest->resumeState.hash, src->resumeState.hash,
1058-
sizeof(src->resumeState.hash));
1059-
}
1097+
_TranslateSha2State(magic, dest->resumeState.hash, src->resumeState.hash,
1098+
(uint32_t)sizeof(src->resumeState.hash),
1099+
(uint32_t)sizeof(uint64_t));
10601100
WH_T32(magic, dest, src, resumeState.hashType);
10611101

10621102
ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->input, &dest->input);
@@ -1070,20 +1110,28 @@ int wh_MessageCrypto_TranslateSha512DmaRequest(
10701110
return 0;
10711111
}
10721112

1073-
/* SHA2 DMA Response translation */
1113+
/* SHA2 DMA Response translation, treating hash as a finalized digest */
10741114
int wh_MessageCrypto_TranslateSha2DmaResponse(
10751115
uint16_t magic, const whMessageCrypto_Sha2DmaResponse* src,
10761116
whMessageCrypto_Sha2DmaResponse* dest)
1117+
{
1118+
return wh_MessageCrypto_TranslateSha2DmaResponse_ex(magic, src, dest, 0);
1119+
}
1120+
1121+
/* SHA2 DMA Response translation. stateWordSize is the chaining word size when
1122+
* hash carries intermediate state, or 0 when it carries a finalized digest. */
1123+
int wh_MessageCrypto_TranslateSha2DmaResponse_ex(
1124+
uint16_t magic, const whMessageCrypto_Sha2DmaResponse* src,
1125+
whMessageCrypto_Sha2DmaResponse* dest, uint32_t stateWordSize)
10771126
{
10781127
if ((src == NULL) || (dest == NULL)) {
10791128
return WH_ERROR_BADARGS;
10801129
}
10811130

10821131
WH_T32(magic, dest, src, hiLen);
10831132
WH_T32(magic, dest, src, loLen);
1084-
if (src != dest) {
1085-
memcpy(dest->hash, src->hash, sizeof(src->hash));
1086-
}
1133+
_TranslateSha2State(magic, dest->hash, src->hash,
1134+
(uint32_t)sizeof(src->hash), stateWordSize);
10871135
WH_T32(magic, dest, src, hashType);
10881136

10891137
return wh_MessageCrypto_TranslateDmaAddrStatus(magic, &src->dmaAddrStatus,

src/wh_server_crypto.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4234,8 +4234,9 @@ static int _HandleSha256(whServerContext* ctx, uint16_t magic, int devId,
42344234

42354235
/* Translate the response */
42364236
if (ret == 0) {
4237-
ret =
4238-
wh_MessageCrypto_TranslateSha2Response(magic, &res, cryptoDataOut);
4237+
ret = wh_MessageCrypto_TranslateSha2Response_ex(
4238+
magic, &res, cryptoDataOut,
4239+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint32_t));
42394240
if (ret == 0) {
42404241
*outSize = sizeof(res);
42414242
}
@@ -4325,8 +4326,9 @@ static int _HandleSha224(whServerContext* ctx, uint16_t magic, int devId,
43254326

43264327
/* Translate the response */
43274328
if (ret == 0) {
4328-
ret =
4329-
wh_MessageCrypto_TranslateSha2Response(magic, &res, cryptoDataOut);
4329+
ret = wh_MessageCrypto_TranslateSha2Response_ex(
4330+
magic, &res, cryptoDataOut,
4331+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint32_t));
43304332
if (ret == 0) {
43314333
*outSize = sizeof(res);
43324334
}
@@ -4421,8 +4423,9 @@ static int _HandleSha384(whServerContext* ctx, uint16_t magic, int devId,
44214423

44224424
/* Translate the response */
44234425
if (ret == 0) {
4424-
ret =
4425-
wh_MessageCrypto_TranslateSha2Response(magic, &res, cryptoDataOut);
4426+
ret = wh_MessageCrypto_TranslateSha2Response_ex(
4427+
magic, &res, cryptoDataOut,
4428+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint64_t));
44264429
if (ret == 0) {
44274430
*outSize = sizeof(res);
44284431
}
@@ -4545,8 +4548,9 @@ static int _HandleSha512(whServerContext* ctx, uint16_t magic, int devId,
45454548

45464549
/* Translate the response */
45474550
if (ret == 0) {
4548-
ret =
4549-
wh_MessageCrypto_TranslateSha2Response(magic, &res, cryptoDataOut);
4551+
ret = wh_MessageCrypto_TranslateSha2Response_ex(
4552+
magic, &res, cryptoDataOut,
4553+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint64_t));
45504554
if (ret == 0) {
45514555
*outSize = sizeof(res);
45524556
}
@@ -5920,8 +5924,9 @@ static int _HandleSha256Dma(whServerContext* ctx, uint16_t magic, int devId,
59205924
}
59215925
}
59225926

5923-
(void)wh_MessageCrypto_TranslateSha2DmaResponse(
5924-
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut);
5927+
(void)wh_MessageCrypto_TranslateSha2DmaResponse_ex(
5928+
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut,
5929+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint32_t));
59255930
*outSize = sizeof(res);
59265931

59275932
return ret;
@@ -6024,8 +6029,9 @@ static int _HandleSha224Dma(whServerContext* ctx, uint16_t magic, int devId,
60246029
}
60256030
}
60266031

6027-
(void)wh_MessageCrypto_TranslateSha2DmaResponse(
6028-
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut);
6032+
(void)wh_MessageCrypto_TranslateSha2DmaResponse_ex(
6033+
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut,
6034+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint32_t));
60296035
*outSize = sizeof(res);
60306036

60316037
return ret;
@@ -6128,8 +6134,9 @@ static int _HandleSha384Dma(whServerContext* ctx, uint16_t magic, int devId,
61286134
}
61296135
}
61306136

6131-
(void)wh_MessageCrypto_TranslateSha2DmaResponse(
6132-
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut);
6137+
(void)wh_MessageCrypto_TranslateSha2DmaResponse_ex(
6138+
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut,
6139+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint64_t));
61336140
*outSize = sizeof(res);
61346141

61356142
return ret;
@@ -6266,8 +6273,9 @@ static int _HandleSha512Dma(whServerContext* ctx, uint16_t magic, int devId,
62666273
}
62676274
}
62686275

6269-
(void)wh_MessageCrypto_TranslateSha2DmaResponse(
6270-
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut);
6276+
(void)wh_MessageCrypto_TranslateSha2DmaResponse_ex(
6277+
magic, &res, (whMessageCrypto_Sha2DmaResponse*)cryptoDataOut,
6278+
req.isLastBlock ? 0 : (uint32_t)sizeof(uint64_t));
62716279
*outSize = sizeof(res);
62726280

62736281
return ret;

0 commit comments

Comments
 (0)