summaryrefslogtreecommitdiff
path: root/wolfcrypt/src/port/af_alg
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-22 08:34:12 -0700
committerauth12 <[email protected]>2020-07-22 08:34:12 -0700
commit5015ddb9b1eee748efc24056e46f81888c975f7a (patch)
treea810f6ee90f8bfe0e934fdd9142198e6b3862957 /wolfcrypt/src/port/af_alg
downloadwolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.tar.xz
wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.zip
Initial commit
Diffstat (limited to 'wolfcrypt/src/port/af_alg')
-rw-r--r--wolfcrypt/src/port/af_alg/afalg_aes.c900
-rw-r--r--wolfcrypt/src/port/af_alg/afalg_hash.c339
-rw-r--r--wolfcrypt/src/port/af_alg/wc_afalg.c141
3 files changed, 1380 insertions, 0 deletions
diff --git a/wolfcrypt/src/port/af_alg/afalg_aes.c b/wolfcrypt/src/port/af_alg/afalg_aes.c
new file mode 100644
index 0000000..2d1d41a
--- /dev/null
+++ b/wolfcrypt/src/port/af_alg/afalg_aes.c
@@ -0,0 +1,900 @@
+/* afalg_aes.c
+ *
+ * Copyright (C) 2006-2020 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 <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#if !defined(NO_AES) && (defined(WOLFSSL_AFALG) || \
+ defined(WOLFSSL_AFALG_XILINX_AES))
+
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/port/af_alg/wc_afalg.h>
+
+#include <sys/uio.h> /* for readv */
+
+#ifdef NO_INLINE
+ #include <wolfssl/wolfcrypt/misc.h>
+#else
+ #define WOLFSSL_MISC_INCLUDED
+ #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ #define WOLFSSL_XILINX_ALIGN sizeof(wolfssl_word)
+#endif
+
+static const char WC_TYPE_SYMKEY[] = "skcipher";
+
+static int wc_AesSetup(Aes* aes, const char* type, const char* name, int ivSz, int aadSz)
+{
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ byte* key = (byte*)aes->msgBuf;
+#else
+ byte* key = (byte*)aes->key;
+#endif
+
+ aes->rdFd = wc_Afalg_CreateRead(aes->alFd, type, name);
+ if (aes->rdFd < 0) {
+ WOLFSSL_MSG("Unable to accept and get AF_ALG read socket");
+ aes->rdFd = WC_SOCK_NOTSET;
+ return aes->rdFd;
+ }
+
+ if (setsockopt(aes->alFd, SOL_ALG, ALG_SET_KEY, key, aes->keylen) != 0) {
+ WOLFSSL_MSG("Unable to set AF_ALG key");
+ aes->rdFd = WC_SOCK_NOTSET;
+ return WC_AFALG_SOCK_E;
+ }
+ ForceZero(key, sizeof(aes->key));
+
+ /* set up CMSG headers */
+ XMEMSET((byte*)&(aes->msg), 0, sizeof(struct msghdr));
+
+ aes->msg.msg_control = key; /* use existing key buffer for
+ * control buffer */
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ aes->msg.msg_controllen = CMSG_SPACE(4) +
+ CMSG_SPACE(sizeof(struct af_alg_iv) + ivSz);
+ (void)aadSz;
+#else
+ aes->msg.msg_controllen = CMSG_SPACE(4);
+ if (aadSz > 0) {
+ aes->msg.msg_controllen += CMSG_SPACE(4);
+ }
+ if (ivSz > 0) {
+ aes->msg.msg_controllen += CMSG_SPACE((sizeof(struct af_alg_iv) + ivSz));
+ }
+#endif
+
+ if (wc_Afalg_SetOp(CMSG_FIRSTHDR(&(aes->msg)), aes->dir) < 0) {
+ WOLFSSL_MSG("Error with setting AF_ALG operation");
+ aes->rdFd = WC_SOCK_NOTSET;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef WOLFSSL_AFALG
+int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen,
+ const byte* iv, int dir)
+{
+#if defined(AES_MAX_KEY_SIZE)
+ const word32 max_key_len = (AES_MAX_KEY_SIZE / 8);
+#endif
+
+ if (aes == NULL ||
+ !((keylen == 16) || (keylen == 24) || (keylen == 32))) {
+ return BAD_FUNC_ARG;
+ }
+
+#if defined(AES_MAX_KEY_SIZE)
+ /* Check key length */
+ if (keylen > max_key_len) {
+ return BAD_FUNC_ARG;
+ }
+#endif
+ aes->keylen = keylen;
+ aes->rounds = keylen/4 + 6;
+
+#ifdef WOLFSSL_AES_COUNTER
+ aes->left = 0;
+#endif
+
+ aes->rdFd = WC_SOCK_NOTSET;
+ aes->alFd = wc_Afalg_Socket();
+ if (aes->alFd < 0) {
+ WOLFSSL_MSG("Unable to open an AF_ALG socket");
+ return WC_AFALG_SOCK_E;
+ }
+
+ /* save key until type is known i.e. CBC, ECB, ... */
+ XMEMCPY((byte*)(aes->key), userKey, keylen);
+ aes->dir = dir;
+
+ return wc_AesSetIV(aes, iv);
+}
+#endif
+
+/* AES-CBC */
+#if defined(HAVE_AES_CBC) && defined(WOLFSSL_AFALG)
+ static const char WC_NAME_AESCBC[] = "cbc(aes)";
+
+ int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+ {
+ struct cmsghdr* cmsg;
+ struct iovec iov;
+ int ret;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (aes->rdFd == WC_SOCK_NOTSET) {
+ if ((ret = wc_AesSetup(aes, WC_TYPE_SYMKEY, WC_NAME_AESCBC,
+ AES_IV_SIZE, 0)) != 0) {
+ WOLFSSL_MSG("Error with first time setup of AF_ALG socket");
+ return ret;
+ }
+ }
+
+ sz = sz - (sz % AES_BLOCK_SIZE);
+ if ((sz / AES_BLOCK_SIZE) > 0) {
+ /* update IV */
+ cmsg = CMSG_FIRSTHDR(&(aes->msg));
+ ret = wc_Afalg_SetIv(CMSG_NXTHDR(&(aes->msg), cmsg),
+ (byte*)(aes->reg), AES_IV_SIZE);
+ if (ret < 0) {
+ WOLFSSL_MSG("Error setting IV");
+ return ret;
+ }
+
+ /* set data to be encrypted */
+ iov.iov_base = (byte*)in;
+ iov.iov_len = sz;
+
+ aes->msg.msg_iov = &iov;
+ aes->msg.msg_iovlen = 1; /* # of iov structures */
+
+ ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = (int)read(aes->rdFd, out, sz);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* set IV for next CBC call */
+ XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+ }
+
+ return 0;
+ }
+
+ #ifdef HAVE_AES_DECRYPT
+ int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+ {
+ struct cmsghdr* cmsg;
+ struct iovec iov;
+ int ret;
+
+ if (aes == NULL || out == NULL || in == NULL
+ || sz % AES_BLOCK_SIZE != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (aes->rdFd == WC_SOCK_NOTSET) {
+ if ((ret = wc_AesSetup(aes, WC_TYPE_SYMKEY, WC_NAME_AESCBC,
+ AES_IV_SIZE, 0)) != 0) {
+ return ret;
+ }
+ }
+
+ if ((sz / AES_BLOCK_SIZE) > 0) {
+ /* update IV */
+ cmsg = CMSG_FIRSTHDR(&(aes->msg));
+ ret = wc_Afalg_SetIv(CMSG_NXTHDR(&(aes->msg), cmsg),
+ (byte*)(aes->reg), AES_IV_SIZE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* set data to be decrypted */
+ iov.iov_base = (byte*)in;
+ iov.iov_len = sz;
+
+ aes->msg.msg_iov = &iov;
+ aes->msg.msg_iovlen = 1; /* # of iov structures */
+
+ /* set IV for next CBC call */
+ XMEMCPY(aes->reg, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+ ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = (int)read(aes->rdFd, out, sz);
+ if (ret < 0) {
+ return ret;
+ }
+
+ }
+
+ return 0;
+ }
+ #endif
+
+#endif /* HAVE_AES_CBC */
+
+
+/* AES-DIRECT */
+#if (defined(WOLFSSL_AES_DIRECT) || defined(HAVE_AES_ECB)) && \
+ defined(WOLFSSL_AFALG)
+
+static const char WC_NAME_AESECB[] = "ecb(aes)";
+
+/* common code between ECB encrypt and decrypt
+ * returns 0 on success */
+static int wc_Afalg_AesDirect(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+ struct iovec iov;
+ int ret;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (aes->rdFd == WC_SOCK_NOTSET) {
+ if ((ret = wc_AesSetup(aes, WC_TYPE_SYMKEY, WC_NAME_AESECB,
+ 0, 0)) != 0) {
+ WOLFSSL_MSG("Error with first time setup of AF_ALG socket");
+ return ret;
+ }
+ }
+
+ /* set data to be encrypted */
+ iov.iov_base = (byte*)in;
+ iov.iov_len = sz;
+
+ aes->msg.msg_iov = &iov;
+ aes->msg.msg_iovlen = 1; /* # of iov structures */
+
+ ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = (int)read(aes->rdFd, out, sz);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+
+#if defined(WOLFSSL_AES_DIRECT) && defined(WOLFSSL_AFALG)
+void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in)
+{
+ if (wc_Afalg_AesDirect(aes, out, in, AES_BLOCK_SIZE) != 0) {
+ WOLFSSL_MSG("Error with AES encrypt direct call");
+ }
+}
+
+
+void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in)
+{
+ if (wc_Afalg_AesDirect(aes, out, in, AES_BLOCK_SIZE) != 0) {
+ WOLFSSL_MSG("Error with AES decrypt direct call");
+ }
+}
+
+
+int wc_AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
+ const byte* iv, int dir)
+{
+ return wc_AesSetKey(aes, userKey, keylen, iv, dir);
+}
+#endif
+
+
+/* AES-CTR */
+#if defined(WOLFSSL_AES_COUNTER) && defined(WOLFSSL_AFALG)
+ static const char WC_NAME_AESCTR[] = "ctr(aes)";
+
+ /* Increment AES counter */
+ static WC_INLINE void IncrementAesCounter(byte* inOutCtr)
+ {
+ /* in network byte order so start at end and work back */
+ int i;
+ for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+ if (++inOutCtr[i]) /* we're done unless we overflow */
+ return;
+ }
+ }
+
+ int wc_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+ {
+ struct cmsghdr* cmsg;
+ struct iovec iov[2];
+ int ret;
+ byte* tmp;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* consume any unused bytes left in aes->tmp */
+ tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left;
+ while (aes->left && sz) {
+ *(out++) = *(in++) ^ *(tmp++);
+ aes->left--;
+ sz--;
+ }
+
+ if (aes->rdFd == WC_SOCK_NOTSET) {
+ if ((ret = wc_AesSetup(aes, WC_TYPE_SYMKEY, WC_NAME_AESCTR,
+ AES_IV_SIZE, 0)) != 0) {
+ WOLFSSL_MSG("Error with first time setup of AF_ALG socket");
+ return ret;
+ }
+ }
+
+ if (sz > 0) {
+ aes->left = sz % AES_BLOCK_SIZE;
+
+ /* clear previously leftover data */
+ tmp = (byte*)aes->tmp;
+ XMEMSET(tmp, 0, AES_BLOCK_SIZE);
+
+ /* update IV */
+ cmsg = CMSG_FIRSTHDR(&(aes->msg));
+ ret = wc_Afalg_SetIv(CMSG_NXTHDR(&(aes->msg), cmsg),
+ (byte*)(aes->reg), AES_IV_SIZE);
+ if (ret < 0) {
+ WOLFSSL_MSG("Error setting IV");
+ return ret;
+ }
+
+ /* set data to be encrypted */
+ iov[0].iov_base = (byte*)in;
+ iov[0].iov_len = sz - aes->left;
+
+ iov[1].iov_base = tmp;
+ if (aes->left > 0) {
+ XMEMCPY(tmp, in + sz - aes->left, aes->left);
+ iov[1].iov_len = AES_BLOCK_SIZE;
+ }
+ else {
+ iov[1].iov_len = 0;
+ }
+
+ aes->msg.msg_iov = iov;
+ aes->msg.msg_iovlen = 2; /* # of iov structures */
+
+ ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+
+ /* set buffers to hold result and left over stream */
+ iov[0].iov_base = (byte*)out;
+ iov[0].iov_len = sz - aes->left;
+
+ iov[1].iov_base = tmp;
+ if (aes->left > 0) {
+ iov[1].iov_len = AES_BLOCK_SIZE;
+ }
+ else {
+ iov[1].iov_len = 0;
+ }
+
+ ret = (int)readv(aes->rdFd, iov, 2);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (aes->left > 0) {
+ XMEMCPY(out + sz - aes->left, tmp, aes->left);
+ aes->left = AES_BLOCK_SIZE - aes->left;
+ }
+ }
+
+ /* adjust counter after call to hardware */
+ while (sz >= AES_BLOCK_SIZE) {
+ IncrementAesCounter((byte*)aes->reg);
+ sz -= AES_BLOCK_SIZE;
+ }
+
+ if (aes->left > 0) {
+ IncrementAesCounter((byte*)aes->reg);
+ }
+
+ return 0;
+ }
+#endif /* WOLFSSL_AES_COUNTER */
+
+
+#ifdef HAVE_AESGCM
+
+
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ static const char WC_NAME_AESGCM[] = "xilinx-zynqmp-aes";
+ static const char* WC_TYPE_AEAD = WC_TYPE_SYMKEY;
+#else
+ static const char WC_NAME_AESGCM[] = "gcm(aes)";
+ static const char WC_TYPE_AEAD[] = "aead";
+#endif
+
+#ifndef WC_SYSTEM_AESGCM_IV
+/* size of IV allowed on system for AES-GCM */
+#define WC_SYSTEM_AESGCM_IV 12
+#endif
+
+#ifndef WOLFSSL_MAX_AUTH_TAG_SZ
+/* size of tag is restricted by system for AES-GCM
+ * check 'cat /proc/crypto' to see restricted size */
+#define WOLFSSL_MAX_AUTH_TAG_SZ 16
+#endif
+
+#ifdef WOLFSSL_AFALG_XILINX_AES
+/* Xilinx uses a slightly different function because the default AES key is also
+ * needed if handling additional data with creating/validating the TAG.
+ *
+ * returns 0 on success
+ */
+int wc_AesGcmSetKey_ex(Aes* aes, const byte* key, word32 len, word32 kup)
+#else
+int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
+#endif
+{
+#if defined(AES_MAX_KEY_SIZE)
+ const word32 max_key_len = (AES_MAX_KEY_SIZE / 8);
+#endif
+
+ if (aes == NULL ||
+ !((len == 16) || (len == 24) || (len == 32))) {
+ return BAD_FUNC_ARG;
+ }
+
+#if defined(AES_MAX_KEY_SIZE)
+ /* Check key length */
+ if (len > max_key_len) {
+ return BAD_FUNC_ARG;
+ }
+#endif
+ aes->keylen = len;
+ aes->rounds = len/4 + 6;
+
+ aes->rdFd = WC_SOCK_NOTSET;
+ aes->alFd = wc_Afalg_Socket();
+ if (aes->alFd < 0) {
+ WOLFSSL_MSG("Unable to open an AF_ALG socket");
+ return WC_AFALG_SOCK_E;
+ }
+
+ /* save key until direction is known i.e. encrypt or decrypt */
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ (void)kup; /* using alternate buffer because software key is needed */
+ XMEMCPY((byte*)(aes->msgBuf), key, len);
+#else
+ XMEMCPY((byte*)(aes->key), key, len);
+#endif
+
+ return 0;
+}
+
+
+
+/* Performs AES-GCM encryption and returns 0 on success
+ *
+ * Warning: If using Xilinx hardware acceleration it is assumed that the out
+ * buffer is large enough to hold both cipher text and tag. That is
+ * sz | 16 bytes. The input and output buffer is expected to be 64 bit
+ * aligned
+ *
+ */
+int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
+ const byte* iv, word32 ivSz,
+ byte* authTag, word32 authTagSz,
+ const byte* authIn, word32 authInSz)
+{
+ struct cmsghdr* cmsg;
+ struct iovec iov[3];
+ int ret;
+ struct msghdr* msg;
+ byte scratch[AES_BLOCK_SIZE];
+
+ /* argument checks */
+ if (aes == NULL || authTagSz > AES_BLOCK_SIZE) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (ivSz != WC_SYSTEM_AESGCM_IV || authTagSz > WOLFSSL_MAX_AUTH_TAG_SZ) {
+ WOLFSSL_MSG("IV/AAD size not supported on system");
+ return BAD_FUNC_ARG;
+ }
+
+ if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) {
+ WOLFSSL_MSG("GcmEncrypt authTagSz too small error");
+ return BAD_FUNC_ARG;
+ }
+
+ if (aes->rdFd == WC_SOCK_NOTSET) {
+ aes->dir = AES_ENCRYPTION;
+ if ((ret = wc_AesSetup(aes, WC_TYPE_AEAD, WC_NAME_AESGCM, ivSz,
+ authInSz)) != 0) {
+ WOLFSSL_MSG("Error with first time setup of AF_ALG socket");
+ return ret;
+ }
+
+ /* note that if the ivSz was to change, the msg_controllen would need
+ reset */
+
+#ifndef WOLFSSL_AFALG_XILINX_AES
+ /* set auth tag
+ * @TODO case where tag size changes between calls? */
+ ret = setsockopt(aes->alFd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL,
+ authTagSz);
+ if (ret != 0) {
+ perror("set tag");
+ WOLFSSL_MSG("Unable to set AF_ALG tag size ");
+ return WC_AFALG_SOCK_E;
+ }
+#endif
+ }
+
+
+ msg = &(aes->msg);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg = CMSG_NXTHDR(msg, cmsg);
+
+ /* set IV and AAD size */
+ ret = wc_Afalg_SetIv(cmsg, (byte*)iv, ivSz);
+ if (ret < 0) {
+ WOLFSSL_MSG("Error setting IV");
+ return ret;
+
+ }
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ if (sz > 0) {
+ #ifndef NO_WOLFSSL_ALLOC_ALIGN
+ byte* tmp = NULL;
+ #endif
+ if ((wolfssl_word)in % WOLFSSL_XILINX_ALIGN) {
+ #ifndef NO_WOLFSSL_ALLOC_ALIGN
+ byte* tmp_align;
+ tmp = (byte*)XMALLOC(sz + WOLFSSL_XILINX_ALIGN +
+ AES_BLOCK_SIZE, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (tmp == NULL) {
+ return MEMORY_E;
+ }
+ tmp_align = tmp + (WOLFSSL_XILINX_ALIGN -
+ ((size_t)tmp % WOLFSSL_XILINX_ALIGN));
+ XMEMCPY(tmp_align, in, sz);
+ iov[0].iov_base = tmp_align;
+ #else
+ WOLFSSL_MSG("Buffer expected to be word aligned");
+ return BAD_ALIGN_E;
+ #endif
+ }
+ else {
+ iov[0].iov_base = (byte*)in;
+ }
+ iov[0].iov_len = sz + AES_BLOCK_SIZE;
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = 1; /* # of iov structures */
+
+ ret = (int)sendmsg(aes->rdFd, msg, 0);
+ #ifndef NO_WOLFSSL_ALLOC_ALIGN
+ XFREE(tmp, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = read(aes->rdFd, out, sz + AES_BLOCK_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+ XMEMCPY(authTag, out + sz, authTagSz);
+ }
+
+ /* handle completing tag with using software if additional data added */
+ if (authIn != NULL && authInSz > 0) {
+ byte initalCounter[AES_BLOCK_SIZE];
+ XMEMSET(initalCounter, 0, AES_BLOCK_SIZE);
+ XMEMCPY(initalCounter, iv, ivSz);
+ initalCounter[AES_BLOCK_SIZE - 1] = 1;
+ GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
+ wc_AesEncryptDirect(aes, scratch, initalCounter);
+ xorbuf(authTag, scratch, authTagSz);
+ }
+#else
+ if (authInSz > 0) {
+ cmsg = CMSG_NXTHDR(msg, cmsg);
+ ret = wc_Afalg_SetAad(cmsg, authInSz);
+ if (ret < 0) {
+ WOLFSSL_MSG("Unable to set AAD size");
+ return ret;
+ }
+ }
+
+ /* set data to be encrypted*/
+ iov[0].iov_base = (byte*)authIn;
+ iov[0].iov_len = authInSz;
+
+ iov[1].iov_base = (byte*)in;
+ iov[1].iov_len = sz;
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = 2; /* # of iov structures */
+
+ ret = (int)sendmsg(aes->rdFd, msg, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ {
+ byte* tmp = (byte*)XMALLOC(authInSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (tmp == NULL) {
+ return MEMORY_E;
+ }
+ /* first 16 bytes was all 0's */
+ iov[0].iov_base = tmp;
+ (void)scratch;
+ iov[0].iov_len = authInSz;
+
+ iov[1].iov_base = out;
+ iov[1].iov_len = sz;
+
+ iov[2].iov_base = authTag;
+ iov[2].iov_len = authTagSz;
+
+ ret = (int)readv(aes->rdFd, iov, 3);
+ XFREE(tmp, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ if (ret < 0) {
+ return ret;
+ }
+#endif
+
+
+ return 0;
+}
+
+#if defined(HAVE_AES_DECRYPT) || defined(HAVE_AESGCM_DECRYPT)
+/* Performs AES-GCM decryption and returns 0 on success
+ *
+ * Warning: If using Xilinx hardware acceleration it is assumed that the in
+ * buffer is large enough to hold both cipher text and tag. That is
+ * sz | 16 bytes
+ */
+int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
+ const byte* iv, word32 ivSz,
+ const byte* authTag, word32 authTagSz,
+ const byte* authIn, word32 authInSz)
+{
+ struct cmsghdr* cmsg;
+ struct msghdr* msg;
+ struct iovec iov[3];
+ byte scratch[AES_BLOCK_SIZE];
+ int ret;
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ byte* tag = (byte*)authTag;
+ byte buf[AES_BLOCK_SIZE];
+ byte initalCounter[AES_BLOCK_SIZE];
+#ifndef NO_WOLFSSL_ALLOC_ALIGN
+ byte* tmp = NULL;
+#endif
+#endif
+
+ /* argument checks */
+ if (aes == NULL || authTagSz > AES_BLOCK_SIZE) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (ivSz != WC_SYSTEM_AESGCM_IV || authTagSz > WOLFSSL_MAX_AUTH_TAG_SZ) {
+ WOLFSSL_MSG("IV/AAD size not supported on system");
+ return BAD_FUNC_ARG;
+ }
+
+ if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) {
+ WOLFSSL_MSG("GcmEncrypt authTagSz too small error");
+ return BAD_FUNC_ARG;
+ }
+
+ if (aes->rdFd == WC_SOCK_NOTSET) {
+ aes->dir = AES_DECRYPTION;
+ if ((ret = wc_AesSetup(aes, WC_TYPE_AEAD, WC_NAME_AESGCM, ivSz,
+ authInSz)) != 0) {
+ WOLFSSL_MSG("Error with first time setup of AF_ALG socket");
+ return ret;
+ }
+
+#ifndef WOLFSSL_AFALG_XILINX_AES
+ /* set auth tag
+ * @TODO case where tag size changes between calls? */
+ ret = setsockopt(aes->alFd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL,
+ authTagSz);
+ if (ret != 0) {
+ WOLFSSL_MSG("Unable to set AF_ALG tag size ");
+ return WC_AFALG_SOCK_E;
+ }
+#endif
+ }
+
+ /* set IV and AAD size */
+ msg = &aes->msg;
+ if ((cmsg = CMSG_FIRSTHDR(msg)) == NULL) {
+ return WC_AFALG_SOCK_E;
+ }
+ if (wc_Afalg_SetOp(cmsg, aes->dir) < 0) {
+ WOLFSSL_MSG("Error with setting AF_ALG operation");
+ return WC_AFALG_SOCK_E;
+ }
+ if ((cmsg = CMSG_NXTHDR(msg, cmsg)) == NULL) {
+ return WC_AFALG_SOCK_E;
+ }
+ ret = wc_Afalg_SetIv(cmsg, (byte*)iv, ivSz);
+ if (ret < 0) {
+ return ret;
+ }
+
+#ifdef WOLFSSL_AFALG_XILINX_AES
+ /* check for and handle additional data */
+ if (authIn != NULL && authInSz > 0) {
+
+ XMEMSET(initalCounter, 0, AES_BLOCK_SIZE);
+ XMEMCPY(initalCounter, iv, ivSz);
+ initalCounter[AES_BLOCK_SIZE - 1] = 1;
+ tag = buf;
+ GHASH(aes, NULL, 0, in, sz, tag, AES_BLOCK_SIZE);
+ wc_AesEncryptDirect(aes, scratch, initalCounter);
+ xorbuf(tag, scratch, AES_BLOCK_SIZE);
+ if (ret != 0) {
+ return AES_GCM_AUTH_E;
+ }
+ }
+
+ /* it is assumed that in buffer size is large enough to hold TAG */
+ XMEMCPY((byte*)in + sz, tag, AES_BLOCK_SIZE);
+ if ((wolfssl_word)in % WOLFSSL_XILINX_ALIGN) {
+ #ifndef NO_WOLFSSL_ALLOC_ALIGN
+ byte* tmp_align;
+ tmp = (byte*)XMALLOC(sz + WOLFSSL_XILINX_ALIGN +
+ AES_BLOCK_SIZE, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (tmp == NULL) {
+ return MEMORY_E;
+ }
+ tmp_align = tmp + (WOLFSSL_XILINX_ALIGN -
+ ((size_t)tmp % WOLFSSL_XILINX_ALIGN));
+ XMEMCPY(tmp_align, in, sz + AES_BLOCK_SIZE);
+ iov[0].iov_base = tmp_align;
+ #else
+ WOLFSSL_MSG("Buffer expected to be word aligned");
+ return BAD_ALIGN_E;
+ #endif
+ }
+ else {
+ iov[0].iov_base = (byte*)in;
+ }
+ iov[0].iov_len = sz + AES_BLOCK_SIZE;
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = 1;
+
+ ret = sendmsg(aes->rdFd, msg, 0);
+#ifndef NO_WOLFSSL_ALLOC_ALIGN
+ XFREE(tmp, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = read(aes->rdFd, out, sz + AES_BLOCK_SIZE);
+ if (ret < 0) {
+ return AES_GCM_AUTH_E;
+ }
+
+ /* check on tag */
+ if (authIn != NULL && authInSz > 0) {
+ GHASH(aes, authIn, authInSz, in, sz, tag, AES_BLOCK_SIZE);
+ wc_AesEncryptDirect(aes, scratch, initalCounter);
+ xorbuf(tag, scratch, AES_BLOCK_SIZE);
+ if (ConstantCompare(tag, authTag, authTagSz) != 0) {
+ return AES_GCM_AUTH_E;
+ }
+ }
+
+#else
+ if (authInSz > 0) {
+ cmsg = CMSG_NXTHDR(msg, cmsg);
+ ret = wc_Afalg_SetAad(cmsg, authInSz);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /* set data to be decrypted*/
+ iov[0].iov_base = (byte*)authIn;
+ iov[0].iov_len = authInSz;
+ iov[1].iov_base = (byte*)in;
+ iov[1].iov_len = sz;
+ iov[2].iov_base = (byte*)authTag;
+ iov[2].iov_len = authTagSz;
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = 3; /* # of iov structures */
+ ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ {
+ byte* tmp = (byte*)XMALLOC(authInSz, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (tmp == NULL) {
+ return MEMORY_E;
+ }
+ iov[0].iov_base = tmp;
+ iov[0].iov_len = authInSz;
+ iov[1].iov_base = out;
+ iov[1].iov_len = sz;
+ ret = (int)readv(aes->rdFd, iov, 2);
+ XFREE(tmp, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ if (ret < 0) {
+ return AES_GCM_AUTH_E;
+ }
+ (void)scratch;
+#endif
+
+ return 0;
+}
+#endif /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */
+#endif /* HAVE_AESGCM */
+
+
+#ifdef HAVE_AES_ECB
+int wc_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+ return wc_Afalg_AesDirect(aes, out, in, sz);
+}
+
+
+int wc_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
+{
+ return wc_Afalg_AesDirect(aes, out, in, sz);
+}
+#endif /* HAVE_AES_ECB */
+#endif /* !NO_AES && WOLFSSL_AFALG */
+
diff --git a/wolfcrypt/src/port/af_alg/afalg_hash.c b/wolfcrypt/src/port/af_alg/afalg_hash.c
new file mode 100644
index 0000000..41e57bc
--- /dev/null
+++ b/wolfcrypt/src/port/af_alg/afalg_hash.c
@@ -0,0 +1,339 @@
+/* afalg_hash.c
+ *
+ * Copyright (C) 2006-2020 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 <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(WOLFSSL_AFALG_HASH) || (defined(WOLFSSL_AFALG_XILINX_SHA3) \
+ && defined(WOLFSSL_SHA3))
+
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#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";
+
+
+/* generic AF_ALG hash free */
+static void AfalgHashFree(wolfssl_AFALG_Hash* hash)
+{
+ if (hash == NULL)
+ return;
+
+ if (hash->alFd > 0) {
+ close(hash->alFd);
+ hash->alFd = -1; /* avoid possible double close on socket */
+ }
+ if (hash->rdFd > 0) {
+ close(hash->rdFd);
+ hash->rdFd = -1; /* avoid possible double close on socket */
+ }
+
+ #if defined(WOLFSSL_AFALG_HASH_KEEP)
+ if (hash->msg != NULL) {
+ XFREE(hash->msg, hash->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ hash->msg = NULL;
+ }
+ #endif
+}
+
+
+/* generic hash init for AF_ALG, returns 0 on success */
+static int AfalgHashInit(wolfssl_AFALG_Hash* hash, void* heap, int devId,
+ const char* type)
+{
+ if (hash == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ (void)devId; /* no async for now */
+ XMEMSET(hash, 0, sizeof(wolfssl_AFALG_Hash));
+ hash->heap = heap;
+
+ hash->len = 0;
+ hash->used = 0;
+ hash->msg = NULL;
+ hash->alFd = -1;
+ hash->rdFd = -1;
+
+ 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) {
+ close(hash->alFd);
+ return WC_AFALG_SOCK_E;
+ }
+
+ return 0;
+
+}
+
+
+/* generic hash update for AF_ALG, returns 0 on success */
+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
+ /* keep full message to hash at end instead of incremental updates */
+ 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;
+ }
+ 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;
+}
+
+
+/* generic hash final for AF_ALG, return 0 on success */
+static int AfalgHashFinal(wolfssl_AFALG_Hash* hash, byte* out, word32 outSz,
+ const char* type)
+{
+ int ret;
+ void* heap;
+
+ if (hash == NULL || out == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ heap = hash->heap; /* keep because AfalgHashInit clears the pointer */
+#ifdef WOLFSSL_AFALG_HASH_KEEP
+ /* keep full message to out at end instead of incremental updates */
+ if ((ret = (int)send(hash->rdFd, hash->msg, hash->used, 0)) < 0) {
+ return ret;
+ }
+ XFREE(hash->msg, heap, DYNAMIC_TYPE_TMP_BUFFER);
+ hash->msg = NULL;
+#else
+ if ((ret = (int)send(hash->rdFd, NULL, 0, 0)) < 0) {
+ return ret;
+ }
+#endif
+
+ if ((ret = (int)read(hash->rdFd, out, outSz)) != (int)outSz) {
+ return ret;
+ }
+
+ AfalgHashFree(hash);
+ return AfalgHashInit(hash, heap, 0, type);
+}
+
+
+/* generic function to get intermediate hash */
+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 ret;
+ }
+ 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
+}
+
+
+/* generic struct copy for AF_ALG, returns 0 on success */
+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
+ 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);
+#endif
+
+ dst->rdFd = accept(src->rdFd, NULL, 0);
+ dst->alFd = accept(src->alFd, NULL, 0);
+
+ if (dst->rdFd == -1 || dst->alFd == -1) {
+ AfalgHashFree(dst);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#if !defined(NO_SHA256) && defined(WOLFSSL_AFALG_HASH)
+#include <wolfssl/wolfcrypt/sha256.h>
+
+static const char WC_NAME_SHA256[] = "sha256";
+
+
+/* create AF_ALG sockets for SHA256 operation */
+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 /* !NO_SHA256 */
+
+
+
+#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);
+}
+
+
+/* create AF_ALG sockets for SHA256 operation */
+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 /* WOLFSSL_SHA3 && WOLFSSL_AFALG_XILINX_SHA3 */
+
+#endif /* WOLFSSL_AFALG */
diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c
new file mode 100644
index 0000000..0a91b51
--- /dev/null
+++ b/wolfcrypt/src/port/af_alg/wc_afalg.c
@@ -0,0 +1,141 @@
+/* wc_afalg.c
+ *
+ * Copyright (C) 2006-2020 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 <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+#if defined(WOLFSSL_AFALG) || defined(WOLFSSL_AFALG_XILINX)
+
+#include <wolfssl/wolfcrypt/port/af_alg/wc_afalg.h>
+#include <linux/if_alg.h>
+
+
+/* Sets the type of socket address to use */
+void wc_Afalg_SockAddr(struct sockaddr_alg* in, const char* type, const char* name)
+{
+ in->salg_family = AF_ALG;
+ XSTRNCPY((char*)in->salg_type, type, XSTRLEN(type));
+ in->salg_type[XSTRLEN(type)] = '\0';
+ XSTRNCPY((char*)in->salg_name, name, XSTRLEN(name));
+ in->salg_name[XSTRLEN(name)] = '\0';
+}
+
+
+/* returns the socket accepting on with success
+ * negative values are returned in fail cases */
+int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock)
+{
+ if (bind(sock, (const struct sockaddr*)in, inSz) < 0) {
+ WOLFSSL_MSG("Failed to bind with AF_ALG");
+ return WC_AFALG_SOCK_E;
+ }
+
+ return accept(sock, NULL, 0);
+}
+
+
+/* creates a new AF_ALG socket and returns it
+ * negative values are returned in fail cases */
+int wc_Afalg_Socket(void)
+{
+ int sock;
+
+ if ((sock = socket(AF_ALG, SOCK_SEQPACKET, 0)) < 0) {
+ WOLFSSL_MSG("Failed to get AF_ALG socket");
+ return WC_AFALG_SOCK_E;
+ }
+
+ return sock;
+}
+
+
+/* binds and creates the read fd */
+int wc_Afalg_CreateRead(int sock, const char* type, const char* name)
+{
+ struct sockaddr_alg sa = {0};
+ wc_Afalg_SockAddr(&sa, type, name);
+ return wc_Afalg_Accept(&sa, sizeof(sa), sock);
+}
+
+
+/* sets the IV in CMSG structure, returns 0 on success */
+int wc_Afalg_SetIv(struct cmsghdr* cmsg, byte* iv, word32 ivSz)
+{
+ struct af_alg_iv* afIv;
+
+ if (cmsg == NULL || iv == NULL) {
+ WOLFSSL_MSG("Null cmsg or iv passed in");
+ return BAD_FUNC_ARG;
+ }
+
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) + ivSz);
+ afIv = (void*)CMSG_DATA(cmsg);
+ afIv->ivlen = ivSz;
+ XMEMCPY(afIv->iv, iv, ivSz);
+
+ return 0;
+}
+
+
+/* sets the AAD size in CMSG structure, returns 0 on success */
+int wc_Afalg_SetAad(struct cmsghdr* cmsg, word32 sz)
+{
+ if (cmsg == NULL) {
+ WOLFSSL_MSG("Null cmsg passed in");
+ return BAD_FUNC_ARG;
+ }
+
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(word32));
+ *((word32*)CMSG_DATA(cmsg)) = sz;
+
+ return 0;
+}
+
+
+/* sets the operation type in CMSG structure, returns 0 on success
+ *
+ * dir 0 is encryption 1 is decryption
+ */
+int wc_Afalg_SetOp(struct cmsghdr* cmsg, int dir)
+{
+ if (cmsg == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ cmsg->cmsg_len = CMSG_LEN(4);
+ *((word32*)CMSG_DATA(cmsg)) = (dir == 1)? ALG_OP_DECRYPT : ALG_OP_ENCRYPT;
+
+ return 0;
+}
+
+#endif /* !NO_AES && WOLFSSL_AFALG */
+