diff --git a/configure.ac b/configure.ac index 37f1657be..1334f99b0 100644 --- a/configure.ac +++ b/configure.ac @@ -1149,6 +1149,22 @@ fi AM_CONDITIONAL([BUILD_DES3], [test "x$ENABLED_DES3" = "xyes"]) +# IDEA +AC_ARG_ENABLE([idea], +[ --enable-idea Enable IDEA (default: disabled)], +[ ENABLED_IDEA=$enableval ], +[ ENABLED_IDEA=no ] +) + +if test "x$ENABLED_IDEA" = "xyes" +then +AM_CFLAGS="$AM_CFLAGS -DHAVE_IDEA" +fi + +AM_CONDITIONAL([BUILD_IDEA], [test "x$ENABLED_IDEA" = "xyes"]) + + + # ARC4 AC_ARG_ENABLE([arc4], [ --enable-arc4 Enable ARC4 (default: disabled)], @@ -2401,6 +2417,7 @@ echo " * AES-NI: $ENABLED_AESNI" echo " * AES-GCM: $ENABLED_AESGCM" echo " * AES-CCM: $ENABLED_AESCCM" echo " * DES3: $ENABLED_DES3" +echo " * IDEA: $ENABLED_IDEA" echo " * Camellia: $ENABLED_CAMELLIA" echo " * NULL Cipher: $ENABLED_NULL_CIPHER" echo " * MD5: $ENABLED_MD5" diff --git a/src/include.am b/src/include.am index f594b1cf9..d2605a797 100644 --- a/src/include.am +++ b/src/include.am @@ -205,6 +205,10 @@ if BUILD_SRP src_libwolfssl_la_SOURCES += wolfcrypt/src/srp.c endif +if BUILD_IDEA +src_libwolfssl_la_SOURCES += wolfcrypt/src/idea.c +endif + if !BUILD_CRYPTONLY # ssl files src_libwolfssl_la_SOURCES += \ diff --git a/src/internal.c b/src/internal.c index 5eca2264e..bc48149fc 100644 --- a/src/internal.c +++ b/src/internal.c @@ -611,6 +611,10 @@ void InitCiphers(WOLFSSL* ssl) #ifdef HAVE_ONE_TIME_AUTH ssl->auth.setup = 0; #endif +#ifdef HAVE_IDEA + ssl->encrypt.idea = NULL; + ssl->decrypt.idea = NULL; +#endif } @@ -667,6 +671,10 @@ void FreeCiphers(WOLFSSL* ssl) #ifdef HAVE_POLY1305 XFREE(ssl->auth.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER); #endif +#ifdef HAVE_IDEA + XFREE(ssl->encrypt.idea, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.idea, ssl->heap, DYNAMIC_TYPE_CIPHER); +#endif } @@ -1461,6 +1469,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA, } #endif +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + if (haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_IDEA_CBC_SHA; + } +#endif + suites->suiteSz = idx; InitSuitesHashSigAlgo(suites, haveECDSAsig, haveRSAsig, 0); @@ -3784,6 +3799,11 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) if (requirement == REQUIRES_NTRU) return 1; break; + + case SSL_RSA_WITH_IDEA_CBC_SHA : + if (requirement == REQUIRES_RSA) + return 1; + break; #endif case TLS_PSK_WITH_AES_128_GCM_SHA256 : @@ -5920,6 +5940,12 @@ static INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz) break; #endif + #ifdef HAVE_IDEA + case wolfssl_idea: + wc_IdeaCbcEncrypt(ssl->encrypt.idea, out, input, sz); + break; + #endif + default: WOLFSSL_MSG("wolfSSL Encrypt programming error"); ret = ENCRYPT_ERROR; @@ -6075,6 +6101,12 @@ static INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input, break; #endif + #ifdef HAVE_IDEA + case wolfssl_idea: + wc_IdeaCbcDecrypt(ssl->decrypt.idea, plain, input, sz); + break; + #endif + default: WOLFSSL_MSG("wolfSSL Decrypt programming error"); ret = DECRYPT_ERROR; @@ -6814,6 +6846,7 @@ int ProcessReply(WOLFSSL* ssl) ssl->buffers.inputBuffer.idx, ssl->curSize); if (ret < 0) { + WOLFSSL_MSG("Decrypt failed"); WOLFSSL_ERROR(ret); return DECRYPT_ERROR; } @@ -6830,6 +6863,7 @@ int ProcessReply(WOLFSSL* ssl) &ssl->keys.padSz); } if (ret < 0) { + WOLFSSL_MSG("VerifyMac failed"); WOLFSSL_ERROR(ret); return DECRYPT_ERROR; } @@ -8874,6 +8908,10 @@ static const char* const cipher_names[] = #ifdef HAVE_RENEGOTIATION_INDICATION "RENEGOTIATION-INFO", #endif + +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + "IDEA-CBC-SHA", +#endif }; @@ -9272,6 +9310,10 @@ static int cipher_name_idx[] = #ifdef HAVE_RENEGOTIATION_INDICATION TLS_EMPTY_RENEGOTIATION_INFO_SCSV, #endif + +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + SSL_RSA_WITH_IDEA_CBC_SHA, +#endif }; diff --git a/src/keys.c b/src/keys.c index 41b5a941f..5ca1b72f7 100644 --- a/src/keys.c +++ b/src/keys.c @@ -1757,6 +1757,23 @@ int SetCipherSpecs(WOLFSSL* ssl) break; #endif +#ifdef BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + case SSL_RSA_WITH_IDEA_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = wolfssl_idea; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = IDEA_KEY_SIZE; + ssl->specs.block_size = IDEA_BLOCK_SIZE; + ssl->specs.iv_size = IDEA_IV_SIZE; + + break; +#endif + default: WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs"); return UNSUPPORTED_SUITE; @@ -2279,6 +2296,55 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, } #endif +#ifdef HAVE_IDEA + if (specs->bulk_cipher_algorithm == wolfssl_idea) { + int ideaRet; + + if (enc && enc->idea == NULL) + enc->idea = (Idea*)XMALLOC(sizeof(Idea), heap, DYNAMIC_TYPE_CIPHER); + if (enc && enc->idea == NULL) + return MEMORY_E; + + if (dec && dec->idea == NULL) + dec->idea = (Idea*)XMALLOC(sizeof(Idea), heap, DYNAMIC_TYPE_CIPHER); + if (dec && dec->idea == NULL) + return MEMORY_E; + + if (side == WOLFSSL_CLIENT_END) { + if (enc) { + ideaRet = wc_IdeaSetKey(enc->idea, keys->client_write_key, + specs->key_size, keys->client_write_IV, + IDEA_ENCRYPTION); + if (ideaRet != 0) return ideaRet; + } + if (dec) { + ideaRet = wc_IdeaSetKey(dec->idea, keys->server_write_key, + specs->key_size, keys->server_write_IV, + IDEA_DECRYPTION); + if (ideaRet != 0) return ideaRet; + } + } + else { + if (enc) { + ideaRet = wc_IdeaSetKey(enc->idea, keys->server_write_key, + specs->key_size, keys->server_write_IV, + IDEA_ENCRYPTION); + if (ideaRet != 0) return ideaRet; + } + if (dec) { + ideaRet = wc_IdeaSetKey(dec->idea, keys->client_write_key, + specs->key_size, keys->client_write_IV, + IDEA_DECRYPTION); + if (ideaRet != 0) return ideaRet; + } + } + if (enc) + enc->setup = 1; + if (dec) + dec->setup = 1; + } +#endif + #ifdef HAVE_NULL_CIPHER if (specs->bulk_cipher_algorithm == wolfssl_cipher_null) { if (enc) diff --git a/src/sniffer.c b/src/sniffer.c index fa371ca2b..dc02b6aea 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -1939,6 +1939,12 @@ static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) break; #endif + #ifdef HAVE_IDEA + case wolfssl_idea: + wc_IdeaCbcDecrypt(ssl->decrypt.idea, output, input, sz); + break; + #endif + default: Trace(BAD_DECRYPT_TYPE); ret = -1; diff --git a/src/ssl.c b/src/ssl.c index 7ad1ba83d..8bf5c867a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -76,6 +76,7 @@ #include #include #include + #include #include #include #ifdef HAVE_STUNNEL @@ -1614,6 +1615,10 @@ static const int EVP_DES_SIZE = 7; static const char *EVP_DES_EDE3_CBC = "DES-EDE3-CBC"; static const int EVP_DES_EDE3_SIZE = 12; +#ifdef HAVE_IDEA +static const char *EVP_IDEA_CBC = "IDEA-CBC"; +static const int EVP_IDEA_SIZE = 8; +#endif /* our KeyPemToDer password callback, password in userData */ static INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata) @@ -8119,7 +8124,13 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return type; } - +#ifdef HAVE_IDEA + const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_idea_cbc(void) + { + WOLFSSL_ENTER("wolfSSL_EVP_idea_cbc"); + return EVP_IDEA_CBC; + } +#endif const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_enc_null(void) { static const char* type = "NULL"; @@ -8166,7 +8177,7 @@ int wolfSSL_set_compression(WOLFSSL* ssl) const WOLFSSL_EVP_CIPHER* type, byte* key, byte* iv, int enc) { -#if defined(NO_AES) && defined(NO_DES3) +#if defined(NO_AES) && defined(NO_DES3) && !defined(HAVE_IDEA) (void)iv; (void)enc; #else @@ -8354,6 +8365,25 @@ int wolfSSL_set_compression(WOLFSSL* ssl) wc_Arc4SetKey(&ctx->cipher.arc4, key, ctx->keyLen); } #endif /* NO_RC4 */ +#ifdef HAVE_IDEA + else if (ctx->cipherType == IDEA_CBC_TYPE || + (type && XSTRNCMP(type, EVP_IDEA_CBC, EVP_IDEA_SIZE) == 0)) { + WOLFSSL_MSG(EVP_IDEA_CBC); + ctx->cipherType = IDEA_CBC_TYPE; + ctx->keyLen = IDEA_KEY_SIZE; + if (enc == 0 || enc == 1) + ctx->enc = enc ? 1 : 0; + if (key) { + ret = wc_IdeaSetKey(&ctx->cipher.idea, key, ctx->keyLen, iv, + ctx->enc ? IDEA_ENCRYPTION : IDEA_DECRYPTION); + if (ret != 0) + return ret; + } + + if (iv && key == NULL) + wc_IdeaSetIV(&ctx->cipher.idea, iv); + } +#endif /* HAVE_IDEA */ else if (ctx->cipherType == NULL_CIPHER_TYPE || (type && XSTRNCMP(type, "NULL", 4) == 0)) { WOLFSSL_MSG("NULL cipher"); @@ -8455,6 +8485,14 @@ int wolfSSL_set_compression(WOLFSSL* ssl) break; #endif +#ifdef HAVE_IDEA + case IDEA_CBC_TYPE : + if (ctx->enc) + wc_IdeaCbcEncrypt(&ctx->cipher.idea, dst, src, len); + else + wc_IdeaCbcDecrypt(&ctx->cipher.idea, dst, src, len); + break; +#endif case NULL_CIPHER_TYPE : XMEMCPY(dst, src, len); break; @@ -8518,6 +8556,12 @@ int wolfSSL_set_compression(WOLFSSL* ssl) break; #endif +#ifdef HAVE_IDEA + case IDEA_CBC_TYPE : + WOLFSSL_MSG("IDEA CBC"); + memcpy(ctx->iv, &ctx->cipher.idea.reg, IDEA_BLOCK_SIZE); + break; +#endif case ARC4_TYPE : WOLFSSL_MSG("ARC4"); break; @@ -8579,6 +8623,12 @@ int wolfSSL_set_compression(WOLFSSL* ssl) break; #endif +#ifdef HAVE_IDEA + case IDEA_CBC_TYPE : + WOLFSSL_MSG("IDEA CBC"); + memcpy(&ctx->cipher.idea.reg, ctx->iv, IDEA_BLOCK_SIZE); + break; +#endif case ARC4_TYPE : WOLFSSL_MSG("ARC4"); break; @@ -10003,6 +10053,11 @@ const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher) case SSL_RSA_WITH_3DES_EDE_CBC_SHA : return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; #endif + #ifdef HAVE_IDEA + case SSL_RSA_WITH_IDEA_CBC_SHA : + return "SSL_RSA_WITH_IDEA_CBC_SHA"; + #endif + case TLS_RSA_WITH_AES_128_CBC_SHA : return "TLS_RSA_WITH_AES_128_CBC_SHA"; case TLS_RSA_WITH_AES_256_CBC_SHA : @@ -13509,7 +13564,11 @@ int wolfSSL_EVP_CIPHER_CTX_iv_length(const WOLFSSL_EVP_CIPHER_CTX* ctx) case DES_EDE3_CBC_TYPE : WOLFSSL_MSG("DES EDE3 CBC"); return DES_BLOCK_SIZE; - +#ifdef HAVE_IDEA + case IDEA_CBC_TYPE : + WOLFSSL_MSG("IDEA CBC"); + return IDEA_BLOCK_SIZE; +#endif case ARC4_TYPE : WOLFSSL_MSG("ARC4"); return 0; diff --git a/tests/test-dtls.conf b/tests/test-dtls.conf index 7a9c041e5..7a821fa04 100644 --- a/tests/test-dtls.conf +++ b/tests/test-dtls.conf @@ -84,6 +84,16 @@ -v 3 -l RC4-SHA +# server DTLSv1 IDEA-CBC-SHA +-u +-v 2 +-l IDEA-CBC-SHA + +# client DTLSv1 IDEA-CBC-SHA +-u +-v 2 +-l IDEA-CBC-SHA + # server DTLSv1 DES-CBC3-SHA -u -v 2 diff --git a/tests/test-qsh.conf b/tests/test-qsh.conf index 0f59c428f..c465531bb 100644 --- a/tests/test-qsh.conf +++ b/tests/test-qsh.conf @@ -103,6 +103,14 @@ -v 0 -l QSH:DES-CBC3-SHA +# server SSLv3 IDEA-CBC-SHA +-v 0 +-l QSH:IDEA-CBC-SHA + +# client SSLv3 IDEA-CBC-SHA +-v 0 +-l QSH:IDEA-CBC-SHA + # server TLSv1 RC4-SHA -v 1 -l QSH:RC4-SHA @@ -127,6 +135,14 @@ -v 1 -l QSH:DES-CBC3-SHA +# server TLSv1 IDEA-CBC-SHA +-v 1 +-l QSH:IDEA-CBC-SHA + +# client TLSv1 IDEA-CBC-SHA +-v 1 +-l QSH:IDEA-CBC-SHA + # server TLSv1 AES128-SHA -v 1 -l QSH:AES128-SHA @@ -175,6 +191,14 @@ -v 2 -l QSH:RC4-MD5 +# server TLSv1.1 IDEA-CBC-SHA +-v 2 +-l QSH:IDEA-CBC-SHA + +# client TLSv1.1 IDEA-CBC-SHA +-v 2 +-l QSH:IDEA-CBC-SHA + # server TLSv1.1 DES-CBC3-SHA -v 2 -l QSH:DES-CBC3-SHA diff --git a/tests/test.conf b/tests/test.conf index 9e6d0674a..5dda708b3 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -103,6 +103,14 @@ -v 0 -l DES-CBC3-SHA +# server SSLv3 IDEA-CBC-SHA +-v 0 +-l IDEA-CBC-SHA + +# client SSLv3 IDEA-CBC-SHA +-v 0 +-l IDEA-CBC-SHA + # server TLSv1 RC4-SHA -v 1 -l RC4-SHA @@ -127,6 +135,14 @@ -v 1 -l DES-CBC3-SHA +# server TLSv1 IDEA-CBC-SHA +-v 1 +-l IDEA-CBC-SHA + +# client TLSv1 IDEA-CBC-SHA +-v 1 +-l IDEA-CBC-SHA + # server TLSv1 AES128-SHA -v 1 -l AES128-SHA @@ -175,6 +191,14 @@ -v 2 -l RC4-MD5 +# server TLSv1.1 IDEA-CBC-SHA +-v 2 +-l IDEA-CBC-SHA + +# client TLSv1.1 IDEA-CBC-SHA +-v 2 +-l IDEA-CBC-SHA + # server TLSv1.1 DES-CBC3-SHA -v 2 -l DES-CBC3-SHA diff --git a/wolfcrypt/src/idea.c b/wolfcrypt/src/idea.c new file mode 100644 index 000000000..3daee1a10 --- /dev/null +++ b/wolfcrypt/src/idea.c @@ -0,0 +1,279 @@ +/* idea.c + * + * Copyright (C) 2006-2015 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL 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. + * + * wolfSSL 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_CONFIG_H + #include +#endif + +#include + +#include + +#ifdef HAVE_IDEA + +#include + +#include +#include + +#ifdef NO_INLINE + #include +#else + #include +#endif + +/* multiplication of x and y modulo 2^16+1 + * IDEA specify a special case when an entry value is 0 ( x or y) + * then it must be replaced by 2^16 + */ +static INLINE word16 idea_mult(word16 x, word16 y) +{ + word32 mul, res; + + mul = (word32)x * (word32)y; + if (mul) { + res = (mul & IDEA_MASK) - (mul >> 16); + res -= (res >> 16); + return (word16) ((res <=0 ? res+IDEA_MODULO : res) & IDEA_MASK); + } + + /* x == 0 or y == 0 */ + return (-x -y + 1); +} + +/* compute 1/a modulo 2^16+1 using Extended euclidean algorithm + * adapted from fp_invmod */ +static INLINE word16 idea_invmod(word16 x) +{ + int u, v, b, d; + + if (x <= 1) + return x; + + u = IDEA_MODULO; + v = x; + d = 1; + b = 0; + + do { + while (!(u & 1)) { + u >>= 1; + if (b & 1) + b -= IDEA_MODULO; + b >>= 1; + } + + while (!(v & 1)) { + v >>= 1; + if (d & 1) { + d -= IDEA_MODULO; + } + d >>= 1; + } + + if (u >= v) { + u -= v; + b -= d; + } else { + v -= u; + d -= b; + } + } while (u); + + /* d is now the inverse, put positive value if required */ + if (d < 0) + d += IDEA_MODULO; + + return (word16)(d & IDEA_MASK); +} + +/* generate the 52 16-bits key sub-blocks from the 128 key */ +int wc_IdeaSetKey(Idea *idea, const byte* key, word16 keySz, + const byte *iv, int dir) +{ + word16 idx = 0; + word32 t; + short i; + + if (idea == NULL || key == NULL || keySz != IDEA_KEY_SIZE || + (dir != IDEA_ENCRYPTION && dir != IDEA_DECRYPTION)) + return BAD_FUNC_ARG; + + /* initial key schedule for 0 -> 7 */ + for (i = 0; i < IDEA_ROUNDS; i++) { + idea->skey[i] = (word16)key[idx++] << 8; + idea->skey[i] |= (word16)key[idx++]; + } + + /* shift phase key schedule for 8 -> 51 */ + for (i = IDEA_ROUNDS; i < IDEA_SK_NUM; i++) { + t = (word32)idea->skey[((i+1) & 7) ? i-7 : i-15] << 9; + t |= (word32)idea->skey[((i+2) & 7) < 2 ? i-14 : i-6] >> 7; + idea->skey[i] = (word16)(t & IDEA_MASK); + } + + /* compute decryption key from encryption key */ + if (dir == IDEA_DECRYPTION) { + word16 enckey[IDEA_SK_NUM]; + + /* put encryption key in tmp buffer */ + memcpy(enckey, idea->skey, sizeof(idea->skey)); + + idx = 0; + + idea->skey[6*IDEA_ROUNDS] = idea_invmod(enckey[idx++]); + idea->skey[6*IDEA_ROUNDS+1] = (IDEA_2EXP16 - enckey[idx++]) & IDEA_MASK; + idea->skey[6*IDEA_ROUNDS+2] = (IDEA_2EXP16 - enckey[idx++]) & IDEA_MASK; + idea->skey[6*IDEA_ROUNDS+3] = idea_invmod(enckey[idx++]); + + for (i = 6*(IDEA_ROUNDS-1); i >= 0; i -= 6) { + idea->skey[i+4] = enckey[idx++]; + idea->skey[i+5] = enckey[idx++]; + + idea->skey[i] = idea_invmod(enckey[idx++]); + if (i) { + idea->skey[i+2] = (IDEA_2EXP16 - enckey[idx++]) & IDEA_MASK; + idea->skey[i+1] = (IDEA_2EXP16 - enckey[idx++]) & IDEA_MASK; + } + else { + idea->skey[1] = (IDEA_2EXP16 - enckey[idx++]) & IDEA_MASK; + idea->skey[2] = (IDEA_2EXP16 - enckey[idx++]) & IDEA_MASK; + } + + idea->skey[i+3] = idea_invmod(enckey[idx++]); + } + + /* erase temporary buffer */ + ForceZero(enckey, sizeof(enckey)); + } + + /* set the iv */ + return wc_IdeaSetIV(idea, iv); +} + +/* set the IV in the Idea key structuve */ +int wc_IdeaSetIV(Idea *idea, const byte* iv) +{ + if (idea == NULL) + return BAD_FUNC_ARG; + + if (iv != NULL) + XMEMCPY(idea->reg, iv, IDEA_BLOCK_SIZE); + else + XMEMSET(idea->reg, 0, IDEA_BLOCK_SIZE); + + return 0; +} + +/* encryption/decryption for a block (64 bits) + */ +void wc_IdeaCipher(Idea *idea, byte* out, const byte* in) +{ + word32 t1, t2; + word16 i, skey_idx = 0, idx = 0; + word16 x[4]; + + /* put input byte block in word16 */ + for (i = 0; i < IDEA_BLOCK_SIZE/2; i++) { + x[i] = (word16)in[idx++] << 8; + x[i] |= (word16)in[idx++]; + } + + for (i = 0; i < IDEA_ROUNDS; i++) { + x[0] = idea_mult(x[0], idea->skey[skey_idx++]); + x[1] = ((word32)x[1] + (word32)idea->skey[skey_idx++]) & IDEA_MASK; + x[2] = ((word32)x[2] + (word32)idea->skey[skey_idx++]) & IDEA_MASK; + x[3] = idea_mult(x[3], idea->skey[skey_idx++]); + + t2 = x[0] ^ x[2]; + t2 = idea_mult(t2, idea->skey[skey_idx++]); + t1 = (t2 + (x[1] ^ x[3])) & IDEA_MASK; + t1 = idea_mult(t1, idea->skey[skey_idx++]); + t2 = (t1 + t2) & IDEA_MASK; + + x[0] ^= t1; + x[3] ^= t2; + + t2 ^= x[1]; + x[1] = x[2] ^ t1; + x[2] = t2; + } + + x[0] = idea_mult(x[0], idea->skey[skey_idx++]); + out[0] = (x[0] >> 8) & 0xFF; + out[1] = x[0] & 0xFF; + + x[2] = ((word32)x[2] + (word32)idea->skey[skey_idx++]) & IDEA_MASK; + out[2] = (x[2] >> 8) & 0xFF; + out[3] = x[2] & 0xFF; + + x[1] = ((word32)x[1] + (word32)idea->skey[skey_idx++]) & IDEA_MASK; + out[4] = (x[1] >> 8) & 0xFF; + out[5] = x[1] & 0xFF; + + x[3] = idea_mult(x[3], idea->skey[skey_idx++]); + out[6] = (x[3] >> 8) & 0xFF; + out[7] = x[3] & 0xFF; +} + +int wc_IdeaCbcEncrypt(Idea *idea, byte* out, const byte* in, word32 len) +{ + int blocks; + + if (idea == NULL || out == NULL || in == NULL) + return BAD_FUNC_ARG; + + blocks = len / IDEA_BLOCK_SIZE; + while (blocks--) { + xorbuf(idea->reg, in, IDEA_BLOCK_SIZE); + wc_IdeaCipher(idea, idea->reg, idea->reg); + XMEMCPY(out, idea->reg, IDEA_BLOCK_SIZE); + + out += IDEA_BLOCK_SIZE; + in += IDEA_BLOCK_SIZE; + } + + return 0; +} + +int wc_IdeaCbcDecrypt(Idea *idea, byte* out, const byte* in, word32 len) +{ + int blocks; + byte tmp[IDEA_BLOCK_SIZE]; + + if (idea == NULL || out == NULL || in == NULL) + return BAD_FUNC_ARG; + + blocks = len / IDEA_BLOCK_SIZE; + while (blocks--) { + XMEMCPY(tmp, in, IDEA_BLOCK_SIZE); + wc_IdeaCipher(idea, out, tmp); + xorbuf(out, idea->reg, IDEA_BLOCK_SIZE); + XMEMCPY(idea->reg, tmp, IDEA_BLOCK_SIZE); + + out += IDEA_BLOCK_SIZE; + in += IDEA_BLOCK_SIZE; + } + + return 0; +} + +#endif /* HAVE_IDEA */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ca60d3f42..5a234c4bb 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -211,6 +212,9 @@ int pbkdf2_test(void); #if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) int certext_test(void); #endif +#ifdef HAVE_IDEA +int idea_test(void); +#endif /* General big buffer size for many tests. */ #define FOURK_BUF 4096 @@ -475,6 +479,13 @@ int wolfcrypt_test(void* args) printf( "CAMELLIA test passed!\n"); #endif +#ifdef HAVE_IDEA + if ( (ret = idea_test()) != 0) + return err_sys("IDEA test failed!\n", ret); + else + printf( "IDEA test passed!\n"); +#endif + if ( (ret = random_test()) != 0) return err_sys("RANDOM test failed!\n", ret); else @@ -3178,6 +3189,180 @@ int camellia_test(void) } #endif /* HAVE_CAMELLIA */ +#ifdef HAVE_IDEA +int idea_test(void) +{ + int ret; + word16 i, j; + + Idea idea; + byte data[IDEA_BLOCK_SIZE]; + + /* Project NESSIE test vectors */ +#define IDEA_NB_TESTS 6 +#define IDEA_NB_TESTS_EXTRA 4 + + const byte v_key[IDEA_NB_TESTS][IDEA_KEY_SIZE] = { + { 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37 }, + { 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, + { 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, + { 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 }, + }; + + const byte v1_plain[IDEA_NB_TESTS][IDEA_BLOCK_SIZE] = { + { 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37 }, + { 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84 }, + { 0xDB, 0x2D, 0x4A, 0x92, 0xAA, 0x68, 0x27, 0x3F }, + { 0xF1, 0x29, 0xA6, 0x60, 0x1E, 0xF6, 0x2A, 0x47 }, + }; + + byte v1_cipher[IDEA_NB_TESTS][IDEA_BLOCK_SIZE] = { + { 0x54, 0xCF, 0x21, 0xE3, 0x89, 0xD8, 0x73, 0xEC }, + { 0x85, 0x52, 0x4D, 0x41, 0x0E, 0xB4, 0x28, 0xAE }, + { 0xF5, 0x26, 0xAB, 0x9A, 0x62, 0xC0, 0xD2, 0x58 }, + { 0xC8, 0xFB, 0x51, 0xD3, 0x51, 0x66, 0x27, 0xA8 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84 }, + }; + + byte v1_cipher_100[IDEA_NB_TESTS_EXTRA][IDEA_BLOCK_SIZE] = { + { 0x12, 0x46, 0x2F, 0xD0, 0xFB, 0x3A, 0x63, 0x39 }, + { 0x15, 0x61, 0xE8, 0xC9, 0x04, 0x54, 0x8B, 0xE9 }, + { 0x42, 0x12, 0x2A, 0x94, 0xB0, 0xF6, 0xD2, 0x43 }, + { 0x53, 0x4D, 0xCD, 0x48, 0xDD, 0xD5, 0xF5, 0x9C }, + }; + + byte v1_cipher_1000[IDEA_NB_TESTS_EXTRA][IDEA_BLOCK_SIZE] = { + { 0x44, 0x1B, 0x38, 0x5C, 0x77, 0x29, 0x75, 0x34 }, + { 0xF0, 0x4E, 0x58, 0x88, 0x44, 0x99, 0x22, 0x2D }, + { 0xB3, 0x5F, 0x93, 0x7F, 0x6A, 0xA0, 0xCD, 0x1F }, + { 0x9A, 0xEA, 0x46, 0x8F, 0x42, 0x9B, 0xBA, 0x15 }, + }; + + /* CBC test */ + const char *message = "International Data Encryption Algorithm"; + byte msg_enc[40], msg_dec[40]; + + for (i = 0; i < IDEA_NB_TESTS; i++) { + /* Set encryption key */ + memset(&idea, 0, sizeof(Idea)); + ret = wc_IdeaSetKey(&idea, v_key[i], IDEA_KEY_SIZE, + NULL, IDEA_ENCRYPTION); + if (ret != 0) { + printf("wc_IdeaSetKey (enc) failed\n"); + return -1; + } + + /* Data encryption */ + wc_IdeaCipher(&idea, data, v1_plain[i]); + if (XMEMCMP(&v1_cipher[i], data, IDEA_BLOCK_SIZE)) { + printf("Bad encryption\n"); + return -1; + } + + /* Set decryption key */ + memset(&idea, 0, sizeof(Idea)); + ret = wc_IdeaSetKey(&idea, v_key[i], IDEA_KEY_SIZE, + NULL, IDEA_DECRYPTION); + if (ret != 0) { + printf("wc_IdeaSetKey (dec) failed\n"); + return -1; + } + + /* Data decryption */ + wc_IdeaCipher(&idea, data, data); + if (XMEMCMP(v1_plain[i], data, IDEA_BLOCK_SIZE)) { + printf("Bad decryption\n"); + return -1; + } + + /* Set encryption key */ + memset(&idea, 0, sizeof(Idea)); + ret = wc_IdeaSetKey(&idea, v_key[i], IDEA_KEY_SIZE, + v_key[i], IDEA_ENCRYPTION); + if (ret != 0) { + printf("wc_IdeaSetKey (enc) failed\n"); + return -1; + } + + memset(msg_enc, 0, sizeof(msg_enc)); + ret = wc_IdeaCbcEncrypt(&idea, msg_enc, (byte *)message, + (word32)strlen(message)+1); + if (ret != 0) { + printf("wc_IdeaCbcEncrypt failed\n"); + return -1; + } + + /* Set decryption key */ + memset(&idea, 0, sizeof(Idea)); + ret = wc_IdeaSetKey(&idea, v_key[i], IDEA_KEY_SIZE, + v_key[i], IDEA_DECRYPTION); + if (ret != 0) { + printf("wc_IdeaSetKey (dec) failed\n"); + return -1; + } + + memset(msg_dec, 0, sizeof(msg_dec)); + ret = wc_IdeaCbcDecrypt(&idea, msg_dec, msg_enc, + (word32)strlen(message)+1); + if (ret != 0) { + printf("wc_IdeaCbcDecrypt failed\n"); + return -1; + } + + if (XMEMCMP(message, msg_dec, (word32)strlen(message))) { + printf("Bad CBC decryption\n"); + return -1; + } + } + + for (i = 0; i < IDEA_NB_TESTS_EXTRA; i++) { + /* Set encryption key */ + memset(&idea, 0, sizeof(Idea)); + ret = wc_IdeaSetKey(&idea, v_key[i], IDEA_KEY_SIZE, + NULL, IDEA_ENCRYPTION); + if (ret != 0) { + printf("wc_IdeaSetKey (enc) failed\n"); + return -1; + } + + /* 100 times data encryption */ + XMEMCPY(data, v1_plain[i], IDEA_BLOCK_SIZE); + for (j = 0; j < 100; j++) { + wc_IdeaCipher(&idea, data, data); + } + + if (XMEMCMP(v1_cipher_100[i], data, IDEA_BLOCK_SIZE)) { + printf("Bad encryption (100 times)\n"); + return -1; + } + + /* 1000 times data encryption */ + XMEMCPY(data, v1_plain[i], IDEA_BLOCK_SIZE); + for (j = 0; j < 1000; j++) { + wc_IdeaCipher(&idea, data, data); + } + + if (XMEMCMP(v1_cipher_1000[i], data, IDEA_BLOCK_SIZE)) { + printf("Bad encryption (100 times)\n"); + return -1; + } + } + + return 0; +} +#endif /* HAVE_IDEA */ + #if defined(HAVE_HASHDRBG) || defined(NO_RC4) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index bb7437e68..74c8ddd9a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -88,6 +88,10 @@ #include #endif +#ifdef HAVE_IDEA + #include +#endif + #include #ifdef WOLFSSL_CALLBACKS @@ -241,6 +245,12 @@ typedef byte word24[3]; #endif #endif + #if !defined(NO_RSA) && defined(HAVE_IDEA) + #if !defined(NO_SHA) && defined(WOLFSSL_STATIC_RSA) + #define BUILD_SSL_RSA_WITH_IDEA_CBC_SHA + #endif + #endif + #if !defined(NO_RSA) && !defined(NO_AES) && !defined(NO_TLS) #if !defined(NO_SHA) #if defined(WOLFSSL_STATIC_RSA) @@ -642,6 +652,9 @@ typedef byte word24[3]; #define HAVE_PFS #endif +#if defined(BUILD_SSL_RSA_WITH_IDEA_CBC_SHA) + #define BUILD_IDEA +#endif /* actual cipher values, 2nd byte */ enum { @@ -661,6 +674,7 @@ enum { SSL_RSA_WITH_RC4_128_SHA = 0x05, SSL_RSA_WITH_RC4_128_MD5 = 0x04, SSL_RSA_WITH_3DES_EDE_CBC_SHA = 0x0A, + SSL_RSA_WITH_IDEA_CBC_SHA = 0x07, /* ECC suites, first byte is 0xC0 (ECC_BYTE) */ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0x14, @@ -1841,6 +1855,9 @@ typedef struct Ciphers { #endif #ifdef BUILD_RABBIT Rabbit* rabbit; +#endif +#ifdef HAVE_IDEA + Idea* idea; #endif byte setup; /* have we set it up flag for detection */ } Ciphers; diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index bc6b2baf3..6d3449f07 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -73,6 +73,7 @@ WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_aes_256_ctr(void); WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_des_cbc(void); WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_des_ede3_cbc(void); WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_rc4(void); +WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_idea_cbc(void); WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_enc_null(void); @@ -109,6 +110,9 @@ typedef union { Des3 des3; #endif Arc4 arc4; +#ifdef HAVE_IDEA + Idea idea; +#endif } WOLFSSL_Cipher; @@ -126,6 +130,7 @@ enum { EVP_PKEY_RSA = 11, EVP_PKEY_DSA = 12, EVP_PKEY_EC = 13, + IDEA_CBC_TYPE = 14, NID_sha1 = 64, NID_md5 = 4 }; @@ -224,6 +229,7 @@ typedef WOLFSSL_EVP_CIPHER_CTX EVP_CIPHER_CTX; #define EVP_des_cbc wolfSSL_EVP_des_cbc #define EVP_des_ede3_cbc wolfSSL_EVP_des_ede3_cbc #define EVP_rc4 wolfSSL_EVP_rc4 +#define EVP_idea_cbc wolfSSL_EVP_idea_cbc #define EVP_enc_null wolfSSL_EVP_enc_null #define EVP_MD_size wolfSSL_EVP_MD_size diff --git a/wolfssl/wolfcrypt/idea.h b/wolfssl/wolfcrypt/idea.h new file mode 100644 index 000000000..c3e70c16b --- /dev/null +++ b/wolfssl/wolfcrypt/idea.h @@ -0,0 +1,65 @@ +/* idea.h + * + * Copyright (C) 2006-2015 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL 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. + * + * wolfSSL 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 WOLF_CRYPT_IDEA_H +#define WOLF_CRYPT_IDEA_H + +#include + +#ifdef HAVE_IDEA + +#ifdef __cplusplus + extern "C" { +#endif + +enum { + IDEA_MODULO = 0x10001, /* 2^16+1 */ + IDEA_2EXP16 = 0x10000, /* 2^16 */ + IDEA_MASK = 0xFFFF, /* 16 bits set to one */ + IDEA_ROUNDS = 8, /* number of rounds for IDEA */ + IDEA_SK_NUM = (6*IDEA_ROUNDS + 4), /* number of subkeys */ + IDEA_KEY_SIZE = 16, /* size of key in bytes */ + IDEA_BLOCK_SIZE = 8, /* size of IDEA blocks in bytes */ + IDEA_IV_SIZE = 8, /* size of IDEA IV in bytes */ + IDEA_ENCRYPTION = 0, + IDEA_DECRYPTION = 1 +}; + +/* IDEA encryption and decryption */ +typedef struct Idea { + byte reg[IDEA_BLOCK_SIZE]; /* for CBC mode */ + word16 skey[IDEA_SK_NUM]; /* 832 bits expanded key */ +} Idea; + +WOLFSSL_API int wc_IdeaSetKey(Idea *idea, const byte* key, word16 keySz, + const byte *iv, int dir); +WOLFSSL_API int wc_IdeaSetIV(Idea *idea, const byte* iv); +WOLFSSL_API void wc_IdeaCipher(Idea *idea, byte* out, const byte* in); +WOLFSSL_API int wc_IdeaCbcEncrypt(Idea *idea, byte* out, + const byte* in, word32 len); +WOLFSSL_API int wc_IdeaCbcDecrypt(Idea *idea, byte* out, + const byte* in, word32 len); +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* HAVE_IDEA */ +#endif /* WOLF_CRYPT_IDEA_H */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 8387ed7df..452fe8f18 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -47,6 +47,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/blake2-impl.h \ wolfssl/wolfcrypt/tfm.h \ wolfssl/wolfcrypt/srp.h \ + wolfssl/wolfcrypt/idea.h \ wolfssl/wolfcrypt/types.h \ wolfssl/wolfcrypt/visibility.h \ wolfssl/wolfcrypt/logging.h \