Add ChaCha20 as available cipher in the EVP API.

- wire the wc_ChaCha_* implementation into the EVP API
  as `wolfSSL_EVP_chacha20`
- follow IV conversions of OpenSSL
- add test case
- have QUIC support use this for header protection when
  CHACHA20_POLY1305 has been negotiated in the handshake.
This commit is contained in:
Stefan Eissing
2022-09-02 11:15:40 +02:00
committed by Stefan Eissing
parent 483d7189c7
commit 9f47999002
5 changed files with 183 additions and 3 deletions

View File

@@ -1006,7 +1006,7 @@ const WOLFSSL_EVP_CIPHER* wolfSSL_quic_get_hp(WOLFSSL* ssl)
#endif
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
case TLS_CHACHA20_POLY1305_SHA256:
evp_cipher = wolfSSL_EVP_chacha20_poly1305();
evp_cipher = wolfSSL_EVP_chacha20();
break;
#endif
#if defined(WOLFSSL_AES_COUNTER) && defined(WOLFSSL_AES_128)

View File

@@ -38918,6 +38918,11 @@ int wolfSSL_RAND_poll(void)
break;
#endif
#ifdef HAVE_CHACHA
case CHACHA20_TYPE:
break;
#endif
case NULL_CIPHER_TYPE :
WOLFSSL_MSG("NULL");
break;
@@ -39007,6 +39012,11 @@ int wolfSSL_RAND_poll(void)
break;
#endif
#ifdef HAVE_CHACHA
case CHACHA20_TYPE:
break;
#endif
case NULL_CIPHER_TYPE :
WOLFSSL_MSG("NULL");
break;

View File

@@ -52094,6 +52094,68 @@ static int test_wolfssl_EVP_chacha20_poly1305(void)
return 0;
}
static int test_wolfssl_EVP_chacha20(void)
{
#if defined(OPENSSL_EXTRA) && defined(HAVE_CHACHA)
byte key[CHACHA_MAX_KEY_SZ];
byte iv [WOLFSSL_EVP_CHACHA_IV_BYTES];
byte plainText[] = {0xDE, 0xAD, 0xBE, 0xEF};
byte cipherText[sizeof(plainText)];
byte decryptedText[sizeof(plainText)];
EVP_CIPHER_CTX* ctx;
int outSz;
printf(testingFmt, "test_wolfssl_EVP_chacha20");
/* Encrypt. */
AssertNotNull((ctx = EVP_CIPHER_CTX_new()));
AssertIntEQ(EVP_EncryptInit_ex(ctx, EVP_chacha20(), NULL, NULL,
NULL), WOLFSSL_SUCCESS);
/* Any tag length must fail - not an AEAD cipher. */
AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE, NULL), WOLFSSL_FAILURE);
AssertIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), WOLFSSL_SUCCESS);
AssertIntEQ(EVP_EncryptUpdate(ctx, cipherText, &outSz, plainText,
sizeof(plainText)), WOLFSSL_SUCCESS);
AssertIntEQ(outSz, sizeof(plainText));
AssertIntEQ(EVP_EncryptFinal_ex(ctx, cipherText, &outSz), WOLFSSL_SUCCESS);
AssertIntEQ(outSz, 0);
EVP_CIPHER_CTX_free(ctx);
/* Decrypt. */
AssertNotNull((ctx = EVP_CIPHER_CTX_new()));
AssertIntEQ(EVP_DecryptInit_ex(ctx, EVP_chacha20(), NULL, NULL,
NULL), WOLFSSL_SUCCESS);
AssertIntEQ(EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv), WOLFSSL_SUCCESS);
AssertIntEQ(EVP_DecryptUpdate(ctx, decryptedText, &outSz, cipherText,
sizeof(cipherText)), WOLFSSL_SUCCESS);
AssertIntEQ(outSz, sizeof(cipherText));
AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptedText, &outSz),
WOLFSSL_SUCCESS);
AssertIntEQ(outSz, 0);
EVP_CIPHER_CTX_free(ctx);
/* Test partial Inits. CipherInit() allow setting of key and iv
* in separate calls. */
AssertNotNull((ctx = EVP_CIPHER_CTX_new()));
AssertIntEQ(wolfSSL_EVP_CipherInit(ctx, EVP_chacha20(),
key, NULL, 1), WOLFSSL_SUCCESS);
AssertIntEQ(wolfSSL_EVP_CipherInit(ctx, NULL, NULL, iv, 1),
WOLFSSL_SUCCESS);
AssertIntEQ(EVP_DecryptUpdate(ctx, decryptedText, &outSz, cipherText,
sizeof(cipherText)), WOLFSSL_SUCCESS);
AssertIntEQ(outSz, sizeof(cipherText));
AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptedText, &outSz),
WOLFSSL_SUCCESS);
AssertIntEQ(outSz, 0);
EVP_CIPHER_CTX_free(ctx);
printf(resultFmt, passed);
#endif
return 0;
}
static int test_wolfSSL_EVP_PKEY_hkdf(void)
{
#if defined(OPENSSL_EXTRA) && defined(HAVE_HKDF)
@@ -57991,6 +58053,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfssl_EVP_aes_gcm_AAD_2_parts),
TEST_DECL(test_wolfssl_EVP_aes_gcm),
TEST_DECL(test_wolfssl_EVP_chacha20_poly1305),
TEST_DECL(test_wolfssl_EVP_chacha20),
TEST_DECL(test_wolfSSL_EVP_PKEY_hkdf),
TEST_DECL(test_wolfSSL_PKEY_up_ref),
TEST_DECL(test_wolfSSL_EVP_Cipher_extra),

View File

@@ -166,6 +166,10 @@
static const char EVP_CHACHA20_POLY1305[] = "CHACHA20-POLY1305";
#endif
#ifdef HAVE_CHACHA
static const char EVP_CHACHA20[] = "CHACHA20";
#endif
static const char EVP_NULL[] = "NULL";
#define EVP_CIPHER_TYPE_MATCHES(x, y) (XSTRCMP(x,y) == 0)
@@ -246,6 +250,9 @@ int wolfSSL_EVP_Cipher_key_length(const WOLFSSL_EVP_CIPHER* c)
#endif
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
case CHACHA20_POLY1305_TYPE: return 32;
#endif
#ifdef HAVE_CHACHA
case CHACHA20_TYPE: return CHACHA_MAX_KEY_SZ;
#endif
default:
return 0;
@@ -702,6 +709,16 @@ int wolfSSL_EVP_CipherUpdate(WOLFSSL_EVP_CIPHER_CTX *ctx,
return WOLFSSL_SUCCESS;
}
}
#endif
#ifdef HAVE_CHACHA
case CHACHA20_TYPE:
/* CHACHAFIXME */
if (wc_Chacha_Process(&ctx->cipher.chacha, out, in, inl) != 0) {
WOLFSSL_MSG("wc_ChaCha_Process failed");
return WOLFSSL_FAILURE;
}
*outl = inl;
return WOLFSSL_SUCCESS;
#endif
default:
/* fall-through */
@@ -1298,6 +1315,11 @@ static unsigned int cipherType(const WOLFSSL_EVP_CIPHER *cipher)
return CHACHA20_POLY1305_TYPE;
#endif
#ifdef HAVE_CHACHA
else if (EVP_CIPHER_TYPE_MATCHES(cipher, EVP_CHACHA20))
return CHACHA20_TYPE;
#endif
else return 0;
}
@@ -1371,6 +1393,12 @@ int wolfSSL_EVP_CIPHER_block_size(const WOLFSSL_EVP_CIPHER *cipher)
case CHACHA20_POLY1305_TYPE:
return 1;
#endif
#ifdef HAVE_CHACHA
case CHACHA20_TYPE:
return 1;
#endif
default:
return 0;
}
@@ -1443,6 +1471,10 @@ unsigned long WOLFSSL_CIPHER_mode(const WOLFSSL_EVP_CIPHER *cipher)
case CHACHA20_POLY1305_TYPE:
return WOLFSSL_EVP_CIPH_STREAM_CIPHER |
WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER;
#endif
#ifdef HAVE_CHACHA
case CHACHA20_TYPE:
return WOLFSSL_EVP_CIPH_STREAM_CIPHER;
#endif
default:
return 0;
@@ -4176,6 +4208,10 @@ static const struct cipher{
{CHACHA20_POLY1305_TYPE, EVP_CHACHA20_POLY1305, NID_chacha20_poly1305},
#endif
#ifdef HAVE_CHACHA
{CHACHA20_TYPE, EVP_CHACHA20, NID_chacha20},
#endif
{ 0, NULL, 0}
};
@@ -4275,6 +4311,9 @@ const WOLFSSL_EVP_CIPHER *wolfSSL_EVP_get_cipherbyname(const char *name)
#endif
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
{EVP_CHACHA20_POLY1305, "chacha20-poly1305"},
#endif
#ifdef HAVE_CHACHA
{EVP_CHACHA20, "chacha20"},
#endif
{ NULL, NULL}
};
@@ -4394,6 +4433,11 @@ const WOLFSSL_EVP_CIPHER *wolfSSL_EVP_get_cipherbynid(int id)
return wolfSSL_EVP_chacha20_poly1305();
#endif
#ifdef HAVE_CHACHA
case NID_chacha20:
return wolfSSL_EVP_chacha20();
#endif
default:
WOLFSSL_MSG("Bad cipher id value");
}
@@ -5298,6 +5342,14 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
}
#endif
#ifdef HAVE_CHACHA
const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_chacha20(void)
{
WOLFSSL_ENTER("wolfSSL_EVP_chacha20");
return EVP_CHACHA20;
}
#endif
const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_enc_null(void)
{
WOLFSSL_ENTER("wolfSSL_EVP_enc_null");
@@ -6652,6 +6704,40 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
}
}
#endif
#ifdef HAVE_CHACHA
if (ctx->cipherType == CHACHA20_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_CHACHA20))) {
WOLFSSL_MSG("EVP_CHACHA20");
ctx->cipherType = CHACHA20_TYPE;
ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE;
ctx->keyLen = CHACHA_MAX_KEY_SZ;
ctx->block_size = 1;
ctx->ivSz = WOLFSSL_EVP_CHACHA_IV_BYTES;
if (enc == 0 || enc == 1) {
ctx->enc = (byte) enc;
}
if (key != NULL && wc_Chacha_SetKey(&ctx->cipher.chacha,
key, ctx->keyLen) != 0) {
WOLFSSL_MSG("wc_Chacha_SetKey() failed");
return WOLFSSL_FAILURE;
}
if (iv != NULL) {
/* a bit silly. chacha takes an iv+counter and internally
* combines them to a new iv. EVP is given exactly *one* iv,
* so to pass it into chacha, we have to revert that first.
* The counter comes first in little-endian */
word32 counter = (uint32_t)iv[0] + (uint32_t)(iv[1] << 8) +
(uint32_t)(iv[2] << 16) + (uint32_t)(iv[3] << 24);
if (wc_Chacha_SetIV(&ctx->cipher.chacha,
iv + sizeof(counter), counter) != 0) {
WOLFSSL_MSG("wc_Chacha_SetIV() failed");
return WOLFSSL_FAILURE;
}
}
/* CHACHAFIXME */
}
#endif
#ifndef NO_DES3
if (ctx->cipherType == DES_CBC_TYPE ||
(type && EVP_CIPHER_TYPE_MATCHES(type, EVP_DES_CBC))) {
@@ -8423,6 +8509,11 @@ int wolfSSL_EVP_CIPHER_CTX_iv_length(const WOLFSSL_EVP_CIPHER_CTX* ctx)
WOLFSSL_MSG("CHACHA20 POLY1305");
return CHACHA20_POLY1305_AEAD_IV_SIZE;
#endif /* HAVE_CHACHA HAVE_POLY1305 */
#ifdef HAVE_CHACHA
case CHACHA20_TYPE:
WOLFSSL_MSG("CHACHA20");
return WOLFSSL_EVP_CHACHA_IV_BYTES;
#endif /* HAVE_CHACHA */
case NULL_CIPHER_TYPE :
WOLFSSL_MSG("NULL");
@@ -8512,6 +8603,11 @@ int wolfSSL_EVP_CIPHER_iv_length(const WOLFSSL_EVP_CIPHER* cipher)
return CHACHA20_POLY1305_AEAD_IV_SIZE;
#endif
#ifdef HAVE_CHACHA
if (XSTRCMP(name, EVP_CHACHA20) == 0)
return WOLFSSL_EVP_CHACHA_IV_BYTES;
#endif
(void)name;
return 0;

View File

@@ -139,6 +139,11 @@ WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_rc2_cbc(void);
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_chacha20_poly1305(void);
#endif
#ifdef HAVE_CHACHA
/* ChaCha IV + counter is set as one IV in EVP */
#define WOLFSSL_EVP_CHACHA_IV_BYTES (CHACHA_IV_BYTES + sizeof(word32))
WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_chacha20(void);
#endif
typedef union {
@@ -212,6 +217,9 @@ typedef union {
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
ChaChaPoly_Aead chachaPoly;
#endif
#ifdef HAVE_CHACHA
ChaCha chacha;
#endif
} WOLFSSL_Cipher;
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
@@ -282,7 +290,8 @@ enum {
AES_256_OFB_TYPE = 35,
AES_128_XTS_TYPE = 36,
AES_256_XTS_TYPE = 37,
CHACHA20_POLY1305_TYPE = 38
CHACHA20_POLY1305_TYPE = 38,
CHACHA20_TYPE = 39
};
enum {
@@ -357,7 +366,8 @@ enum {
NID_aes_256_xts = 914,
NID_camellia_128_cbc = 751,
NID_camellia_256_cbc = 753,
NID_chacha20_poly1305 = 1018
NID_chacha20_poly1305 = 1018,
NID_chacha20 = 1019
};
enum {
@@ -898,6 +908,7 @@ WOLFSSL_API int wolfSSL_EVP_SignInit_ex(WOLFSSL_EVP_MD_CTX* ctx,
#define EVP_des_ede3_cbc wolfSSL_EVP_des_ede3_cbc
#define EVP_des_ede3_ecb wolfSSL_EVP_des_ede3_ecb
#define EVP_rc4 wolfSSL_EVP_rc4
#define EVP_chacha20 wolfSSL_EVP_chacha20
#define EVP_chacha20_poly1305 wolfSSL_EVP_chacha20_poly1305
#define EVP_enc_null wolfSSL_EVP_enc_null