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
403 changes: 403 additions & 0 deletions src/wh_client_crypto.c

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions src/wh_client_cryptocb.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,62 @@ int wh_Client_CryptoCbStd(int devId, wc_CryptoInfo* info, void* inCtx)
}
} break;
#endif /* WOLFSSL_SHA3 */
#if defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256)
#ifdef WOLFSSL_SHAKE128
case WC_HASH_TYPE_SHAKE128:
#endif
#ifdef WOLFSSL_SHAKE256
case WC_HASH_TYPE_SHAKE256:
#endif
{
/* SHAKE output length the caller chooses, so outSz is
* meaningful only on a finalize. Digest set to NULL means
* update, non-NULL means finalize. */
wc_Shake* sha = info->hash.sha3;
#ifdef WOLFSSL_HASH_FLAGS
/* Keccak mode swaps SHAKE256's 0x1f padding for 0x01, and the
* flag is not carried on the wire, so the server would produce
* different output. Fall through to the software path. */
if (sha != NULL &&
(sha->flags & WC_HASH_SHA3_KECCAK256) != 0u) {
ret = CRYPTOCB_UNAVAILABLE;
break;
}
#endif

/* wolfCrypt accepts a finalize with outSz set to 0: it
* produces nothing and only resets the context, so there is
* nothing worth a round trip. Decline so the software path
* keeps that behaviour rather than turning it into an error. */
if (info->hash.digest != NULL && info->hash.outSz == 0) {
ret = CRYPTOCB_UNAVAILABLE;
break;
}

switch (info->hash.type) {
#ifdef WOLFSSL_SHAKE128
case WC_HASH_TYPE_SHAKE128:
ret = wh_Client_Shake128(ctx, sha, info->hash.in,
info->hash.inSz,
info->hash.digest,
info->hash.outSz);
break;
#endif
#ifdef WOLFSSL_SHAKE256
case WC_HASH_TYPE_SHAKE256:
ret = wh_Client_Shake256(ctx, sha, info->hash.in,
info->hash.inSz,
info->hash.digest,
info->hash.outSz);
break;
#endif
}
/* Requested output size is too big, surface error. */
if (ret == WH_ERROR_NOSPACE) {
ret = CRYPTOCB_UNAVAILABLE;
}
} break;
#endif /* WOLFSSL_SHAKE128 || WOLFSSL_SHAKE256 */
default:
ret = CRYPTOCB_UNAVAILABLE;
break;
Expand Down
29 changes: 29 additions & 0 deletions src/wh_message_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,35 @@ int wh_MessageCrypto_TranslateSha3Response(
return 0;
}

/* SHAKE Request translation. The input and output data follows these structs
* and are byte arrays, so neither translation touches them. */
int wh_MessageCrypto_TranslateShakeRequest(
uint16_t magic, const whMessageCrypto_ShakeRequest* src,
whMessageCrypto_ShakeRequest* dest)
{
if ((src == NULL) || (dest == NULL)) {
return WH_ERROR_BADARGS;
}
WH_T32(magic, dest, src, isLastBlock);
WH_T32(magic, dest, src, inSz);
WH_T32(magic, dest, src, outSz);
return wh_MessageCrypto_TranslateSha3State(magic, &src->resumeState,
&dest->resumeState);
}

/* SHAKE Response translation */
int wh_MessageCrypto_TranslateShakeResponse(
uint16_t magic, const whMessageCrypto_ShakeResponse* src,
whMessageCrypto_ShakeResponse* dest)
{
if ((src == NULL) || (dest == NULL)) {
return WH_ERROR_BADARGS;
}
WH_T32(magic, dest, src, outSz);
return wh_MessageCrypto_TranslateSha3State(magic, &src->resumeState,
&dest->resumeState);
}


/* CMAC-AES State translation */
int wh_MessageCrypto_TranslateCmacAesState(
Expand Down
151 changes: 151 additions & 0 deletions src/wh_server_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -5155,6 +5155,140 @@ static int _HandleSha3(whServerContext* ctx, int hashType, uint16_t magic,
}
#endif /* WOLFSSL_SHA3 */

#if defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256)
/* SHAKE server handler. Mirrors _HandleSha3 above, with the output length
* coming from the request and the result trailing the response rather than
* sitting in a fixed digest field. */
typedef struct {
uint32_t blockSize;
int (*initFn)(wc_Shake* sha, void* heap, int devId);
int (*updateFn)(wc_Shake* sha, const byte* data, word32 len);
int (*finalFn)(wc_Shake* sha, byte* out, word32 outLen);
void (*freeFn)(wc_Shake* sha);
} _ShakeVariantOps;

static int _ShakeLookupOps(int hashType, _ShakeVariantOps* ops)
{
switch (hashType) {
#ifdef WOLFSSL_SHAKE128
case WC_HASH_TYPE_SHAKE128:
ops->blockSize = WC_SHA3_128_COUNT * 8u;
ops->initFn = wc_InitShake128;
ops->updateFn = wc_Shake128_Update;
ops->finalFn = wc_Shake128_Final;
ops->freeFn = wc_Shake128_Free;
return 0;
#endif
#ifdef WOLFSSL_SHAKE256
case WC_HASH_TYPE_SHAKE256:
ops->blockSize = WC_SHA3_256_COUNT * 8u;
ops->initFn = wc_InitShake256;
ops->updateFn = wc_Shake256_Update;
ops->finalFn = wc_Shake256_Final;
ops->freeFn = wc_Shake256_Free;
return 0;
#endif
default:
return WH_ERROR_BADARGS;
}
}

static int _HandleShake(whServerContext* ctx, int hashType, uint16_t magic,
int devId, const void* cryptoDataIn, uint16_t inSize,
void* cryptoDataOut, uint16_t* outSize)
{
int ret = 0;
wc_Shake shake[1];
whMessageCrypto_ShakeRequest req;
whMessageCrypto_ShakeResponse res = {0};
const uint8_t* inData;
uint8_t* outData;
_ShakeVariantOps ops;

(void)ctx;

ret = _ShakeLookupOps(hashType, &ops);
if (ret != 0) {
return ret;
}

if (inSize < sizeof(whMessageCrypto_ShakeRequest)) {
return WH_ERROR_BADARGS;
}

ret = wh_MessageCrypto_TranslateShakeRequest(magic, cryptoDataIn, &req);
if (ret != 0) {
return ret;
}

if ((uint32_t)req.inSz >
(uint32_t)(inSize - sizeof(whMessageCrypto_ShakeRequest))) {
return WH_ERROR_BADARGS;
}
if (!req.isLastBlock && (req.inSz % ops.blockSize) != 0) {
return WH_ERROR_BADARGS;
}
if (req.isLastBlock && req.inSz >= ops.blockSize) {
return WH_ERROR_BADARGS;
}
/* A SHAKE produces whatever was asked for, bounded by what fits back */
if (req.isLastBlock) {
if ((req.outSz == 0) ||
(req.outSz > WH_MESSAGE_CRYPTO_SHAKE_MAX_INLINE_OUTPUT_SZ)) {
return WH_ERROR_BADARGS;
}
}

inData = (const uint8_t*)cryptoDataIn +
sizeof(whMessageCrypto_ShakeRequest);
outData =
(uint8_t*)cryptoDataOut + sizeof(whMessageCrypto_ShakeResponse);

ret = ops.initFn(shake, NULL, devId);
if (ret != 0) {
return ret;
}

/* Restore intermediate state from the client; the server is stateless
* otherwise and the partial block lives only on the client. */
memcpy(shake->s, req.resumeState.s, sizeof(shake->s));

if (req.inSz > 0) {
ret = ops.updateFn(shake, inData, req.inSz);
}
if (ret == 0) {
if (req.isLastBlock) {
ret = ops.finalFn(shake, outData, req.outSz);
if (ret == 0) {
res.outSz = req.outSz;
}
}
else {
/* Post-condition: whole-block input must leave i == 0. */
if (shake->i != 0) {
ret = WH_ERROR_ABORTED;
}
else {
res.outSz = 0;
memcpy(res.resumeState.s, shake->s, sizeof(res.resumeState.s));
}
}
}

ops.freeFn(shake);

if (ret == 0) {
ret = wh_MessageCrypto_TranslateShakeResponse(magic, &res,
cryptoDataOut);
if (ret == 0) {
*outSize = (uint16_t)(sizeof(res) + res.outSz);
}
}

return ret;
}
#endif /* WOLFSSL_SHAKE128 || WOLFSSL_SHAKE256 */

#ifdef WOLFSSL_HAVE_MLDSA

#ifndef WOLFSSL_MLDSA_NO_MAKE_KEY
Expand Down Expand Up @@ -6289,6 +6423,23 @@ int wh_Server_HandleCryptoRequest(whServerContext* ctx, uint16_t magic,
}
break;
#endif /* WOLFSSL_SHA3 */
#if defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256)
#ifdef WOLFSSL_SHAKE128
case WC_HASH_TYPE_SHAKE128:
#endif
#ifdef WOLFSSL_SHAKE256
case WC_HASH_TYPE_SHAKE256:
#endif
WH_DEBUG_SERVER("SHAKE req recv. type:%u\n",
rqstHeader.algoType);
ret = _HandleShake(ctx, rqstHeader.algoType, magic, devId,
cryptoDataIn, cryptoInSize,
cryptoDataOut, &cryptoOutSize);
if (ret != 0) {
WH_DEBUG_SERVER("SHAKE ret = %d\n", ret);
}
break;
#endif /* WOLFSSL_SHAKE128 || WOLFSSL_SHAKE256 */
default:
ret = NOT_COMPILED_IN;
break;
Expand Down
Loading
Loading