Merged new cipher layer enhancements
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 354c6c2..aafbfb6 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -504,6 +504,9 @@
     md_context_t md_ctx_enc;            /*!<  MAC (encryption)        */
     md_context_t md_ctx_dec;            /*!<  MAC (decryption)        */
 
+    cipher_context_t cipher_ctx_enc;    /*!<  encryption context      */
+    cipher_context_t cipher_ctx_dec;    /*!<  decryption context      */
+
     uint32_t ctx_enc[SSL_CTX_MAX / 4];  /*!<  encryption context      */
     uint32_t ctx_dec[SSL_CTX_MAX / 4];  /*!<  decryption context      */
 
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index ed95d3e..52d4b33 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -355,6 +355,7 @@
 
 int ssl_derive_keys( ssl_context *ssl )
 {
+    int ret = 0;
     unsigned char tmp[64];
     unsigned char keyblk[256];
     unsigned char *key1;
@@ -632,48 +633,73 @@
 
     switch( cipher_info->type )
     {
-#if defined(POLARSSL_ARC4_C)
         case POLARSSL_CIPHER_ARC4_128:
-            arc4_setup( (arc4_context *) transform->ctx_enc, key1,
-                        transform->keylen );
-            arc4_setup( (arc4_context *) transform->ctx_dec, key2,
-                        transform->keylen );
-            break;
-#endif
-
-#if defined(POLARSSL_DES_C)
         case POLARSSL_CIPHER_DES_EDE3_CBC:
-             des3_set3key_enc( (des3_context *) transform->ctx_enc, key1 );
-             des3_set3key_dec( (des3_context *) transform->ctx_dec, key2 );
-             break;
-#endif
-
-#if defined(POLARSSL_AES_C)
-        case POLARSSL_CIPHER_AES_128_CBC:
-        case POLARSSL_CIPHER_AES_256_CBC:
-            aes_setkey_enc( (aes_context*) transform->ctx_enc, key1,
-                            cipher_info->key_length );
-            aes_setkey_dec( (aes_context*) transform->ctx_dec, key2,
-                            cipher_info->key_length );
-            break;
-#endif
-
-#if defined(POLARSSL_CAMELLIA_C)
         case POLARSSL_CIPHER_CAMELLIA_128_CBC:
         case POLARSSL_CIPHER_CAMELLIA_256_CBC:
-            camellia_setkey_enc( (camellia_context*) transform->ctx_enc, key1,
-                                 cipher_info->key_length );
-            camellia_setkey_dec( (camellia_context*) transform->ctx_dec, key2,
-                                 cipher_info->key_length );
-            break;
-#endif
-
-#if defined(POLARSSL_DES_C)
+        case POLARSSL_CIPHER_AES_128_CBC:
+        case POLARSSL_CIPHER_AES_256_CBC:
         case POLARSSL_CIPHER_DES_CBC:
-            des_setkey_enc( (des_context *) transform->ctx_enc, key1 );
-            des_setkey_dec( (des_context *) transform->ctx_dec, key2 );
+            if( ( ret = cipher_init_ctx( &transform->cipher_ctx_enc,
+                                         cipher_info ) ) != 0 )
+            {
+                return( ret );
+            }
+
+            if( ( ret = cipher_init_ctx( &transform->cipher_ctx_dec,
+                                         cipher_info ) ) != 0 )
+            {
+                return( ret );
+            }
+
+            if( cipher_info->type == POLARSSL_CIPHER_ARC4_128 )
+            {
+                if( ( ret = cipher_setkey( &transform->cipher_ctx_enc, key1,
+                                           cipher_info->key_length / 8,
+                                           POLARSSL_ENCRYPT ) ) != 0 )
+                {
+                    return( ret );
+                }
+
+                if( ( ret = cipher_setkey( &transform->cipher_ctx_dec, key2,
+                                           cipher_info->key_length / 8,
+                                           POLARSSL_DECRYPT ) ) != 0 )
+                {
+                    return( ret );
+                }
+            }
+            else
+            {
+                if( ( ret = cipher_setkey( &transform->cipher_ctx_enc, key1,
+                                           cipher_info->key_length,
+                                           POLARSSL_ENCRYPT ) ) != 0 )
+                {
+                    return( ret );
+                }
+
+                if( ( ret = cipher_setkey( &transform->cipher_ctx_dec, key2,
+                                           cipher_info->key_length,
+                                           POLARSSL_DECRYPT ) ) != 0 )
+                {
+                    return( ret );
+                }
+            }
+
+            if( cipher_info->mode == POLARSSL_MODE_CBC )
+            {
+                if( ( ret = cipher_set_padding_mode( &transform->cipher_ctx_enc,
+                                                     POLARSSL_PADDING_NONE ) ) != 0 )
+                {
+                    return( ret );
+                }
+
+                if( ( ret = cipher_set_padding_mode( &transform->cipher_ctx_dec,
+                                                     POLARSSL_PADDING_NONE ) ) != 0 )
+                {
+                    return( ret );
+                }
+            }
             break;
-#endif
 
 #if defined(POLARSSL_GCM_C)
         case POLARSSL_CIPHER_AES_128_GCM:
@@ -913,9 +939,11 @@
     }
     else
 #endif /* POLARSSL_CIPHER_NULL_CIPHER */
-#if defined(POLARSSL_ARC4_C)
     if( ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_ARC4_128 )
     {
+        int ret;
+        size_t olen = 0;
+
         padlen = 0;
 
         SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, "
@@ -925,12 +953,43 @@
         SSL_DEBUG_BUF( 4, "before encrypt: output payload",
                        ssl->out_msg, ssl->out_msglen );
 
-        arc4_crypt( (arc4_context *) ssl->transform_out->ctx_enc,
-                    ssl->out_msglen, ssl->out_msg,
-                    ssl->out_msg );
+        if( ( ret = cipher_reset( &ssl->transform_out->cipher_ctx_enc,
+                                  ssl->transform_out->iv_enc,
+                                  ssl->transform_out->ivlen, NULL, 0 ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( ( ret = cipher_update( &ssl->transform_out->cipher_ctx_enc,
+                                   ssl->out_msg, ssl->out_msglen, ssl->out_msg,
+                                   &olen ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( ssl->out_msglen != olen )
+        {
+            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect %d %d",
+                                ssl->out_msglen, olen ) );
+            // TODO Real error number
+            return( -1 );
+        }
+
+        if( ( ret = cipher_finish( &ssl->transform_out->cipher_ctx_enc,
+                                   ssl->out_msg + olen, &olen, NULL, 0 ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( 0 != olen )
+        {
+            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect %d %d",
+                                0, olen ) );
+            // TODO Real error number
+            return( -1 );
+        }
     }
     else
-#endif /* POLARSSL_ARC4_C */
 #if defined(POLARSSL_GCM_C)
     if( ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_AES_128_GCM ||
         ssl->transform_out->ciphersuite_info->cipher == POLARSSL_CIPHER_AES_256_GCM )
@@ -999,8 +1058,10 @@
     else
 #endif /* POLARSSL_GCM_C */
     {
+        int ret;
         unsigned char *enc_msg;
         size_t enc_msglen;
+        size_t olen = 0;
 
         padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) %
                  ssl->transform_out->ivlen;
@@ -1049,43 +1110,47 @@
         SSL_DEBUG_BUF( 4, "before encrypt: output payload",
                        ssl->out_iv, ssl->out_msglen );
 
-        switch( ssl->transform_out->ciphersuite_info->cipher )
+        if( ( ret = cipher_reset( &ssl->transform_out->cipher_ctx_enc,
+                                  ssl->transform_out->iv_enc,
+                                  ssl->transform_out->ivlen, NULL, 0 ) ) != 0 )
         {
-#if defined(POLARSSL_DES_C)
-            case POLARSSL_CIPHER_DES_CBC:
-                des_crypt_cbc( (des_context *) ssl->transform_out->ctx_enc,
-                               DES_ENCRYPT, enc_msglen,
-                               ssl->transform_out->iv_enc, enc_msg, enc_msg );
-                break;
-
-            case POLARSSL_CIPHER_DES_EDE3_CBC:
-                des3_crypt_cbc( (des3_context *) ssl->transform_out->ctx_enc,
-                               DES_ENCRYPT, enc_msglen,
-                               ssl->transform_out->iv_enc, enc_msg, enc_msg );
-                break;
-#endif
-
-#if defined(POLARSSL_AES_C)
-            case POLARSSL_CIPHER_AES_128_CBC:
-            case POLARSSL_CIPHER_AES_256_CBC:
-                aes_crypt_cbc( (aes_context *) ssl->transform_out->ctx_enc,
-                               AES_ENCRYPT, enc_msglen,
-                               ssl->transform_out->iv_enc, enc_msg, enc_msg );
-                break;
-#endif
-
-#if defined(POLARSSL_CAMELLIA_C)
-            case POLARSSL_CIPHER_CAMELLIA_128_CBC:
-            case POLARSSL_CIPHER_CAMELLIA_256_CBC:
-                camellia_crypt_cbc( (camellia_context *) ssl->transform_out->ctx_enc,
-                                    CAMELLIA_ENCRYPT, enc_msglen,
-                                    ssl->transform_out->iv_enc, enc_msg, enc_msg );
-                break;
-#endif
-
-            default:
-                return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+            return( ret );
         }
+
+        if( ( ret = cipher_update( &ssl->transform_out->cipher_ctx_enc,
+                                   enc_msg, enc_msglen, enc_msg,
+                                   &olen ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        enc_msglen -= olen;
+
+        if( ( ret = cipher_finish( &ssl->transform_out->cipher_ctx_enc,
+                                   enc_msg + olen, &olen, NULL, 0 ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( enc_msglen != olen )
+        {
+            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect %d %d",
+                                enc_msglen, olen ) );
+            // TODO Real error number
+            return( -1 );
+        }
+
+#if defined(POLARSSL_SSL_PROTO_SSL3) || defined(POLARSSL_SSL_PROTO_TLS1)
+        if( ssl->minor_ver < SSL_MINOR_VERSION_2 )
+        {
+            /*
+             * Save IV in SSL3 and TLS1
+             */
+            memcpy( ssl->transform_out->iv_enc,
+                    ssl->transform_out->cipher_ctx_enc.iv,
+                    ssl->transform_out->ivlen );
+        }
+#endif
     }
 
     for( i = 8; i > 0; i-- )
@@ -1123,11 +1188,44 @@
 #if defined(POLARSSL_ARC4_C)
     if( ssl->transform_in->ciphersuite_info->cipher == POLARSSL_CIPHER_ARC4_128 )
     {
+        int ret;
+        size_t olen = 0;
+
         padlen = 0;
 
-        arc4_crypt( (arc4_context *) ssl->transform_in->ctx_dec,
-                    ssl->in_msglen, ssl->in_msg,
-                    ssl->in_msg );
+        if( ( ret = cipher_reset( &ssl->transform_in->cipher_ctx_dec,
+                                  ssl->transform_in->iv_dec,
+                                  ssl->transform_in->ivlen, NULL, 0 ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( ( ret = cipher_update( &ssl->transform_in->cipher_ctx_dec,
+                                   ssl->in_msg, ssl->in_msglen, ssl->in_msg,
+                                   &olen ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( ssl->in_msglen != olen )
+        {
+            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect" ) );
+            // TODO Real error number
+            return( -1 );
+        }
+
+        if( ( ret = cipher_finish( &ssl->transform_in->cipher_ctx_dec,
+                                   ssl->in_msg + olen, &olen, NULL, 0  ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( 0 != olen )
+        {
+            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect" ) );
+            // TODO Real error number
+            return( -1 );
+        }
     }
     else
 #endif /* POLARSSL_ARC4_C */
@@ -1190,10 +1288,12 @@
         /*
          * Decrypt and check the padding
          */
+        int ret;
         unsigned char *dec_msg;
         unsigned char *dec_msg_result;
         size_t dec_msglen;
         size_t minlen = 0;
+        size_t olen = 0;
 
         /*
          * Check immediate ciphertext sanity
@@ -1236,44 +1336,46 @@
         }
 #endif /* POLARSSL_SSL_PROTO_TLS1_1 || POLARSSL_SSL_PROTO_TLS1_2 */
 
-        switch( ssl->transform_in->ciphersuite_info->cipher )
+        if( ( ret = cipher_reset( &ssl->transform_in->cipher_ctx_dec,
+                                  ssl->transform_in->iv_dec,
+                                  ssl->transform_in->ivlen, NULL, 0 ) ) != 0 )
         {
-#if defined(POLARSSL_DES_C)
-            case POLARSSL_CIPHER_DES_CBC:
-                des_crypt_cbc( (des_context *) ssl->transform_in->ctx_dec,
-                               DES_DECRYPT, dec_msglen,
-                               ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                break;
-
-            case POLARSSL_CIPHER_DES_EDE3_CBC:
-                des3_crypt_cbc( (des3_context *) ssl->transform_in->ctx_dec,
-                               DES_DECRYPT, dec_msglen,
-                               ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                break;
-#endif
-
-#if defined(POLARSSL_AES_C)
-            case POLARSSL_CIPHER_AES_128_CBC:
-            case POLARSSL_CIPHER_AES_256_CBC:
-                aes_crypt_cbc( (aes_context *) ssl->transform_in->ctx_dec,
-                               AES_DECRYPT, dec_msglen,
-                               ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                break;
-#endif
-
-#if defined(POLARSSL_CAMELLIA_C)
-            case POLARSSL_CIPHER_CAMELLIA_128_CBC:
-            case POLARSSL_CIPHER_CAMELLIA_256_CBC:
-                camellia_crypt_cbc( (camellia_context *) ssl->transform_in->ctx_dec,
-                                    CAMELLIA_DECRYPT, dec_msglen,
-                                    ssl->transform_in->iv_dec, dec_msg, dec_msg_result );
-                break;
-#endif
-
-            default:
-                return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+            return( ret );
         }
 
+        if( ( ret = cipher_update( &ssl->transform_in->cipher_ctx_dec,
+                                   dec_msg, dec_msglen, dec_msg_result,
+                                   &olen ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        dec_msglen -= olen;
+        if( ( ret = cipher_finish( &ssl->transform_in->cipher_ctx_dec,
+                                   dec_msg_result + olen, &olen, NULL, 0  ) ) != 0 )
+        {
+            return( ret );
+        }
+
+        if( dec_msglen != olen )
+        {
+            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect" ) );
+            // TODO Real error number
+            return( -1 );
+        }
+
+#if defined(POLARSSL_SSL_PROTO_SSL3) || defined(POLARSSL_SSL_PROTO_TLS1)
+        if( ssl->minor_ver < SSL_MINOR_VERSION_2 )
+        {
+            /*
+             * Save IV in SSL3 and TLS1
+             */
+            memcpy( ssl->transform_in->iv_dec,
+                    ssl->transform_in->cipher_ctx_dec.iv,
+                    ssl->transform_in->ivlen );
+        }
+#endif
+
         padlen = 1 + ssl->in_msg[ssl->in_msglen - 1];
 
         if( ssl->in_msglen < ssl->transform_in->maclen + padlen )