/* crypto.c * * Copyright (C) 2006-2024 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ /* Implements Microchip CRYPTO API layer */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef WOLFSSL_USER_SETTINGS #include #endif #include #ifdef MICROCHIP_MPLAB_HARMONY #include "system_config.h" #include "crypto/crypto.h" #else #include "crypto.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NO_MD5 /* Initialize MD5 */ int CRYPT_MD5_Initialize(CRYPT_MD5_CTX* md5) { typedef char md5_test[sizeof(CRYPT_MD5_CTX) >= sizeof(Md5) ? 1 : -1]; (void)sizeof(md5_test); if (md5 == NULL) return BAD_FUNC_ARG; return wc_InitMd5((Md5*)md5); } int CRYPT_MD5_DataSizeSet(CRYPT_MD5_CTX* md5, unsigned int sz) { if (md5 == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_PIC32MZ_HASH wc_Md5SizeSet((Md5*)md5, sz); #else (void)sz; #endif return 0; } /* Add data to MD5 */ int CRYPT_MD5_DataAdd(CRYPT_MD5_CTX* md5, const unsigned char* input, unsigned int sz) { if (md5 == NULL || input == NULL) return BAD_FUNC_ARG; return wc_Md5Update((Md5*)md5, input, sz); } /* Get MD5 Final into digest */ int CRYPT_MD5_Finalize(CRYPT_MD5_CTX* md5, unsigned char* digest) { if (md5 == NULL || digest == NULL) return BAD_FUNC_ARG; return wc_Md5Final((Md5*)md5, digest); } #endif #ifndef NO_SHA /* Initialize SHA */ int CRYPT_SHA_Initialize(CRYPT_SHA_CTX* sha) { typedef char sha_test[sizeof(CRYPT_SHA_CTX) >= sizeof(Sha) ? 1 : -1]; (void)sizeof(sha_test); if (sha == NULL) return BAD_FUNC_ARG; return wc_InitSha((wc_Sha*)sha); } int CRYPT_SHA_DataSizeSet(CRYPT_SHA_CTX* sha, unsigned int sz) { if (sha == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_PIC32MZ_HASH wc_ShaSizeSet((wc_Sha*)sha, sz); #else (void)sz; #endif return 0; } /* Add data to SHA */ int CRYPT_SHA_DataAdd(CRYPT_SHA_CTX* sha, const unsigned char* input, unsigned int sz) { if (sha == NULL || input == NULL) return BAD_FUNC_ARG; return wc_ShaUpdate((wc_Sha*)sha, input, sz); } /* Get SHA Final into digest */ int CRYPT_SHA_Finalize(CRYPT_SHA_CTX* sha, unsigned char* digest) { if (sha == NULL || digest == NULL) return BAD_FUNC_ARG; return wc_ShaFinal((wc_Sha*)sha, digest); } #endif #ifndef NO_SHA256 /* Initialize SHA-256 */ int CRYPT_SHA256_Initialize(CRYPT_SHA256_CTX* sha256) { typedef char sha_test[sizeof(CRYPT_SHA256_CTX) >= sizeof(wc_Sha256) ? 1 : -1]; (void)sizeof(sha_test); if (sha256 == NULL) return BAD_FUNC_ARG; return wc_InitSha256((wc_Sha256*)sha256); } int CRYPT_SHA256_DataSizeSet(CRYPT_SHA256_CTX* sha256, unsigned int sz) { if (sha256 == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_PIC32MZ_HASH wc_Sha256SizeSet((wc_Sha256*)sha256, sz); #else (void)sz; #endif return 0; } /* Add data to SHA-256 */ int CRYPT_SHA256_DataAdd(CRYPT_SHA256_CTX* sha256, const unsigned char* input, unsigned int sz) { if (sha256 == NULL || input == NULL) return BAD_FUNC_ARG; return wc_Sha256Update((wc_Sha256*)sha256, input, sz); } /* Get SHA-256 Final into digest */ int CRYPT_SHA256_Finalize(CRYPT_SHA256_CTX* sha256, unsigned char* digest) { if (sha256 == NULL || digest == NULL) return BAD_FUNC_ARG; return wc_Sha256Final((wc_Sha256*)sha256, digest); } #endif #ifdef WOLFSSL_SHA512 #ifdef WOLFSSL_SHA384 /* Initialize SHA-384 */ int CRYPT_SHA384_Initialize(CRYPT_SHA384_CTX* sha384) { typedef char sha_test[sizeof(CRYPT_SHA384_CTX) >= sizeof(wc_Sha384) ? 1 : -1]; (void)sizeof(sha_test); if (sha384 == NULL) return BAD_FUNC_ARG; return wc_InitSha384((wc_Sha384*)sha384); } /* Add data to SHA-384 */ int CRYPT_SHA384_DataAdd(CRYPT_SHA384_CTX* sha384, const unsigned char* input, unsigned int sz) { if (sha384 == NULL || input == NULL) return BAD_FUNC_ARG; return wc_Sha384Update((wc_Sha384*)sha384, input, sz); } /* Get SHA-384 Final into digest */ int CRYPT_SHA384_Finalize(CRYPT_SHA384_CTX* sha384, unsigned char* digest) { if (sha384 == NULL || digest == NULL) return BAD_FUNC_ARG; return wc_Sha384Final((wc_Sha384*)sha384, digest); } #endif /* Initialize SHA-512 */ int CRYPT_SHA512_Initialize(CRYPT_SHA512_CTX* sha512) { typedef char sha_test[sizeof(CRYPT_SHA512_CTX) >= sizeof(wc_Sha512) ? 1 : -1]; (void)sizeof(sha_test); if (sha512 == NULL) return BAD_FUNC_ARG; return wc_InitSha512((wc_Sha512*)sha512); } /* Add data to SHA-512 */ int CRYPT_SHA512_DataAdd(CRYPT_SHA512_CTX* sha512, const unsigned char* input, unsigned int sz) { if (sha512 == NULL || input == NULL) return BAD_FUNC_ARG; return wc_Sha512Update((wc_Sha512*)sha512, input, sz); } /* Get SHA-512 Final into digest */ int CRYPT_SHA512_Finalize(CRYPT_SHA512_CTX* sha512, unsigned char* digest) { if (sha512 == NULL || digest == NULL) return BAD_FUNC_ARG; return wc_Sha512Final((wc_Sha512*)sha512, digest); } #endif #ifndef NO_HMAC /* Set HMAC key with type */ int CRYPT_HMAC_SetKey(CRYPT_HMAC_CTX* hmac, int type, const unsigned char* key, unsigned int sz) { /* compile-time check to verify CRYPT_HMAC_CTX is large enough to hold Hmac */ typedef char hmac_test[sizeof(CRYPT_HMAC_CTX) >= sizeof(Hmac) ? 1 : -1]; (void)sizeof(hmac_test); if (hmac == NULL || key == NULL) return BAD_FUNC_ARG; if (type != CRYPT_HMAC_SHA && type != CRYPT_HMAC_SHA256 && type != CRYPT_HMAC_SHA384 && type != CRYPT_HMAC_SHA512) { return BAD_FUNC_ARG; /* bad hmac type */ } return wc_HmacSetKey((Hmac*)hmac, type, key, sz); } int CRYPT_HMAC_DataAdd(CRYPT_HMAC_CTX* hmac, const unsigned char* input, unsigned int sz) { if (hmac == NULL || input == NULL) return BAD_FUNC_ARG; return wc_HmacUpdate((Hmac*)hmac, input, sz); } /* Get HMAC Final into digest */ int CRYPT_HMAC_Finalize(CRYPT_HMAC_CTX* hmac, unsigned char* digest) { if (hmac == NULL || digest == NULL) return BAD_FUNC_ARG; return wc_HmacFinal((Hmac*)hmac, digest); } #endif #ifdef HAVE_LIBZ /* Huffman Compression, set flag to do static, otherwise dynamic */ /* return compressed size, otherwise < 0 for error */ int CRYPT_HUFFMAN_Compress(unsigned char* out, unsigned int outSz, const unsigned char* in, unsigned int inSz, unsigned int flags) { if (out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_Compress(out, outSz, in, inSz, flags); } /* Huffman DeCompression, self determines type */ /* return decompressed size, otherwise < 0 for error */ int CRYPT_HUFFMAN_DeCompress(unsigned char* out, unsigned int outSz, const unsigned char* in, unsigned int inSz) { if (out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_DeCompress(out, outSz, in, inSz); } #endif #ifndef NO_RNG /* RNG Initialize, < 0 on error */ int CRYPT_RNG_Initialize(CRYPT_RNG_CTX* rng) { typedef char rng_test[sizeof(CRYPT_RNG_CTX) >= sizeof(WC_RNG) ? 1 : -1]; (void)sizeof(rng_test); if (rng == NULL) return BAD_FUNC_ARG; return wc_InitRng((WC_RNG*)rng); } /* RNG Get single bytes, < 0 on error */ int CRYPT_RNG_Get(CRYPT_RNG_CTX* rng, unsigned char* b) { if (rng == NULL || b == NULL) return BAD_FUNC_ARG; return wc_RNG_GenerateByte((WC_RNG*)rng, (byte*)b); } /* RNG Block Generation of sz bytes, < 0 on error */ int CRYPT_RNG_BlockGenerate(CRYPT_RNG_CTX* rng, unsigned char* b, unsigned int sz) { if (rng == NULL || b == NULL) return BAD_FUNC_ARG; return wc_RNG_GenerateBlock((WC_RNG*)rng, b, sz); } #endif #ifndef NO_DES3 /* Triple DES Key Set, may have iv, will have direction */ int CRYPT_TDES_KeySet(CRYPT_TDES_CTX* tdes, const unsigned char* key, const unsigned char* iv, int dir) { typedef char tdes_test[sizeof(CRYPT_TDES_CTX) >= sizeof(Des3) ? 1 : -1]; (void)sizeof(tdes_test); if (tdes == NULL || key == NULL) return BAD_FUNC_ARG; return wc_Des3_SetKey((Des3*)tdes, key, iv, dir); } /* Triple DES Iv Set, sometimes added later */ int CRYPT_TDES_IvSet(CRYPT_TDES_CTX* tdes, const unsigned char* iv) { if (tdes == NULL || iv == NULL) return BAD_FUNC_ARG; return wc_Des3_SetIV((Des3*)tdes, iv); } /* Triple DES CBC Encrypt */ int CRYPT_TDES_CBC_Encrypt(CRYPT_TDES_CTX* tdes, unsigned char* out, const unsigned char* in, unsigned int inSz) { if (tdes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_Des3_CbcEncrypt((Des3*)tdes, out, in, inSz); } /* Triple DES CBC Decrypt */ int CRYPT_TDES_CBC_Decrypt(CRYPT_TDES_CTX* tdes, unsigned char* out, const unsigned char* in, unsigned int inSz) { if (tdes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_Des3_CbcDecrypt((Des3*)tdes, out, in, inSz); } #endif #ifndef NO_AES /* AES Key Set, may have iv, will have direction */ int CRYPT_AES_KeySet(CRYPT_AES_CTX* aes, const unsigned char* key, unsigned int keyLen, const unsigned char* iv, int dir) { typedef char aes_test[sizeof(CRYPT_AES_CTX) >= sizeof(Aes) ? 1 : -1]; (void)sizeof(aes_test); if (aes == NULL || key == NULL) return BAD_FUNC_ARG; return wc_AesSetKey((Aes*)aes, key, keyLen, iv, dir); } /* AES Iv Set, sometimes added later */ int CRYPT_AES_IvSet(CRYPT_AES_CTX* aes, const unsigned char* iv) { if (aes == NULL || iv == NULL) return BAD_FUNC_ARG; return wc_AesSetIV((Aes*)aes, iv); } /* AES CBC Encrypt */ int CRYPT_AES_CBC_Encrypt(CRYPT_AES_CTX* aes, unsigned char* out, const unsigned char* in, unsigned int inSz) { if (aes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_AesCbcEncrypt((Aes*)aes, out, in, inSz); } /* AES CBC Decrypt */ int CRYPT_AES_CBC_Decrypt(CRYPT_AES_CTX* aes, unsigned char* out, const unsigned char* in, unsigned int inSz) { if (aes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_AesCbcDecrypt((Aes*)aes, out, in, inSz); } #endif #ifdef WOLFSSL_AES_COUNTER /* AES CTR Encrypt (used for decrypt too, with ENCRYPT key setup) */ int CRYPT_AES_CTR_Encrypt(CRYPT_AES_CTX* aes, unsigned char* out, const unsigned char* in, unsigned int inSz) { if (aes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; return wc_AesCtrEncrypt((Aes*)aes, out, in, inSz); } #endif #ifdef WOLFSSL_AES_DIRECT /* AES Direct mode encrypt, one block at a time */ int CRYPT_AES_DIRECT_Encrypt(CRYPT_AES_CTX* aes, unsigned char* out, const unsigned char* in) { if (aes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; wc_AesEncryptDirect((Aes*)aes, out, in); return 0; } /* AES Direct mode decrypt, one block at a time */ int CRYPT_AES_DIRECT_Decrypt(CRYPT_AES_CTX* aes, unsigned char* out, const unsigned char* in) { if (aes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; wc_AesDecryptDirect((Aes*)aes, out, in); return 0; } #endif #ifndef NO_RSA /* RSA Initialize */ int CRYPT_RSA_Initialize(CRYPT_RSA_CTX* rsa) { if (rsa == NULL) return BAD_FUNC_ARG; rsa->holder = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); if (rsa->holder == NULL) return -1; return wc_InitRsaKey((RsaKey*)rsa->holder, NULL); } /* RSA Free resources */ int CRYPT_RSA_Free(CRYPT_RSA_CTX* rsa) { if (rsa == NULL) return BAD_FUNC_ARG; wc_FreeRsaKey((RsaKey*)rsa->holder); XFREE(rsa->holder, NULL, DYNAMIC_TYPE_RSA); rsa->holder = NULL; return 0; } /* RSA Public key decode ASN.1 */ int CRYPT_RSA_PublicKeyDecode(CRYPT_RSA_CTX* rsa, const unsigned char* in, unsigned int inSz) { unsigned int idx = 0; (void)idx; if (rsa == NULL || in == NULL) return BAD_FUNC_ARG; return wc_RsaPublicKeyDecode(in, &idx, (RsaKey*)rsa->holder, inSz); } /* RSA Private key decode ASN.1 */ int CRYPT_RSA_PrivateKeyDecode(CRYPT_RSA_CTX* rsa, const unsigned char* in, unsigned int inSz) { unsigned int idx = 0; (void)idx; if (rsa == NULL || in == NULL) return BAD_FUNC_ARG; return wc_RsaPrivateKeyDecode(in, &idx, (RsaKey*)rsa->holder, inSz); } /* RSA Public Encrypt */ int CRYPT_RSA_PublicEncrypt(CRYPT_RSA_CTX* rsa, unsigned char* out, unsigned int outSz, const unsigned char* in, unsigned int inSz, CRYPT_RNG_CTX* rng) { if (rsa == NULL || in == NULL || out == NULL || rng == NULL) return BAD_FUNC_ARG; return wc_RsaPublicEncrypt(in, inSz, out, outSz, (RsaKey*)rsa->holder, (WC_RNG*)rng); } /* RSA Private Decrypt */ int CRYPT_RSA_PrivateDecrypt(CRYPT_RSA_CTX* rsa, unsigned char* out, unsigned int outSz, const unsigned char* in, unsigned int inSz) { if (rsa == NULL || in == NULL || out == NULL) return BAD_FUNC_ARG; return wc_RsaPrivateDecrypt(in, inSz, out, outSz, (RsaKey*)rsa->holder); } /* RSA Get Encrypt size helper */ int CRYPT_RSA_EncryptSizeGet(CRYPT_RSA_CTX* rsa) { if (rsa == NULL) return BAD_FUNC_ARG; return wc_RsaEncryptSize((RsaKey*)rsa->holder); } int CRYPT_RSA_SetRng(CRYPT_RSA_CTX* rsa, CRYPT_RNG_CTX* rng) { if (rsa == NULL) return BAD_FUNC_ARG; #ifdef WC_RSA_BLINDING return wc_RsaSetRNG((RsaKey*)rsa->holder, (WC_RNG*)rng); #else (void)rng; return 0; #endif } #endif #ifdef HAVE_ECC /* ECC init */ int CRYPT_ECC_Initialize(CRYPT_ECC_CTX* ecc) { if (ecc == NULL) return BAD_FUNC_ARG; ecc->holder = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); if (ecc->holder == NULL) return -1; wc_ecc_init((ecc_key*)ecc->holder); return 0; } /* ECC free resources */ int CRYPT_ECC_Free(CRYPT_ECC_CTX* ecc) { if (ecc == NULL) return BAD_FUNC_ARG; wc_ecc_free((ecc_key*)ecc->holder); XFREE(ecc->holder, NULL, DYNAMIC_TYPE_ECC); ecc->holder = NULL; return 0; } /* ECC Public x963 Export */ int CRYPT_ECC_PublicExport(CRYPT_ECC_CTX* ecc, unsigned char* out, unsigned int outSz, unsigned int* usedSz) { int ret; unsigned int inOut = outSz; if (ecc == NULL || out == NULL) return BAD_FUNC_ARG; ret = wc_ecc_export_x963((ecc_key*)ecc->holder, out, &inOut); *usedSz = inOut; return ret; } /* ECC Public x963 Import */ int CRYPT_ECC_PublicImport(CRYPT_ECC_CTX* ecc, const unsigned char* in, unsigned int inSz) { if (ecc == NULL || in == NULL) return BAD_FUNC_ARG; return wc_ecc_import_x963(in, inSz, (ecc_key*)ecc->holder); } /* ECC Private x963 Import */ int CRYPT_ECC_PrivateImport(CRYPT_ECC_CTX* ecc, const unsigned char* priv, unsigned int privSz, const unsigned char* pub, unsigned int pubSz) { if (ecc == NULL || priv == NULL || pub == NULL) return BAD_FUNC_ARG; return wc_ecc_import_private_key(priv, privSz, pub, pubSz, (ecc_key*)ecc->holder); } /* ECC DHE Make key */ int CRYPT_ECC_DHE_KeyMake(CRYPT_ECC_CTX* ecc, CRYPT_RNG_CTX* rng, int keySz) { if (ecc == NULL || rng == NULL) return BAD_FUNC_ARG; return wc_ecc_make_key((WC_RNG*)rng, keySz, (ecc_key*)ecc->holder); } /* ECC DHE Make shared secret with our private and peer public */ int CRYPT_ECC_DHE_SharedSecretMake(CRYPT_ECC_CTX* priv, CRYPT_ECC_CTX* pub, unsigned char* out, unsigned int outSz, unsigned int* usedSz) { int ret; unsigned int inOut = outSz; #if defined(ECC_TIMING_RESISTANT) WC_RNG rng; #endif if (priv == NULL || pub == NULL || out == NULL || usedSz == NULL) return BAD_FUNC_ARG; #if defined(ECC_TIMING_RESISTANT) ret = wc_InitRng(&rng); if (ret != 0) return ret; ret = wc_ecc_set_rng((ecc_key*)priv->holder, &rng); if (ret != 0) { wc_FreeRng(&rng); return ret; } #endif ret = wc_ecc_shared_secret((ecc_key*)priv->holder, (ecc_key*)pub->holder, out, &inOut); *usedSz = inOut; #if defined(ECC_TIMING_RESISTANT) wc_FreeRng(&rng); #endif return ret; } /* ECC DSA Hash Sign */ int CRYPT_ECC_DSA_HashSign(CRYPT_ECC_CTX* ecc, CRYPT_RNG_CTX* rng, unsigned char* sig, unsigned int sigSz, unsigned int* usedSz, const unsigned char* in, unsigned int inSz) { int ret; unsigned int inOut = sigSz; if (ecc == NULL || rng == NULL || sig == NULL || usedSz == NULL || in == NULL) return BAD_FUNC_ARG; ret = wc_ecc_sign_hash(in, inSz, sig, &inOut, (WC_RNG*)rng, (ecc_key*)ecc->holder); *usedSz = inOut; return ret; } /* ECC DSA Hash Verify */ int CRYPT_ECC_DSA_HashVerify(CRYPT_ECC_CTX* ecc, const unsigned char* sig, unsigned int sigSz, unsigned char* hash, unsigned int hashSz, int* status) { if (ecc == NULL || sig == NULL || hash == NULL || status == NULL) return BAD_FUNC_ARG; return wc_ecc_verify_hash(sig, sigSz, hash, hashSz, status, (ecc_key*)ecc->holder); } /* ECC get key size helper */ int CRYPT_ECC_KeySizeGet(CRYPT_ECC_CTX* ecc) { if (ecc == NULL) return BAD_FUNC_ARG; return wc_ecc_size((ecc_key*)ecc->holder); } /* ECC get signature size helper */ int CRYPT_ECC_SignatureSizeGet(CRYPT_ECC_CTX* ecc) { if (ecc == NULL) return BAD_FUNC_ARG; return wc_ecc_sig_size((ecc_key*)ecc->holder); } #endif /* Save error string from err to str which needs to be >= 80 chars */ int CRYPT_ERROR_StringGet(int err, char* str) { if (str == NULL) return BAD_FUNC_ARG; wc_ErrorString(err, str); return 0; }