Skip to content

Commit 5e898d7

Browse files
committed
wolfcrypt: support CHAR_BIT != 8 (WOLFSSL_WIDE_BYTE) targets - infra, hashes, DRBG
Enables wolfCrypt on toolchains where a C byte/char is wider than 8 bits (e.g. TI C2000 C28x, CHAR_BIT == 16), all gated on WOLFSSL_WIDE_BYTE and a no-op on 8-bit-byte targets (the default fast paths are left exactly as-is): - types.h: auto-set WOLFSSL_WIDE_BYTE for CHAR_BIT != 8 / known TI C2000 toolchains (and define CHAR_BIT = 16 when <limits.h> is absent); wc_port.h/.c widen the atomic init-state bitfield + CHAR_BIT static assert for 16-bit int. - settings.h + sp_int.h: allow SP math on a 16-bit-int CPU via WOLFSSL_SP_ALLOW_16BIT_CPU, and detect a 16-bit char in the SP smallest-type selection. - misc.c/misc.h: shared big-endian octet<->word helpers (WordsFromBytesBE32/64, BytesFromWordsBE32/64) for WOLFSSL_WIDE_BYTE, where a word cannot be aliased as an octet stream. They are CHAR_BIT-generic, cl2000-safe (loads accumulate with <<= 8, since (word)octet << 24 is miscompiled as a 16-bit shift), in-place safe for the SHA schedule, and store by octet count for partial digests. misc.c rotate width uses CHAR_BIT. - coding.c: mask the constant-time base64 result to an octet. - sha256.c/sha512.c: use the shared helpers for the schedule load and digest store, plus a CHAR_BIT*sizeof length carry; sha3.c: octet-wise Keccak squeeze. - random.c: Hash-DRBG length + reseed-counter serialization via the shared helpers (and an octet-masked carry) under WOLFSSL_WIDE_BYTE; default builds keep the word-aliasing path unchanged. WOLFSSL_WIDE_BYTE replaces the earlier WOLFSSL_NO_OCTET_BYTE working name.
1 parent 3f9ae22 commit 5e898d7

13 files changed

Lines changed: 376 additions & 30 deletions

File tree

.wolfssl_known_macro_extras

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ WOLFSSL_CLANG_TIDY
747747
WOLFSSL_CLIENT_EXAMPLE
748748
WOLFSSL_CONTIKI
749749
WOLFSSL_CRL_ALLOW_MISSING_CDP
750+
WOLFSSL_DILITHIUM_VERIFY_SMALLEST_MEM
750751
WOLFSSL_DISABLE_EARLY_SANITY_CHECKS
751752
WOLFSSL_DRBG_SHA256
752753
WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID
@@ -1115,6 +1116,12 @@ __SUNPRO_CC
11151116
__SVR4
11161117
__TASKING__
11171118
__TI_COMPILER_VERSION__
1119+
__TMS320C2000__
1120+
__TMS320C2800__
1121+
__TMS320C28XX__
1122+
__TMS320C54X__
1123+
__TMS320C5500__
1124+
__TMS320C55X__
11181125
__TURBOC__
11191126
__UNIX__
11201127
__USE_GNU

wolfcrypt/src/coding.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static WC_INLINE byte Base64_Char2Val_CT(byte c)
7272
v |= ((slashStart >> 8) ^ (slashEnd >> 8)) & (slashStart + 63 + 1);
7373
v |= ((plusStart >> 8) ^ (plusEnd >> 8)) & (plusStart + 62 + 1);
7474

75-
return (byte)(v - 1);
75+
return WC_OCTET(v - 1);
7676
}
7777

7878
#ifndef BASE64_NO_TABLE

wolfcrypt/src/misc.c

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,28 +108,28 @@ masking and clearing memory logic.
108108

109109
WC_MISC_STATIC WC_INLINE word32 rotlFixed(word32 x, word32 y)
110110
{
111-
return (x << y) | (x >> (sizeof(x) * 8 - y));
111+
return (x << y) | (x >> (sizeof(x) * CHAR_BIT - y));
112112
}
113113

114114
/* This routine performs a right circular arithmetic shift of <x> by <y> value. */
115115
WC_MISC_STATIC WC_INLINE word32 rotrFixed(word32 x, word32 y)
116116
{
117-
return (x >> y) | (x << (sizeof(x) * 8 - y));
117+
return (x >> y) | (x << (sizeof(x) * CHAR_BIT - y));
118118
}
119119

120120
#endif
121121

122122
/* This routine performs a left circular arithmetic shift of <x> by <y> value */
123123
WC_MISC_STATIC WC_INLINE word16 rotlFixed16(word16 x, word16 y)
124124
{
125-
return (word16)((x << y) | (x >> (sizeof(x) * 8U - y)));
125+
return (word16)((x << y) | (x >> (sizeof(x) * CHAR_BIT - y)));
126126
}
127127

128128

129129
/* This routine performs a right circular arithmetic shift of <x> by <y> value */
130130
WC_MISC_STATIC WC_INLINE word16 rotrFixed16(word16 x, word16 y)
131131
{
132-
return (word16)((x >> y) | (x << (sizeof(x) * 8U - y)));
132+
return (word16)((x >> y) | (x << (sizeof(x) * CHAR_BIT - y)));
133133
}
134134

135135
/* This routine performs a byte swap of 32-bit word value. */
@@ -329,13 +329,13 @@ WC_MISC_STATIC WC_INLINE void writeUnalignedWords64(byte *out, const word64 *in,
329329

330330
WC_MISC_STATIC WC_INLINE word64 rotlFixed64(word64 x, word64 y)
331331
{
332-
return (x << y) | (x >> (sizeof(y) * 8 - y));
332+
return (x << y) | (x >> (sizeof(y) * CHAR_BIT - y));
333333
}
334334

335335

336336
WC_MISC_STATIC WC_INLINE word64 rotrFixed64(word64 x, word64 y)
337337
{
338-
return (x >> y) | (x << (sizeof(y) * 8 - y));
338+
return (x >> y) | (x << (sizeof(y) * CHAR_BIT - y));
339339
}
340340

341341

@@ -410,6 +410,69 @@ WC_MISC_STATIC WC_INLINE void ByteReverseWords64(word64* out, const word64* in,
410410

411411
#endif /* WORD64_AVAILABLE && !WOLFSSL_NO_WORD64_OPS */
412412

413+
#ifdef WOLFSSL_WIDE_BYTE
414+
/* Big-endian octet <-> word conversion for targets where a C 'byte' (char) is
415+
* wider than 8 bits (WOLFSSL_WIDE_BYTE, i.e. CHAR_BIT != 8 - e.g. the TI C2000
416+
* C28x). There a word holds several octets per addressable cell, so it cannot
417+
* be aliased as an octet stream (XMEMCPY / ByteReverseWords / (byte) casts all
418+
* assume one octet per cell). These helpers move between an octet stream (one
419+
* octet per byte cell) and big-endian words with shifts, correct for any
420+
* CHAR_BIT. Shared by SHA-2 (schedule load + digest store) and the Hash-DRBG.
421+
*
422+
* Loads accumulate through a word with <<= 8 so each shift is unambiguously
423+
* full-word width: a single (word32)octet << 24 is miscompiled as a 16-bit
424+
* shift by the TI cl2000 (the top octets are dropped). A load reads all of a
425+
* word's octets before writing the word, so it is safe in place over the
426+
* destination word buffer. Stores take an octet count (not a word count) so a
427+
* partial trailing word works - e.g. SHA-512/224's 28-octet digest. */
428+
WC_MISC_STATIC WC_INLINE void WordsFromBytesBE32(word32* w, const byte* b,
429+
word32 wordCnt)
430+
{
431+
word32 i;
432+
word32 r;
433+
for (i = 0; i < wordCnt; i++) {
434+
r = (word32)(b[(i * 4) + 0] & 0xFF); r <<= 8;
435+
r |= (word32)(b[(i * 4) + 1] & 0xFF); r <<= 8;
436+
r |= (word32)(b[(i * 4) + 2] & 0xFF); r <<= 8;
437+
r |= (word32)(b[(i * 4) + 3] & 0xFF);
438+
w[i] = r;
439+
}
440+
}
441+
WC_MISC_STATIC WC_INLINE void BytesFromWordsBE32(byte* b, const word32* w,
442+
word32 byteCnt)
443+
{
444+
word32 i;
445+
for (i = 0; i < byteCnt; i++) {
446+
b[i] = (byte)((w[i >> 2] >> (24 - ((i & 0x3) * 8))) & 0xFF);
447+
}
448+
}
449+
#ifdef WORD64_AVAILABLE
450+
WC_MISC_STATIC WC_INLINE void WordsFromBytesBE64(word64* w, const byte* b,
451+
word32 wordCnt)
452+
{
453+
word32 i;
454+
int j;
455+
word64 r;
456+
for (i = 0; i < wordCnt; i++) {
457+
r = 0;
458+
for (j = 0; j < 8; j++) {
459+
r <<= 8;
460+
r |= (word64)(b[(i * 8) + j] & 0xFF);
461+
}
462+
w[i] = r;
463+
}
464+
}
465+
WC_MISC_STATIC WC_INLINE void BytesFromWordsBE64(byte* b, const word64* w,
466+
word32 byteCnt)
467+
{
468+
word32 i;
469+
for (i = 0; i < byteCnt; i++) {
470+
b[i] = (byte)((w[i >> 3] >> (56 - ((i & 0x7) * 8))) & 0xFF);
471+
}
472+
}
473+
#endif /* WORD64_AVAILABLE */
474+
#endif /* WOLFSSL_WIDE_BYTE */
475+
413476
#ifndef WOLFSSL_NO_XOR_OPS
414477

415478
/* Leave no doubt that WOLFSSL_WORD_SIZE is a power of 2. */

wolfcrypt/src/random.c

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,10 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type,
464464
byte ctr;
465465
word32 i;
466466
word32 len;
467-
word32 bits = (outSz * 8); /* reverse byte order */
467+
word32 bits = (outSz * 8);
468+
#ifdef WOLFSSL_WIDE_BYTE
469+
byte bitsBuf[4]; /* the 32-bit length as four big-endian octets */
470+
#endif
468471
#ifdef WOLFSSL_SMALL_STACK_CACHE
469472
wc_Sha256* sha = &drbg->sha256;
470473
#else
@@ -489,7 +492,11 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type,
489492
return DRBG_FAILURE;
490493
#endif
491494

492-
#ifdef LITTLE_ENDIAN_ORDER
495+
#ifdef WOLFSSL_WIDE_BYTE
496+
/* A word32 cannot be aliased as an octet stream where a C byte is wider
497+
* than 8 bits; emit the length as four big-endian octets (shared helper). */
498+
BytesFromWordsBE32(bitsBuf, &bits, 4);
499+
#elif defined(LITTLE_ENDIAN_ORDER)
493500
bits = ByteReverseWord32(bits);
494501
#endif
495502
len = (outSz / OUTPUT_BLOCK_LEN)
@@ -509,7 +516,11 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type,
509516
ret = wc_Sha256Update(sha, &ctr, sizeof(ctr));
510517
if (ret == 0) {
511518
ctr++;
519+
#ifdef WOLFSSL_WIDE_BYTE
520+
ret = wc_Sha256Update(sha, bitsBuf, sizeof(bitsBuf));
521+
#else
512522
ret = wc_Sha256Update(sha, (byte*)&bits, sizeof(bits));
523+
#endif
513524
}
514525

515526
if (ret == 0) {
@@ -666,7 +677,7 @@ static WC_INLINE void array_add_one(byte* data, word32 dataSz)
666677
{
667678
int i;
668679
for (i = (int)dataSz - 1; i >= 0; i--) {
669-
data[i]++;
680+
data[i] = WC_OCTET(data[i] + 1);
670681
if (data[i] != 0) break;
671682
}
672683
}
@@ -789,14 +800,14 @@ static WC_INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen
789800
dIdx = (int)dLen - 1;
790801
for (sIdx = (int)sLen - 1; sIdx >= 0; sIdx--) {
791802
carry = (word16)(carry + d[dIdx] + s[sIdx]);
792-
d[dIdx] = (byte)carry;
803+
d[dIdx] = WC_OCTET(carry);
793804
carry >>= 8;
794805
dIdx--;
795806
}
796807

797808
for (; dIdx >= 0; dIdx--) {
798809
carry = (word16)(carry + d[dIdx]);
799-
d[dIdx] = (byte)carry;
810+
d[dIdx] = WC_OCTET(carry);
800811
carry >>= 8;
801812
}
802813
}
@@ -820,6 +831,9 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz,
820831
#else
821832
word32 reseedCtr;
822833
#endif
834+
#ifdef WOLFSSL_WIDE_BYTE
835+
byte ctrBuf[8]; /* reseed counter as big-endian octets */
836+
#endif
823837

824838
if (drbg == NULL) {
825839
return DRBG_FAILURE;
@@ -914,6 +928,17 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz,
914928
if (ret == 0) {
915929
array_add(drbg->V, sizeof(drbg->V), digest, WC_SHA256_DIGEST_SIZE);
916930
array_add(drbg->V, sizeof(drbg->V), drbg->C, sizeof(drbg->C));
931+
#ifdef WOLFSSL_WIDE_BYTE
932+
/* A word cannot be aliased as an octet stream where a C byte is
933+
* wider than 8 bits; add the counter as big-endian octets. */
934+
#ifdef WORD64_AVAILABLE
935+
BytesFromWordsBE64(ctrBuf, &reseedCtr, 8);
936+
array_add(drbg->V, sizeof(drbg->V), ctrBuf, 8);
937+
#else
938+
BytesFromWordsBE32(ctrBuf, &reseedCtr, 4);
939+
array_add(drbg->V, sizeof(drbg->V), ctrBuf, 4);
940+
#endif
941+
#else
917942
#ifdef LITTLE_ENDIAN_ORDER
918943
#ifdef WORD64_AVAILABLE
919944
reseedCtr = ByteReverseWord64(reseedCtr);
@@ -923,6 +948,7 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz,
923948
#endif
924949
array_add(drbg->V, sizeof(drbg->V),
925950
(byte*)&reseedCtr, sizeof(reseedCtr));
951+
#endif
926952
ret = DRBG_SUCCESS;
927953
}
928954
drbg->reseedCtr++;
@@ -1050,6 +1076,9 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz,
10501076
word32 i;
10511077
word32 len;
10521078
word32 bits = (outSz * 8);
1079+
#ifdef WOLFSSL_WIDE_BYTE
1080+
byte bitsBuf[4]; /* the 32-bit length as four big-endian octets */
1081+
#endif
10531082
#ifdef WOLFSSL_SMALL_STACK_CACHE
10541083
wc_Sha512* sha = &drbg->sha512;
10551084
#else
@@ -1082,7 +1111,9 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz,
10821111
return DRBG_FAILURE;
10831112
#endif
10841113

1085-
#ifdef LITTLE_ENDIAN_ORDER
1114+
#ifdef WOLFSSL_WIDE_BYTE
1115+
BytesFromWordsBE32(bitsBuf, &bits, 4); /* see Hash_df */
1116+
#elif defined(LITTLE_ENDIAN_ORDER)
10861117
bits = ByteReverseWord32(bits);
10871118
#endif
10881119
len = (outSz / OUTPUT_BLOCK_LEN_SHA512)
@@ -1102,7 +1133,11 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz,
11021133
ret = wc_Sha512Update(sha, &ctr, sizeof(ctr));
11031134
if (ret == 0) {
11041135
ctr++;
1136+
#ifdef WOLFSSL_WIDE_BYTE
1137+
ret = wc_Sha512Update(sha, bitsBuf, sizeof(bitsBuf));
1138+
#else
11051139
ret = wc_Sha512Update(sha, (byte*)&bits, sizeof(bits));
1140+
#endif
11061141
}
11071142

11081143
if (ret == 0) {
@@ -1300,6 +1335,9 @@ static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out,
13001335
#endif
13011336
byte type;
13021337
word64 reseedCtr;
1338+
#ifdef WOLFSSL_WIDE_BYTE
1339+
byte ctrBuf[8]; /* reseed counter as big-endian octets */
1340+
#endif
13031341

13041342
if (drbg == NULL) {
13051343
return DRBG_FAILURE;
@@ -1377,11 +1415,17 @@ static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out,
13771415
array_add(drbg->V, sizeof(drbg->V), digest,
13781416
WC_SHA512_DIGEST_SIZE);
13791417
array_add(drbg->V, sizeof(drbg->V), drbg->C, sizeof(drbg->C));
1418+
#ifdef WOLFSSL_WIDE_BYTE
1419+
/* See Hash_DRBG_Generate. */
1420+
BytesFromWordsBE64(ctrBuf, &reseedCtr, 8);
1421+
array_add(drbg->V, sizeof(drbg->V), ctrBuf, 8);
1422+
#else
13801423
#ifdef LITTLE_ENDIAN_ORDER
13811424
reseedCtr = ByteReverseWord64(reseedCtr);
13821425
#endif
13831426
array_add(drbg->V, sizeof(drbg->V),
13841427
(byte*)&reseedCtr, sizeof(reseedCtr));
1428+
#endif
13851429
ret = DRBG_SUCCESS;
13861430
}
13871431
drbg->reseedCtr++;

0 commit comments

Comments
 (0)