From 205da484163e6957d4cec5a9da1a9f2ceefa66ab Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 7 Jul 2017 15:12:51 -0700 Subject: [PATCH] Fixes for building ARMv8. Adds missing SHA224 and AES KeyWrap. Fixes for FE/GE warning with Aarch32. Fix possible build error with `ed25519_test` with `ret` not defined. --- wolfcrypt/src/port/arm/armv8-aes.c | 171 ++++++++++++++++++++ wolfcrypt/src/port/arm/armv8-sha256.c | 221 ++++++++++++++++++++++---- wolfcrypt/test/test.c | 3 +- wolfssl/wolfcrypt/fe_operations.h | 2 +- 4 files changed, 360 insertions(+), 37 deletions(-) diff --git a/wolfcrypt/src/port/arm/armv8-aes.c b/wolfcrypt/src/port/arm/armv8-aes.c index 0dc43e4e4..fff935ea6 100644 --- a/wolfcrypt/src/port/arm/armv8-aes.c +++ b/wolfcrypt/src/port/arm/armv8-aes.c @@ -4645,6 +4645,177 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) #endif /* HAVE_AES_DECRYPT */ #endif /* WOLFSSL_AES_DIRECT */ +#ifdef HAVE_AES_KEYWRAP + +/* Initialize key wrap counter with value */ +static INLINE void InitKeyWrapCounter(byte* inOutCtr, word32 value) +{ + int i; + word32 bytes; + + bytes = sizeof(word32); + for (i = 0; i < (int)sizeof(word32); i++) { + inOutCtr[i+sizeof(word32)] = (value >> ((bytes - 1) * 8)) & 0xFF; + bytes--; + } +} + +/* Increment key wrap counter */ +static INLINE void IncrementKeyWrapCounter(byte* inOutCtr) +{ + int i; + + /* in network byte order so start at end and work back */ + for (i = KEYWRAP_BLOCK_SIZE - 1; i >= 0; i--) { + if (++inOutCtr[i]) /* we're done unless we overflow */ + return; + } +} + +/* Decrement key wrap counter */ +static INLINE void DecrementKeyWrapCounter(byte* inOutCtr) +{ + int i; + + for (i = KEYWRAP_BLOCK_SIZE - 1; i >= 0; i--) { + if (--inOutCtr[i] != 0xFF) /* we're done unless we underflow */ + return; + } +} + +/* perform AES key wrap (RFC3394), return out sz on success, negative on err */ +int wc_AesKeyWrap(const byte* key, word32 keySz, const byte* in, word32 inSz, + byte* out, word32 outSz, const byte* iv) +{ + Aes aes; + byte* r; + word32 i; + int ret, j; + + byte t[KEYWRAP_BLOCK_SIZE]; + byte tmp[AES_BLOCK_SIZE]; + + /* n must be at least 2, output size is n + 8 bytes */ + if (key == NULL || in == NULL || inSz < 2 || + out == NULL || outSz < (inSz + KEYWRAP_BLOCK_SIZE)) + return BAD_FUNC_ARG; + + /* input must be multiple of 64-bits */ + if (inSz % KEYWRAP_BLOCK_SIZE != 0) + return BAD_FUNC_ARG; + + /* user IV is optional */ + if (iv == NULL) { + XMEMSET(tmp, 0xA6, KEYWRAP_BLOCK_SIZE); + } else { + XMEMCPY(tmp, iv, KEYWRAP_BLOCK_SIZE); + } + + r = out + 8; + XMEMCPY(r, in, inSz); + XMEMSET(t, 0, sizeof(t)); + + ret = wc_AesSetKey(&aes, key, keySz, NULL, AES_ENCRYPTION); + if (ret != 0) + return ret; + + for (j = 0; j <= 5; j++) { + for (i = 1; i <= inSz / KEYWRAP_BLOCK_SIZE; i++) { + + /* load R[i] */ + XMEMCPY(tmp + KEYWRAP_BLOCK_SIZE, r, KEYWRAP_BLOCK_SIZE); + + wc_AesEncryptDirect(&aes, tmp, tmp); + + /* calculate new A */ + IncrementKeyWrapCounter(t); + xorbuf(tmp, t, KEYWRAP_BLOCK_SIZE); + + /* save R[i] */ + XMEMCPY(r, tmp + KEYWRAP_BLOCK_SIZE, KEYWRAP_BLOCK_SIZE); + r += KEYWRAP_BLOCK_SIZE; + } + r = out + KEYWRAP_BLOCK_SIZE; + } + + /* C[0] = A */ + XMEMCPY(out, tmp, KEYWRAP_BLOCK_SIZE); + + return inSz + KEYWRAP_BLOCK_SIZE; +} + +int wc_AesKeyUnWrap(const byte* key, word32 keySz, const byte* in, word32 inSz, + byte* out, word32 outSz, const byte* iv) +{ + Aes aes; + byte* r; + word32 i, n; + int ret, j; + + byte t[KEYWRAP_BLOCK_SIZE]; + byte tmp[AES_BLOCK_SIZE]; + + const byte* expIv; + const byte defaultIV[] = { + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 + }; + + (void)iv; + + if (key == NULL || in == NULL || inSz < 3 || + out == NULL || outSz < (inSz - KEYWRAP_BLOCK_SIZE)) + return BAD_FUNC_ARG; + + /* input must be multiple of 64-bits */ + if (inSz % KEYWRAP_BLOCK_SIZE != 0) + return BAD_FUNC_ARG; + + /* user IV optional */ + if (iv != NULL) { + expIv = iv; + } else { + expIv = defaultIV; + } + + /* A = C[0], R[i] = C[i] */ + XMEMCPY(tmp, in, KEYWRAP_BLOCK_SIZE); + XMEMCPY(out, in + KEYWRAP_BLOCK_SIZE, inSz - KEYWRAP_BLOCK_SIZE); + XMEMSET(t, 0, sizeof(t)); + + ret = wc_AesSetKey(&aes, key, keySz, NULL, AES_DECRYPTION); + if (ret != 0) + return ret; + + /* initialize counter to 6n */ + n = (inSz - 1) / KEYWRAP_BLOCK_SIZE; + InitKeyWrapCounter(t, 6 * n); + + for (j = 5; j >= 0; j--) { + for (i = n; i >= 1; i--) { + + /* calculate A */ + xorbuf(tmp, t, KEYWRAP_BLOCK_SIZE); + DecrementKeyWrapCounter(t); + + /* load R[i], starting at end of R */ + r = out + ((i - 1) * KEYWRAP_BLOCK_SIZE); + XMEMCPY(tmp + KEYWRAP_BLOCK_SIZE, r, KEYWRAP_BLOCK_SIZE); + wc_AesDecryptDirect(&aes, tmp, tmp); + + /* save R[i] */ + XMEMCPY(r, tmp + KEYWRAP_BLOCK_SIZE, KEYWRAP_BLOCK_SIZE); + } + } + + /* verify IV */ + if (XMEMCMP(tmp, expIv, KEYWRAP_BLOCK_SIZE) != 0) + return BAD_KEYWRAP_IV_E; + + return inSz - KEYWRAP_BLOCK_SIZE; +} + +#endif /* HAVE_AES_KEYWRAP */ + int wc_AesGetKeySize(Aes* aes, word32* keySize) { int ret = 0; diff --git a/wolfcrypt/src/port/arm/armv8-sha256.c b/wolfcrypt/src/port/arm/armv8-sha256.c index 48d7230ef..6f708915f 100644 --- a/wolfcrypt/src/port/arm/armv8-sha256.c +++ b/wolfcrypt/src/port/arm/armv8-sha256.c @@ -26,7 +26,9 @@ #include -#if !defined(NO_SHA256) && defined(WOLFSSL_ARMASM) +#ifdef WOLFSSL_ARMASM +#if !defined(NO_SHA256) || defined(WOLFSSL_SHA224) + #include #include #include @@ -56,7 +58,7 @@ static const ALIGN32 word32 K[64] = { }; -int wc_InitSha256_ex(Sha256* sha256, void* heap, int devId) +static int InitSha256(Sha256* sha256) { int ret = 0; @@ -77,41 +79,25 @@ int wc_InitSha256_ex(Sha256* sha256, void* heap, int devId) sha256->loLen = 0; sha256->hiLen = 0; - (void)heap; - (void)devId; - return ret; } -int wc_InitSha256(Sha256* sha256) -{ - return wc_InitSha256_ex(sha256, NULL, INVALID_DEVID); -} - -void wc_Sha256Free(Sha256* sha256) -{ - (void)sha256; -} - static INLINE void AddLength(Sha256* sha256, word32 len) { word32 tmp = sha256->loLen; - if ( (sha256->loLen += len) < tmp) + if ((sha256->loLen += len) < tmp) sha256->hiLen++; /* carry low to high */ } #ifdef __aarch64__ + /* ARMv8 hardware accleration */ -int wc_Sha256Update(Sha256* sha256, const byte* data, word32 len) +static INLINE int Sha256Update(Sha256* sha256, const byte* data, word32 len) { word32 add; word32 numBlocks; - if (sha256 == NULL || (data == NULL && len != 0)) { - return BAD_FUNC_ARG; - } - /* only perform actions if a buffer is passed in */ if (len > 0) { /* fill leftover buffer with data */ @@ -320,14 +306,10 @@ int wc_Sha256Update(Sha256* sha256, const byte* data, word32 len) } -int wc_Sha256Final(Sha256* sha256, byte* hash) +static INLINE int Sha256Final(Sha256* sha256, byte* hash) { byte* local; - if (sha256 == NULL || hash == NULL) { - return BAD_FUNC_ARG; - } - local = (byte*)sha256->buffer; AddLength(sha256, sha256->buffLen); /* before adding pads */ @@ -667,20 +649,17 @@ int wc_Sha256Final(Sha256* sha256, byte* hash) "v22", "v23", "v24", "v25" ); - return wc_InitSha256(sha256); /* reset state */ + return 0; } #else /* not using 64 bit */ + /* ARMv8 hardware accleration Aarch32 */ -int wc_Sha256Update(Sha256* sha256, const byte* data, word32 len) +static INLINE int Sha256Update(Sha256* sha256, const byte* data, word32 len) { word32 add; word32 numBlocks; - if (sha256 == NULL || (data == NULL && len != 0)) { - return BAD_FUNC_ARG; - } - /* only perform actions if a buffer is passed in */ if (len > 0) { /* fill leftover buffer with data */ @@ -903,7 +882,7 @@ int wc_Sha256Update(Sha256* sha256, const byte* data, word32 len) } -int wc_Sha256Final(Sha256* sha256, byte* hash) +static INLINE int Sha256Final(Sha256* sha256, byte* hash) { byte* local; @@ -1298,12 +1277,66 @@ int wc_Sha256Final(Sha256* sha256, byte* hash) "q15" ); - return wc_InitSha256(sha256); /* reset state */ + return 0; } #endif /* __aarch64__ */ +#ifndef NO_SHA256 + +int wc_InitSha256_ex(Sha256* sha256, void* heap, int devId) +{ + int ret = 0; + + if (sha256 == NULL) + return BAD_FUNC_ARG; + + sha256->heap = heap; + + ret = InitSha256(sha256); + if (ret != 0) + return ret; + + (void)devId; + + return ret; +} + +int wc_InitSha256(Sha256* sha256) +{ + return wc_InitSha256_ex(sha256, NULL, INVALID_DEVID); +} + +void wc_Sha256Free(Sha256* sha256) +{ + (void)sha256; +} + +int wc_Sha256Update(Sha256* sha256, const byte* data, word32 len) +{ + if (sha256 == NULL || (data == NULL && len != 0)) { + return BAD_FUNC_ARG; + } + + return Sha256Update(sha256, data, len); +} + +int wc_Sha256Final(Sha256* sha256, byte* hash) +{ + int ret; + + if (sha256 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + ret = Sha256Final(sha256, hash); + if (ret != 0) + return ret; + + return InitSha256(sha256); /* reset state */ +} + int wc_Sha256GetHash(Sha256* sha256, byte* hash) { int ret; @@ -1331,4 +1364,122 @@ int wc_Sha256Copy(Sha256* src, Sha256* dst) return ret; } -#endif /* NO_SHA256 and WOLFSSL_ARMASM */ +#endif /* !NO_SHA256 */ + + +#ifdef WOLFSSL_SHA224 + static int InitSha224(Sha224* sha224) + { + + int ret = 0; + + if (sha224 == NULL) { + return BAD_FUNC_ARG; + } + + sha224->digest[0] = 0xc1059ed8; + sha224->digest[1] = 0x367cd507; + sha224->digest[2] = 0x3070dd17; + sha224->digest[3] = 0xf70e5939; + sha224->digest[4] = 0xffc00b31; + sha224->digest[5] = 0x68581511; + sha224->digest[6] = 0x64f98fa7; + sha224->digest[7] = 0xbefa4fa4; + + sha224->buffLen = 0; + sha224->loLen = 0; + sha224->hiLen = 0; + + return ret; + } + + int wc_InitSha224_ex(Sha224* sha224, void* heap, int devId) + { + int ret = 0; + + if (sha224 == NULL) + return BAD_FUNC_ARG; + + sha224->heap = heap; + + ret = InitSha224(sha224); + if (ret != 0) + return ret; + + (void)devId; + + return ret; + } + + int wc_InitSha224(Sha224* sha224) + { + return wc_InitSha224_ex(sha224, NULL, INVALID_DEVID); + } + + int wc_Sha224Update(Sha224* sha224, const byte* data, word32 len) + { + int ret; + + if (sha224 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + + ret = Sha256Update((Sha256 *)sha224, data, len); + + return ret; + } + + int wc_Sha224Final(Sha224* sha224, byte* hash) + { + int ret; + word32 hashTmp[SHA256_DIGEST_SIZE/sizeof(word32)]; + + if (sha224 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + ret = Sha256Final((Sha256*)sha224, (byte*)hashTmp); + if (ret != 0) + return ret; + + XMEMCPY(hash, hashTmp, SHA224_DIGEST_SIZE); + + return InitSha224(sha224); /* reset state */ + } + + void wc_Sha224Free(Sha224* sha224) + { + if (sha224 == NULL) + return; + } + + int wc_Sha224GetHash(Sha224* sha224, byte* hash) + { + int ret; + Sha224 tmpSha224; + + if (sha224 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + ret = wc_Sha224Copy(sha224, &tmpSha224); + if (ret == 0) { + ret = wc_Sha224Final(&tmpSha224, hash); + } + return ret; + } + int wc_Sha224Copy(Sha224* src, Sha224* dst) + { + int ret = 0; + + if (src == NULL || dst == NULL) + return BAD_FUNC_ARG; + + XMEMCPY(dst, src, sizeof(Sha224)); + + return ret; + } + +#endif /* WOLFSSL_SHA224 */ + +#endif /* !NO_SHA256 || WOLFSSL_SHA224 */ +#endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 942f4e0b3..633908136 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -11693,6 +11693,7 @@ done: int ed25519_test(void) { + int ret; WC_RNG rng; #if defined(HAVE_ED25519_SIGN) && defined(HAVE_ED25519_KEY_EXPORT) &&\ defined(HAVE_ED25519_KEY_IMPORT) @@ -11701,7 +11702,7 @@ int ed25519_test(void) byte exportSKey[ED25519_KEY_SIZE]; word32 exportPSz; word32 exportSSz; - int i, ret; + int i; word32 outlen; #ifdef HAVE_ED25519_VERIFY int verify; diff --git a/wolfssl/wolfcrypt/fe_operations.h b/wolfssl/wolfcrypt/fe_operations.h index 0cb616e4e..342ca28cc 100644 --- a/wolfssl/wolfcrypt/fe_operations.h +++ b/wolfssl/wolfcrypt/fe_operations.h @@ -90,7 +90,7 @@ WOLFSSL_LOCAL void fe_mul121666(fe,fe); WOLFSSL_LOCAL void fe_cmov(fe,const fe, int); WOLFSSL_LOCAL void fe_pow22523(fe,const fe); -#if defined(HAVE___UINT128_T) +#if !defined(CURVE25519_SMALL) || !defined(ED25519_SMALL) /* 64 type needed for SHA512 */ WOLFSSL_LOCAL uint64_t load_3(const unsigned char *in); WOLFSSL_LOCAL uint64_t load_4(const unsigned char *in);