diff --git a/configure.ac b/configure.ac index 7b36bbcf6..13f1fdac5 100644 --- a/configure.ac +++ b/configure.ac @@ -401,6 +401,21 @@ fi AM_CONDITIONAL([BUILD_AESNI], [test "x$ENABLED_AESNI" = "xyes"]) +# POLY1305 +AC_ARG_ENABLE([poly1305], + [ --enable-poly1305 Enable CyaSSL POLY1305 support (default: disabled)], + [ ENABLED_POLY1305=$enableval ], + [ ENABLED_POLY1305=no ] + ) + +if test "$ENABLED_POLY1305" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_POLY1305" +fi + +AM_CONDITIONAL([BUILD_POLY1305], [test "x$ENABLED_POLY1305" = "xyes"]) + + # Camellia AC_ARG_ENABLE([camellia], [ --enable-camellia Enable CyaSSL Camellia support (default: disabled)], @@ -1062,6 +1077,21 @@ fi AM_CONDITIONAL([BUILD_RABBIT], [test "x$ENABLED_RABBIT" = "xyes"]) +# CHACHA +AC_ARG_ENABLE([chacha], + [ --enable-chacha Enable CHACHA (default: disabled)], + [ ENABLED_CHACHA=$enableval ], + [ ENABLED_CHACHA=no ] + ) + +if test "$ENABLED_CHACHA" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_CHACHA" +fi + +AM_CONDITIONAL([BUILD_CHACHA], [test "x$ENABLED_CHACHA" = "xyes"]) + + # FIPS AC_ARG_ENABLE([fips], [ --enable-fips Enable FIPS 140-2 (default: disabled)], @@ -1797,11 +1827,13 @@ echo " * certgen: $ENABLED_CERTGEN" echo " * certreq: $ENABLED_CERTREQ" echo " * HC-128: $ENABLED_HC128" echo " * RABBIT: $ENABLED_RABBIT" +echo " * CHACHA: $ENABLED_CHACHA" echo " * Hash DRBG: $ENABLED_HASHDRBG" echo " * PWDBASED: $ENABLED_PWDBASED" echo " * HKDF: $ENABLED_HKDF" echo " * MD4: $ENABLED_MD4" echo " * PSK: $ENABLED_PSK" +echo " * Poly1305: $ENABLED_POLY1305" echo " * LEANPSK: $ENABLED_LEANPSK" echo " * RSA: $ENABLED_RSA" echo " * DSA: $ENABLED_DSA" diff --git a/ctaocrypt/benchmark/benchmark.c b/ctaocrypt/benchmark/benchmark.c index f51966f49..929e42266 100644 --- a/ctaocrypt/benchmark/benchmark.c +++ b/ctaocrypt/benchmark/benchmark.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -85,10 +87,12 @@ void bench_des(void); void bench_arc4(void); void bench_hc128(void); void bench_rabbit(void); +void bench_chacha(void); void bench_aes(int); void bench_aesgcm(void); void bench_aesccm(void); void bench_aesctr(void); +void bench_poly1305(void); void bench_camellia(void); void bench_md5(void); @@ -189,6 +193,9 @@ int benchmark_test(void *args) #ifndef NO_RABBIT bench_rabbit(); #endif +#ifdef HAVE_CHACHA + bench_chacha(); +#endif #ifndef NO_DES3 bench_des(); #endif @@ -198,6 +205,9 @@ int benchmark_test(void *args) #ifndef NO_MD5 bench_md5(); #endif +#ifdef HAVE_POLY1305 + bench_poly1305(); +#endif #ifndef NO_SHA bench_sha(); #endif @@ -425,6 +435,41 @@ void bench_aesccm(void) #endif +#ifdef HAVE_POLY1305 +void bench_poly1305() +{ + Poly1305 enc; + byte mac[16]; + double start, total, persec; + int i; + int ret; + + + ret = Poly1305SetKey(&enc, key, 32); + if (ret != 0) { + printf("Poly1305SetKey failed, ret = %d\n", ret); + return; + } + start = current_time(1); + + for(i = 0; i < numBlocks; i++) + Poly1305Update(&enc, plain, sizeof(plain)); + + Poly1305Final(&enc, mac); + total = current_time(0) - start; + + persec = 1 / total * numBlocks; +#ifdef BENCH_EMBEDDED + /* since using kB, convert to MB/s */ + persec = persec / 1024; +#endif + + printf("POLY1305 %d %s took %5.3f seconds, %7.3f MB/s\n", numBlocks, + blockType, total, persec); +} +#endif /* HAVE_POLY1305 */ + + #ifdef HAVE_CAMELLIA void bench_camellia(void) { @@ -580,6 +625,33 @@ void bench_rabbit(void) #endif /* NO_RABBIT */ +#ifdef HAVE_CHACHA +void bench_chacha(void) +{ + ChaCha enc; + double start, total, persec; + int i; + + Chacha_SetKey(&enc, key, 16); + start = current_time(1); + + for (i = 0; i < numBlocks; i++) { + Chacha_SetIV(&enc, iv, 0); + Chacha_Process(&enc, cipher, plain, sizeof(plain)); + } + total = current_time(0) - start; + persec = 1 / total * numBlocks; +#ifdef BENCH_EMBEDDED + /* since using kB, convert to MB/s */ + persec = persec / 1024; +#endif + + printf("CHACHA %d %s took %5.3f seconds, %7.3f MB/s\n", numBlocks, blockType, total, persec); + +} +#endif /* HAVE_CHACHA*/ + + #ifndef NO_MD5 void bench_md5(void) { diff --git a/ctaocrypt/ctaocrypt.vcproj b/ctaocrypt/ctaocrypt.vcproj index d07147d57..0f8779e04 100755 --- a/ctaocrypt/ctaocrypt.vcproj +++ b/ctaocrypt/ctaocrypt.vcproj @@ -216,6 +216,10 @@ RelativePath=".\include\rabbit.h" > + + @@ -304,6 +308,10 @@ RelativePath=".\src\rabbit.c" > + + diff --git a/ctaocrypt/src/chacha.c b/ctaocrypt/src/chacha.c new file mode 100644 index 000000000..9fc8e7be1 --- /dev/null +++ b/ctaocrypt/src/chacha.c @@ -0,0 +1,250 @@ +/* chacha.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL 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. + * + * CyaSSL 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-1301, USA + * + * based from + * chacha-ref.c version 20080118 + * D. J. Bernstein + * Public domain. + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef HAVE_CHACHA + +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #include +#endif + +#ifdef CHACHA_AEAD_TEST + #include +#endif + +#ifdef BIG_ENDIAN_ORDER + #define LITTLE32(x) ByteReverseWord32(x) +#else + #define LITTLE32(x) (x) +#endif + +/* Number of rounds */ +#define ROUNDS 20 + +#define U32C(v) (v##U) +#define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF)) +#define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0]) + +#define ROTATE(v,c) rotlFixed(v, c) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); + + +/** + * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version + * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB. + */ +int Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter) +{ + word32 temp[3]; /* used for alignment of memory */ + XMEMSET(temp, 0, 12); + + if (ctx == NULL) + return BAD_FUNC_ARG; + +#ifdef CHACHA_AEAD_TEST + word32 i; + printf("NONCE : "); + for (i = 0; i < 12; i++) { + printf("%02x", inIv[i]); + } + printf("\n\n"); +#endif + + XMEMCPY(temp, inIv, 12); + + ctx->X[12] = counter; /* block counter */ + ctx->X[13] = temp[0]; /* fixed variable from nonce */ + ctx->X[14] = temp[1]; /* counter from nonce */ + ctx->X[15] = temp[2]; /* counter from nonce */ + + return 0; +} + +/* "expand 32-byte k" as unsigned 32 byte */ +static const word32 sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574}; +/* "expand 16-byte k" as unsigned 16 byte */ +static const word32 tau[4] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574}; + +/** + * Key setup. 8 word iv (nonce) + */ +int Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz) +{ + const word32* constants; + const byte* k; + + if (ctx == NULL) + return BAD_FUNC_ARG; + +#ifdef XSTREAM_ALIGN + word32 alignKey[keySz / 4]; + if ((word)key % 4) { + CYASSL_MSG("ChachaSetKey unaligned key"); + XMEMCPY(alignKey, key, sizeof(alignKey)); + k = (byte*)alignKey; + } + else { + k = key; + } +#else + k = key; +#endif /* XSTREAM_ALIGN */ + +#ifdef CHACHA_AEAD_TEST + word32 i; + printf("ChaCha key used :\n"); + for (i = 0; i < keySz; i++) { + printf("%02x", key[i]); + if ((i + 1) % 8 == 0) + printf("\n"); + } + printf("\n\n"); +#endif + + ctx->X[4] = U8TO32_LITTLE(k + 0); + ctx->X[5] = U8TO32_LITTLE(k + 4); + ctx->X[6] = U8TO32_LITTLE(k + 8); + ctx->X[7] = U8TO32_LITTLE(k + 12); + if (keySz == 32) { + k += 16; + constants = sigma; + } + else { + /* key size of 128 */ + if (keySz != 16) + return BAD_FUNC_ARG; + + constants = tau; + } + ctx->X[ 8] = U8TO32_LITTLE(k + 0); + ctx->X[ 9] = U8TO32_LITTLE(k + 4); + ctx->X[10] = U8TO32_LITTLE(k + 8); + ctx->X[11] = U8TO32_LITTLE(k + 12); + ctx->X[ 0] = U8TO32_LITTLE(constants + 0); + ctx->X[ 1] = U8TO32_LITTLE(constants + 1); + ctx->X[ 2] = U8TO32_LITTLE(constants + 2); + ctx->X[ 3] = U8TO32_LITTLE(constants + 3); + + return 0; +} + +/** + * Converts word into bytes with rotations having been done. + */ +static INLINE void Chacha_wordtobyte(word32 output[16], const word32 input[16]) +{ + word32 x[16]; + word32 i; + + for (i = 0; i < 16; i++) { + x[i] = input[i]; + } + + for (i = (ROUNDS); 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 < 16; i++) { + x[i] = PLUS(x[i], input[i]); + } + + for (i = 0; i < 16; i++) { + output[i] = LITTLE32(x[i]); + } +} + +/** + * Encrypt a stream of bytes + */ +static void Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c, + word32 bytes) +{ + byte* output; + word32 temp[16]; /* used to make sure aligned */ + word32 i; + + output = (byte*)temp; + + if (!bytes) return; + for (;;) { + Chacha_wordtobyte(temp, ctx->X); + ctx->X[12] = PLUSONE(ctx->X[12]); + if (bytes <= 64) { + for (i = 0; i < bytes; ++i) { + c[i] = m[i] ^ output[i]; + } + return; + } + for (i = 0; i < 64; ++i) { + c[i] = m[i] ^ output[i]; + } + bytes -= 64; + c += 64; + m += 64; + } +} + +/** + * API to encrypt/decrypt a message of any size. + */ +int Chacha_Process(ChaCha* ctx, byte* output, const byte* input, word32 msglen) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + Chacha_encrypt_bytes(ctx, input, output, msglen); + + return 0; +} + +#endif /* HAVE_CHACHA*/ + diff --git a/ctaocrypt/src/poly1305.c b/ctaocrypt/src/poly1305.c new file mode 100644 index 000000000..c73a9cb49 --- /dev/null +++ b/ctaocrypt/src/poly1305.c @@ -0,0 +1,538 @@ +/* poly1305.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL 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. + * + * CyaSSL 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-1301, USA + * + * Based off the public domain implementations by Andrew Moon + * and Daniel J. Bernstein + */ + +#ifdef HAVE_POLY1305 + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #include +#endif +#ifdef CHACHA_AEAD_TEST + #include +#endif + +#ifdef _MSC_VER + /* 4127 warning constant while(1) */ + #pragma warning(disable: 4127) +#endif + +#if defined(POLY130564) + + #if defined(_MSC_VER) + #define POLY1305_NOINLINE __declspec(noinline) + #elif defined(__GNUC__) + #define POLY1305_NOINLINE __attribute__((noinline)) + #else + #define POLY1305_NOINLINE + #endif + + #if defined(_MSC_VER) + #include + + typedef struct word128 { + word64 lo; + word64 hi; + } word128; + + #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) + #define ADD(out, in) { word64 t = out.lo; out.lo += in.lo; + out.hi += (out.lo < t) + in.hi; } + #define ADDLO(out, in) { word64 t = out.lo; out.lo += in; + out.hi += (out.lo < t); } + #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) + #define LO(in) (in.lo) + + #elif defined(__GNUC__) + #if defined(__SIZEOF_INT128__) + typedef unsigned __int128 word128; + #else + typedef unsigned word128 __attribute__((mode(TI))); + #endif + + #define MUL(out, x, y) out = ((word128)x * y) + #define ADD(out, in) out += in + #define ADDLO(out, in) out += in + #define SHR(in, shift) (word64)(in >> (shift)) + #define LO(in) (word64)(in) + #endif + + static word64 U8TO64(const byte* p) { + return + (((word64)(p[0] & 0xff) ) | + ((word64)(p[1] & 0xff) << 8) | + ((word64)(p[2] & 0xff) << 16) | + ((word64)(p[3] & 0xff) << 24) | + ((word64)(p[4] & 0xff) << 32) | + ((word64)(p[5] & 0xff) << 40) | + ((word64)(p[6] & 0xff) << 48) | + ((word64)(p[7] & 0xff) << 56)); + } + + static void U64TO8(byte* p, word64 v) { + p[0] = (v ) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + p[4] = (v >> 32) & 0xff; + p[5] = (v >> 40) & 0xff; + p[6] = (v >> 48) & 0xff; + p[7] = (v >> 56) & 0xff; + } + +#else /* if not 64 bit then use 32 bit */ + + static word32 U8TO32(const byte *p) { + return + (((word32)(p[0] & 0xff) ) | + ((word32)(p[1] & 0xff) << 8) | + ((word32)(p[2] & 0xff) << 16) | + ((word32)(p[3] & 0xff) << 24)); + } + + static void U32TO8(byte *p, word32 v) { + p[0] = (v ) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + } +#endif + +static void poly1305_blocks(Poly1305* ctx, const unsigned char *m, + size_t bytes) { +#ifdef POLY130564 + + const word64 hibit = (ctx->final) ? 0 : ((word64)1 << 40); /* 1 << 128 */ + word64 r0,r1,r2; + word64 s1,s2; + word64 h0,h1,h2; + word64 c; + word128 d0,d1,d2,d; + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); + + while (bytes >= POLY1305_BLOCK_SIZE) { + word64 t0,t1; + + /* h += m[i] */ + t0 = U8TO64(&m[0]); + t1 = U8TO64(&m[8]); + + h0 += (( t0 ) & 0xfffffffffff); + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); + h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; + + /* h *= r */ + MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); + MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); + MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); + + /* (partial) h %= p */ + c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; + ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; + ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; + h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; + h1 += c; + + m += POLY1305_BLOCK_SIZE; + bytes -= POLY1305_BLOCK_SIZE; + } + + ctx->h[0] = h0; + ctx->h[1] = h1; + ctx->h[2] = h2; + +#else /* if not 64 bit then use 32 bit */ + + const word32 hibit = (ctx->final) ? 0 : (1 << 24); /* 1 << 128 */ + word32 r0,r1,r2,r3,r4; + word32 s1,s2,s3,s4; + word32 h0,h1,h2,h3,h4; + word64 d0,d1,d2,d3,d4; + word32 c; + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + r3 = ctx->r[3]; + r4 = ctx->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + h3 = ctx->h[3]; + h4 = ctx->h[4]; + + while (bytes >= POLY1305_BLOCK_SIZE) { + /* h += m[i] */ + h0 += (U8TO32(m+ 0) ) & 0x3ffffff; + h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m+12) >> 8) | hibit; + + /* h *= r */ + d0 = ((word64)h0 * r0) + ((word64)h1 * s4) + ((word64)h2 * s3) + + ((word64)h3 * s2) + ((word64)h4 * s1); + d1 = ((word64)h0 * r1) + ((word64)h1 * r0) + ((word64)h2 * s4) + + ((word64)h3 * s3) + ((word64)h4 * s2); + d2 = ((word64)h0 * r2) + ((word64)h1 * r1) + ((word64)h2 * r0) + + ((word64)h3 * s4) + ((word64)h4 * s3); + d3 = ((word64)h0 * r3) + ((word64)h1 * r2) + ((word64)h2 * r1) + + ((word64)h3 * r0) + ((word64)h4 * s4); + d4 = ((word64)h0 * r4) + ((word64)h1 * r3) + ((word64)h2 * r2) + + ((word64)h3 * r1) + ((word64)h4 * r0); + + /* (partial) h %= p */ + c = (word32)(d0 >> 26); h0 = (word32)d0 & 0x3ffffff; + d1 += c; c = (word32)(d1 >> 26); h1 = (word32)d1 & 0x3ffffff; + d2 += c; c = (word32)(d2 >> 26); h2 = (word32)d2 & 0x3ffffff; + d3 += c; c = (word32)(d3 >> 26); h3 = (word32)d3 & 0x3ffffff; + d4 += c; c = (word32)(d4 >> 26); h4 = (word32)d4 & 0x3ffffff; + h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; + h1 += c; + + m += POLY1305_BLOCK_SIZE; + bytes -= POLY1305_BLOCK_SIZE; + } + + ctx->h[0] = h0; + ctx->h[1] = h1; + ctx->h[2] = h2; + ctx->h[3] = h3; + ctx->h[4] = h4; + +#endif /* end of 64 bit cpu blocks or 32 bit cpu */ +} + + +int Poly1305SetKey(Poly1305* ctx, const byte* key, word32 keySz) { + + if (keySz != 32 || ctx == NULL) + return BAD_FUNC_ARG; + +#ifdef CHACHA_AEAD_TEST + word32 k; + printf("Poly key used:\n"); + for (k = 0; k < keySz; k++) { + printf("%02x", key[k]); + if ((k+1) % 8 == 0) + printf("\n"); + } + printf("\n"); +#endif + +#if defined(POLY130564) + + word64 t0,t1; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + t0 = U8TO64(key + 0); + t1 = U8TO64(key + 8); + + ctx->r[0] = ( t0 ) & 0xffc0fffffff; + ctx->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + ctx->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; + + /* h (accumulator) = 0 */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + + /* save pad for later */ + ctx->pad[0] = U8TO64(key + 16); + ctx->pad[1] = U8TO64(key + 24); + +#else /* if not 64 bit then use 32 bit */ + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + ctx->r[0] = (U8TO32(key + 0) ) & 0x3ffffff; + ctx->r[1] = (U8TO32(key + 3) >> 2) & 0x3ffff03; + ctx->r[2] = (U8TO32(key + 6) >> 4) & 0x3ffc0ff; + ctx->r[3] = (U8TO32(key + 9) >> 6) & 0x3f03fff; + ctx->r[4] = (U8TO32(key + 12) >> 8) & 0x00fffff; + + /* h = 0 */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + ctx->h[3] = 0; + ctx->h[4] = 0; + + /* save pad for later */ + ctx->pad[0] = U8TO32(key + 16); + ctx->pad[1] = U8TO32(key + 20); + ctx->pad[2] = U8TO32(key + 24); + ctx->pad[3] = U8TO32(key + 28); + +#endif + + ctx->leftover = 0; + ctx->final = 0; + + return 0; +} + + +int Poly1305Final(Poly1305* ctx, byte* mac) { + + if (ctx == NULL) + return BAD_FUNC_ARG; + +#if defined(POLY130564) + + word64 h0,h1,h2,c; + word64 g0,g1,g2; + word64 t0,t1; + + /* process the remaining block */ + if (ctx->leftover) { + size_t i = ctx->leftover; + ctx->buffer[i] = 1; + for (i = i + 1; i < POLY1305_BLOCK_SIZE; i++) + ctx->buffer[i] = 0; + ctx->final = 1; + poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE); + } + + /* fully carry h */ + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + + c = (h1 >> 44); h1 &= 0xfffffffffff; + h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; + h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; + h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; + h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; + h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; + g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; + g2 = h2 + c - ((word64)1 << 42); + + /* select h if h < p, or h + -p if h >= p */ + c = (g2 >> ((sizeof(word64) * 8) - 1)) - 1; + g0 &= c; + g1 &= c; + g2 &= c; + c = ~c; + h0 = (h0 & c) | g0; + h1 = (h1 & c) | g1; + h2 = (h2 & c) | g2; + + /* h = (h + pad) */ + t0 = ctx->pad[0]; + t1 = ctx->pad[1]; + + h0 += (( t0 ) & 0xfffffffffff) ; + c = (h0 >> 44); h0 &= 0xfffffffffff; + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; + c = (h1 >> 44); h1 &= 0xfffffffffff; + h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; + h2 &= 0x3ffffffffff; + + /* mac = h % (2^128) */ + h0 = ((h0 ) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + U64TO8(mac + 0, h0); + U64TO8(mac + 8, h1); + + /* zero out the state */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + ctx->r[0] = 0; + ctx->r[1] = 0; + ctx->r[2] = 0; + ctx->pad[0] = 0; + ctx->pad[1] = 0; + +#else /* if not 64 bit then use 32 bit */ + + word32 h0,h1,h2,h3,h4,c; + word32 g0,g1,g2,g3,g4; + word64 f; + word32 mask; + + /* process the remaining block */ + if (ctx->leftover) { + size_t i = ctx->leftover; + ctx->buffer[i++] = 1; + for (; i < POLY1305_BLOCK_SIZE; i++) + ctx->buffer[i] = 0; + ctx->final = 1; + poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE); + } + + /* fully carry h */ + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + h3 = ctx->h[3]; + h4 = ctx->h[4]; + + c = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + c - (1 << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(word32) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (word64)h0 + ctx->pad[0] ; h0 = (word32)f; + f = (word64)h1 + ctx->pad[1] + (f >> 32); h1 = (word32)f; + f = (word64)h2 + ctx->pad[2] + (f >> 32); h2 = (word32)f; + f = (word64)h3 + ctx->pad[3] + (f >> 32); h3 = (word32)f; + + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); + + /* zero out the state */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + ctx->h[3] = 0; + ctx->h[4] = 0; + ctx->r[0] = 0; + ctx->r[1] = 0; + ctx->r[2] = 0; + ctx->r[3] = 0; + ctx->r[4] = 0; + ctx->pad[0] = 0; + ctx->pad[1] = 0; + ctx->pad[2] = 0; + ctx->pad[3] = 0; + +#endif + + return 0; +} + + +int Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) { + + if (ctx == NULL) + return BAD_FUNC_ARG; + +#ifdef CHACHA_AEAD_TEST + word32 k; + printf("Raw input to poly:\n"); + for (k = 0; k < bytes; k++) { + printf("%02x", m[k]); + if ((k+1) % 16 == 0) + printf("\n"); + } + printf("\n"); +#endif + size_t i; + + /* handle leftover */ + if (ctx->leftover) { + size_t want = (POLY1305_BLOCK_SIZE - ctx->leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + ctx->buffer[ctx->leftover + i] = m[i]; + bytes -= want; + m += want; + ctx->leftover += want; + if (ctx->leftover < POLY1305_BLOCK_SIZE) + return 0; + poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE); + ctx->leftover = 0; + } + + /* process full blocks */ + if (bytes >= POLY1305_BLOCK_SIZE) { + size_t want = (bytes & ~(POLY1305_BLOCK_SIZE - 1)); + poly1305_blocks(ctx, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) + ctx->buffer[ctx->leftover + i] = m[i]; + ctx->leftover += bytes; + } + return 0; +} +#endif /* HAVE_POLY1305 */ + diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index 7f7191cb0..73011d6da 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -48,12 +48,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #ifdef HAVE_ECC @@ -152,9 +154,11 @@ int hkdf_test(void); int arc4_test(void); int hc128_test(void); int rabbit_test(void); +int chacha_test(void); int des_test(void); int des3_test(void); int aes_test(void); +int poly1305_test(void); int aesgcm_test(void); int gmac_test(void); int aesccm_test(void); @@ -367,6 +371,13 @@ void ctaocrypt_test(void* args) printf( "Rabbit test passed!\n"); #endif +#ifdef HAVE_CHACHA + if ( (ret = chacha_test()) != 0) + err_sys("Chacha test failed!\n", ret); + else + printf( "Chacha test passed!\n"); +#endif + #ifndef NO_DES3 if ( (ret = des_test()) != 0) err_sys("DES test failed!\n", ret); @@ -387,6 +398,13 @@ void ctaocrypt_test(void* args) else printf( "AES test passed!\n"); +#ifdef HAVE_POLY1305 + if ( (ret = poly1305_test()) != 0) + err_sys("POLY1305 test failed!\n", ret); + else + printf( "POLY1305 test passed!\n"); +#endif + #ifdef HAVE_AESGCM if ( (ret = aesgcm_test()) != 0) err_sys("AES-GCM test failed!\n", ret); @@ -1816,6 +1834,107 @@ int rabbit_test(void) #endif /* NO_RABBIT */ +#ifdef HAVE_CHACHA +int chacha_test(void) +{ + byte cipher[32]; + byte plain[32]; + byte input[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + word32 keySz; + int i; + int times = 4; + + const byte key1[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + const byte key2[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 + }; + + const byte key3[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + /* 128 bit key */ + const byte key4[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + + const byte* keys[] = {key1, key2, key3, key4}; + + const byte ivs1[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + const byte ivs2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + const byte ivs3[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}; + const byte ivs4[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + + const byte* ivs[] = {ivs1, ivs2, ivs3, ivs4}; + + + byte a[] = {0x76,0xb8,0xe0,0xad,0xa0,0xf1,0x3d,0x90}; + byte b[] = {0x45,0x40,0xf0,0x5a,0x9f,0x1f,0xb2,0x96}; + byte c[] = {0xde,0x9c,0xba,0x7b,0xf3,0xd6,0x9e,0xf5}; + byte d[] = {0x89,0x67,0x09,0x52,0x60,0x83,0x64,0xfd}; + + byte* test_chacha[4]; + + test_chacha[0] = a; + test_chacha[1] = b; + test_chacha[2] = c; + test_chacha[3] = d; + + for (i = 0; i < times; ++i) { + if (i < 3) { + keySz = 32; + } + else { + keySz = 16; + } + ChaCha enc; + ChaCha dec; + + XMEMCPY(plain, keys[i], keySz); + XMEMSET(cipher, 0, 32); + XMEMCPY(cipher + 4, ivs[i], 8); + + Chacha_SetKey(&enc, keys[i], keySz); + Chacha_SetKey(&dec, keys[i], keySz); + + Chacha_SetIV(&enc, cipher,0); + Chacha_SetIV(&dec, cipher,0); + XMEMCPY(plain, input, 8); + + Chacha_Process(&enc, cipher, plain, (word32)8); + Chacha_Process(&dec, plain, cipher, (word32)8); + + if (memcmp(test_chacha[i], cipher, 8)) + return -130 - 5 - i; + + if (memcmp(plain, input, 8)) + return -130 - i; + } + + return 0; +} +#endif /* HAVE_CHACHA */ + + #ifndef NO_DES3 int des_test(void) { @@ -2126,6 +2245,96 @@ int aes_test(void) return 0; } +#ifdef HAVE_POLY1305 +int poly1305_test(void) +{ + int ret = 0; + int i; + byte tag[16]; + Poly1305 enc; + + const byte msg[] = + { + 0x43,0x72,0x79,0x70,0x74,0x6f,0x67,0x72, + 0x61,0x70,0x68,0x69,0x63,0x20,0x46,0x6f, + 0x72,0x75,0x6d,0x20,0x52,0x65,0x73,0x65, + 0x61,0x72,0x63,0x68,0x20,0x47,0x72,0x6f, + 0x75,0x70 + }; + + const byte msg2[] = + { + 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72, + 0x6c,0x64,0x21 + }; + + const byte msg3[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + const byte correct[] = + { + 0xa8,0x06,0x1d,0xc1,0x30,0x51,0x36,0xc6, + 0xc2,0x2b,0x8b,0xaf,0x0c,0x01,0x27,0xa9 + + }; + + const byte correct2[] = + { + 0xa6,0xf7,0x45,0x00,0x8f,0x81,0xc9,0x16, + 0xa2,0x0d,0xcc,0x74,0xee,0xf2,0xb2,0xf0 + }; + + const byte correct3[] = + { + 0x49,0xec,0x78,0x09,0x0e,0x48,0x1e,0xc6, + 0xc2,0x6b,0x33,0xb9,0x1c,0xcc,0x03,0x07 + }; + + const byte key[] = { + 0x85,0xd6,0xbe,0x78,0x57,0x55,0x6d,0x33, + 0x7f,0x44,0x52,0xfe,0x42,0xd5,0x06,0xa8, + 0x01,0x03,0x80,0x8a,0xfb,0x0d,0xb2,0xfd, + 0x4a,0xbf,0xf6,0xaf,0x41,0x49,0xf5,0x1b + }; + + const byte key2[] = { + 0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20, + 0x33,0x32,0x2d,0x62,0x79,0x74,0x65,0x20, + 0x6b,0x65,0x79,0x20,0x66,0x6f,0x72,0x20, + 0x50,0x6f,0x6c,0x79,0x31,0x33,0x30,0x35 + }; + + const byte* msgs[] = {msg, msg2, msg3}; + word32 szm[] = {sizeof(msg),sizeof(msg2),sizeof(msg3)}; + const byte* keys[] = {key, key2, key2}; + const byte* tests[] = {correct, correct2, correct3}; + + for (i = 0; i < 3; i++) { + ret = Poly1305SetKey(&enc, keys[i], 32); + if (ret != 0) + return -1001; + + ret = Poly1305Update(&enc, msgs[i], szm[i]); + if (ret != 0) + return -1005; + + ret = Poly1305Final(&enc, tag); + if (ret != 0) + return -60; + + if (memcmp(tag, tests[i], sizeof(tag))) + return -61; + } + + return 0; +} +#endif /* HAVE_POLY1305 */ + #ifdef HAVE_AESGCM int aesgcm_test(void) { diff --git a/cyassl/ctaocrypt/chacha.h b/cyassl/ctaocrypt/chacha.h new file mode 100644 index 000000000..baad676af --- /dev/null +++ b/cyassl/ctaocrypt/chacha.h @@ -0,0 +1,55 @@ +/* chacha.h + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL 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. + * + * CyaSSL 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-1301, USA + */ + +#ifndef CHACHA_H +#define CHACHA_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + CHACHA_ENC_TYPE = 7 /* cipher unique type */ +}; + +typedef struct ChaCha { + word32 X[16]; /* state of cipher */ +} ChaCha; + +CYASSL_API int Chacha_Process(ChaCha* ctx, byte* cipher, const byte* plain, + word32 msglen); +CYASSL_API int Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz); + +/** + * IV(nonce) changes with each record + * counter is for what value the block counter should start ... usually 0 + */ +CYASSL_API int Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif + diff --git a/cyassl/ctaocrypt/include.am b/cyassl/ctaocrypt/include.am index b3cf210a4..f03b67334 100644 --- a/cyassl/ctaocrypt/include.am +++ b/cyassl/ctaocrypt/include.am @@ -6,6 +6,7 @@ nobase_include_HEADERS+= \ cyassl/ctaocrypt/arc4.h \ cyassl/ctaocrypt/asn.h \ cyassl/ctaocrypt/asn_public.h \ + cyassl/ctaocrypt/poly1305.h \ cyassl/ctaocrypt/camellia.h \ cyassl/ctaocrypt/coding.h \ cyassl/ctaocrypt/compress.h \ @@ -26,6 +27,7 @@ nobase_include_HEADERS+= \ cyassl/ctaocrypt/wc_port.h \ cyassl/ctaocrypt/pwdbased.h \ cyassl/ctaocrypt/rabbit.h \ + cyassl/ctaocrypt/chacha.h \ cyassl/ctaocrypt/random.h \ cyassl/ctaocrypt/ripemd.h \ cyassl/ctaocrypt/rsa.h \ diff --git a/cyassl/ctaocrypt/poly1305.h b/cyassl/ctaocrypt/poly1305.h new file mode 100644 index 000000000..8f5df5caa --- /dev/null +++ b/cyassl/ctaocrypt/poly1305.h @@ -0,0 +1,82 @@ +/* poly1305.h + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL 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. + * + * CyaSSL 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-1301, USA + */ + + +#ifdef HAVE_POLY1305 + +#ifndef CTAO_CRYPT_POLY1305_H +#define CTAO_CRYPT_POLY1305_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* auto detect between 32bit / 64bit */ +#define HAS_SIZEOF_INT128_64BIT (defined(__SIZEOF_INT128__) && defined(__LP64__)) +#define HAS_MSVC_64BIT (defined(_MSC_VER) && defined(_M_X64)) +#define HAS_GCC_4_4_64BIT (defined(__GNUC__) && defined(__LP64__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)))) + +#if (HAS_SIZEOF_INT128_64BIT || HAS_MSVC_64BIT || HAS_GCC_4_4_64BIT) +#define POLY130564 +#else +#define POLY130532 +#endif + +enum { + POLY1305 = 7, + POLY1305_BLOCK_SIZE = 16, + POLY1305_DIGEST_SIZE = 16, + POLY1305_PAD_SIZE = 56 +}; + +/* Poly1305 state */ +typedef struct Poly1305 { +#if defined(POLY130564) + word64 r[3]; + word64 h[3]; + word64 pad[2]; +#else + word32 r[5]; + word32 h[5]; + word32 pad[4]; +#endif + size_t leftover; + unsigned char buffer[POLY1305_BLOCK_SIZE]; + unsigned char final; +} Poly1305; + + +/* does init */ + +CYASSL_API int Poly1305SetKey(Poly1305* poly1305, const byte* key, word32 kySz); +CYASSL_API int Poly1305Update(Poly1305* poly1305, const byte*, word32); +CYASSL_API int Poly1305Final(Poly1305* poly1305, byte* tag); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_POLY1305_H */ + +#endif /* HAVE_POLY1305 */ + diff --git a/cyassl/internal.h b/cyassl/internal.h index a3359e6b1..9aeb1d643 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -31,10 +31,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -465,9 +467,23 @@ void c32to24(word32 in, word24 out); #define BUILD_ARC4 #endif +#ifdef HAVE_CHACHA + #define CHACHA20_BLOCK_SIZE 16 + /* ChaCha - Poly AEAD suites */ + #if defined(HAVE_POLY1305) && !defined(NO_SHA256) + #if defined(HAVE_ECC) + #if !defined(NO_RSA) + #define BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + #endif + #define BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + #endif + #if !defined(NO_DH) && !defined(NO_RSA) + #define BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + #endif + #endif /* end of ChaCha - Poly AEAD suites */ +#endif - -#if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) +#if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) || defined(HAVE_CHACHA) #define HAVE_AEAD #endif @@ -592,13 +608,18 @@ enum { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xbe, TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0xc4, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0x13, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0x14, + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0x15, + /* Renegotiation Indication Extension Special Suite */ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0xff }; enum Misc { - ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ + ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ + CHACHA_BYTE = 0xCC, /* ChaCha first cipher suite */ SEND_CERT = 1, SEND_BLANK_CERT = 2, @@ -721,6 +742,12 @@ enum Misc { CAMELLIA_256_KEY_SIZE = 32, /* for 256 bit */ CAMELLIA_IV_SIZE = 16, /* always block size */ + CHACHA20_256_KEY_SIZE = 32, /* for 256 bit */ + CHACHA20_128_KEY_SIZE = 16, /* for 128 bit */ + CHACHA20_IV_SIZE = 8, /* 64 bits for iv */ + + POLY1305_AUTH_SZ = 16, /* 128 bits */ + HC_128_KEY_SIZE = 16, /* 128 bits */ HC_128_IV_SIZE = 16, /* also 128 bits */ @@ -1495,6 +1522,12 @@ typedef struct Ciphers { #ifdef HAVE_CAMELLIA Camellia* cam; #endif +#ifdef HAVE_CHACHA + ChaCha* chacha; +#endif +#ifdef HAVE_POLY1305 + Poly1305* poly1305; +#endif #ifdef HAVE_HC128 HC128* hc128; #endif @@ -1681,6 +1714,10 @@ typedef struct Options { byte usingNonblock; /* set when using nonblocking socket */ byte saveArrays; /* save array Memory for user get keys or psk */ +#ifdef HAVE_POLY1305 + byte oldPoly; /* set when to use old rfc way of poly*/ +#endif + #ifndef NO_PSK byte havePSK; /* psk key set by user */ psk_client_callback client_psk_cb; diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 3289445a9..7109b0726 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -217,6 +217,10 @@ CYASSL_API int CyaSSL_use_RSAPrivateKey_file(CYASSL*, const char*, int); const char*, int); #endif +#ifdef HAVE_POLY1305 + CYASSL_API int CyaSSL_use_old_poly(CYASSL*, int); +#endif + #ifdef HAVE_NTRU CYASSL_API int CyaSSL_CTX_use_NTRUPrivateKey_file(CYASSL_CTX*, const char*); /* load NTRU private key blob */ @@ -1064,6 +1068,7 @@ enum BulkCipherAlgorithm { cyassl_aes, cyassl_aes_gcm, cyassl_aes_ccm, + cyassl_chacha, cyassl_camellia, cyassl_hc128, /* CyaSSL extensions */ cyassl_rabbit diff --git a/examples/client/client.c b/examples/client/client.c index 0e3f33d54..81fb0723c 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -622,6 +622,15 @@ THREAD_RETURN CYASSL_THREAD client_test(void* args) else { tcp_connect(&sockfd, host, port, 0); } + +#ifdef HAVE_POLY1305 + /* use old poly to connect with google server */ + if (!XSTRNCMP(domain, "www.google.com", 14)) { + if (CyaSSL_use_old_poly(ssl, 1) != 0) + err_sys("unable to set to old poly"); + } +#endif + CyaSSL_set_fd(ssl, sockfd); #ifdef HAVE_CRL if (CyaSSL_EnableCRL(ssl, CYASSL_CRL_CHECKALL) != SSL_SUCCESS) diff --git a/src/include.am b/src/include.am index d4a32684b..48b895d13 100644 --- a/src/include.am +++ b/src/include.am @@ -55,6 +55,10 @@ if BUILD_AES src_libcyassl_la_SOURCES += ctaocrypt/src/aes.c endif +if BUILD_POLY1305 +src_libcyassl_la_SOURCES += ctaocrypt/src/poly1305.c +endif + if BUILD_DES3 src_libcyassl_la_SOURCES += ctaocrypt/src/des3.c endif @@ -119,6 +123,10 @@ if BUILD_RABBIT src_libcyassl_la_SOURCES += ctaocrypt/src/rabbit.c endif +if BUILD_CHACHA +src_libcyassl_la_SOURCES += ctaocrypt/src/chacha.c +endif + if !BUILD_INLINE src_libcyassl_la_SOURCES += ctaocrypt/src/misc.c endif diff --git a/src/internal.c b/src/internal.c index cf4067a88..7b635f1c7 100644 --- a/src/internal.c +++ b/src/internal.c @@ -38,7 +38,7 @@ #include "ntru_crypto.h" #endif -#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) +#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST) #ifdef FREESCALE_MQX #include #else @@ -203,7 +203,8 @@ static INLINE void c16toa(word16 u16, byte* c) } -#if !defined(NO_OLD_TLS) || defined(HAVE_AESCCM) || defined(HAVE_AESGCM) +#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \ + || defined(HAVE_AESGCM) /* convert 32 bit integer to opaque */ static INLINE void c32toa(word32 u32, byte* c) { @@ -527,6 +528,14 @@ void InitCiphers(CYASSL* ssl) #ifdef BUILD_RABBIT ssl->encrypt.rabbit = NULL; ssl->decrypt.rabbit = NULL; +#endif +#ifdef HAVE_CHACHA + ssl->encrypt.chacha = NULL; + ssl->decrypt.chacha = NULL; +#endif +#ifdef HAVE_POLY1305 + ssl->encrypt.poly1305 = NULL; + ssl->decrypt.poly1305 = NULL; #endif ssl->encrypt.setup = 0; ssl->decrypt.setup = 0; @@ -579,6 +588,14 @@ void FreeCiphers(CYASSL* ssl) XFREE(ssl->encrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.rabbit, ssl->heap, DYNAMIC_TYPE_CIPHER); #endif +#ifdef HAVE_CHACHA + XFREE(ssl->encrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif +#ifdef HAVE_POLY1305 + XFREE(ssl->encrypt.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif } @@ -891,6 +908,27 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveRSA, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + if (tls && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + if (tls && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256; + } +#endif + #ifdef BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA if (tls && haveRSAsig && haveStaticECC) { suites->suites[idx++] = ECC_BYTE; @@ -1634,6 +1672,9 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->options.groupMessages = ctx->groupMessages; ssl->options.usingNonblock = 0; ssl->options.saveArrays = 0; +#ifdef HAVE_POLY1305 + ssl->options.oldPoly = 0; +#endif #ifndef NO_CERTS /* ctx still owns certificate, certChain, key, dh, and cm */ @@ -3151,6 +3192,30 @@ static int BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) the key exchange so ECHDE_RSA requires an rsa key thus rsa_kea */ static int CipherRequires(byte first, byte second, int requirement) { + + if (first == CHACHA_BYTE) { + + switch (second) { + + case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; + } + } + /* ECC extensions */ if (first == ECC_BYTE) { @@ -4677,7 +4742,8 @@ static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, #endif -#if !defined(NO_OLD_TLS) || defined(HAVE_AESCCM) || defined(HAVE_AESGCM) +#if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \ + || defined(HAVE_AESGCM) static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) { if (verify) @@ -4696,6 +4762,333 @@ static INLINE void AeadIncrementExpIV(CYASSL* ssl) if (++ssl->keys.aead_exp_IV[i]) return; } } + + +#ifdef HAVE_POLY1305 +/*more recent rfc's concatonate input for poly1305 differently*/ +static int Poly1305Tag(CYASSL* ssl, byte* additional, const byte* out, + byte* cipher, word16 sz, byte* tag) +{ + int ret = 0; + int paddingSz = 0; + int msglen = (sz - ssl->specs.aead_mac_size); + word32 keySz = 32; + byte padding[16]; + + if (msglen < 0) + return INPUT_CASE_ERROR; + + XMEMSET(padding, 0, sizeof(padding)); + + if ((ret = Poly1305SetKey(ssl->encrypt.poly1305, cipher, keySz)) != 0) + return ret; + + /* additional input to poly1305 */ + if ((ret = Poly1305Update(ssl->encrypt.poly1305, additional, + CHACHA20_BLOCK_SIZE)) != 0) + return ret; + + /* cipher input */ + if ((ret = Poly1305Update(ssl->encrypt.poly1305, out, msglen)) != 0) + return ret; + + /* handle padding for cipher input to make it 16 bytes long */ + if (msglen % 16 != 0) { + paddingSz = (16 - (sz - ssl->specs.aead_mac_size) % 16); + if (paddingSz < 0) + return INPUT_CASE_ERROR; + + if ((ret = Poly1305Update(ssl->encrypt.poly1305, padding, paddingSz)) + != 0) + return ret; + } + + /* add size of AD and size of cipher to poly input */ + XMEMSET(padding, 0, sizeof(padding)); + padding[0] = CHACHA20_BLOCK_SIZE; + + /* 32 bit size of cipher to 64 bit endian */ + padding[8] = msglen & 0xff; + padding[9] = (msglen >> 8) & 0xff; + padding[10] = (msglen >>16) & 0xff; + padding[11] = (msglen >>24) & 0xff; + if ((ret = Poly1305Update(ssl->encrypt.poly1305, padding, sizeof(padding))) + != 0) + return ret; + + /* generate tag */ + if ((ret = Poly1305Final(ssl->encrypt.poly1305, tag)) != 0) + return ret; + + return ret; +} + + +/* Used for the older version of creating AEAD tags with Poly1305 */ +static int Poly1305TagOld(CYASSL* ssl, byte* additional, const byte* out, + byte* cipher, word16 sz, byte* tag) +{ + int ret = 0; + int msglen = (sz - ssl->specs.aead_mac_size); + word32 keySz = 32; + byte padding[8]; /* used to temporarly store lengths */ + +#ifdef CHACHA_AEAD_TEST + printf("Using old version of poly1305 input.\n"); +#endif + + if (msglen < 0) + return INPUT_CASE_ERROR; + + if ((ret = Poly1305SetKey(ssl->encrypt.poly1305, cipher, keySz)) != 0) + return ret; + + /* add TLS compressed length and additional input to poly1305 */ + additional[AEAD_AUTH_DATA_SZ - 2] = (msglen >> 8) & 0xff; + additional[AEAD_AUTH_DATA_SZ - 1] = msglen & 0xff; + if ((ret = Poly1305Update(ssl->encrypt.poly1305, additional, + AEAD_AUTH_DATA_SZ)) != 0) + return ret; + + /* length of additional input plus padding */ + XMEMSET(padding, 0, sizeof(padding)); + padding[0] = AEAD_AUTH_DATA_SZ; + if ((ret = Poly1305Update(ssl->encrypt.poly1305, padding, + sizeof(padding))) != 0) + return ret; + + + /* add cipher info and then its length */ + XMEMSET(padding, 0, sizeof(padding)); + if ((ret = Poly1305Update(ssl->encrypt.poly1305, out, msglen)) != 0) + return ret; + + /* 32 bit size of cipher to 64 bit endian */ + padding[0] = msglen & 0xff; + padding[1] = (msglen >> 8) & 0xff; + padding[2] = (msglen >> 16) & 0xff; + padding[3] = (msglen >> 24) & 0xff; + if ((ret = Poly1305Update(ssl->encrypt.poly1305, padding, sizeof(padding))) + != 0) + return ret; + + /* generate tag */ + if ((ret = Poly1305Final(ssl->encrypt.poly1305, tag)) != 0) + return ret; + + return ret; +} +#endif /*HAVE_POLY1305*/ + + +#ifdef HAVE_CHACHA +static int ChachaAEADEncrypt(CYASSL* ssl, byte* out, const byte* input, + word16 sz) +{ + const byte* additionalSrc = input - RECORD_HEADER_SZ; + int ret = 0; + byte tag[POLY1305_AUTH_SZ]; + byte additional[CHACHA20_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */ + + XMEMSET(tag, 0, sizeof(tag)); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE); + + /* get nonce */ + c32toa(ssl->keys.sequence_number, nonce + AEAD_IMP_IV_SZ + + AEAD_SEQ_OFFSET); + + /* opaque SEQ number stored for AD */ + c32toa(GetSEQIncrement(ssl, 0), additional + AEAD_SEQ_OFFSET); + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + c16toa(ssl->keys.dtls_epoch, additional); + additionalSrc -= DTLS_HANDSHAKE_EXTRA; + } + #endif + + XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3); + + #ifdef CHACHA_AEAD_TEST + int i; + printf("Encrypt Additional : "); + for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) { + printf("%02x", additional[i]); + } + printf("\n\n"); + printf("input before encryption :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", input[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + /* set the nonce for chacha and get poly1305 key */ + if ((ret = Chacha_SetIV(ssl->encrypt.chacha, nonce, 0)) != 0) + return ret; + + if ((ret = Chacha_Process(ssl->encrypt.chacha, cipher, + cipher, sizeof(cipher))) != 0) + return ret; + + /* encrypt the plain text */ + if ((ret = Chacha_Process(ssl->encrypt.chacha, out, input, + sz - ssl->specs.aead_mac_size)) != 0) + return ret; + + #ifdef HAVE_POLY1305 + /* get the tag : future use of hmac could go here*/ + if (ssl->options.oldPoly == 1) { + if ((ret = Poly1305TagOld(ssl, additional, (const byte* )out, + cipher, sz, tag)) != 0) + return ret; + } + else { + if ((ret = Poly1305Tag(ssl, additional, (const byte* )out, + cipher, sz, tag)) != 0) + return ret; + } + #endif + + /* append tag to ciphertext */ + XMEMCPY(out + sz - ssl->specs.aead_mac_size, tag, sizeof(tag)); + + AeadIncrementExpIV(ssl); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + + #ifdef CHACHA_AEAD_TEST + printf("mac tag :\n"); + for (i = 0; i < 16; i++) { + printf("%02x", tag[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n\noutput after encrypt :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", out[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + return ret; +} + + +static int ChachaAEADDecrypt(CYASSL* ssl, byte* plain, const byte* input, + word16 sz) +{ + byte additional[CHACHA20_BLOCK_SIZE]; + byte nonce[AEAD_NONCE_SZ]; + byte tag[POLY1305_AUTH_SZ]; + byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ + int i; + int ret = 0; + + XMEMSET(tag, 0, sizeof(tag)); + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE); + + #ifdef CHACHA_AEAD_TEST + printf("input before decrypt :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", input[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + /* get nonce */ + c32toa(ssl->keys.peer_sequence_number, nonce + AEAD_IMP_IV_SZ + + AEAD_SEQ_OFFSET); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + /* get AD info */ + additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; + additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; + additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + + /* Store the type, version. */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + c16toa(ssl->keys.dtls_state.curEpoch, additional); + #endif + + #ifdef CHACHA_AEAD_TEST + printf("Decrypt Additional : "); + for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) { + printf("%02x", additional[i]); + } + printf("\n\n"); + #endif + + /* set nonce and get poly1305 key */ + if ((ret = Chacha_SetIV(ssl->decrypt.chacha, nonce, 0)) != 0) + return ret; + + if ((ret = Chacha_Process(ssl->decrypt.chacha, cipher, + cipher, sizeof(cipher))) != 0) + return ret; + + #ifdef HAVE_POLY1305 + /* get the tag : future use of hmac could go here*/ + if (ssl->options.oldPoly == 1) { + if ((ret = Poly1305TagOld(ssl, additional, input, cipher, + sz, tag)) != 0) + return ret; + } + else { + if ((ret = Poly1305Tag(ssl, additional, input, cipher, + sz, tag)) != 0) + return ret; + } + #endif + + /* check mac sent along with packet */ + ret = 0; + for (i = 0; i < ssl->specs.aead_mac_size; i++) { + if ((input + sz - ssl->specs.aead_mac_size)[i] != tag[i]) + ret = 1; + } + + if (ret == 1) { + CYASSL_MSG("Mac did not match"); + SendAlert(ssl, alert_fatal, bad_record_mac); + XMEMSET(nonce, 0, AEAD_NONCE_SZ); + return VERIFY_MAC_ERROR; + } + + /* if mac was good decrypt message */ + if ((ret = Chacha_Process(ssl->decrypt.chacha, plain, input, + sz - ssl->specs.aead_mac_size)) != 0) + return ret; + + #ifdef CHACHA_AEAD_TEST + printf("plain after decrypt :\n"); + for (i = 0; i < sz; i++) { + printf("%02x", plain[i]); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); + #endif + + return ret; +} +#endif /* HAVE_CHACHA */ #endif @@ -4831,6 +5224,11 @@ static INLINE int Encrypt(CYASSL* ssl, byte* out, const byte* input, word16 sz) return RabbitProcess(ssl->encrypt.rabbit, out, input, sz); #endif + #ifdef HAVE_CHACHA + case cyassl_chacha: + return ChachaAEADEncrypt(ssl, out, input, sz); + #endif + #ifdef HAVE_NULL_CIPHER case cyassl_cipher_null: if (input != out) { @@ -4976,6 +5374,11 @@ static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, return RabbitProcess(ssl->decrypt.rabbit, plain, input, sz); #endif + #ifdef HAVE_CHACHA + case cyassl_chacha: + return ChachaAEADDecrypt(ssl, plain, input, sz); + #endif + #ifdef HAVE_NULL_CIPHER case cyassl_cipher_null: if (input != plain) { @@ -5017,8 +5420,9 @@ static int SanityCheckCipherText(CYASSL* ssl, word32 encryptSz) minLength += ssl->specs.block_size; /* explicit IV */ } else if (ssl->specs.cipher_type == aead) { - minLength = ssl->specs.aead_mac_size + AEAD_EXP_IV_SZ; - /* explicit IV + authTag size */ + minLength = ssl->specs.aead_mac_size; /* authTag size */ + if (ssl->specs.bulk_cipher_algorithm != cyassl_chacha) + minLength += AEAD_EXP_IV_SZ; /* explicit IV */ } if (encryptSz < minLength) { @@ -5326,7 +5730,8 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) ivExtra = ssl->specs.block_size; } else if (ssl->specs.cipher_type == aead) { - ivExtra = AEAD_EXP_IV_SZ; + if (ssl->specs.bulk_cipher_algorithm != cyassl_chacha) + ivExtra = AEAD_EXP_IV_SZ; } dataSz = msgSz - ivExtra - ssl->keys.padSz; @@ -5717,7 +6122,8 @@ int ProcessReply(CYASSL* ssl) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) ssl->buffers.inputBuffer.idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ - if (ssl->specs.cipher_type == aead) + if (ssl->specs.cipher_type == aead && + ssl->specs.bulk_cipher_algorithm != cyassl_chacha) ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ; #endif /* ATOMIC_USER */ } @@ -5734,7 +6140,8 @@ int ProcessReply(CYASSL* ssl) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) ssl->buffers.inputBuffer.idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ - if (ssl->specs.cipher_type == aead) + if (ssl->specs.cipher_type == aead && + ssl->specs.bulk_cipher_algorithm != cyassl_chacha) ssl->buffers.inputBuffer.idx += AEAD_EXP_IV_SZ; ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer + @@ -6166,7 +6573,9 @@ static int BuildMessage(CYASSL* ssl, byte* output, int outSz, #ifdef HAVE_AEAD if (ssl->specs.cipher_type == aead) { - ivSz = AEAD_EXP_IV_SZ; + if (ssl->specs.bulk_cipher_algorithm != cyassl_chacha) + ivSz = AEAD_EXP_IV_SZ; + sz += (ivSz + ssl->specs.aead_mac_size - digestSz); XMEMCPY(iv, ssl->keys.aead_exp_IV, AEAD_EXP_IV_SZ); } @@ -7434,6 +7843,18 @@ static const char* const cipher_names[] = "ECDH-ECDSA-AES256-SHA384", #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + "ECDHE-RSA-CHACHA20-POLY1305", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + "ECDHE-ECDSA-CHACHA20-POLY1305", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + "DHE-RSA-CHACHA20-POLY1305", +#endif + }; @@ -7807,7 +8228,19 @@ static int cipher_name_idx[] = #endif #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, #endif }; @@ -7854,8 +8287,12 @@ int SetCipherList(Suites* s, const char* list) for (i = 0; i < suiteSz; i++) if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { - if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM")) - s->suites[idx++] = ECC_BYTE; /* ECC suite */ + if (XSTRSTR(name, "CHACHA")) + s->suites[idx++] = CHACHA_BYTE; + else if (XSTRSTR(name, "EC") || XSTRSTR(name, "CCM")) { + + s->suites[idx++] = ECC_BYTE; /* ECC suite */ + } else s->suites[idx++] = 0x00; /* normal */ s->suites[idx++] = (byte)cipher_name_idx[i]; diff --git a/src/keys.c b/src/keys.c index bb703a186..9905bd313 100644 --- a/src/keys.c +++ b/src/keys.c @@ -28,7 +28,7 @@ #include #include -#ifdef SHOW_SECRETS +#if defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST) #ifdef FREESCALE_MQX #include #else @@ -49,6 +49,69 @@ int SetCipherSpecs(CYASSL* ssl) } #endif /* NO_CYASSL_CLIENT */ + /* Chacha extensions, 0xcc */ + if (ssl->options.cipherSuite0 == CHACHA_BYTE) { + + switch (ssl->options.cipherSuite) { +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = cyassl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = cyassl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = cyassl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + + break; +#endif + default: + CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs ChaCha"); + return UNSUPPORTED_SUITE; + } + } + /* ECC extensions, or AES-CCM */ if (ssl->options.cipherSuite0 == ECC_BYTE) { @@ -792,7 +855,8 @@ int SetCipherSpecs(CYASSL* ssl) return UNSUPPORTED_SUITE; } /* switch */ } /* if */ - if (ssl->options.cipherSuite0 != ECC_BYTE) { /* normal suites */ + if (ssl->options.cipherSuite0 != ECC_BYTE && + ssl->options.cipherSuite0 != CHACHA_BYTE) { /* normal suites */ switch (ssl->options.cipherSuite) { #ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA @@ -1774,7 +1838,62 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, dec->setup = 1; } #endif + +#ifdef HAVE_POLY1305 + /* set up memory space for poly1305 */ + if (enc->poly1305 == NULL) + enc->poly1305 = (Poly1305*)malloc(sizeof(Poly1305)); + if (enc->poly1305 == NULL) + return MEMORY_E; + if (dec->poly1305 == NULL) + dec->poly1305 = + (Poly1305*)XMALLOC(sizeof(Poly1305), heap, DYNAMIC_TYPE_CIPHER); + if (dec->poly1305 == NULL) + return MEMORY_E; +#endif +#ifdef HAVE_CHACHA + if (specs->bulk_cipher_algorithm == cyassl_chacha) { + int chachaRet; + if (enc->chacha == NULL) + enc->chacha = (ChaCha*)malloc(sizeof(ChaCha)); + if (enc->chacha == NULL) + return MEMORY_E; + if (dec->chacha == NULL) + dec->chacha = + (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER); + if (dec->chacha == NULL) + return MEMORY_E; + if (side == CYASSL_CLIENT_END) { + chachaRet = Chacha_SetKey(enc->chacha, keys->client_write_key, + specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, + keys->client_write_IV, AEAD_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + chachaRet = Chacha_SetKey(dec->chacha, keys->server_write_key, + specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, + keys->server_write_IV, AEAD_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + } + else { + chachaRet = Chacha_SetKey(enc->chacha, keys->server_write_key, + specs->key_size); + XMEMCPY(keys->aead_enc_imp_IV, + keys->server_write_IV, AEAD_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + chachaRet = Chacha_SetKey(dec->chacha, keys->client_write_key, + specs->key_size); + XMEMCPY(keys->aead_dec_imp_IV, + keys->client_write_IV, AEAD_IMP_IV_SZ); + if (chachaRet != 0) return chachaRet; + } + + enc->setup = 1; + dec->setup = 1; + } +#endif + #ifdef HAVE_HC128 if (specs->bulk_cipher_algorithm == cyassl_hc128) { int hcRet; diff --git a/src/ssl.c b/src/ssl.c index 9f1a5f107..1b99e98fd 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -194,6 +194,16 @@ void CyaSSL_free(CYASSL* ssl) CYASSL_LEAVE("SSL_free", 0); } +#ifdef HAVE_POLY1305 +/* set if to use old poly 1 for yes 0 to use new poly */ +int CyaSSL_use_old_poly(CYASSL* ssl, int value) +{ + CYASSL_ENTER("SSL_use_old_poly"); + ssl->options.oldPoly = value; + CYASSL_LEAVE("SSL_use_old_poly", 0); + return 0; +} +#endif int CyaSSL_set_fd(CYASSL* ssl, int fd) { @@ -324,6 +334,9 @@ int CyaSSL_GetObjectSize(void) #endif #ifndef NO_RABBIT printf(" sizeof rabbit = %lu\n", sizeof(Rabbit)); +#endif +#ifdef HAVE_CHACHA + printf(" sizeof chacha = %lu\n", sizeof(Chacha)); #endif printf("sizeof cipher specs = %lu\n", sizeof(CipherSpecs)); printf("sizeof keys = %lu\n", sizeof(Keys)); @@ -8362,6 +8375,25 @@ CYASSL_X509* CyaSSL_X509_load_certificate_file(const char* fname, int format) CYASSL_ENTER("SSL_CIPHER_get_name"); #ifndef NO_ERROR_STRINGS if (cipher) { +#if defined(HAVE_CHACHA) + if (cipher->ssl->options.cipherSuite0 == CHACHA_BYTE) { + /* ChaCha suites */ + switch (cipher->ssl->options.cipherSuite) { +#ifdef HAVE_CHACHA + #ifndef NO_RSA + case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"; + + case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : + return "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"; + #endif + case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 : + return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"; +#endif + } + } +#endif + #if defined(HAVE_ECC) || defined(HAVE_AESCCM) /* Awkwardly, the ECC cipher suites use the ECC_BYTE as expected, * but the AES-CCM cipher suites also use it, even the ones that @@ -8508,8 +8540,10 @@ CYASSL_X509* CyaSSL_X509_load_certificate_file(const char* fname, int format) } } #endif /* ECC */ - if (cipher->ssl->options.cipherSuite0 != ECC_BYTE) { - /* normal suites */ + if (cipher->ssl->options.cipherSuite0 != ECC_BYTE && + cipher->ssl->options.cipherSuite0 != CHACHA_BYTE) { + + /* normal suites */ switch (cipher->ssl->options.cipherSuite) { #ifndef NO_RSA #ifndef NO_RC4 diff --git a/tests/test-dtls.conf b/tests/test-dtls.conf index cc3a6aeb5..887afb18d 100644 --- a/tests/test-dtls.conf +++ b/tests/test-dtls.conf @@ -1,3 +1,69 @@ +# server DTLSv1 DHE-RSA-CHACHA20-POLY1305 +-u +-v 2 +-l DHE-RSA-CHACHA20-POLY1305 + +# client DTLSv1 DHE-RSA-CHACHA20-POLY1305 +-u +-v 2 +-l DHE-RSA-CHACHA20-POLY1305 + +# server DTLSv1 ECDHE-RSA-CHACHA20-POLY1305 +-u +-v 2 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# client DTLSv1 ECDHE-RSA-CHACHA20-POLY1305 +-u +-v 2 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# server DTLSv1 ECDHE-EDCSA-CHACHA20-POLY1305 +-u +-v 2 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client DTLSv1 ECDHE-ECDSA-CHACHA20-POLY1305 +-u +-v 2 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + +# server DTLSv1.2 DHE-RSA-CHACHA20-POLY1305 +-u +-v 3 +-l DHE-RSA-CHACHA20-POLY1305 + +# client DTLSv1.2 DHE-RSA-CHACHA20-POLY1305 +-u +-v 3 +-l DHE-RSA-CHACHA20-POLY1305 + +# server DTLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 +-u +-v 3 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# client DTLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 +-u +-v 3 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# server DTLSv1.2 ECDHE-EDCSA-CHACHA20-POLY1305 +-u +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client DTLSv1.2 ECDHE-ECDSA-CHACHA20-POLY1305 +-u +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + # server DTLSv1 RC4-SHA -u -v 2 diff --git a/tests/test.conf b/tests/test.conf index 71735d2cd..b3656f112 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -1,3 +1,84 @@ +# server TLSv1 DHE-RSA-CHACHA20-POLY1305 +-v 1 +-l DHE-RSA-CHACHA20-POLY1305 + +# client TLSv1 DHE-RSA-CHACHA20-POLY1305 +-v 1 +-l DHE-RSA-CHACHA20-POLY1305 + +# server TLSv1 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 1 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 1 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + +# server TLSv1 ECDHE-RSA-CHACHA20-POLY1305 +-v 1 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# client TLSv1 ECDHE-RSA-CHACHA20-POLY1305 +-v 1 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.1 DHE-RSA-CHACHA20-POLY1305 +-v 2 +-l DHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.1 DHE-RSA-CHACHA20-POLY1305 +-v 2 +-l DHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.1 ECDHE-RSA-CHACHA20-POLY1305 +-v 2 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.1 ECDHE-RSA-CHACHA20-POLY1305 +-v 2 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.1 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 2 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.1 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 2 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + +# server TLSv1.2 DHE-RSA-CHACHA20-POLY1305 +-v 3 +-l DHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.2 DHE-RSA-CHACHA20-POLY1305 +-v 3 +-l DHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 +-v 3 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# client TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 +-v 3 +-l ECDHE-RSA-CHACHA20-POLY1305 + +# server TLSv1.2 ECDHE-EDCSA-CHACHA20-POLY1305 +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-CHACHA20-POLY1305 +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305 +-A ./certs/server-ecc.pem + # server SSLv3 RC4-SHA -v 0 -l RC4-SHA