#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(WOLFSSL_AFALG_HASH) || (defined(WOLFSSL_AFALG_XILINX_SHA3) \
&& defined(WOLFSSL_SHA3))
#include <wolfssl/wolfcrypt/port/af_alg/wc_afalg.h>
#include <wolfssl/wolfcrypt/port/af_alg/afalg_hash.h>
static const char WC_TYPE_HASH[] = "hash";
static void AfalgHashFree(wolfssl_AFALG_Hash* hash)
{
if (hash == NULL)
return;
if (hash->alFd > WC_SOCK_NOTSET) {
(void)close(hash->alFd);
hash->alFd = WC_SOCK_NOTSET;
}
if (hash->rdFd > WC_SOCK_NOTSET) {
(void)close(hash->rdFd);
hash->rdFd = WC_SOCK_NOTSET;
}
#if defined(WOLFSSL_AFALG_HASH_KEEP)
XFREE(hash->msg, hash->heap, DYNAMIC_TYPE_TMP_BUFFER);
hash->msg = NULL;
#endif
}
static int AfalgHashInit(wolfssl_AFALG_Hash* hash, void* heap, int devId,
const char* type)
{
if (hash == NULL) {
return BAD_FUNC_ARG;
}
(void)devId;
XMEMSET(hash, 0, sizeof(wolfssl_AFALG_Hash));
hash->heap = heap;
hash->len = 0;
hash->used = 0;
hash->msg = NULL;
hash->alFd = WC_SOCK_NOTSET;
hash->rdFd = WC_SOCK_NOTSET;
hash->alFd = wc_Afalg_Socket();
if (hash->alFd < 0) {
return WC_AFALG_SOCK_E;
}
hash->rdFd = wc_Afalg_CreateRead(hash->alFd, WC_TYPE_HASH, type);
if (hash->rdFd < 0) {
(void)close(hash->alFd);
hash->alFd = WC_SOCK_NOTSET;
return WC_AFALG_SOCK_E;
}
return 0;
}
static int AfalgHashUpdate(wolfssl_AFALG_Hash* hash, const byte* in, word32 sz)
{
if (hash == NULL || (sz > 0 && in == NULL)) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_AFALG_HASH_KEEP
if (hash->len < hash->used + sz) {
if (hash->msg == NULL) {
hash->msg = (byte*)XMALLOC(hash->used + sz, hash->heap,
DYNAMIC_TYPE_TMP_BUFFER);
} else {
byte* pt = (byte*)XREALLOC(hash->msg, hash->used + sz, hash->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (pt == NULL) {
return MEMORY_E;
}
hash->msg = pt;
}
if (hash->msg == NULL) {
return MEMORY_E;
}
hash->len = hash->used + sz;
}
if (sz > 0) {
XMEMCPY(hash->msg + hash->used, in, sz);
hash->used += sz;
}
#else
int ret;
if ((ret = (int)send(hash->rdFd, in, sz, MSG_MORE)) < 0) {
return ret;
}
#endif
return 0;
}
static int AfalgHashFinal(wolfssl_AFALG_Hash* hash, byte* out, word32 outSz,
const char* type)
{
int ret;
if (hash == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_AFALG_HASH_KEEP
if ((ret = (int)send(hash->rdFd, hash->msg, hash->used, 0)) < 0) {
ret = WC_AFALG_SOCK_E;
goto out;
}
XFREE(hash->msg, hash->heap, DYNAMIC_TYPE_TMP_BUFFER);
hash->msg = NULL;
#else
if ((ret = (int)send(hash->rdFd, NULL, 0, 0)) < 0) {
ret = WC_AFALG_SOCK_E;
goto out;
}
#endif
if ((ret = (int)read(hash->rdFd, out, outSz)) != (int)outSz) {
ret = WC_AFALG_SOCK_E;
goto out;
}
ret = 0;
out:
AfalgHashFree(hash);
if (ret != 0)
return ret;
else
return AfalgHashInit(hash, hash->heap, 0, type);
}
static int AfalgHashGet(wolfssl_AFALG_Hash* hash, byte* out, word32 outSz)
{
int ret;
if (hash == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
(void)ret;
#ifdef WOLFSSL_AFALG_HASH_KEEP
if ((ret = (int)send(hash->rdFd, hash->msg, hash->used, 0)) < 0) {
return ret;
}
if ((ret = (int)read(hash->rdFd, out, outSz)) != (int)outSz) {
return WC_AFALG_SOCK_E;
}
return 0;
#else
(void)hash;
(void)out;
(void)outSz;
WOLFSSL_MSG("Compile with WOLFSSL_AFALG_HASH_KEEP for this feature");
return NOT_COMPILED_IN;
#endif
}
static int AfalgHashCopy(wolfssl_AFALG_Hash* src, wolfssl_AFALG_Hash* dst)
{
if (src == NULL || dst == NULL) {
return BAD_FUNC_ARG;
}
XMEMCPY(dst, src, sizeof(wolfssl_AFALG_Hash));
#ifdef WOLFSSL_AFALG_HASH_KEEP
if (src->len > 0) {
dst->msg = (byte*)XMALLOC(src->len, dst->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (dst->msg == NULL) {
return MEMORY_E;
}
XMEMCPY(dst->msg, src->msg, src->len);
}
else {
dst->msg = NULL;
}
#endif
dst->rdFd = accept(src->rdFd, NULL, 0);
dst->alFd = accept(src->alFd, NULL, 0);
if (dst->rdFd == WC_SOCK_NOTSET || dst->alFd == WC_SOCK_NOTSET) {
AfalgHashFree(dst);
return WC_AFALG_SOCK_E;
}
return 0;
}
#if !defined(NO_SHA256) && defined(WOLFSSL_AFALG_HASH)
#include <wolfssl/wolfcrypt/sha256.h>
static const char WC_NAME_SHA256[] = "sha256";
int wc_InitSha256_ex(wc_Sha256* sha, void* heap, int devId)
{
return AfalgHashInit(sha, heap, devId, WC_NAME_SHA256);
}
int wc_Sha256Update(wc_Sha256* sha, const byte* in, word32 sz)
{
return AfalgHashUpdate(sha, in, sz);
}
int wc_Sha256Final(wc_Sha256* sha, byte* hash)
{
return AfalgHashFinal(sha, hash, WC_SHA256_DIGEST_SIZE, WC_NAME_SHA256);
}
int wc_Sha256GetHash(wc_Sha256* sha, byte* hash)
{
return AfalgHashGet(sha, hash, WC_SHA256_DIGEST_SIZE);
}
int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst)
{
return AfalgHashCopy(src, dst);
}
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_AFALG_XILINX_SHA3)
#include <wolfssl/wolfcrypt/sha3.h>
static const char WC_NAME_SHA3[] = "xilinx-keccak-384";
void wc_Sha3_384_Free(wc_Sha3* sha)
{
AfalgHashFree(sha);
}
int wc_InitSha3_384(wc_Sha3* sha, void* heap, int devId)
{
return AfalgHashInit(sha, heap, devId, WC_NAME_SHA3);
}
int wc_Sha3_384_Update(wc_Sha3* sha, const byte* in, word32 sz)
{
#ifndef WOLFSSL_AFALG_HASH_KEEP
if (sz % 4) {
WOLFSSL_MSG("Alignment issue. Message size needs to be divisible by 4")
return BAD_FUNC_ARG;
}
#endif
return AfalgHashUpdate(sha, in, sz);
}
int wc_Sha3_384_Final(wc_Sha3* sha, byte* hash)
{
if (sha == NULL || hash == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_AFALG_HASH_KEEP
if (sha->used % 4) {
WOLFSSL_MSG("Alignment issue. Message size needs to be divisible by 4");
return BAD_FUNC_ARG;
}
#endif
return AfalgHashFinal(sha, hash, WC_SHA3_384_DIGEST_SIZE, WC_NAME_SHA3);
}
int wc_Sha3_384_GetHash(wc_Sha3* sha, byte* hash)
{
if (sha == NULL || hash == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_AFALG_HASH_KEEP
if (sha->used % 4) {
WOLFSSL_MSG("Alignment issue. Message size needs to be divisible by 4");
return BAD_FUNC_ARG;
}
#endif
return AfalgHashGet(sha, hash, WC_SHA3_384_DIGEST_SIZE);
}
int wc_Sha3_384_Copy(wc_Sha3* src, wc_Sha3* dst)
{
return AfalgHashCopy(src, dst);
}
#endif
#endif