From cb756397b35b9e2de082e7ba1e245087fdd32ee2 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Wed, 18 Jul 2018 17:26:25 -0600 Subject: [PATCH] inital AES-CBC with af_alg progress on AES-GCM with AF_ALG and add SHA256 add aes-gcm test cases and finish logic of aes-gcm with AF_ALG formating of tabs and white space add files to dist adding ecb and ctr mode with af_alg make length of buffers for ctr be AES_BLOCK_SIZE formating and add support for sha256 copy/gethash sanity checks on arguments cast return values and valgrind tests make it easier to use sha256 with af_alg remove hard tabs add endif for after rebase --- configure.ac | 29 +- src/include.am | 11 + tests/api.c | 4 +- wolfcrypt/benchmark/benchmark.c | 27 +- wolfcrypt/src/aes.c | 38 ++ wolfcrypt/src/error.c | 3 + wolfcrypt/src/hash.c | 1 + wolfcrypt/src/hmac.c | 37 ++ wolfcrypt/src/include.am | 4 +- wolfcrypt/src/port/af_alg/afalg_aes.c | 691 +++++++++++++++++++++ wolfcrypt/src/port/af_alg/afalg_hash.c | 193 ++++++ wolfcrypt/src/port/af_alg/wc_afalg.c | 141 +++++ wolfcrypt/src/sha256.c | 32 +- wolfcrypt/src/wc_port.c | 4 + wolfcrypt/test/test.c | 182 +++++- wolfssl/wolfcrypt/aes.h | 11 + wolfssl/wolfcrypt/error-crypt.h | 4 +- wolfssl/wolfcrypt/include.am | 4 +- wolfssl/wolfcrypt/port/af_alg/afalg_hash.h | 47 ++ wolfssl/wolfcrypt/port/af_alg/wc_afalg.h | 44 ++ wolfssl/wolfcrypt/sha256.h | 2 + 21 files changed, 1496 insertions(+), 13 deletions(-) create mode 100644 wolfcrypt/src/port/af_alg/afalg_aes.c create mode 100644 wolfcrypt/src/port/af_alg/afalg_hash.c create mode 100644 wolfcrypt/src/port/af_alg/wc_afalg.c create mode 100644 wolfssl/wolfcrypt/port/af_alg/afalg_hash.h create mode 100644 wolfssl/wolfcrypt/port/af_alg/wc_afalg.h diff --git a/configure.ac b/configure.ac index 7c6384b42..a1b43e73f 100644 --- a/configure.ac +++ b/configure.ac @@ -977,6 +977,22 @@ fi AM_CONDITIONAL([BUILD_AESNI], [test "x$ENABLED_AESNI" = "xyes"]) +# Linux af_alg +AC_ARG_ENABLE([afalg], + [AS_HELP_STRING([--enable-afalg],[Enable Linux af_alg use for crypto (default: disabled)])], + [ ENABLED_AFALG=$enableval ], + [ ENABLED_AFALG=no ] + ) + +if test "$ENABLED_AFALG" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AFALG" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AFALG_HASH" +fi + +AM_CONDITIONAL([BUILD_AFALG], [test "x$ENABLED_AFALG" = "xyes"]) + + # Camellia AC_ARG_ENABLE([camellia], [AS_HELP_STRING([--enable-camellia],[Enable wolfSSL Camellia support (default: disabled)])], @@ -2114,7 +2130,7 @@ AM_CONDITIONAL([BUILD_SELFTEST], [test "x$ENABLED_SELFTEST" = "xyes"]) SHA224_DEFAULT=no if test "$host_cpu" = "x86_64" || test "$host_cpu" = "aarch64" then - if test "x$ENABLED_FIPS" = "xno" || test "x$FIPS_VERSION" = "xv2" + if test "x$ENABLED_AFALG" = "xno" && ( test "x$ENABLED_FIPS" = "xno" || test "x$FIPS_VERSION" = "xv2" ) then SHA224_DEFAULT=yes fi @@ -3276,6 +3292,12 @@ then then AC_MSG_ERROR([please disable ecc if disabling asn.]) fi + + if test "$ENABLED_AFALG" = "yes" + then + # for TLS connections the intermediate hash needs to store buffer + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AFALG_HASH_KEEP" + fi fi @@ -4211,6 +4233,10 @@ AS_IF([test "x$ENABLED_SCTP" = "xyes"], AS_IF([test "x$ENABLED_MCAST" = "xyes"], [AM_CFLAGS="-DWOLFSSL_MULTICAST $AM_CFLAGS"]) +# WOLFSSL_AFALG does not support SHA224 yet +AS_IF([(test "x$ENABLED_AFALG" = "xyes") && (test "x$ENABLED_SHA224" = "xyes")], + [AC_MSG_ERROR([--enable-sha224 with --enable-afalg not yet supported])]) + # SCTP and Multicast require DTLS AS_IF([(test "x$ENABLED_DTLS" = "xno") && \ (test "x$ENABLED_SCTP" = "xyes" || test "x$ENABLED_MCAST" = "xyes")], @@ -4564,6 +4590,7 @@ echo " * Write duplicate: $ENABLED_WRITEDUP" echo " * Intel Quick Assist: $ENABLED_INTEL_QA" echo " * Xilinx Hardware Acc.: $ENABLED_XILINX" echo " * Inline Code: $ENABLED_INLINE" +echo " * Linux AF_ALG: $ENABLED_AFALG" echo "" echo "---" diff --git a/src/include.am b/src/include.am index 6cef15cd1..65477c7c9 100644 --- a/src/include.am +++ b/src/include.am @@ -148,6 +148,10 @@ src_libwolfssl_la_SOURCES += wolfcrypt/src/sha256.c endif endif +if BUILD_AFALG +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/af_alg/afalg_hash.c +endif + if BUILD_WOLFEVENT src_libwolfssl_la_SOURCES += wolfcrypt/src/wolfevent.c endif @@ -193,6 +197,9 @@ src_libwolfssl_la_SOURCES += wolfcrypt/src/aes.c if BUILD_ARMASM src_libwolfssl_la_SOURCES += wolfcrypt/src/port/arm/armv8-aes.c endif +if BUILD_AFALG +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/af_alg/afalg_aes.c +endif endif endif @@ -375,6 +382,10 @@ if BUILD_IDEA src_libwolfssl_la_SOURCES += wolfcrypt/src/idea.c endif +if BUILD_AFALG +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/af_alg/wc_afalg.c +endif + if !BUILD_CRYPTONLY # ssl files src_libwolfssl_la_SOURCES += \ diff --git a/tests/api.c b/tests/api.c index acea3c1f4..a62bdee6c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -8697,7 +8697,9 @@ static int test_wc_AesGcmSetKey (void) static int test_wc_AesGcmEncryptDecrypt (void) { int ret = 0; -#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) + /* WOLFSSL_AFALG requires 12 byte IV */ +#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) && \ + !defined(WOLFSSL_AFALG) Aes aes; byte key32[] = diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 16d36440a..9d4008405 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1733,6 +1733,7 @@ static void bench_aesgcm_internal(int doAsync, const byte* key, word32 keySz, { int ret = 0, i, count = 0, times, pending = 0; Aes enc[BENCH_MAX_PENDING]; + Aes dec[BENCH_MAX_PENDING]; double start; DECLARE_VAR(bench_additional, byte, AES_AUTH_ADD_SZ, HEAP_HINT); @@ -1789,7 +1790,21 @@ exit_aes_gcm: bench_stats_sym_finish(encLabel, doAsync, count, bench_size, start, ret); #ifdef HAVE_AES_DECRYPT - /* GCM uses same routine in backend for both encrypt and decrypt */ + /* init keys */ + for (i = 0; i < BENCH_MAX_PENDING; i++) { + if ((ret = wc_AesInit(&dec[i], HEAP_HINT, + doAsync ? devId : INVALID_DEVID)) != 0) { + printf("AesInit failed, ret = %d\n", ret); + goto exit; + } + + ret = wc_AesGcmSetKey(&dec[i], key, keySz); + if (ret != 0) { + printf("AesGcmSetKey failed, ret = %d\n", ret); + goto exit; + } + } + bench_stats_start(&count, &start); do { for (times = 0; times < numBlocks || pending > 0; ) { @@ -1797,12 +1812,12 @@ exit_aes_gcm: /* while free pending slots in queue, submit ops */ for (i = 0; i < BENCH_MAX_PENDING; i++) { - if (bench_async_check(&ret, BENCH_ASYNC_GET_DEV(&enc[i]), 0, ×, numBlocks, &pending)) { - ret = wc_AesGcmDecrypt(&enc[i], bench_plain, + if (bench_async_check(&ret, BENCH_ASYNC_GET_DEV(&dec[i]), 0, ×, numBlocks, &pending)) { + ret = wc_AesGcmDecrypt(&dec[i], bench_plain, bench_cipher, BENCH_SIZE, iv, ivSz, bench_tag, AES_AUTH_TAG_SZ, bench_additional, aesAuthAddSz); - if (!bench_async_handle(&ret, BENCH_ASYNC_GET_DEV(&enc[i]), 0, ×, &pending)) { + if (!bench_async_handle(&ret, BENCH_ASYNC_GET_DEV(&dec[i]), 0, ×, &pending)) { goto exit_aes_gcm_dec; } } @@ -1812,6 +1827,10 @@ exit_aes_gcm: } while (bench_stats_sym_check(start)); exit_aes_gcm_dec: bench_stats_sym_finish(decLabel, doAsync, count, bench_size, start, ret); + + for (i = 0; i < BENCH_MAX_PENDING; i++) { + wc_AesFree(&dec[i]); + } #endif /* HAVE_AES_DECRYPT */ (void)decLabel; diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 02df4cf37..714e23a14 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -726,6 +726,9 @@ wc_AesEncryptDirect(aes, outBlock, inBlock); return 0; } + +#elif defined(WOLFSSL_AFALG) + #else /* using wolfCrypt software AES implementation */ @@ -1936,6 +1939,9 @@ static void wc_AesDecrypt(Aes* aes, const byte* inBlock, byte* outBlock) #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES) /* implemented in wolfcrypt/src/port/caam/caam_aes.c */ +#elif defined(WOLFSSL_AFALG) + /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */ + #else static int wc_AesSetKeyLocal(Aes* aes, const byte* userKey, word32 keylen, const byte* iv, int dir) @@ -2253,6 +2259,9 @@ int wc_AesSetIV(Aes* aes, const byte* iv) #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES) /* implemented in wolfcrypt/src/port/caam/caam_aes.c */ + #elif defined(WOLFSSL_AFALG) + /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */ + #else /* Allow direct access to one block encrypt */ void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in) @@ -2775,6 +2784,9 @@ int wc_AesSetIV(Aes* aes, const byte* iv) #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES) /* implemented in wolfcrypt/src/port/caam/caam_aes.c */ +#elif defined(WOLFSSL_AFALG) + /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */ + #else int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) @@ -3096,6 +3108,9 @@ int wc_AesSetIV(Aes* aes, const byte* iv) #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES) /* implemented in wolfcrypt/src/port/caam/caam_aes.c */ + #elif defined(WOLFSSL_AFALG) + /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */ + #else /* Use software based AES counter */ @@ -3205,6 +3220,10 @@ static WC_INLINE void IncCtr(byte* ctr, word32 ctrSz) #ifdef WOLFSSL_ARMASM /* implementation is located in wolfcrypt/src/port/arm/armv8-aes.c */ + +#elif defined(WOLFSSL_AFALG) + /* implemented in wolfcrypt/src/port/afalg/afalg_aes.c */ + #else /* software + AESNI implementation */ #if !defined(FREESCALE_LTC_AES_GCM) @@ -8932,6 +8951,7 @@ int wc_Gmac(const byte* key, word32 keySz, byte* iv, word32 ivSz, if (ret == 0) ret = wc_AesGcmEncrypt_ex(&aes, NULL, NULL, 0, iv, ivSz, authTag, authTagSz, authIn, authInSz); + wc_AesFree(&aes); ForceZero(&aes, sizeof(aes)); return ret; @@ -8956,6 +8976,7 @@ int wc_GmacVerify(const byte* key, word32 keySz, if (ret == 0) ret = wc_AesGcmDecrypt(&aes, NULL, NULL, 0, iv, ivSz, authTag, authTagSz, authIn, authInSz); + wc_AesFree(&aes); ForceZero(&aes, sizeof(aes)); return ret; @@ -9390,6 +9411,11 @@ int wc_AesInit(Aes* aes, void* heap, int devId) (void)devId; #endif /* WOLFSSL_ASYNC_CRYPT */ +#ifdef WOLFSSL_AFALG + aes->alFd = -1; + aes->rdFd = -1; +#endif + return ret; } @@ -9402,6 +9428,14 @@ void wc_AesFree(Aes* aes) #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES) wolfAsync_DevCtxFree(&aes->asyncDev, WOLFSSL_ASYNC_MARKER_AES); #endif /* WOLFSSL_ASYNC_CRYPT */ +#ifdef WOLFSSL_AFALG + if (aes->rdFd > 0) { /* negative is error case */ + close(aes->rdFd); + } + if (aes->alFd > 0) { + close(aes->alFd); + } +#endif /* WOLFSSL_AFALG */ } @@ -9442,6 +9476,10 @@ int wc_AesGetKeySize(Aes* aes, word32* keySize) #ifdef HAVE_AES_ECB #if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_AES) /* implemented in wolfcrypt/src/port/caam/caam_aes.c */ + +#elif defined(WOLFSSL_AFALG) + /* implemented in wolfcrypt/src/port/af_alg/afalg_aes.c */ + #else /* software implementation */ diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 0a32d332d..04bb47287 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -482,6 +482,9 @@ const char* wc_GetErrorString(int error) case DH_CHECK_PRIV_E: return "DH Check Private Key failure"; + case WC_AFALG_SOCK_E: + return "AF_ALG socket error"; + default: return "unknown error number"; diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c index 78fdaa189..ced259fa9 100644 --- a/wolfcrypt/src/hash.c +++ b/wolfcrypt/src/hash.c @@ -840,6 +840,7 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) } wc_Sha256Free(sha256); } + wc_Sha256Free(sha256); #ifdef WOLFSSL_SMALL_STACK diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index af9d38fd4..c4e5e75e5 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -1070,6 +1070,43 @@ void wc_HmacFree(Hmac* hmac) #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC) wolfAsync_DevCtxFree(&hmac->asyncDev, WOLFSSL_ASYNC_MARKER_HMAC); #endif /* WOLFSSL_ASYNC_CRYPT */ + + switch (hmac->macType) { + #ifndef NO_MD5 + case WC_MD5: + wc_Md5Free(&hmac->hash.md5); + break; + #endif /* !NO_MD5 */ + + #ifndef NO_SHA + case WC_SHA: + wc_ShaFree(&hmac->hash.sha); + break; + #endif /* !NO_SHA */ + + #ifdef WOLFSSL_SHA224 + case WC_SHA224: + wc_Sha224Free(&hmac->hash.sha224); + break; + #endif /* WOLFSSL_SHA224 */ + + #ifndef NO_SHA256 + case WC_SHA256: + wc_Sha256Free(&hmac->hash.sha256); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA512 + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + wc_Sha384Free(&hmac->hash.sha384); + break; + #endif /* WOLFSSL_SHA384 */ + case WC_SHA512: + wc_Sha512Free(&hmac->hash.sha512); + break; + #endif /* WOLFSSL_SHA512 */ + } } int wolfSSL_GetHmacMaxSize(void) diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index c10257c36..b8d8c0c50 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -62,7 +62,9 @@ EXTRA_DIST += wolfcrypt/src/port/ti/ti-aes.c \ wolfcrypt/src/port/caam/caam_sha.c \ wolfcrypt/src/port/caam/caam_doc.pdf \ wolfcrypt/src/port/st/stm32.c \ - wolfcrypt/src/port/st/stsafe.c + wolfcrypt/src/port/st/stsafe.c \ + wolfcrypt/src/port/af_alg/afalg_aes.c \ + wolfcrypt/src/port/af_alg/afalg_hash.c if BUILD_CRYPTODEV src_libwolfssl_la_SOURCES += wolfcrypt/src/cryptodev.c 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 000000000..35a41ab31 --- /dev/null +++ b/wolfcrypt/src/port/af_alg/afalg_aes.c @@ -0,0 +1,691 @@ +/* afalg_aes.c + * + * Copyright (C) 2006-2018 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 +#include + +#if !defined(NO_AES) && defined(WOLFSSL_AFALG) + +#include +#include +#include + +#include /* for readv */ + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +static const char WC_TYPE_SYMKEY[] = "skcipher"; +static const char WC_NAME_AESCBC[] = "cbc(aes)"; + +static int wc_AesSetup(Aes* aes, const char* type, const char* name, int ivSz, int aadSz) +{ + 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, (byte*)aes->key, aes->keylen) != 0) { + WOLFSSL_MSG("Unable to set AF_ALG key"); + aes->rdFd = WC_SOCK_NOTSET; + return WC_AFALG_SOCK_E; + } + ForceZero((byte*)aes->key, sizeof(aes->key)); + + /* set up CMSG headers */ + XMEMSET((byte*)&(aes->msg), 0, sizeof(struct msghdr)); + + aes->msg.msg_control = (byte*)(aes->key); /* use existing key buffer for + * control buffer */ + 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)); + } + + 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; +} + + +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); +} + + +/* AES-CBC */ +#ifdef HAVE_AES_CBC + 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) + +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) +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) + 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 + +static const char WC_TYPE_AEAD[] = "aead"; +static const char WC_NAME_AESGCM[] = "gcm(aes)"; + +#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 + +int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) +{ +#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 */ + XMEMCPY((byte*)(aes->key), key, len); + + return 0; +} + + + +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[16]; + + /* 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 */ + + /* 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; + } + } + + 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; + + } + + 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; + + aes->msg.msg_iov = iov; + aes->msg.msg_iovlen = 2; /* # of iov structures */ + + ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0); + if (ret < 0) { + perror("sendmsg error"); + return ret; + } + + /* first 16 bytes was all 0's */ + iov[0].iov_base = 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); + if (ret < 0) { + perror("read error"); + return ret; + } + + return 0; +} + +#if defined(HAVE_AES_DECRYPT) || defined(HAVE_AESGCM_DECRYPT) +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 iovec iov[3]; + int ret; + struct msghdr* msg; + byte scratch[16]; + + /* 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; + } + + /* 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; + } + } + + + /* set IV and AAD size */ + msg = &(aes->msg); + cmsg = CMSG_FIRSTHDR(msg); + cmsg = CMSG_NXTHDR(msg, cmsg); + ret = wc_Afalg_SetIv(cmsg, (byte*)iv, ivSz); + if (ret < 0) { + return ret; + } + + 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; + + aes->msg.msg_iov = iov; + aes->msg.msg_iovlen = 3; /* # of iov structures */ + + ret = (int)sendmsg(aes->rdFd, &(aes->msg), 0); + if (ret < 0) { + return ret; + } + + iov[0].iov_base = scratch; + iov[0].iov_len = authInSz; + + iov[1].iov_base = out; + iov[1].iov_len = sz; + + ret = (int)readv(aes->rdFd, iov, 2); + if (ret < 0) { + return AES_GCM_AUTH_E; + } + + 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 000000000..c007e97dc --- /dev/null +++ b/wolfcrypt/src/port/af_alg/afalg_hash.c @@ -0,0 +1,193 @@ +/* afalg_hash.c + * + * Copyright (C) 2006-2018 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 + +#if defined(WOLFSSL_AFALG_HASH) + +#include +#include +#include + +static const char WC_TYPE_HASH[] = "hash"; + +#if !defined(NO_SHA256) +#include + +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) +{ + if (sha == NULL) { + return BAD_FUNC_ARG; + } + + (void)devId; /* no async for now */ + XMEMSET(sha, 0, sizeof(wc_Sha256)); + sha->heap = heap; + + sha->len = 0; + sha->used = 0; + sha->msg = NULL; + sha->alFd = -1; + sha->rdFd = -1; + + sha->alFd = wc_Afalg_Socket(); + if (sha->alFd < 0) { + return WC_AFALG_SOCK_E; + } + + sha->rdFd = wc_Afalg_CreateRead(sha->alFd, WC_TYPE_HASH, WC_NAME_SHA256); + if (sha->rdFd < 0) { + return WC_AFALG_SOCK_E; + } + + return 0; +} + + +int wc_Sha256Update(wc_Sha256* sha, const byte* in, word32 sz) +{ + if (sha == 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 (sha->len < sha->used + sz) { + if (sha->msg == NULL) { + sha->msg = (byte*)XMALLOC(sha->used + sz, sha->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } else { + byte* pt = (byte*)XREALLOC(sha->msg, sha->used + sz, sha->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (pt == NULL) { + return MEMORY_E; + } + sha->msg = pt; + } + if (sha->msg == NULL) { + return MEMORY_E; + } + sha->len = sha->used + sz; + } + XMEMCPY(sha->msg + sha->used, in, sz); + sha->used += sz; +#else + int ret; + + if ((ret = (int)send(sha->rdFd, in, sz, MSG_MORE)) < 0) { + return ret; + } +#endif + return 0; +} + + +int wc_Sha256Final(wc_Sha256* sha, byte* hash) +{ + int ret; + + if (sha == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_AFALG_HASH_KEEP + /* keep full message to hash at end instead of incremental updates */ + if ((ret = (int)send(sha->rdFd, sha->msg, sha->used, 0)) < 0) { + return ret; + } + XFREE(sha->msg, sha->heap, DYNAMIC_TYPE_TMP_BUFFER); + sha->msg = NULL; +#else + if ((ret = (int)send(sha->rdFd, NULL, 0, 0)) < 0) { + return ret; + } +#endif + + if ((ret = (int)read(sha->rdFd, hash, WC_SHA256_DIGEST_SIZE)) != + WC_SHA256_DIGEST_SIZE) { + return ret; + } + + wc_Sha256Free(sha); + return wc_InitSha256_ex(sha, sha->heap, 0); +} + + +int wc_Sha256GetHash(wc_Sha256* sha, byte* hash) +{ + int ret; + + if (sha == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + (void)ret; +#ifdef WOLFSSL_AFALG_HASH_KEEP + if ((ret = (int)send(sha->rdFd, sha->msg, sha->used, 0)) < 0) { + return ret; + } + + if ((ret = (int)read(sha->rdFd, hash, WC_SHA256_DIGEST_SIZE)) != + WC_SHA256_DIGEST_SIZE) { + return ret; + } + return 0; +#else + (void)sha; + (void)hash; + + WOLFSSL_MSG("Compile with WOLFSSL_AFALG_HASH_KEEP for this feature"); + return NOT_COMPILED_IN; +#endif +} + +int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + + XMEMCPY(dst, src, sizeof(wc_Sha256)); + dst->rdFd = accept(src->rdFd, NULL, 0); + dst->alFd = accept(src->alFd, NULL, 0); + + if (dst->rdFd == -1 || dst->alFd == -1) { + return -1; + } + + return 0; +} + +#endif /* !NO_SHA256 */ + + + + +#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 000000000..1078e05c1 --- /dev/null +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -0,0 +1,141 @@ +/* wc_afalg.c + * + * Copyright (C) 2006-2017 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 +#include +#include + +#if !defined(NO_AES) && defined(WOLFSSL_AFALG) + +#include +#include + + +/* 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 = {}; + 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 */ + diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 98c397a64..78fe6b7d7 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -135,7 +135,8 @@ #if !defined(WOLFSSL_PIC32MZ_HASH) && !defined(STM32_HASH_SHA2) && \ - (!defined(WOLFSSL_IMX6_CAAM) || defined(NO_IMX6_CAAM_HASH)) + (!defined(WOLFSSL_IMX6_CAAM) || defined(NO_IMX6_CAAM_HASH)) && \ + !defined(WOLFSSL_AFALG_HASH) static int InitSha256(wc_Sha256* sha256) { int ret = 0; @@ -439,6 +440,10 @@ static int InitSha256(wc_Sha256* sha256) #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH) /* functions defined in wolfcrypt/src/port/caam/caam_sha256.c */ + +#elif defined(WOLFSSL_AFALG_HASH) + /* implemented in wolfcrypt/src/port/af_alg/afalg_hash.c */ + #else #define NEED_SOFT_SHA256 @@ -2572,6 +2577,10 @@ SHA256_NOINLINE static int Transform_Sha256_AVX2_RORX_Len(wc_Sha256* sha256, #elif defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH) /* functions defined in wolfcrypt/src/port/caam/caam_sha256.c */ + +//#elif defined(WOLFSSL_AFALG_HASH) +// /* implemented in wolfcrypt/src/port/af_alg/afalg_hash.c */ + #else #define NEED_SOFT_SHA224 @@ -2735,10 +2744,24 @@ void wc_Sha256Free(wc_Sha256* sha256) #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_SHA256) wolfAsync_DevCtxFree(&sha256->asyncDev, WOLFSSL_ASYNC_MARKER_SHA256); #endif /* WOLFSSL_ASYNC_CRYPT */ - #ifdef WOLFSSL_PIC32MZ_HASH wc_Sha256Pic32Free(sha256); #endif +#if defined(WOLFSSL_AFALG_HASH) + if (sha256->alFd > 0) { + close(sha256->alFd); + } + if (sha256->rdFd > 0) { + close(sha256->rdFd); + } + + #if defined(WOLFSSL_AFALG_HASH_KEEP) + if (sha256->msg != NULL) { + XFREE(sha256->msg, sha256->heap, DYNAMIC_TYPE_TMP_BUFFER); + sha256->msg = NULL; + } + #endif +#endif /* WOLFSSL_AFALG_HASH */ } #endif /* !WOLFSSL_TI_HASH */ @@ -2782,6 +2805,10 @@ void wc_Sha256Free(wc_Sha256* sha256) } #endif /* WOLFSSL_SHA224 */ +#ifdef WOLFSSL_AFALG_HASH + /* implemented in wolfcrypt/src/port/af_alg/afalg_hash.c */ +#else + int wc_Sha256GetHash(wc_Sha256* sha256, byte* hash) { int ret; @@ -2818,6 +2845,7 @@ int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) return ret; } +#endif #endif /* !WOLFSSL_TI_HASH */ #endif /* NO_SHA256 */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index a9290dcd7..53876df75 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -164,6 +164,10 @@ int wolfCrypt_Init(void) WOLFSSL_MSG("Using ARM hardware acceleration"); #endif + #ifdef WOLFSSL_AFALG + WOLFSSL_MSG("Using AF_ALG for crypto acceleration"); + #endif + #if !defined(WOLFCRYPT_ONLY) && \ ( defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) ) wolfSSL_EVP_init(); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 941bec873..ffb68ddbc 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -270,6 +270,7 @@ int aes256_test(void); int cmac_test(void); int poly1305_test(void); int aesgcm_test(void); +int aesgcm_default_test(void); int gmac_test(void); int aesccm_test(void); int aeskeywrap_test(void); @@ -751,10 +752,19 @@ initDefaultName(); printf( "AES256 test passed!\n"); #endif #ifdef HAVE_AESGCM + #ifndef WOLFSSL_AFALG if ( (ret = aesgcm_test()) != 0) return err_sys("AES-GCM test failed!\n", ret); else - printf( "AES-GCM test passed!\n"); + #endif + { + if ((ret = aesgcm_default_test()) != 0) { + return err_sys("AES-GCM test failed!\n", ret); + } + else { + printf( "AES-GCM test passed!\n"); + } + } #endif #if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128) @@ -2045,8 +2055,9 @@ int sha256_test(void) for (i = 0; i < times; ++i) { ret = wc_Sha256Update(&sha, (byte*)test_sha[i].input, (word32)test_sha[i].inLen); - if (ret != 0) + if (ret != 0) { ERROR_OUT(-2202 - i, exit); + } ret = wc_Sha256GetHash(&sha, hashcopy); if (ret != 0) ERROR_OUT(-2203 - i, exit); @@ -6542,6 +6553,173 @@ int aes256_test(void) #ifdef HAVE_AESGCM + +static int aesgcm_default_test_helper(byte* key, int keySz, byte* iv, int ivSz, + byte* plain, int plainSz, byte* cipher, int cipherSz, + byte* aad, int aadSz, byte* tag, int tagSz) +{ +Aes enc; +Aes dec; + + byte resultT[AES_BLOCK_SIZE]; + byte resultP[AES_BLOCK_SIZE * 3]; + byte resultC[AES_BLOCK_SIZE * 3]; + int result; + + XMEMSET(resultT, 0, sizeof(resultT)); + XMEMSET(resultC, 0, sizeof(resultC)); + XMEMSET(resultP, 0, sizeof(resultP)); + + if (wc_AesInit(&enc, HEAP_HINT, devId) != 0) { + return -5700; + } + + result = wc_AesGcmSetKey(&enc, key, keySz); + if (result != 0) + return -4701; + + /* AES-GCM encrypt and decrypt both use AES encrypt internally */ + result = wc_AesGcmEncrypt(&enc, resultC, plain, plainSz, iv, ivSz, + resultT, tagSz, aad, aadSz); + +#if defined(WOLFSSL_ASYNC_CRYPT) + result = wc_AsyncWait(result, &enc.asyncDev, WC_ASYNC_FLAG_NONE); +#endif + if (result != 0) + return -4702; + if (XMEMCMP(cipher, resultC, cipherSz)) + return -4703; + if (XMEMCMP(tag, resultT, tagSz)) + return -4704; + + wc_AesFree(&enc); + +#ifdef HAVE_AES_DECRYPT + result = wc_AesGcmSetKey(&dec, key, keySz); + if (result != 0) + return -4705; + + result = wc_AesGcmDecrypt(&dec, resultP, resultC, cipherSz, + iv, ivSz, resultT, tagSz, aad, aadSz); +#if defined(WOLFSSL_ASYNC_CRYPT) + result = wc_AsyncWait(result, &dec.asyncDev, WC_ASYNC_FLAG_NONE); +#endif + if (result != 0) + return -4706; + if (XMEMCMP(plain, resultP, plainSz)) + return -4707; + + wc_AesFree(&dec); +#endif /* HAVE_AES_DECRYPT */ + + return 0; +} + + +/* tests that only use 12 byte IV and 16 or less byte AAD + * test vectors are from NIST SP 800-38D + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES*/ +int aesgcm_default_test(void) +{ +byte key1[] = { +0x29, 0x8e, 0xfa, 0x1c, 0xcf, 0x29, 0xcf, 0x62, +0xae, 0x68, 0x24, 0xbf, 0xc1, 0x95, 0x57, 0xfc +}; + +byte iv1[] = { +0x6f, 0x58, 0xa9, 0x3f, 0xe1, 0xd2, 0x07, 0xfa, +0xe4, 0xed, 0x2f, 0x6d +}; + +byte plain1[] = { +0xcc, 0x38, 0xbc, 0xcd, 0x6b, 0xc5, 0x36, 0xad, +0x91, 0x9b, 0x13, 0x95, 0xf5, 0xd6, 0x38, 0x01, +0xf9, 0x9f, 0x80, 0x68, 0xd6, 0x5c, 0xa5, 0xac, +0x63, 0x87, 0x2d, 0xaf, 0x16, 0xb9, 0x39, 0x01 +}; + +byte aad1[] = { +0x02, 0x1f, 0xaf, 0xd2, 0x38, 0x46, 0x39, 0x73, +0xff, 0xe8, 0x02, 0x56, 0xe5, 0xb1, 0xc6, 0xb1 +}; + +byte cipher1[] = { +0xdf, 0xce, 0x4e, 0x9c, 0xd2, 0x91, 0x10, 0x3d, +0x7f, 0xe4, 0xe6, 0x33, 0x51, 0xd9, 0xe7, 0x9d, +0x3d, 0xfd, 0x39, 0x1e, 0x32, 0x67, 0x10, 0x46, +0x58, 0x21, 0x2d, 0xa9, 0x65, 0x21, 0xb7, 0xdb +}; + +byte tag1[] = { +0x54, 0x24, 0x65, 0xef, 0x59, 0x93, 0x16, 0xf7, +0x3a, 0x7a, 0x56, 0x05, 0x09, 0xa2, 0xd9, 0xf2 +}; + + +byte key2[] = { +0x01, 0x6d, 0xbb, 0x38, 0xda, 0xa7, 0x6d, 0xfe, +0x7d, 0xa3, 0x84, 0xeb, 0xf1, 0x24, 0x03, 0x64 +}; + +byte iv2[] = { +0x07, 0x93, 0xef, 0x3a, 0xda, 0x78, 0x2f, 0x78, +0xc9, 0x8a, 0xff, 0xe3 +}; + +byte plain2[] = { +0x4b, 0x34, 0xa9, 0xec, 0x57, 0x63, 0x52, 0x4b, +0x19, 0x1d, 0x56, 0x16, 0xc5, 0x47, 0xf6, 0xb7 +}; + +byte cipher2[] = { +0x60, 0x9a, 0xa3, 0xf4, 0x54, 0x1b, 0xc0, 0xfe, +0x99, 0x31, 0xda, 0xad, 0x2e, 0xe1, 0x5d, 0x0c +}; + +byte tag2[] = { +0x33, 0xaf, 0xec, 0x59, 0xc4, 0x5b, 0xaf, 0x68, +0x9a, 0x5e, 0x1b, 0x13, 0xae, 0x42, 0x36, 0x19 +}; + +byte key3[] = { +0xb0, 0x1e, 0x45, 0xcc, 0x30, 0x88, 0xaa, 0xba, +0x9f, 0xa4, 0x3d, 0x81, 0xd4, 0x81, 0x82, 0x3f +}; + +byte iv3[] = { +0x5a, 0x2c, 0x4a, 0x66, 0x46, 0x87, 0x13, 0x45, +0x6a, 0x4b, 0xd5, 0xe1 +}; + +byte tag3[] = { +0x01, 0x42, 0x80, 0xf9, 0x44, 0xf5, 0x3c, 0x68, +0x11, 0x64, 0xb2, 0xff +}; + +int ret; + ret = aesgcm_default_test_helper(key1, sizeof(key1), iv1, sizeof(iv1), + plain1, sizeof(plain1), cipher1, sizeof(cipher1), + aad1, sizeof(aad1), tag1, sizeof(tag1)); + if (ret != 0) { + return ret; + } + + ret = aesgcm_default_test_helper(key2, sizeof(key2), iv2, sizeof(iv2), + plain2, sizeof(plain2), cipher2, sizeof(cipher2), + NULL, 0, tag2, sizeof(tag2)); + if (ret != 0) { + return ret; + } + ret = aesgcm_default_test_helper(key3, sizeof(key3), iv3, sizeof(iv3), + NULL, 0, NULL, 0, + NULL, 0, tag3, sizeof(tag3)); + if (ret != 0) { + return ret; + } + + return 0; +} + int aesgcm_test(void) { Aes enc; diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h index 35b30d57b..6a423135a 100644 --- a/wolfssl/wolfcrypt/aes.h +++ b/wolfssl/wolfcrypt/aes.h @@ -68,6 +68,11 @@ #include "xsecure_aes.h" #endif +#ifdef WOLFSSL_AFALG +/* included for struct msghdr */ +#include +#endif + #if defined(HAVE_AESGCM) && !defined(WC_NO_RNG) #include #endif @@ -150,6 +155,12 @@ typedef struct Aes { XCsuDma dma; word32 key_init[8]; word32 kup; +#endif +#ifdef WOLFSSL_AFALG + int alFd; /* server socket to bind to */ + int rdFd; /* socket to read from */ + struct msghdr msg; + int dir; /* flag for encrpyt or decrypt */ #endif void* heap; /* memory hint to use */ } Aes; diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 87a5d0201..2a1963bfd 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -213,7 +213,9 @@ enum { RSA_KEY_PAIR_E = -262, /* RSA Key Pair-Wise Consistency check fail. */ DH_CHECK_PRIV_E = -263, /* DH Check Priv Key error */ - WC_LAST_E = -263, /* Update this to indicate last error */ + WC_AFALG_SOCK_E = -264, /* AF_ALG socket error */ + + WC_LAST_E = -264, /* Update this to indicate last error */ MIN_CODE_E = -300 /* errors -101 - -299 */ /* add new companion error id strings for any new error codes diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index f8210801f..d335b5c0b 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -77,7 +77,9 @@ noinst_HEADERS+= \ wolfssl/wolfcrypt/port/caam/wolfcaam.h \ wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h \ wolfssl/wolfcrypt/port/st/stm32.h \ - wolfssl/wolfcrypt/port/st/stsafe.h + wolfssl/wolfcrypt/port/st/stsafe.h \ + wolfssl/wolfcrypt/port/af_alg/afalg_hash.h \ + wolfssl/wolfcrypt/port/af_alg/wc_afalg.h if BUILD_ASYNCCRYPT nobase_include_HEADERS+= wolfssl/wolfcrypt/async.h diff --git a/wolfssl/wolfcrypt/port/af_alg/afalg_hash.h b/wolfssl/wolfcrypt/port/af_alg/afalg_hash.h new file mode 100644 index 000000000..4a87169b0 --- /dev/null +++ b/wolfssl/wolfcrypt/port/af_alg/afalg_hash.h @@ -0,0 +1,47 @@ +/* afalg_hash.h + * + * Copyright (C) 2006-2018 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 + */ + + +#ifndef WOLF_CRYPT_AFALG_HASH_H +#define WOLF_CRYPT_AFALG_HASH_H + +#include + +#undef WOLFSSL_NO_HASH_RAW +#define WOLFSSL_NO_HASH_RAW + +typedef struct { + byte* msg; + void* heap; + word32 used; + word32 len; + int alFd; + int rdFd; +} wolfssl_AFALG_Hash; + + + +#if !defined(NO_SHA256) + typedef wolfssl_AFALG_Hash wc_Sha256; +#endif + +#endif /* WOLF_CRYPT_AFALG_HASH_H */ + diff --git a/wolfssl/wolfcrypt/port/af_alg/wc_afalg.h b/wolfssl/wolfcrypt/port/af_alg/wc_afalg.h new file mode 100644 index 000000000..1b9eac7c2 --- /dev/null +++ b/wolfssl/wolfcrypt/port/af_alg/wc_afalg.h @@ -0,0 +1,44 @@ +/* wc_afalg.h + * + * Copyright (C) 2006-2017 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 + */ + + +#ifndef WOLFSSL_AFALG_H +#define WOLFSSL_AFALG_H + +#include + +#include +#include +#include + +#define WC_SOCK_NOTSET -1 + + +WOLFSSL_LOCAL void wc_Afalg_SockAddr(struct sockaddr_alg* in, const char* type, const char* name); +WOLFSSL_LOCAL int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock); +WOLFSSL_LOCAL int wc_Afalg_Socket(void); +WOLFSSL_LOCAL int wc_Afalg_CreateRead(int sock, const char* type, const char* name); +WOLFSSL_LOCAL int wc_Afalg_SetIv(struct cmsghdr* cmsg, byte* iv, word32 ivSz); +WOLFSSL_LOCAL int wc_Afalg_SetOp(struct cmsghdr* cmsg, int dir); +WOLFSSL_LOCAL int wc_Afalg_SetAad(struct cmsghdr* cmsg, word32 sz); + +#endif /* WOLFSSL_AFALG_H */ + diff --git a/wolfssl/wolfcrypt/sha256.h b/wolfssl/wolfcrypt/sha256.h index 59f2d4587..6d535a8be 100644 --- a/wolfssl/wolfcrypt/sha256.h +++ b/wolfssl/wolfcrypt/sha256.h @@ -113,6 +113,8 @@ enum { #include "wolfssl/wolfcrypt/port/ti/ti-hash.h" #elif defined(WOLFSSL_IMX6_CAAM) #include "wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h" +#elif defined(WOLFSSL_AFALG_HASH) + #include "wolfssl/wolfcrypt/port/af_alg/afalg_hash.h" #else /* wc_Sha256 digest */ typedef struct wc_Sha256 {