diff --git a/sm2.c b/sm2.c index 3fabe00..61a3f54 100644 --- a/sm2.c +++ b/sm2.c @@ -28,6 +28,9 @@ #if defined(WOLFSSL_SM2) && defined(HAVE_ECC) #include +#ifdef WOLF_CRYPTO_CB + #include +#endif #include #include #include @@ -293,6 +296,23 @@ int wc_ecc_sm2_create_digest(const byte *id, word16 idSz, err = BUFFER_E; } +#ifdef WOLF_CRYPTO_CB + if (err == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (key->devId != INVALID_DEVID) + #endif + { + err = wc_CryptoCb_Sm2CreateDigest(id, idSz, msg, msgSz, hashType, + out, outSz, key); + if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return err; + } + /* fall-through when unavailable */ + err = 0; + } + } +#endif + #ifdef WOLFSSL_SMALL_STACK if (err == 0) { hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), key->heap, @@ -356,6 +376,20 @@ int wc_ecc_sm2_make_key(WC_RNG* rng, ecc_key* key, int flags) int wc_ecc_sm2_shared_secret(ecc_key* priv, ecc_key* pub, byte* out, word32* outLen) { +#ifdef WOLF_CRYPTO_CB + /* Check for NULL pointers to mirror the software path. */ + if ((priv != NULL) && (pub != NULL) && (out != NULL) && (outLen != NULL)) { + #ifndef WOLF_CRYPTO_CB_FIND + if (priv->devId != INVALID_DEVID) + #endif + { + int ret = wc_CryptoCb_Sm2SharedSecret(priv, pub, out, outLen); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + } + } +#endif return wc_ecc_shared_secret(priv, pub, out, outLen); } @@ -630,6 +664,22 @@ int wc_ecc_sm2_sign_hash(const byte* hash, word32 hashSz, byte* sig, err = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + if (err == MP_OKAY) { + #ifndef WOLF_CRYPTO_CB_FIND + if (key->devId != INVALID_DEVID) + #endif + { + err = wc_CryptoCb_Sm2Sign(hash, hashSz, sig, + sigSz, rng, key); + if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return err; + } + err = MP_OKAY; + } + } +#endif + #ifdef WOLFSSL_SMALL_STACK if (err == MP_OKAY) { /* Allocate MP integers. */ @@ -1019,6 +1069,22 @@ int wc_ecc_sm2_verify_hash(const byte* sig, word32 sigSz, const byte* hash, err = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + if (err == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (key->devId != INVALID_DEVID) + #endif + { + err = wc_CryptoCb_Sm2Verify(sig, sigSz, hash, + hashSz, res, key); + if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return err; + } + err = 0; + } + } +#endif + #ifdef WOLFSSL_SMALL_STACK if (err == 0) { /* Allocate MP integers. */ diff --git a/sm3.c b/sm3.c index 1e93dba..2df8d99 100644 --- a/sm3.c +++ b/sm3.c @@ -29,6 +29,9 @@ #include #include +#ifdef WOLF_CRYPTO_CB + #include +#endif #include #ifdef NO_INLINE @@ -839,8 +842,9 @@ int wc_InitSm3(wc_Sm3* sm3, void* heap, int devId) { int ret = 0; - /* No device support yet. */ +#ifndef WOLF_CRYPTO_CB (void)devId; +#endif /* Validate parameters. */ if (sm3 == NULL) { @@ -852,6 +856,11 @@ int wc_InitSm3(wc_Sm3* sm3, void* heap, int devId) sm3_init(sm3); sm3->heap = heap; + #ifdef WOLF_CRYPTO_CB + /* Cache the device to offer hashing to. */ + sm3->devId = devId; + sm3->devCtx = NULL; + #endif #ifdef WOLFSSL_HASH_FLAGS sm3->flags = 0; #endif @@ -934,6 +943,21 @@ int wc_Sm3Update(wc_Sm3* sm3, const byte* data, word32 len) } #endif +#ifdef WOLF_CRYPTO_CB + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm3->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm3Hash(sm3, data, len, NULL); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + if ((ret == 0) && (len > 0)) { /* Always add to length. */ sm3_add_to_len(sm3, len); @@ -1056,6 +1080,21 @@ int wc_Sm3Final(wc_Sm3* sm3, byte* hash) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm3->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm3Hash(sm3, NULL, 0, hash); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + if (ret == 0) { byte* buffer8 = (byte*)sm3->buffer; @@ -1091,6 +1130,20 @@ int wc_Sm3Final(wc_Sm3* sm3, byte* hash) */ void wc_Sm3Free(wc_Sm3* sm3) { +#if defined(WOLF_CRYPTO_CB) && \ + defined(WOLF_CRYPTO_CB_FREE) + /* Check we have something to work with. */ + if (sm3 != NULL) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm3->devId != INVALID_DEVID) + #endif + { + /* Let the device release any state it holds for this context. */ + (void)wc_CryptoCb_Free(sm3->devId, WC_ALGO_TYPE_HASH, + WC_HASH_TYPE_SM3, 0, sm3); + } + } +#endif (void)sm3; } @@ -1101,6 +1154,9 @@ void wc_Sm3Free(wc_Sm3* sm3) * @param [in] src SM3 hash object to copy. * @param [in, out] dst SM3 hash object to copy into. */ +/* Defined below; used by wc_Sm3GetHash() for a device aware copy. */ +int wc_Sm3Copy(const wc_Sm3* src, wc_Sm3* dst); + static void sm3_copy(const wc_Sm3* src, wc_Sm3* dst) { XMEMCPY(dst, src, sizeof(wc_Sm3)); @@ -1123,7 +1179,7 @@ int wc_Sm3GetHash(wc_Sm3* sm3, byte* hash) { int ret = 0; #ifdef WOLFSSL_SMALL_STACK - wc_Sm3* sm3Copy; + wc_Sm3* sm3Copy = NULL; #else wc_Sm3 sm3Copy[1]; #endif @@ -1144,18 +1200,21 @@ int wc_Sm3GetHash(wc_Sm3* sm3, byte* hash) } #endif if (ret == 0) { - /* Get a copy of the hash object. */ - sm3_copy(sm3, sm3Copy); + ret = wc_Sm3Copy(sm3, sm3Copy); + } + if (ret == 0) { /* Calculate final hash value. */ ret = wc_Sm3Final(sm3Copy, hash); /* Dispose of hash object. */ wc_Sm3Free(sm3Copy); + } - #ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK + if (sm3Copy != NULL) { /* Free the SM3 hash object that was the copy. */ XFREE(sm3Copy, sm3->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif } +#endif return ret; } @@ -1176,6 +1235,26 @@ int wc_Sm3Copy(const wc_Sm3* src, wc_Sm3* dst) ret = BAD_FUNC_ARG; } +#if defined(WOLF_CRYPTO_CB) && \ + defined(WOLF_CRYPTO_CB_COPY) + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (src->devId != INVALID_DEVID) + #endif + { + /* The struct copy below would alias the device context, leaving + * two objects sharing one handle. Let the device duplicate it. */ + ret = wc_CryptoCb_Copy(src->devId, WC_ALGO_TYPE_HASH, + WC_HASH_TYPE_SM3, (void*)src, (void*)dst); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + /* Fall through to software when the device declines. */ + ret = 0; + } + } +#endif + if (ret == 0) { sm3_copy(src, dst); } diff --git a/sm3.h b/sm3.h index 83ae194..d32abe0 100644 --- a/sm3.h +++ b/sm3.h @@ -58,6 +58,11 @@ struct wc_Sm3 { word32 hiLen; /* Dynamic allocation hint. */ void* heap; +#ifdef WOLF_CRYPTO_CB + /* Device to offer hashing to, and its context. */ + int devId; + void* devCtx; +#endif #ifdef WOLFSSL_HASH_FLAGS /* Flags of hash object - see enum wc_HashFlags. */ word32 flags; diff --git a/sm4.c b/sm4.c index b011f23..faa8389 100644 --- a/sm4.c +++ b/sm4.c @@ -28,6 +28,9 @@ #ifdef WOLFSSL_SM4 #include +#ifdef WOLF_CRYPTO_CB + #include +#endif #ifdef NO_INLINE #include @@ -645,8 +648,9 @@ int wc_Sm4Init(wc_Sm4* sm4, void* heap, int devId) { int ret = 0; - /* No device support yet. */ +#ifndef WOLF_CRYPTO_CB (void)devId; +#endif /* Validate parameters. */ if (sm4 == NULL) { @@ -659,6 +663,11 @@ int wc_Sm4Init(wc_Sm4* sm4, void* heap, int devId) /* Cache heap hint to use with any dynamic allocations. */ sm4->heap = heap; +#ifdef WOLF_CRYPTO_CB + /* Cache the device to offer operations to. */ + sm4->devId = devId; + sm4->devCtx = NULL; +#endif } return ret; @@ -674,8 +683,25 @@ void wc_Sm4Free(wc_Sm4* sm4) { /* Check we have something to work with. */ if (sm4 != NULL) { + #if defined(WOLF_CRYPTO_CB) && \ + defined(WOLF_CRYPTO_CB_FREE) + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + /* Let the device release any state it holds for this context. */ + (void)wc_CryptoCb_Free(sm4->devId, WC_ALGO_TYPE_CIPHER, + WC_CIPHER_SM4, 0, sm4); + /* Clear the handle so a second free cannot resubmit it. */ + sm4->devCtx = NULL; + } + #endif /* Must zeroize key schedule. */ ForceZero(sm4->ks, sizeof(sm4->ks)); + #ifdef WOLF_CRYPTO_CB + /* The raw key kept for a device is key material too. */ + ForceZero(sm4->devKey, sizeof(sm4->devKey)); + #endif #if defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_CTR) /* CTR keystream and CBC decrypt plaintext both land in tmp. */ ForceZero(sm4->tmp, sizeof(sm4->tmp)); @@ -696,6 +722,14 @@ static void sm4_set_key(wc_Sm4* sm4, const byte* key) { /* Create key schedule. */ sm4_key_schedule(key, sm4->ks); +#ifdef WOLF_CRYPTO_CB + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + XMEMCPY(sm4->devKey, key, SM4_KEY_SIZE); + } +#endif /* Mark key as having been set. */ sm4->keySet = 1; } @@ -774,6 +808,31 @@ int wc_Sm4SetIV(wc_Sm4* sm4, const byte* iv) #ifdef WOLFSSL_SM4_ECB +/* Encrypt whole blocks with SM4-ECB in software. + * + * The public wc_Sm4EcbEncrypt() offers the work to a crypto callback device + * first. Internal callers use this worker instead, so blocks of a larger + * operation - the GCM counters - do not go back through the callback. + * + * @param [in] sm4 SM4 algorithm object with a key set. + * @param [out] out Byte array in which to place encrypted data. + * @param [in] in Array of bytes to encrypt. + * @param [in] sz Number of bytes to encrypt. Multiple of block size. + */ +static void sm4_ecb_encrypt_blocks(const wc_Sm4* sm4, byte* out, + const byte* in, word32 sz) +{ + /* Encrypt all bytes. */ + while (sz > 0) { + /* Encrypt a block. */ + sm4_encrypt(sm4->ks, in, out); + /* Move on to next block. */ + in += SM4_BLOCK_SIZE; + out += SM4_BLOCK_SIZE; + sz -= SM4_BLOCK_SIZE; + } +} + /* Encrypt bytes using SM4-ECB. * * Length of input must be a multiple of the block size. @@ -801,21 +860,29 @@ int wc_Sm4EcbEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4EcbEncrypt(sm4, out, in, sz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key has been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; } if (ret == 0) { - /* Encrypt all bytes. */ - while (sz > 0) { - /* Encrypt a block. */ - sm4_encrypt(sm4->ks, in, out); - /* Move on to next block. */ - in += SM4_BLOCK_SIZE; - out += SM4_BLOCK_SIZE; - sz -= SM4_BLOCK_SIZE; - } + sm4_ecb_encrypt_blocks(sm4, out, in, sz); } return ret; @@ -849,6 +916,22 @@ int wc_Sm4EcbDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4EcbDecrypt(sm4, out, in, sz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key has been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -901,6 +984,22 @@ int wc_Sm4CbcEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4CbcEncrypt(sm4, out, in, sz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key and IV have been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -956,6 +1055,22 @@ int wc_Sm4CbcDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4CbcDecrypt(sm4, out, in, sz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key and IV have been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -1049,6 +1164,22 @@ int wc_Sm4CtrEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4CtrEncrypt(sm4, out, in, sz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key and IV have been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -1216,7 +1347,7 @@ static void sm4_gcm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, /* Reset number of blocks. */ blocks = sz / SM4_BLOCK_SIZE; /* Encrypt the counters. */ - wc_Sm4EcbEncrypt(sm4, out, out, SM4_BLOCK_SIZE * blocks); + sm4_ecb_encrypt_blocks(sm4, out, out, SM4_BLOCK_SIZE * blocks); /* XOR in the plaintext to create cipher text. */ xorbuf(out, in, SM4_BLOCK_SIZE * blocks); /* Step over handled plaintext */ @@ -1348,7 +1479,7 @@ static int sm4_gcm_decrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, /* Reset number of blocks. */ blocks = sz / SM4_BLOCK_SIZE; /* Encrypt the counters. */ - wc_Sm4EcbEncrypt(sm4, out, out, SM4_BLOCK_SIZE * blocks); + sm4_ecb_encrypt_blocks(sm4, out, out, SM4_BLOCK_SIZE * blocks); /* XOR in the plaintext to create cipher text. */ xorbuf(out, in, SM4_BLOCK_SIZE * blocks); /* Step over handled plaintext */ @@ -1472,6 +1603,23 @@ int wc_Sm4GcmEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4GcmEncrypt(sm4, out, in, sz, nonce, + nonceSz, tag, tagSz, aad, aadSz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key has been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -1531,6 +1679,23 @@ int wc_Sm4GcmDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4GcmDecrypt(sm4, out, in, sz, nonce, + nonceSz, tag, tagSz, aad, aadSz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key has been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -1916,6 +2081,23 @@ int wc_Sm4CcmEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, } } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4CcmEncrypt(sm4, out, in, sz, nonce, + nonceSz, tag, tagSz, aad, aadSz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key has been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; @@ -1985,6 +2167,23 @@ int wc_Sm4CcmDecrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, } } +#ifdef WOLF_CRYPTO_CB + /* Offer to the device before the key check: the key may live there. */ + if (ret == 0) { + #ifndef WOLF_CRYPTO_CB_FIND + if (sm4->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Sm4CcmDecrypt(sm4, out, in, sz, nonce, + nonceSz, tag, tagSz, aad, aadSz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + return ret; + } + ret = 0; + } + } +#endif + /* Ensure a key has been set. */ if ((ret == 0) && (!sm4->keySet)) { ret = MISSING_KEY; diff --git a/sm4.h b/sm4.h index c3c4db3..856f261 100644 --- a/sm4.h +++ b/sm4.h @@ -75,6 +75,10 @@ typedef struct wc_Sm4 { #ifdef WOLF_CRYPTO_CB int devId; void* devCtx; + /* Raw key kept for crypto callback devices. The key schedule above cannot + * be turned back into the key it came from, so a device that needs the key + * material reads it from here. */ + byte devKey[SM4_KEY_SIZE]; #endif void* heap; /* memory hint to use */