From 6142c229483f80fe2d86ff6a395dd48f89a2e18d Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 1 Oct 2020 12:21:38 -0500 Subject: [PATCH] add wc_XChaCha_init(), wc_XChaCha20Poly1305_Init(), wc_XChaCha20Poly1305_encrypt_oneshot(), wc_XChaCha20Poly1305_decrypt_oneshot(), and wc_Poly1305_EncodeSizes64(). also, remove redundant arg check (typo) in wc_Poly1305Update(). --- configure.ac | 21 +++ wolfcrypt/src/chacha.c | 79 +++++++++- wolfcrypt/src/chacha20_poly1305.c | 154 +++++++++++++++++++ wolfcrypt/src/poly1305.c | 26 +++- wolfcrypt/test/test.c | 211 ++++++++++++++++++++++++++ wolfssl/wolfcrypt/chacha.h | 8 + wolfssl/wolfcrypt/chacha20_poly1305.h | 25 +++ wolfssl/wolfcrypt/poly1305.h | 3 + 8 files changed, 524 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 8ea7dc0b9..19fbced4e 100644 --- a/configure.ac +++ b/configure.ac @@ -314,6 +314,7 @@ then enable_webserver=yes enable_hc128=yes enable_rabbit=yes + enable_xchacha=yes enable_ocsp=yes enable_ocspstapling=yes enable_ocspstapling2=yes @@ -2998,6 +2999,23 @@ then fi +# XCHACHA +AC_ARG_ENABLE([xchacha], + [AS_HELP_STRING([--enable-xchacha],[Enable XCHACHA (default: disabled).])], + [ ENABLED_XCHACHA=$enableval ], + [ ENABLED_XCHACHA=no] + ) + +if test "$ENABLED_XCHACHA" = "yes" +then + if test "$ENABLED_CHACHA" = "no" + then + AC_MSG_ERROR([XChaCha (--enable-xchacha) depends on ChaCha (--enable-chacha)]) + fi + AM_CFLAGS="$AM_CFLAGS -DHAVE_XCHACHA" +fi + + # Hash DRBG AC_ARG_ENABLE([hashdrbg], [AS_HELP_STRING([--enable-hashdrbg],[Enable Hash DRBG support (default: enabled)])], @@ -5698,6 +5716,7 @@ AM_CONDITIONAL([BUILD_SHA224],[test "x$ENABLED_SHA224" = "xyes" || test "x$ENABL AM_CONDITIONAL([BUILD_SHA3],[test "x$ENABLED_SHA3" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_POLY1305],[test "x$ENABLED_POLY1305" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CHACHA],[test "x$ENABLED_CHACHA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_XCHACHA],[test "x$ENABLED_XCHACHA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_INLINE],[test "x$ENABLED_INLINE" = "xyes"]) AM_CONDITIONAL([BUILD_OCSP],[test "x$ENABLED_OCSP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_OCSP_STAPLING],[test "x$ENABLED_CERTIFICATE_STATUS_REQUEST" = "xyes"]) @@ -5938,6 +5957,7 @@ echo " * SHA-512: $ENABLED_SHA512" echo " * SHA3: $ENABLED_SHA3" echo " * SHAKE256: $ENABLED_SHAKE256" echo " * BLAKE2: $ENABLED_BLAKE2" +echo " * BLAKE2S: $ENABLED_BLAKE2S" echo " * CMAC: $ENABLED_CMAC" echo " * keygen: $ENABLED_KEYGEN" echo " * certgen: $ENABLED_CERTGEN" @@ -5947,6 +5967,7 @@ echo " * certgencache: $ENABLED_certgencache" echo " * HC-128: $ENABLED_HC128" echo " * RABBIT: $ENABLED_RABBIT" echo " * CHACHA: $ENABLED_CHACHA" +echo " * XCHACHA: $ENABLED_XCHACHA" echo " * Hash DRBG: $ENABLED_HASHDRBG" echo " * PWDBASED: $ENABLED_PWDBASED" echo " * scrypt: $ENABLED_SCRYPT" diff --git a/wolfcrypt/src/chacha.c b/wolfcrypt/src/chacha.c index 1a9b634d0..6b6091eb7 100644 --- a/wolfcrypt/src/chacha.c +++ b/wolfcrypt/src/chacha.c @@ -232,6 +232,72 @@ static WC_INLINE void wc_Chacha_wordtobyte(word32 output[CHACHA_CHUNK_WORDS], } } + +#ifdef HAVE_XCHACHA + +/* + * wc_HChacha_block - half a ChaCha block, for XChaCha + * + * see https://tools.ietf.org/html/draft-arciszewski-xchacha-03 + */ +static WC_INLINE void wc_HChacha_block(ChaCha* ctx, word32 stream[CHACHA_CHUNK_WORDS/2], int nrounds) { + word32 x[CHACHA_CHUNK_WORDS]; + word32 i; + + for (i = 0; i < CHACHA_CHUNK_WORDS; i++) { + x[i] = ctx->X[i]; + } + + for (i = nrounds; i > 0; i -= 2) { + QUARTERROUND(0, 4, 8, 12) + QUARTERROUND(1, 5, 9, 13) + QUARTERROUND(2, 6, 10, 14) + QUARTERROUND(3, 7, 11, 15) + QUARTERROUND(0, 5, 10, 15) + QUARTERROUND(1, 6, 11, 12) + QUARTERROUND(2, 7, 8, 13) + QUARTERROUND(3, 4, 9, 14) + } + + for (i = 0; i < CHACHA_CHUNK_WORDS/4; ++i) + stream[i] = x[i]; + for (i = CHACHA_CHUNK_WORDS/4; i < CHACHA_CHUNK_WORDS/2; ++i) + stream[i] = x[i + CHACHA_CHUNK_WORDS/2]; +} + +/* XChaCha -- https://tools.ietf.org/html/draft-arciszewski-xchacha-03 */ +int wc_XChaCha_init(ChaCha *ctx, const byte *key, word32 keySz, const byte *nonce, word32 nonceSz) { + word32 k[CHACHA_MAX_KEY_SZ]; + byte iv[CHACHA_IV_BYTES]; + int ret; + + if (nonceSz < 24) + return BAD_FUNC_ARG; + + XMEMSET(iv, 0, 4); + XMEMCPY(iv + 4, nonce + 16, 8); + + if ((ret = wc_Chacha_SetKey(ctx, key, keySz)) < 0) + return ret; + + if ((ret = wc_Chacha_SetIV(ctx, nonce + 4, U8TO32_LITTLE(nonce))) < 0) + return ret; + + wc_HChacha_block(ctx, k, 20); + + XMEMCPY(&ctx->X[4], k, 8 * sizeof(word32)); + if ((ret = wc_Chacha_SetIV(ctx, iv, 0)) < 0) + return ret; + + XMEMSET(k, 0, sizeof k); + XMEMSET(iv, 0, sizeof iv); + + return 0; +} + +#endif /* HAVE_XCHACHA */ + + #ifdef __cplusplus extern "C" { #endif @@ -301,7 +367,6 @@ static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c, } } - /** * API to encrypt/decrypt a message of any size. */ @@ -361,6 +426,18 @@ int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input, return 0; } +void wc_ChaCha_purge_current_block(ChaCha* ctx) { + if (ctx->left > 0) { +#ifndef USE_INTEL_CHACHA_SPEEDUP + /* the algorithms in chacha_asm.S increment the counter for partial + * blocks, but wc_Chacha_encrypt_bytes() defers. + */ + ctx->X[CHACHA_MATRIX_CNT_IV] = PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]); +#endif + ctx->left = 0; + } +} + #endif /* HAVE_CHACHA*/ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index d2fcee007..508a585c4 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -293,4 +293,158 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, return ret; } +#ifdef HAVE_XCHACHA + +int wc_XChaCha20Poly1305_Init( + ChaChaPoly_Aead *aead, + const byte *ad, word32 ad_len, + const byte *nonce, word32 nonce_len, + const byte *key, word32 key_len, + int isEncrypt) +{ + byte authKey[CHACHA20_POLY1305_AEAD_KEYSIZE]; + int ret; + + if ((ad == NULL) || (nonce == NULL) || (key == NULL)) + return BAD_FUNC_ARG; + + if ((key_len != CHACHA20_POLY1305_AEAD_KEYSIZE) || + (nonce_len != XCHACHA20_POLY1305_AEAD_NONCE_SIZE)) + return BAD_FUNC_ARG; + + if ((ret = wc_XChaCha_init(&aead->chacha, key, key_len, nonce, nonce_len)) < 0) + return ret; + + XMEMSET(authKey, 0, sizeof authKey); + + /* Create the Poly1305 key */ + if ((ret = wc_Chacha_Process(&aead->chacha, authKey, authKey, + (word32)sizeof authKey)) < 0) + return ret; + /* advance to start of the next ChaCha block. */ + wc_ChaCha_purge_current_block(&aead->chacha); + + /* Initialize Poly1305 context */ + if ((ret = wc_Poly1305SetKey(&aead->poly, authKey, + (word32)sizeof authKey)) < 0) + return ret; + + if ((ret = wc_Poly1305Update(&aead->poly, ad, (word32)ad_len)) < 0) + return ret; + + if ((ret = wc_Poly1305_Pad(&aead->poly, (word32)ad_len)) < 0) + return ret; + + aead->isEncrypt = (byte)isEncrypt; + aead->state = CHACHA20_POLY1305_STATE_AAD; + + return 0; +} + +static WC_INLINE int wc_XChaCha20Poly1305_crypt_oneshot( + byte *dst, const size_t dst_space, + const byte *src, const size_t src_len, + const byte *ad, const size_t ad_len, + const byte *nonce, const size_t nonce_len, + const byte *key, const size_t key_len, + int isEncrypt) +{ + ChaChaPoly_Aead aead; + int ret; + ssize_t dst_len = isEncrypt ? + (ssize_t)src_len + POLY1305_DIGEST_SIZE : + (ssize_t)src_len - POLY1305_DIGEST_SIZE; + const byte *src_i; + byte *dst_i; + size_t src_len_rem; + + if ((dst == NULL) || (src == NULL)) + return BAD_FUNC_ARG; + + if ((ssize_t)dst_space < dst_len) + return BUFFER_E; + + if ((ret = wc_XChaCha20Poly1305_Init(&aead, ad, (word32)ad_len, + nonce, (word32)nonce_len, + key, (word32)key_len, 1)) < 0) + goto out; + + /* process the input in 16k pieces to accommodate src_lens that don't fit in a word32, + * and to exploit hot cache for the input data. + */ + for (src_i = src, src_len_rem = isEncrypt ? src_len : (size_t)dst_len, dst_i = dst; + src_len_rem > 0; + ) { + word32 this_src_len = + (src_len_rem > 16384) ? + 16384 : + (word32)src_len_rem; + + if ((ret = wc_Chacha_Process(&aead.chacha, dst_i, src_i, this_src_len)) < 0) + goto out; + + if ((ret = wc_Poly1305Update(&aead.poly, isEncrypt ? dst_i : src_i, this_src_len)) < 0) + goto out; + + src_len_rem -= (size_t)this_src_len; + src_i += this_src_len; + dst_i += this_src_len; + } + + if (aead.poly.leftover) { + if ((ret = wc_Poly1305_Pad(&aead.poly, (word32)aead.poly.leftover)) < 0) + return ret; + } + +#ifdef WORD64_AVAILABLE + ret = wc_Poly1305_EncodeSizes64(&aead.poly, ad_len, isEncrypt ? src_len : (size_t)dst_len); +#else + ret = wc_Poly1305_EncodeSizes(&aead.poly, ad_len, isEncrypt ? src_len : (size_t)dst_len); +#endif + if (ret < 0) + goto out; + + if (isEncrypt) + ret = wc_Poly1305Final(&aead.poly, dst + src_len); + else { + byte outAuthTag[POLY1305_DIGEST_SIZE]; + + if ((ret = wc_Poly1305Final(&aead.poly, outAuthTag)) < 0) + goto out; + + if (ConstantCompare(outAuthTag, src + dst_len, POLY1305_DIGEST_SIZE) != 0) { + ret = MAC_CMP_FAILED_E; + goto out; + } + } + + out: + + XMEMSET(&aead, 0, sizeof aead); + + return ret; +} + +int wc_XChaCha20Poly1305_encrypt_oneshot( + byte *dst, const size_t dst_space, + const byte *src, const size_t src_len, + const byte *ad, const size_t ad_len, + const byte *nonce, const size_t nonce_len, + const byte *key, const size_t key_len) +{ + return wc_XChaCha20Poly1305_crypt_oneshot(dst, dst_space, src, src_len, ad, ad_len, nonce, nonce_len, key, key_len, 1); +} + +int wc_XChaCha20Poly1305_decrypt_oneshot( + byte *dst, const size_t dst_space, + const byte *src, const size_t src_len, + const byte *ad, const size_t ad_len, + const byte *nonce, const size_t nonce_len, + const byte *key, const size_t key_len) +{ + return wc_XChaCha20Poly1305_crypt_oneshot(dst, dst_space, src, src_len, ad, ad_len, nonce, nonce_len, key, key_len, 0); +} + +#endif /* HAVE_XCHACHA */ + #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfcrypt/src/poly1305.c b/wolfcrypt/src/poly1305.c index 2fdd51436..4fde6be95 100644 --- a/wolfcrypt/src/poly1305.c +++ b/wolfcrypt/src/poly1305.c @@ -700,8 +700,6 @@ int wc_Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) } printf("\n"); #endif - if (ctx == NULL || (m == NULL && bytes > 0)) - return BAD_FUNC_ARG; #ifdef USE_INTEL_SPEEDUP #ifdef HAVE_INTEL_AVX2 @@ -837,6 +835,30 @@ int wc_Poly1305_EncodeSizes(Poly1305* ctx, word32 aadSz, word32 dataSz) return ret; } +#ifdef WORD64_AVAILABLE +int wc_Poly1305_EncodeSizes64(Poly1305* ctx, word64 aadSz, word64 dataSz) +{ + int ret; + word64 little64[2]; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef BIG_ENDIAN_ORDER + little64[0] = ByteReverseWord64(aadSz); + little64[1] = ByteReverseWord64(dataSz); +#else + little64[0] = aadSz; + little64[1] = dataSz; +#endif + + ret = wc_Poly1305Update(ctx, (byte *)little64, sizeof(little64)); + + return ret; +} +#endif + /* Takes in an initialized Poly1305 struct that has a key loaded and creates a MAC (tag) using recent TLS AEAD padding scheme. ctx : Initialized Poly1305 struct to use diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index d3d986d79..9c489bbb9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -311,7 +311,9 @@ static int arc4_test(void); static int hc128_test(void); static int rabbit_test(void); static int chacha_test(void); +static int XChaCha_test(void); static int chacha20_poly1305_aead_test(void); +static int XChaCha20Poly1305_test(void); static int des_test(void); static int des3_test(void); static int aes_test(void); @@ -857,6 +859,13 @@ initDefaultName(); test_pass("Chacha test passed!\n"); #endif +#ifdef HAVE_XCHACHA + if ( (ret = XChaCha_test()) != 0) + return err_sys("XChacha test failed!\n", ret); + else + test_pass("XChacha test passed!\n"); +#endif + #ifdef HAVE_POLY1305 if ( (ret = poly1305_test()) != 0) return err_sys("POLY1305 test failed!\n", ret); @@ -871,6 +880,13 @@ initDefaultName(); test_pass("ChaCha20-Poly1305 AEAD test passed!\n"); #endif +#if defined(HAVE_XCHACHA) && defined(HAVE_POLY1305) + if ( (ret = XChaCha20Poly1305_test()) != 0) + return err_sys("XChaCha20-Poly1305 AEAD test failed!\n", ret); + else + test_pass("XChaCha20-Poly1305 AEAD test passed!\n"); +#endif + #ifndef NO_DES3 if ( (ret = des_test()) != 0) return err_sys("DES test failed!\n", ret); @@ -10024,6 +10040,201 @@ static int idea_test(void) } #endif /* HAVE_IDEA */ +#ifdef HAVE_XCHACHA +static int XChaCha_test(void) { + int ret = -1; + + static const byte Plaintext[] = { + 0x54, 0x68, 0x65, 0x20, 0x64, 0x68, 0x6f, 0x6c, 0x65, 0x20, 0x28, 0x70, 0x72, 0x6f, 0x6e, 0x6f, /* The dhole (prono */ + 0x75, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x22, 0x64, 0x6f, 0x6c, 0x65, 0x22, 0x29, 0x20, 0x69, 0x73, /* unced "dole") is */ + 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x74, /* also known as t */ + 0x68, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x74, 0x69, 0x63, 0x20, 0x77, 0x69, 0x6c, 0x64, 0x20, /* he Asiatic wild */ + 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x72, 0x65, 0x64, 0x20, 0x64, 0x6f, 0x67, 0x2c, 0x20, 0x61, 0x6e, /* dog, red dog, an */ + 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x74, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x6f, 0x67, 0x2e, /* d whistling dog. */ + 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, /* It is about the */ + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x47, 0x65, 0x72, 0x6d, 0x61, /* size of a Germa */ + 0x6e, 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, 0x72, 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6c, /* n shepherd but l */ + 0x6f, 0x6f, 0x6b, 0x73, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x61, /* ooks more like a */ + 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 0x67, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x78, /* long-legged fox */ + 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x79, 0x20, 0x65, 0x6c, /* . This highly el */ + 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x6b, 0x69, 0x6c, 0x6c, 0x65, /* usive and skille */ + 0x64, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x73, /* d jumper is clas */ + 0x73, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x77, 0x6f, 0x6c, 0x76, /* sified with wolv */ + 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x79, 0x6f, 0x74, 0x65, 0x73, 0x2c, 0x20, 0x6a, 0x61, 0x63, /* es, coyotes, jac */ + 0x6b, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, 0x78, 0x65, 0x73, 0x20, /* kals, and foxes */ + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x78, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63, /* in the taxonomic */ + 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x20, 0x43, 0x61, 0x6e, 0x69, 0x64, 0x61, 0x65, 0x2e /* family Canidae. */ + }; + + static const byte Key[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + }; + + static const byte IV[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* @ABCDEFGHIJKLMNO */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58 }; /* PQRSTUVW */ + + static const byte Ciphertext[] = { + 0x45, 0x59, 0xab, 0xba, 0x4e, 0x48, 0xc1, 0x61, 0x02, 0xe8, 0xbb, 0x2c, 0x05, 0xe6, 0x94, 0x7f, + 0x50, 0xa7, 0x86, 0xde, 0x16, 0x2f, 0x9b, 0x0b, 0x7e, 0x59, 0x2a, 0x9b, 0x53, 0xd0, 0xd4, 0xe9, + 0x8d, 0x8d, 0x64, 0x10, 0xd5, 0x40, 0xa1, 0xa6, 0x37, 0x5b, 0x26, 0xd8, 0x0d, 0xac, 0xe4, 0xfa, + 0xb5, 0x23, 0x84, 0xc7, 0x31, 0xac, 0xbf, 0x16, 0xa5, 0x92, 0x3c, 0x0c, 0x48, 0xd3, 0x57, 0x5d, + 0x4d, 0x0d, 0x2c, 0x67, 0x3b, 0x66, 0x6f, 0xaa, 0x73, 0x10, 0x61, 0x27, 0x77, 0x01, 0x09, 0x3a, + 0x6b, 0xf7, 0xa1, 0x58, 0xa8, 0x86, 0x42, 0x92, 0xa4, 0x1c, 0x48, 0xe3, 0xa9, 0xb4, 0xc0, 0xda, + 0xec, 0xe0, 0xf8, 0xd9, 0x8d, 0x0d, 0x7e, 0x05, 0xb3, 0x7a, 0x30, 0x7b, 0xbb, 0x66, 0x33, 0x31, + 0x64, 0xec, 0x9e, 0x1b, 0x24, 0xea, 0x0d, 0x6c, 0x3f, 0xfd, 0xdc, 0xec, 0x4f, 0x68, 0xe7, 0x44, + 0x30, 0x56, 0x19, 0x3a, 0x03, 0xc8, 0x10, 0xe1, 0x13, 0x44, 0xca, 0x06, 0xd8, 0xed, 0x8a, 0x2b, + 0xfb, 0x1e, 0x8d, 0x48, 0xcf, 0xa6, 0xbc, 0x0e, 0xb4, 0xe2, 0x46, 0x4b, 0x74, 0x81, 0x42, 0x40, + 0x7c, 0x9f, 0x43, 0x1a, 0xee, 0x76, 0x99, 0x60, 0xe1, 0x5b, 0xa8, 0xb9, 0x68, 0x90, 0x46, 0x6e, + 0xf2, 0x45, 0x75, 0x99, 0x85, 0x23, 0x85, 0xc6, 0x61, 0xf7, 0x52, 0xce, 0x20, 0xf9, 0xda, 0x0c, + 0x09, 0xab, 0x6b, 0x19, 0xdf, 0x74, 0xe7, 0x6a, 0x95, 0x96, 0x74, 0x46, 0xf8, 0xd0, 0xfd, 0x41, + 0x5e, 0x7b, 0xee, 0x2a, 0x12, 0xa1, 0x14, 0xc2, 0x0e, 0xb5, 0x29, 0x2a, 0xe7, 0xa3, 0x49, 0xae, + 0x57, 0x78, 0x20, 0xd5, 0x52, 0x0a, 0x1f, 0x3f, 0xb6, 0x2a, 0x17, 0xce, 0x6a, 0x7e, 0x68, 0xfa, + 0x7c, 0x79, 0x11, 0x1d, 0x88, 0x60, 0x92, 0x0b, 0xc0, 0x48, 0xef, 0x43, 0xfe, 0x84, 0x48, 0x6c, + 0xcb, 0x87, 0xc2, 0x5f, 0x0a, 0xe0, 0x45, 0xf0, 0xcc, 0xe1, 0xe7, 0x98, 0x9a, 0x9a, 0xa2, 0x20, + 0xa2, 0x8b, 0xdd, 0x48, 0x27, 0xe7, 0x51, 0xa2, 0x4a, 0x6d, 0x5c, 0x62, 0xd7, 0x90, 0xa6, 0x63, + 0x93, 0xb9, 0x31, 0x11, 0xc1, 0xa5, 0x5d, 0xd7, 0x42, 0x1a, 0x10, 0x18, 0x49, 0x74, 0xc7, 0xc5 + }; + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + struct ChaCha *chacha = (struct ChaCha *)XMALLOC(sizeof *chacha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + byte *buf1 = (byte *)XMALLOC(sizeof Plaintext, NULL, DYNAMIC_TYPE_TMP_BUFFER); + byte *buf2 = (byte *)XMALLOC(sizeof Plaintext, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if ((chacha == NULL) || (buf1 == NULL) || (buf2 == NULL)) + ERROR_OUT(MEMORY_E, out); +#else + struct ChaCha chacha_buf, *chacha = &chacha_buf; + byte buf1[sizeof Plaintext]; + byte buf2[sizeof Plaintext]; +#endif + + ret = wc_XChaCha_init(chacha, Key, sizeof Key, IV, sizeof IV); + if (ret < 0) + ERROR_OUT(-4770, out); + + ret = wc_Chacha_Process(chacha, buf1, Plaintext, sizeof Plaintext); + if (ret < 0) + ERROR_OUT(-4771, out); + + if (XMEMCMP(buf1, Ciphertext, sizeof Plaintext)) + ERROR_OUT(-4772, out); + + ret = wc_XChaCha_init(chacha, Key, sizeof Key, IV, sizeof IV); + if (ret < 0) + ERROR_OUT(-4773, out); + + ret = wc_Chacha_Process(chacha, buf2, buf1, sizeof Plaintext); + if (ret < 0) + ERROR_OUT(-4774, out); + + if (XMEMCMP(buf2, Plaintext, sizeof Plaintext)) + ERROR_OUT(-4775, out); + + out: + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + if (chacha) + XFREE(chacha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf1) + XFREE(buf1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf2) + XFREE(buf2, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} +#endif /* HAVE_XCHACHA */ + +#if defined(HAVE_XCHACHA) && defined(HAVE_POLY1305) +static int XChaCha20Poly1305_test(void) { + int ret; + + static const byte Plaintext[] = { + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, /* Ladies and Gentl */ + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, /* emen of the clas */ + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, /* s of '99: If I c */ + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, /* ould offer you o */ + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, /* nly one tip for */ + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, /* the future, suns */ + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, /* creen would be i */ + 0x74, 0x2e }; /* t. */ + + static const byte AAD[] = { 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 }; /* PQRS........ */ + + static const byte Key[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + }; + + static const byte IV[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* @ABCDEFGHIJKLMNO */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 }; /* PQRSTUVW */ + + static const byte Ciphertext[] = { + 0xbd, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b, 0x95, 0x76, 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39, + 0x57, 0x2a, 0x17, 0x00, 0x25, 0x2b, 0xfa, 0xcc, 0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 0x6c, 0xbb, + 0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44, 0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39, + 0xae, 0x64, 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16, 0xcb, 0x96, 0xb7, 0x2e, 0x12, 0x13, 0xb4, 0x52, + 0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 0xd9, 0x45, 0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e, + 0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f, 0x76, 0xb2, 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9, + 0x21, 0xf9, 0x66, 0x4c, 0x97, 0x63, 0x7d, 0xa9, 0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 0x8b, 0x13, + 0xb5, 0x2e }; + + static const byte Tag[] = { + 0xc0, 0x87, 0x59, 0x24, 0xc1, 0xc7, 0x98, 0x79, 0x47, 0xde, 0xaf, 0xd8, 0x78, 0x0a, 0xcf, 0x49 + }; + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte *buf1 = (byte *)XMALLOC(sizeof Ciphertext + sizeof Tag, NULL, DYNAMIC_TYPE_TMP_BUFFER); + byte *buf2 = (byte *)XMALLOC(sizeof Plaintext, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#else + byte buf1[sizeof Ciphertext + sizeof Tag]; + byte buf2[sizeof Plaintext]; +#endif + + ret = wc_XChaCha20Poly1305_encrypt_oneshot(buf1, sizeof Ciphertext + sizeof Tag, + Plaintext, sizeof Plaintext, + AAD, sizeof AAD, + IV, sizeof IV, + Key, sizeof Key); + + if (ret < 0) { + printf("wc_XChaCha20Poly1305_encrypt_oneshot failed: %s\n",wc_GetErrorString(ret)); + ERROR_OUT(-4760, out); + } + + if (XMEMCMP(buf1, Ciphertext, sizeof Plaintext)) + ERROR_OUT(-4761, out); + + if (XMEMCMP(buf1 + sizeof Plaintext, Tag, CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE)) + ERROR_OUT(-4762, out); + + ret = wc_XChaCha20Poly1305_decrypt_oneshot(buf2, sizeof Plaintext, + buf1, sizeof Plaintext + sizeof Tag, + AAD, sizeof AAD, + IV, sizeof IV, + Key, sizeof Key); + + if (ret < 0) { + printf("wc_XChaCha20Poly1305_decrypt_oneshot failed: %s\n",wc_GetErrorString(ret)); + ERROR_OUT(-4763, out); + } + + if (XMEMCMP(buf2, Plaintext, sizeof Plaintext)) + ERROR_OUT(-4764, out); + + out: + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(buf1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(buf2, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} +#endif /* defined(HAVE_XCHACHA) && defined(HAVE_POLY1305) */ #ifndef WC_NO_RNG static int _rng_test(WC_RNG* rng, int errorOffset) diff --git a/wolfssl/wolfcrypt/chacha.h b/wolfssl/wolfcrypt/chacha.h index 584cd845d..d6c1b705d 100644 --- a/wolfssl/wolfcrypt/chacha.h +++ b/wolfssl/wolfcrypt/chacha.h @@ -92,8 +92,16 @@ WOLFSSL_API int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter); WOLFSSL_API int wc_Chacha_Process(ChaCha* ctx, byte* cipher, const byte* plain, word32 msglen); + +WOLFSSL_LOCAL void wc_ChaCha_purge_current_block(ChaCha* ctx); + WOLFSSL_API int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz); +#ifdef HAVE_XCHACHA +WOLFSSL_API int wc_XChaCha_init(ChaCha *ctx, const byte *key, word32 keySz, + const byte *nonce, word32 nonceSz); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/chacha20_poly1305.h b/wolfssl/wolfcrypt/chacha20_poly1305.h index d72514c5a..86c61c2ad 100644 --- a/wolfssl/wolfcrypt/chacha20_poly1305.h +++ b/wolfssl/wolfcrypt/chacha20_poly1305.h @@ -48,6 +48,7 @@ or Authenticated Encryption with Additional Data (AEAD) algorithm. #define CHACHA20_POLY1305_AEAD_IV_SIZE 12 #define CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE 16 #define CHACHA20_POLY1305_MAX 4294967295U +#define XCHACHA20_POLY1305_AEAD_NONCE_SIZE 24 enum { CHACHA20_POLY_1305_ENC_TYPE = 8, /* cipher unique type */ @@ -123,6 +124,30 @@ WOLFSSL_API int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, WOLFSSL_API int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); +#ifdef HAVE_XCHACHA + +WOLFSSL_API int wc_XChaCha20Poly1305_Init( + ChaChaPoly_Aead* aead, + const byte *ad, word32 ad_len, + const byte *inKey, word32 inKeySz, + const byte *inIV, word32 inIVSz, + int isEncrypt); + +WOLFSSL_API int wc_XChaCha20Poly1305_encrypt_oneshot( + byte *dst, const size_t dst_space, + const byte *src, const size_t src_len, + const byte *ad, const size_t ad_len, + const byte *nonce, const size_t nonce_len, + const byte *key, const size_t key_len); + +WOLFSSL_API int wc_XChaCha20Poly1305_decrypt_oneshot( + byte *dst, const size_t dst_space, + const byte *src, const size_t src_len, + const byte *ad, const size_t ad_len, + const byte *nonce, const size_t nonce_len, + const byte *key, const size_t key_len); + +#endif /* HAVE_XCHACHA */ #ifdef __cplusplus } /* extern "C" */ diff --git a/wolfssl/wolfcrypt/poly1305.h b/wolfssl/wolfcrypt/poly1305.h index 790ed5db1..d0bb2ff8e 100644 --- a/wolfssl/wolfcrypt/poly1305.h +++ b/wolfssl/wolfcrypt/poly1305.h @@ -116,6 +116,9 @@ WOLFSSL_API int wc_Poly1305Final(Poly1305* poly1305, byte* tag); /* AEAD Functions */ WOLFSSL_API int wc_Poly1305_Pad(Poly1305* ctx, word32 lenToPad); WOLFSSL_API int wc_Poly1305_EncodeSizes(Poly1305* ctx, word32 aadSz, word32 dataSz); +#ifdef WORD64_AVAILABLE +WOLFSSL_API int wc_Poly1305_EncodeSizes64(Poly1305* ctx, word64 aadSz, word64 dataSz); +#endif WOLFSSL_API int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, byte* input, word32 sz, byte* tag, word32 tagSz);