From df0d5f3b083240dd7bd2b7f965ef3e819b2ec3f4 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 24 Jan 2020 15:25:33 -0700 Subject: [PATCH] add EVP_aes_*_ofb implementation and tests, add support for inline with OFB --- src/ssl.c | 78 +++++++++++++++++++ wolfcrypt/src/aes.c | 24 ++++-- wolfcrypt/src/evp.c | 10 +++ wolfcrypt/test/test.c | 174 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 268 insertions(+), 18 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 727a1dbcc..c7ff328c3 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17419,6 +17419,84 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD *md) return ret; } #endif /* WOLFSSL_AES_256 */ + #ifdef WOLFSSL_AES_OFB + #ifdef WOLFSSL_AES_128 + if (ctx->cipherType == AES_128_OFB_TYPE || + (type && XSTRNCMP(type, EVP_AES_128_OFB, EVP_AES_SIZE) == 0)) { + WOLFSSL_MSG("EVP_AES_128_OFB"); + ctx->cipherType = AES_128_OFB_TYPE; + ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE; + ctx->flags |= WOLFSSL_EVP_CIPH_OFB_MODE; + ctx->keyLen = 16; + ctx->block_size = 1; + if (enc == 0 || enc == 1) + ctx->enc = enc ? 1 : 0; + if (key) { + ret = AesSetKey_ex(&ctx->cipher.aes, key, ctx->keyLen, iv, + AES_ENCRYPTION, 0); + if (ret != 0) + return ret; + } + if (iv && key == NULL) { + ret = wc_AesSetIV(&ctx->cipher.aes, iv); + if (ret != 0) + return ret; + } + } + #endif /* WOLFSSL_AES_128 */ + #ifdef WOLFSSL_AES_192 + if (ctx->cipherType == AES_192_OFB_TYPE || + (type && XSTRNCMP(type, EVP_AES_192_OFB, EVP_AES_SIZE) == 0)) { + WOLFSSL_MSG("EVP_AES_192_OFB"); + ctx->cipherType = AES_192_OFB_TYPE; + ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE; + ctx->flags |= WOLFSSL_EVP_CIPH_OFB_MODE; + ctx->keyLen = 24; + ctx->block_size = 1; + if (enc == 0 || enc == 1) + ctx->enc = enc ? 1 : 0; + if (key) { + ret = AesSetKey_ex(&ctx->cipher.aes, key, ctx->keyLen, iv, + AES_ENCRYPTION, 0); + if (ret != 0) + return ret; + } + if (iv && key == NULL) { + ret = wc_AesSetIV(&ctx->cipher.aes, iv); + if (ret != 0) + return ret; + } + } + #endif /* WOLFSSL_AES_192 */ + #ifdef WOLFSSL_AES_256 + if (ctx->cipherType == AES_256_OFB_TYPE || + (type && XSTRNCMP(type, EVP_AES_256_OFB, EVP_AES_SIZE) == 0)) { + WOLFSSL_MSG("EVP_AES_256_OFB"); + ctx->cipherType = AES_256_OFB_TYPE; + ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE; + ctx->flags |= WOLFSSL_EVP_CIPH_OFB_MODE; + ctx->keyLen = 32; + ctx->block_size = 1; + if (enc == 0 || enc == 1) + ctx->enc = enc ? 1 : 0; + if (key) { + ret = AesSetKey_ex(&ctx->cipher.aes, key, ctx->keyLen, iv, + AES_ENCRYPTION, 0); + if (ret != 0){ + WOLFSSL_MSG("AesSetKey() failed"); + return ret; + } + } + if (iv && key == NULL) { + ret = wc_AesSetIV(&ctx->cipher.aes, iv); + if (ret != 0){ + WOLFSSL_MSG("wc_AesSetIV() failed"); + return ret; + } + } + } + #endif /* WOLFSSL_AES_256 */ + #endif /* HAVE_AES_CBC */ #endif /* NO_AES */ #ifndef NO_DES3 diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 61474ec13..3eb781f1f 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -7305,18 +7305,20 @@ static int wc_AesFeedbackEncrypt(Aes* aes, byte* out, const byte* in, } while (sz >= AES_BLOCK_SIZE) { - wc_AesEncryptDirect(aes, out, (byte*)aes->reg); + /* Using aes->tmp here for inline case i.e. in=out */ + wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg); #ifdef WOLFSSL_AES_OFB if (mode == AES_OFB_MODE) { - XMEMCPY(aes->reg, out, AES_BLOCK_SIZE); + XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE); } #endif - xorbuf(out, in, AES_BLOCK_SIZE); + xorbuf((byte*)aes->tmp, in, AES_BLOCK_SIZE); #ifdef WOLFSSL_AES_CFB if (mode == AES_CFB_MODE) { - XMEMCPY(aes->reg, out, AES_BLOCK_SIZE); + XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE); } #endif + XMEMCPY(out, aes->tmp, AES_BLOCK_SIZE); out += AES_BLOCK_SIZE; in += AES_BLOCK_SIZE; sz -= AES_BLOCK_SIZE; @@ -7374,11 +7376,13 @@ static int wc_AesFeedbackDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, return BAD_FUNC_ARG; } + #ifdef WOLFSSL_AES_CFB /* check if more input needs copied over to aes->reg */ if (aes->left && sz && mode == AES_CFB_MODE) { int size = min(aes->left, sz); XMEMCPY((byte*)aes->reg + AES_BLOCK_SIZE - aes->left, in, size); } + #endif /* consume any unused bytes left in aes->tmp */ tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left; @@ -7389,18 +7393,20 @@ static int wc_AesFeedbackDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, } while (sz > AES_BLOCK_SIZE) { - wc_AesEncryptDirect(aes, out, (byte*)aes->reg); + /* Using aes->tmp here for inline case i.e. in=out */ + wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg); #ifdef WOLFSSL_AES_OFB if (mode == AES_OFB_MODE) { - XMEMCPY(aes->reg, out, AES_BLOCK_SIZE); + XMEMCPY((byte*)aes->reg, (byte*)aes->tmp, AES_BLOCK_SIZE); } #endif - xorbuf(out, in, AES_BLOCK_SIZE); + xorbuf((byte*)aes->tmp, in, AES_BLOCK_SIZE); #ifdef WOLFSSL_AES_CFB if (mode == AES_CFB_MODE) { XMEMCPY(aes->reg, in, AES_BLOCK_SIZE); } #endif + XMEMCPY(out, (byte*)aes->tmp, AES_BLOCK_SIZE); out += AES_BLOCK_SIZE; in += AES_BLOCK_SIZE; sz -= AES_BLOCK_SIZE; @@ -7410,12 +7416,16 @@ static int wc_AesFeedbackDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, /* decrypt left over data */ if (sz) { wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg); + #ifdef WOLFSSL_AES_CFB if (mode == AES_CFB_MODE) { XMEMCPY(aes->reg, in, sz); } + #endif + #ifdef WOLFSSL_AES_OFB if (mode == AES_OFB_MODE) { XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE); } + #endif aes->left = AES_BLOCK_SIZE; tmp = (byte*)aes->tmp; diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 16f733e5d..0d411e15c 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -347,6 +347,16 @@ static int evpCipherBlock(WOLFSSL_EVP_CIPHER_CTX *ctx, ret = wc_AesEcbDecrypt(&ctx->cipher.aes, out, in, inl); break; #endif + #if defined(WOLFSSL_AES_OFB) + case AES_128_OFB_TYPE: + case AES_192_OFB_TYPE: + case AES_256_OFB_TYPE: + if (ctx->enc) + ret = wc_AesOfbEncrypt(&ctx->cipher.aes, out, in, inl); + else + ret = wc_AesOfbDecrypt(&ctx->cipher.aes, out, in, inl); + break; + #endif #endif /* !NO_AES */ #ifndef NO_DES3 case DES_CBC_TYPE: diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 1af133352..7eacde33d 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5866,6 +5866,77 @@ int des3_test(void) #endif /* WOLFSSL_AES_CFB */ #ifdef WOLFSSL_AES_OFB +#ifdef OPENSSL_EXTRA +/* pass in the function, key, iv, plain text and expected and this function + * tests that the encryption and decryption is successful */ +static int EVP_test(const WOLFSSL_EVP_CIPHER* type, const byte* key, + const byte* iv, const byte* plain, int plainSz, + const byte* expected, int expectedSz) +{ + EVP_CIPHER_CTX ctx; + int idx, ret = 0, cipherSz; + byte* cipher; + + cipher = (byte*)XMALLOC(plainSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (cipher == NULL) { + return -8000; + } + + + /* test encrypt */ + EVP_CIPHER_CTX_init(&ctx); + if (EVP_CipherInit(&ctx, type, key, iv, 1) == 0) { + ret = -8001; + goto EVP_TEST_END; + } + + if (EVP_CipherUpdate(&ctx, cipher, &idx, plain, plainSz) == 0) { + ret = -8002; + goto EVP_TEST_END; + } + + cipherSz = idx; + if (EVP_CipherFinal(&ctx, cipher + cipherSz, &idx) == 0) { + ret = -8003; + goto EVP_TEST_END; + } + cipherSz += idx; + + if (XMEMCMP(cipher, expected, expectedSz)) { + ret = -8004; + goto EVP_TEST_END; + } + + /* test decrypt */ + EVP_CIPHER_CTX_init(&ctx); + if (EVP_CipherInit(&ctx, type, key, iv, 0) == 0) { + ret = -8005; + goto EVP_TEST_END; + } + + if (EVP_CipherUpdate(&ctx, cipher, &idx, cipher, cipherSz) == 0) { + ret = -8006; + goto EVP_TEST_END; + } + + cipherSz = idx; + if (EVP_CipherFinal(&ctx, cipher + cipherSz, &idx) == 0) { + ret = -8007; + goto EVP_TEST_END; + } + cipherSz += idx; + + if ((plainSz != cipherSz) || XMEMCMP(plain, cipher, cipherSz)) { + ret = -8008; + goto EVP_TEST_END; + } + +EVP_TEST_END: + XFREE(cipher, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#endif /* OPENSSL_EXTRA */ + /* test vector from https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/Block-Ciphers */ int aesofb_test(void) { @@ -5960,6 +6031,14 @@ int des3_test(void) #ifdef WOLFSSL_AES_128 /* 128 key size test */ + #ifdef OPENSSL_EXTRA + ret = EVP_test(EVP_aes_128_ofb(), key2, iv2, plain2, sizeof(plain2), + cipher2, sizeof(cipher2)); + if (ret != 0) { + return ret; + } + #endif + ret = wc_AesSetKey(&enc, key2, sizeof(key2), iv2, AES_ENCRYPTION); if (ret != 0) return -5000; @@ -5990,6 +6069,14 @@ int des3_test(void) #ifdef WOLFSSL_AES_192 /* 192 key size test */ + #ifdef OPENSSL_EXTRA + ret = EVP_test(EVP_aes_192_ofb(), key3, iv3, plain3, sizeof(plain3), + cipher3, sizeof(cipher3)); + if (ret != 0) { + return ret; + } + #endif + ret = wc_AesSetKey(&enc, key3, sizeof(key3), iv3, AES_ENCRYPTION); if (ret != 0) return -5006; @@ -6020,6 +6107,14 @@ int des3_test(void) #ifdef WOLFSSL_AES_256 /* 256 key size test */ + #ifdef OPENSSL_EXTRA + ret = EVP_test(EVP_aes_256_ofb(), key1, iv1, plain1, sizeof(plain1), + cipher1, sizeof(cipher1)); + if (ret != 0) { + return ret; + } + #endif + ret = wc_AesSetKey(&enc, key1, sizeof(key1), iv1, AES_ENCRYPTION); if (ret != 0) return -5012; @@ -6064,10 +6159,8 @@ int des3_test(void) AES_BLOCK_SIZE)) return -5021; #endif /* HAVE_AES_DECRYPT */ -#endif /* WOLFSSL_AES_256 */ -#ifdef WOLFSSL_AES_256 - /* 256 key size test leftover support */ + /* multiple blocks at once */ ret = wc_AesSetKey(&enc, key1, sizeof(key1), iv1, AES_ENCRYPTION); if (ret != 0) return -5022; @@ -6079,36 +6172,93 @@ int des3_test(void) #endif XMEMSET(cipher, 0, sizeof(cipher)); - ret = wc_AesOfbEncrypt(&enc, cipher, plain1, 3); + ret = wc_AesOfbEncrypt(&enc, cipher, plain1, AES_BLOCK_SIZE * 3); if (ret != 0) return -5024; - if (XMEMCMP(cipher, cipher1, 3)) + if (XMEMCMP(cipher, cipher1, AES_BLOCK_SIZE * 3)) return -5025; - ret = wc_AesOfbEncrypt(&enc, cipher + 3, plain1 + 3, AES_BLOCK_SIZE); + #ifdef HAVE_AES_DECRYPT + ret = wc_AesOfbDecrypt(&dec, plain, cipher1, AES_BLOCK_SIZE * 3); if (ret != 0) return -5026; - if (XMEMCMP(cipher + 3, cipher1 + 3, AES_BLOCK_SIZE)) + if (XMEMCMP(plain, plain1, AES_BLOCK_SIZE * 3)) return -5027; + #endif /* HAVE_AES_DECRYPT */ + + /* inline decrypt/encrypt*/ + ret = wc_AesSetKey(&enc, key1, sizeof(key1), iv1, AES_ENCRYPTION); + if (ret != 0) + return -5028; + #ifdef HAVE_AES_DECRYPT + /* decrypt uses AES_ENCRYPTION */ + ret = wc_AesSetKey(&dec, key1, sizeof(key1), iv1, AES_ENCRYPTION); + if (ret != 0) + return -5029; + #endif + + XMEMCPY(cipher, plain1, AES_BLOCK_SIZE * 2); + ret = wc_AesOfbEncrypt(&enc, cipher, cipher, AES_BLOCK_SIZE * 2); + if (ret != 0) + return -5030; + + if (XMEMCMP(cipher, cipher1, AES_BLOCK_SIZE * 2)) + return -5031; + + #ifdef HAVE_AES_DECRYPT + ret = wc_AesOfbDecrypt(&dec, cipher, cipher, AES_BLOCK_SIZE * 2); + if (ret != 0) + return -5032; + + if (XMEMCMP(cipher, plain1, AES_BLOCK_SIZE * 2)) + return -5033; + #endif /* HAVE_AES_DECRYPT */ + + /* 256 key size test leftover support */ + ret = wc_AesSetKey(&enc, key1, sizeof(key1), iv1, AES_ENCRYPTION); + if (ret != 0) + return -5034; + #ifdef HAVE_AES_DECRYPT + /* decrypt uses AES_ENCRYPTION */ + ret = wc_AesSetKey(&dec, key1, sizeof(key1), iv1, AES_ENCRYPTION); + if (ret != 0) + return -5035; + #endif + + XMEMSET(cipher, 0, sizeof(cipher)); + ret = wc_AesOfbEncrypt(&enc, cipher, plain1, 3); + if (ret != 0) + return -5036; + + if (XMEMCMP(cipher, cipher1, 3)) + return -5037; + + ret = wc_AesOfbEncrypt(&enc, cipher + 3, plain1 + 3, AES_BLOCK_SIZE); + if (ret != 0) + return -5038; + + if (XMEMCMP(cipher + 3, cipher1 + 3, AES_BLOCK_SIZE)) + return -5039; #ifdef HAVE_AES_DECRYPT ret = wc_AesOfbDecrypt(&dec, plain, cipher1, 6); if (ret != 0) - return -5028; + return -5040; if (XMEMCMP(plain, plain1, 6)) - return -5029; + return -5041; ret = wc_AesOfbDecrypt(&dec, plain + 6, cipher1 + 6, AES_BLOCK_SIZE); if (ret != 0) - return -5030; + return -5042; if (XMEMCMP(plain + 6, plain1 + 6, AES_BLOCK_SIZE)) - return -5031; + return -5043; #endif /* HAVE_AES_DECRYPT */ #endif /* WOLFSSL_AES_256 */ + return 0; } #endif /* WOLFSSL_AES_OFB */ @@ -14794,6 +14944,8 @@ static int openssl_aes_test(void) #endif /* WOLFSSL_AES_CFB && WOLFSSL_AES_128 */ return 0; } + + #endif /* !defined(NO_AES) && !defined(WOLFCRYPT_ONLY) */ int openssl_test(void)