/* pic32mz-crypt.c * * Copyright (C) 2006-2022 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 */ #ifdef HAVE_CONFIG_H #include #endif #include #ifdef WOLFSSL_MICROCHIP_PIC32MZ #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #endif #include #include #include #ifdef WOLFSSL_PIC32MZ_CRYPT #include #include #endif #ifdef WOLFSSL_PIC32MZ_HASH #include #include #include #endif #if defined(WOLFSSL_PIC32MZ_CRYPT) || defined(WOLFSSL_PIC32MZ_HASH) static int Pic32GetBlockSize(int algo) { switch (algo) { case PIC32_ALGO_HMAC1: return PIC32_BLOCKSIZE_HMAC; case PIC32_ALGO_SHA256: return PIC32_BLOCKSIZE_SHA256; case PIC32_ALGO_SHA1: return PIC32_BLOCKSIZE_SHA1; case PIC32_ALGO_MD5: return PIC32_BLOCKSIZE_MD5; case PIC32_ALGO_AES: return PIC32_BLOCKSIZE_AES; case PIC32_ALGO_TDES: return PIC32_BLOCKSIZE_TDES; case PIC32_ALGO_DES: return PIC32_BLOCKSIZE_DES; } return 0; } static int Pic32Crypto(const byte* pIn, int inLen, word32* pOut, int outLen, int dir, int algo, int cryptoalgo, /* For DES/AES only */ word32* key, int keyLen, word32* iv, int ivLen) { int ret = 0; int blockSize = Pic32GetBlockSize(algo); volatile bufferDescriptor bd __attribute__((aligned (8))); securityAssociation sa __attribute__((aligned (8))); securityAssociation *sa_p; bufferDescriptor *bd_p; byte *in_p; byte *out_p; word32* dst; word32 padRemain; int timeout = 0xFFFFFF; word32* in = (word32*)pIn; word32* out = pOut; int isDynamic = 0; /* check args */ if (in == NULL || inLen <= 0 || out == NULL || blockSize == 0) { return BAD_FUNC_ARG; } /* check pointer alignment - must be word aligned */ if (((size_t)in % sizeof(word32)) || ((size_t)out % sizeof(word32))) { /* dynamically allocate aligned pointers */ isDynamic = 1; in = (word32*)XMALLOC(inLen, NULL, DYNAMIC_TYPE_AES_BUFFER); if (in == NULL) return MEMORY_E; if ((word32*)pIn == pOut) /* inline */ out = (word32*)in; else { out = (word32*)XMALLOC(outLen, NULL, DYNAMIC_TYPE_AES_BUFFER); if (out == NULL) { XFREE(in, NULL, DYNAMIC_TYPE_AES_BUFFER); return MEMORY_E; } } XMEMCPY(in, pIn, inLen); } /* get uncached address */ sa_p = KVA0_TO_KVA1(&sa); bd_p = KVA0_TO_KVA1(&bd); out_p= KVA0_TO_KVA1(out); in_p = KVA0_TO_KVA1(in); /* Sync cache if in physical memory (not flash) */ if (PIC32MZ_IF_RAM(in_p)) { XMEMCPY(in_p, in, inLen); } /* Set up the Security Association */ XMEMSET(sa_p, 0, sizeof(sa)); sa_p->SA_CTRL.ALGO = algo; sa_p->SA_CTRL.ENCTYPE = dir; sa_p->SA_CTRL.FB = 1; /* first block */ sa_p->SA_CTRL.LNC = 1; /* Load new set of keys */ if (key) { /* cipher */ sa_p->SA_CTRL.CRYPTOALGO = cryptoalgo; switch (keyLen) { case 32: sa_p->SA_CTRL.KEYSIZE = PIC32_KEYSIZE_256; break; case 24: case 8: /* DES */ sa_p->SA_CTRL.KEYSIZE = PIC32_KEYSIZE_192; break; case 16: sa_p->SA_CTRL.KEYSIZE = PIC32_KEYSIZE_128; break; } dst = (word32*)KVA0_TO_KVA1(sa.SA_ENCKEY + (sizeof(sa.SA_ENCKEY)/sizeof(word32)) - (keyLen/sizeof(word32))); ByteReverseWords(dst, key, keyLen); if (iv && ivLen > 0) { sa_p->SA_CTRL.LOADIV = 1; dst = (word32*)KVA0_TO_KVA1(sa.SA_ENCIV + (sizeof(sa.SA_ENCIV)/sizeof(word32)) - (ivLen/sizeof(word32))); ByteReverseWords(dst, iv, ivLen); } } else { /* hashing */ sa_p->SA_CTRL.LOADIV = 1; sa_p->SA_CTRL.IRFLAG = 0; /* immediate result for hashing */ dst = (word32*)KVA0_TO_KVA1(sa.SA_AUTHIV + (sizeof(sa.SA_AUTHIV)/sizeof(word32)) - (outLen/sizeof(word32))); ByteReverseWords(dst, out, outLen); } /* Set up the Buffer Descriptor */ XMEMSET(bd_p, 0, sizeof(bd)); bd_p->BD_CTRL.BUFLEN = inLen; padRemain = (inLen % 4); /* make sure buffer is 4-byte multiple */ if (padRemain != 0) { bd_p->BD_CTRL.BUFLEN += (4 - padRemain); } bd_p->BD_CTRL.SA_FETCH_EN = 1; /* Fetch the security association */ bd_p->BD_CTRL.PKT_INT_EN = 1; /* enable interrupt */ bd_p->BD_CTRL.LAST_BD = 1; /* last buffer desc in chain */ bd_p->BD_CTRL.LIFM = 1; /* last in frame */ bd_p->SA_ADDR = (unsigned int)KVA_TO_PA(&sa); bd_p->SRCADDR = (unsigned int)KVA_TO_PA(in); if (key) { /* cipher */ if (in != out) XMEMSET(out_p, 0, outLen); /* clear output buffer */ bd_p->DSTADDR = (unsigned int)KVA_TO_PA(out); } else { /* hashing */ /* digest result returned in UPDPTR */ bd_p->UPDPTR = (unsigned int)KVA_TO_PA(out); } bd_p->NXTPTR = (unsigned int)KVA_TO_PA(&bd); bd_p->MSGLEN = inLen; /* actual message size */ bd_p->BD_CTRL.DESC_EN = 1; /* enable this descriptor */ /* begin access to hardware */ ret = wolfSSL_CryptHwMutexLock(); if (ret == 0) { /* Software Reset the Crypto Engine */ CECON = 1 << 6; while (CECON); /* Clear the interrupt flags */ CEINTSRC = 0xF; /* Run the engine */ CEBDPADDR = (unsigned int)KVA_TO_PA(&bd); CEINTEN = 0x07; /* enable DMA Packet Completion Interrupt */ /* input swap, enable BD fetch and start DMA */ #if PIC32_NO_OUT_SWAP CECON = 0x25; #else CECON = 0xa5; /* bit 7 = enable out swap */ #endif /* wait for operation to complete */ while (CEINTSRCbits.PKTIF == 0 && --timeout > 0) {}; /* Clear the interrupt flags */ CEINTSRC = 0xF; /* check for errors */ if (CESTATbits.ERROP || timeout <= 0) { #if 0 printf("PIC32 Crypto: ERROP %x, ERRPHASE %x, TIMEOUT %s\n", CESTATbits.ERROP, CESTATbits.ERRPHASE, timeout <= 0 ? "yes" : "no"); #endif ret = ASYNC_OP_E; } wolfSSL_CryptHwMutexUnLock(); /* copy result to output */ #if PIC32_NO_OUT_SWAP /* swap bytes */ ByteReverseWords(out, (word32*)out_p, outLen); #elif defined(_SYS_DEVCON_LOCAL_H) /* sync cache */ SYS_DEVCON_DataCacheInvalidate((word32)out, outLen); #else XMEMCPY(out, out_p, outLen); #endif } /* handle unaligned */ if (isDynamic) { /* return result */ XMEMCPY(pOut, out, outLen); /* free dynamic buffers */ XFREE(in, NULL, DYNAMIC_TYPE_AES_BUFFER); if ((word32*)pIn != pOut) XFREE(out, NULL, DYNAMIC_TYPE_AES_BUFFER); } return ret; } #endif /* WOLFSSL_PIC32MZ_CRYPT || WOLFSSL_PIC32MZ_HASH */ #ifdef WOLFSSL_PIC32MZ_HASH #ifdef WOLFSSL_PIC32MZ_LARGE_HASH /* tunable large hash block size */ #ifndef PIC32_BLOCK_SIZE #define PIC32_BLOCK_SIZE 256 #endif #define PIC32MZ_MIN_BLOCK 64 #define PIC32MZ_MAX_BLOCK (32*1024) #ifndef PIC32MZ_MAX_BD #define PIC32MZ_MAX_BD 2 #endif #if PIC32_BLOCK_SIZE < PIC32MZ_MIN_BLOCK #error Encryption block size must be at least 64 bytes. #endif /* Crypt Engine descriptor */ typedef struct { int currBd; int err; unsigned int msgSize; uint32_t processed; uint32_t dbPtr; int engine_ready; volatile bufferDescriptor bd[PIC32MZ_MAX_BD] __attribute__((aligned (8))); securityAssociation sa __attribute__((aligned (8))); } pic32mz_desc; static pic32mz_desc gLHDesc __attribute__((coherent)); static uint8_t gLHDataBuf[PIC32MZ_MAX_BD][PIC32_BLOCK_SIZE] __attribute__((aligned (4), coherent)); static void reset_engine(int algo) { int i; wolfSSL_CryptHwMutexLock(); /* Software reset */ CECON = 1 << 6; while (CECON); /* Clear the interrupt flags */ CEINTSRC = 0xF; /* Make sure everything is clear first before we setup */ XMEMSET(&gLHDesc, 0, sizeof(pic32mz_desc)); /* Set up the Security Association */ gLHDesc.sa.SA_CTRL.ALGO = algo; gLHDesc.sa.SA_CTRL.LNC = 1; gLHDesc.sa.SA_CTRL.FB = 1; gLHDesc.sa.SA_CTRL.ENCTYPE = 1; gLHDesc.sa.SA_CTRL.LOADIV = 1; /* Set up the Buffer Descriptor */ gLHDesc.err = 0; for (i = 0; i < PIC32MZ_MAX_BD; i++) { XMEMSET((void *)&gLHDesc.bd[i], 0, sizeof(gLHDesc.bd[i])); gLHDesc.bd[i].BD_CTRL.LAST_BD = 1; gLHDesc.bd[i].BD_CTRL.LIFM = 1; gLHDesc.bd[i].BD_CTRL.PKT_INT_EN = 1; gLHDesc.bd[i].SA_ADDR = KVA_TO_PA(&gLHDesc.sa); gLHDesc.bd[i].SRCADDR = KVA_TO_PA(&gLHDataBuf[i]); if (PIC32MZ_MAX_BD > i+1) gLHDesc.bd[i].NXTPTR = KVA_TO_PA(&gLHDesc.bd[i+1]); else gLHDesc.bd[i].NXTPTR = KVA_TO_PA(&gLHDesc.bd[0]); XMEMSET((void *)&gLHDataBuf[i], 0, PIC32_BLOCK_SIZE); } gLHDesc.bd[0].BD_CTRL.SA_FETCH_EN = 1; /* Fetch the security association on the first BD */ gLHDesc.dbPtr = 0; gLHDesc.currBd = 0; gLHDesc.msgSize = 0; gLHDesc.processed = 0; CEBDPADDR = KVA_TO_PA(&(gLHDesc.bd[0])); CEPOLLCON = 10; #if PIC32_NO_OUT_SWAP CECON = 0x27; #else CECON = 0xa7; #endif } static void update_engine(const byte *input, word32 len, word32 *hash) { int total; gLHDesc.bd[gLHDesc.currBd].UPDPTR = KVA_TO_PA(hash); /* Add the data to the current buffer. If the buffer fills, start processing it and fill the next one. */ while (len) { /* If we've been given the message size, we can process along the way. Enable the current buffer descriptor if it is full. */ if (gLHDesc.dbPtr >= PIC32_BLOCK_SIZE) { /* Wrap up the buffer descriptor and enable it so the engine can process */ gLHDesc.bd[gLHDesc.currBd].MSGLEN = gLHDesc.msgSize; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.BUFLEN = gLHDesc.dbPtr; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.LAST_BD = 0; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.LIFM = 0; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.DESC_EN = 1; /* Move to the next buffer descriptor, or wrap around. */ gLHDesc.currBd++; if (gLHDesc.currBd >= PIC32MZ_MAX_BD) gLHDesc.currBd = 0; /* Wait until the engine has processed the new BD. */ while (gLHDesc.bd[gLHDesc.currBd].BD_CTRL.DESC_EN); gLHDesc.bd[gLHDesc.currBd].UPDPTR = KVA_TO_PA(hash); gLHDesc.dbPtr = 0; } if (!PIC32MZ_IF_RAM(input)) { /* If we're inputting from flash, let the BD have the address and max the buffer size */ gLHDesc.bd[gLHDesc.currBd].SRCADDR = KVA_TO_PA(input); total = (len > PIC32MZ_MAX_BLOCK ? PIC32MZ_MAX_BLOCK : len); gLHDesc.dbPtr = total; len -= total; input += total; } else { if (len > PIC32_BLOCK_SIZE - gLHDesc.dbPtr) { /* We have more data than can be put in the buffer. Fill what we can.*/ total = PIC32_BLOCK_SIZE - gLHDesc.dbPtr; XMEMCPY(&gLHDataBuf[gLHDesc.currBd][gLHDesc.dbPtr], input, total); len -= total; gLHDesc.dbPtr = PIC32_BLOCK_SIZE; input += total; } else { /* Fill up what we have, but don't turn on the engine.*/ XMEMCPY(&gLHDataBuf[gLHDesc.currBd][gLHDesc.dbPtr], input, len); gLHDesc.dbPtr += len; len = 0; } } } } static void start_engine(void) { /* Wrap up the last buffer descriptor and enable it */ int bufferLen; bufferLen = gLHDesc.dbPtr; if (bufferLen % 4) bufferLen = (bufferLen + 4) - (bufferLen % 4); /* initialize the MSGLEN on engine startup to avoid infinite loop when * length is less than 257 (size of PIC32_BLOCK_SIZE) */ gLHDesc.bd[gLHDesc.currBd].MSGLEN = gLHDesc.msgSize; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.BUFLEN = bufferLen; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.LAST_BD = 1; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.LIFM = 1; gLHDesc.bd[gLHDesc.currBd].BD_CTRL.DESC_EN = 1; } void wait_engine(char *hash, int hash_sz) { int i; unsigned int engineRunning; do { engineRunning = 0; for (i = 0; i < PIC32MZ_MAX_BD; i++) { engineRunning = engineRunning || gLHDesc.bd[i].BD_CTRL.DESC_EN; } } while (engineRunning); #if PIC32_NO_OUT_SWAP /* swap bytes */ ByteReverseWords(hash, KVA0_TO_KVA1(hash), hash_sz); #else /* copy output - hardware already swapped */ XMEMCPY(hash, KVA0_TO_KVA1(hash), hash_sz); #endif wolfSSL_CryptHwMutexUnLock(); } #endif /* WOLFSSL_PIC32MZ_LARGE_HASH */ int wc_Pic32Hash(const byte* in, int inLen, word32* out, int outLen, int algo) { return Pic32Crypto(in, inLen, out, outLen, PIC32_ENCRYPTION, algo, 0, NULL, 0, NULL, 0); } int wc_Pic32HashCopy(hashUpdCache* src, hashUpdCache* dst) { /* mark destination as copy, so cache->buf is not free'd */ if (dst) { dst->isCopy = 1; } return 0; } static int wc_Pic32HashUpdate(hashUpdCache* cache, byte* stdBuf, int stdBufLen, word32* digest, int digestSz, const byte* data, int len, int algo, void* heap) { int ret = 0; word32 newLenUpd, newLenPad, padRemain; byte* newBuf; int isNewBuf = 0; #ifdef WOLFSSL_PIC32MZ_LARGE_HASH /* if final length is set then pass straight to hardware */ if (cache->finalLen) { if (cache->bufLen == 0) { reset_engine(algo); gLHDesc.msgSize = cache->finalLen; } update_engine(data, len, digest); cache->bufLen += len; /* track progress for blockType */ return 0; } #endif /* cache updates */ /* calculate new len */ newLenUpd = cache->updLen + len; /* calculate padded len - pad buffer at 64-bytes for hardware */ newLenPad = newLenUpd; padRemain = (newLenUpd % PIC32_BLOCKSIZE_HASH); if (padRemain != 0) { newLenPad += (PIC32_BLOCKSIZE_HASH - padRemain); } /* determine buffer source */ if (newLenPad <= stdBufLen) { /* use standard buffer */ newBuf = stdBuf; } else if (newLenPad > cache->bufLen) { /* alloc buffer */ newBuf = (byte*)XMALLOC(newLenPad, heap, DYNAMIC_TYPE_HASH_TMP); if (newBuf == NULL) { if (cache->buf != stdBuf && !cache->isCopy) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; cache->updLen = cache->bufLen = 0; } return MEMORY_E; } isNewBuf = 1; cache->isCopy = 0; /* no longer using copy buffer */ } else { /* use existing buffer */ newBuf = cache->buf; } if (cache->buf && cache->updLen > 0) { XMEMCPY(newBuf, cache->buf, cache->updLen); if (isNewBuf && cache->buf != stdBuf) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; } } XMEMCPY(newBuf + cache->updLen, data, len); cache->buf = newBuf; cache->updLen = newLenUpd; cache->bufLen = newLenPad; return ret; } static int wc_Pic32HashFinal(hashUpdCache* cache, byte* stdBuf, word32* digest, byte* hash, int digestSz, int algo, void* heap) { int ret = 0; /* if room add the pad */ if (cache->buf && cache->updLen < cache->bufLen) { cache->buf[cache->updLen] = 0x80; } #ifdef WOLFSSL_PIC32MZ_LARGE_HASH if (cache->finalLen) { /* Only submit to hardware if update data provided matches expected */ if (cache->bufLen == cache->finalLen) { start_engine(); wait_engine((char*)digest, digestSz); XMEMCPY(hash, digest, digestSz); } else { wolfSSL_CryptHwMutexUnLock(); ret = BUFFER_E; } cache->finalLen = 0; } else #endif { if (cache->updLen == 0) { /* handle empty input */ switch (algo) { case PIC32_ALGO_SHA256: { const char* sha256EmptyHash = "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9" "\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52" "\xb8\x55"; XMEMCPY(hash, sha256EmptyHash, digestSz); break; } case PIC32_ALGO_SHA1: { const char* shaEmptyHash = "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18" "\x90\xaf\xd8\x07\x09"; XMEMCPY(hash, shaEmptyHash, digestSz); break; } case PIC32_ALGO_MD5: { const char* md5EmptyHash = "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42" "\x7e"; XMEMCPY(hash, md5EmptyHash, digestSz); break; } } /* switch */ } else { ret = wc_Pic32Hash(cache->buf, cache->updLen, digest, digestSz, algo); if (ret == 0) { XMEMCPY(hash, digest, digestSz); } } if (cache->buf && cache->buf != stdBuf && !cache->isCopy) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; } } cache->buf = NULL; cache->bufLen = cache->updLen = 0; return ret; } static void wc_Pic32HashFree(hashUpdCache* cache, void* heap) { if (cache && cache->buf && !cache->isCopy) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; } } /* API's for compatibility with Harmony wrappers - not used */ #ifndef NO_MD5 int wc_InitMd5_ex(wc_Md5* md5, void* heap, int devId) { if (md5 == NULL) return BAD_FUNC_ARG; XMEMSET(md5, 0, sizeof(wc_Md5)); md5->heap = heap; (void)devId; return 0; } int wc_Md5Update(wc_Md5* md5, const byte* data, word32 len) { if (md5 == NULL || (data == NULL && len > 0)) return BAD_FUNC_ARG; return wc_Pic32HashUpdate(&md5->cache, (byte*)md5->buffer, sizeof(md5->buffer), md5->digest, MD5_DIGEST_SIZE, data, len, PIC32_ALGO_MD5, md5->heap); } int wc_Md5Final(wc_Md5* md5, byte* hash) { int ret; if (md5 == NULL || hash == NULL) return BAD_FUNC_ARG; ret = wc_Pic32HashFinal(&md5->cache, (byte*)md5->buffer, md5->digest, hash, MD5_DIGEST_SIZE, PIC32_ALGO_MD5, md5->heap); wc_InitMd5_ex(md5, md5->heap, INVALID_DEVID); /* reset state */ return ret; } void wc_Md5SizeSet(wc_Md5* md5, word32 len) { if (md5) { #ifdef WOLFSSL_PIC32MZ_LARGE_HASH md5->cache.finalLen = len; #else (void)len; #endif } } void wc_Md5Pic32Free(wc_Md5* md5) { if (md5) { wc_Pic32HashFree(&md5->cache, md5->heap); } } #endif /* !NO_MD5 */ #ifndef NO_SHA int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId) { if (sha == NULL) return BAD_FUNC_ARG; XMEMSET(sha, 0, sizeof(wc_Sha)); sha->heap = heap; (void)devId; return 0; } int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len) { if (sha == NULL || (data == NULL && len > 0)) return BAD_FUNC_ARG; return wc_Pic32HashUpdate(&sha->cache, (byte*)sha->buffer, sizeof(sha->buffer), sha->digest, SHA_DIGEST_SIZE, data, len, PIC32_ALGO_SHA1, sha->heap); } int wc_ShaFinal(wc_Sha* sha, byte* hash) { int ret; if (sha == NULL || hash == NULL) return BAD_FUNC_ARG; ret = wc_Pic32HashFinal(&sha->cache, (byte*)sha->buffer, sha->digest, hash, SHA_DIGEST_SIZE, PIC32_ALGO_SHA1, sha->heap); wc_InitSha_ex(sha, sha->heap, INVALID_DEVID); /* reset state */ return ret; } void wc_ShaSizeSet(wc_Sha* sha, word32 len) { if (sha) { #ifdef WOLFSSL_PIC32MZ_LARGE_HASH sha->cache.finalLen = len; #else (void)len; #endif } } void wc_ShaPic32Free(wc_Sha* sha) { if (sha) { wc_Pic32HashFree(&sha->cache, sha->heap); } } #endif /* !NO_SHA */ #ifndef NO_SHA256 int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId) { if (sha256 == NULL) return BAD_FUNC_ARG; XMEMSET(sha256, 0, sizeof(wc_Sha256)); sha256->heap = heap; (void)devId; return 0; } int wc_Sha256Update(wc_Sha256* sha256, const byte* data, word32 len) { if (sha256 == NULL || (data == NULL && len > 0)) return BAD_FUNC_ARG; return wc_Pic32HashUpdate(&sha256->cache, (byte*)sha256->buffer, sizeof(sha256->buffer), sha256->digest, SHA256_DIGEST_SIZE, data, len, PIC32_ALGO_SHA256, sha256->heap); } int wc_Sha256Final(wc_Sha256* sha256, byte* hash) { int ret; if (sha256 == NULL || hash == NULL) return BAD_FUNC_ARG; ret = wc_Pic32HashFinal(&sha256->cache, (byte*)sha256->buffer, sha256->digest, hash, SHA256_DIGEST_SIZE, PIC32_ALGO_SHA256, sha256->heap); wc_InitSha256_ex(sha256, sha256->heap, INVALID_DEVID); /* reset state */ return ret; } void wc_Sha256SizeSet(wc_Sha256* sha256, word32 len) { if (sha256) { #ifdef WOLFSSL_PIC32MZ_LARGE_HASH sha256->cache.finalLen = len; #else (void)len; #endif } } void wc_Sha256Pic32Free(wc_Sha256* sha256) { if (sha256) { wc_Pic32HashFree(&sha256->cache, sha256->heap); } } #endif /* !NO_SHA256 */ #endif /* WOLFSSL_PIC32MZ_HASH */ #ifdef WOLFSSL_PIC32MZ_CRYPT #if !defined(NO_AES) int wc_Pic32AesCrypt(word32 *key, int keyLen, word32 *iv, int ivLen, byte* out, const byte* in, word32 sz, int dir, int algo, int cryptoalgo) { return Pic32Crypto(in, sz, (word32*)out, sz, dir, algo, cryptoalgo, key, keyLen, iv, ivLen); } #endif /* !NO_AES */ #ifndef NO_DES3 int wc_Pic32DesCrypt(word32 *key, int keyLen, word32 *iv, int ivLen, byte* out, const byte* in, word32 sz, int dir, int algo, int cryptoalgo) { return Pic32Crypto(in, sz, (word32*)out, sz, dir, algo, cryptoalgo, key, keyLen, iv, ivLen); } #endif /* !NO_DES3 */ #endif /* WOLFSSL_PIC32MZ_CRYPT */ #endif /* WOLFSSL_MICROCHIP_PIC32MZ */