Imported Upstream version 0.3.5
[debian/uanytun.git] / src / cipher.c
index 8913f64..f87e2cf 100644 (file)
  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
  *  ethernet, ip, arp ...). satp directly includes cryptography and
- *  message authentication based on the methodes used by SRTP.  It is
+ *  message authentication based on the methods used by SRTP.  It is
  *  intended to deliver a generic, scaleable and secure solution for
  *  tunneling and relaying of packets of any protocol.
- *  
  *
- *  Copyright (C) 2007-2010 Christian Pointner <equinox@anytun.org>
+ *
+ *  Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
  *
  *  This file is part of uAnytun.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  In addition, as a special exception, the copyright holders give
+ *  permission to link the code of portions of this program with the
+ *  OpenSSL library under certain conditions as described in each
+ *  individual source file, and distribute linked combinations
+ *  including the two.
+ *  You must obey the GNU General Public License in all respects
+ *  for all of the code used other than OpenSSL.  If you modify
+ *  file(s) with this exception, you may extend this exception to your
+ *  version of the file(s), but you are not obligated to do so.  If you
+ *  do not wish to do so, delete this exception statement from your
+ *  version.  If you delete this exception statement from all source
+ *  files in the program, then also delete it here.
  */
 
 #include "datatypes.h"
@@ -39,6 +52,9 @@
 #include "encrypted_packet.h"
 
 #include "cipher.h"
+#if defined(USE_NETTLE)
+#include <nettle/ctr.h>
+#endif
 
 #include "log.h"
 
@@ -47,7 +63,7 @@
 
 int cipher_init(cipher_t* c, const char* type)
 {
-  if(!c) 
+  if(!c)
     return -1;
 
   c->key_length_ = 0;
@@ -61,7 +77,7 @@ int cipher_init(cipher_t* c, const char* type)
     if(type[7] == 0) {
       c->key_length_ = C_AESCTR_DEFAULT_KEY_LENGTH;
     }
-    else if(type[7] != '-') 
+    else if(type[7] != '-')
       return -1;
     else {
       const char* tmp = &type[8];
@@ -113,12 +129,12 @@ void cipher_close(cipher_t* c)
 
 int cipher_encrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir, plain_packet_t* in, encrypted_packet_t* out, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux)
 {
-  if(!c) 
+  if(!c)
     return -1;
 
-       int32_t len;
+  int32_t len;
   if(c->type_ == c_null)
-    len = cipher_null_crypt(plain_packet_get_packet(in), plain_packet_get_length(in), 
+    len = cipher_null_crypt(plain_packet_get_packet(in), plain_packet_get_length(in),
                             encrypted_packet_get_payload(out), encrypted_packet_get_payload_length(out));
 #ifndef NO_CRYPT
   else if(c->type_ == c_aes_ctr)
@@ -134,7 +150,7 @@ int cipher_encrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir,
   if(len < 0)
     return 0;
 
-       encrypted_packet_set_sender_id(out, sender_id);
+  encrypted_packet_set_sender_id(out, sender_id);
   encrypted_packet_set_seq_nr(out, seq_nr);
   encrypted_packet_set_mux(out, mux);
 
@@ -145,10 +161,10 @@ int cipher_encrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir,
 
 int cipher_decrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* in, plain_packet_t* out)
 {
-  if(!c) 
+  if(!c)
     return -1;
 
-       int32_t len;
+  int32_t len;
   if(c->type_ == c_null)
     len = cipher_null_crypt(encrypted_packet_get_payload(in), encrypted_packet_get_payload_length(in),
                             plain_packet_get_packet(out), plain_packet_get_length(out));
@@ -163,11 +179,11 @@ int cipher_decrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir,
     log_printf(ERROR, "unknown cipher type");
     return -1;
   }
-  
+
   if(len < 0)
     return 0;
 
-       plain_packet_set_length(out, len);
+  plain_packet_set_length(out, len);
 
   return 0;
 }
@@ -176,7 +192,7 @@ int cipher_decrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir,
 
 int32_t cipher_null_crypt(u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen)
 {
-       memcpy(out, in, (ilen < olen) ? ilen : olen);
+  memcpy(out, in, (ilen < olen) ? ilen : olen);
   return (ilen < olen) ? ilen : olen;
 }
 
@@ -210,9 +226,11 @@ int cipher_aesctr_init(cipher_t* c)
   if(!c->params_)
     return -2;
 
-  cipher_aesctr_param_t* params = c->params_;
-
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  // nothing here
+#elif defined(USE_NETTLE)
+  // nothing here
+#else  // USE_GCRYPT is the default
   int algo;
   switch(c->key_length_) {
   case 128: algo = GCRY_CIPHER_AES128; break;
@@ -224,11 +242,12 @@ int cipher_aesctr_init(cipher_t* c)
   }
   }
 
+  cipher_aesctr_param_t* params = c->params_;
   gcry_error_t err = gcry_cipher_open(&params->handle_, algo, GCRY_CIPHER_MODE_CTR, 0);
   if(err) {
     log_printf(ERROR, "failed to open cipher: %s", gcry_strerror(err));
     return -1;
-  } 
+  }
 #endif
 
   return 0;
@@ -240,13 +259,14 @@ void cipher_aesctr_close(cipher_t* c)
     return;
 
   if(c->params_) {
+#if defined(USE_SSL_CRYPTO)
+    // nothing here
+#elif defined(USE_NETTLE)
+    // nothing here
+#else  // USE_GCRYPT is the default
     cipher_aesctr_param_t* params = c->params_;
-
-#ifndef USE_SSL_CRYPTO
-    if(params->handle_)
-      gcry_cipher_close(params->handle_);
+    gcry_cipher_close(params->handle_);
 #endif
-
     free(c->params_);
   }
 }
@@ -255,7 +275,7 @@ int cipher_aesctr_calc_ctr(cipher_t* c, key_derivation_t* kd, key_derivation_dir
 {
   if(!c || !c->params_)
     return -1;
-  
+
   cipher_aesctr_param_t* params = c->params_;
 
   int ret = key_derivation_generate(kd, dir, LABEL_SALT, seq_nr, c->salt_.buf_, C_AESCTR_SALT_LENGTH);
@@ -288,14 +308,16 @@ int32_t cipher_aesctr_crypt(cipher_t* c, key_derivation_t* kd, key_derivation_di
   int ret = key_derivation_generate(kd, dir, LABEL_ENC, seq_nr, c->key_.buf_, c->key_.length_);
   if(ret < 0)
     return ret;
-  
-#ifdef USE_SSL_CRYPTO
+
+#if defined(USE_SSL_CRYPTO)
   ret = AES_set_encrypt_key(c->key_.buf_, c->key_length_, &params->aes_key_);
   if(ret) {
-    log_printf(ERROR, "failed to set cipher ssl aes-key (code: %d)", ret);
+    log_printf(ERROR, "failed to set cipher key (code: %d)", ret);
     return -1;
   }
-#else
+#elif defined(USE_NETTLE)
+  aes_set_encrypt_key(&params->ctx_, c->key_.length_, c->key_.buf_);
+#else  // USE_GCRYPT is the default
   gcry_error_t err = gcry_cipher_setkey(params->handle_, c->key_.buf_, c->key_.length_);
   if(err) {
     log_printf(ERROR, "failed to set cipher key: %s", gcry_strerror(err));
@@ -308,8 +330,22 @@ int32_t cipher_aesctr_crypt(cipher_t* c, key_derivation_t* kd, key_derivation_di
     log_printf(ERROR, "failed to calculate cipher CTR");
     return ret;
   }
-  
-#ifndef USE_SSL_CRYPTO
+
+#if defined(USE_SSL_CRYPTO)
+  if(C_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
+    log_printf(ERROR, "failed to set cipher CTR: size doesn't fit");
+    return -1;
+  }
+  u_int32_t num = 0;
+  memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
+  AES_ctr128_encrypt(in, out, (ilen < olen) ? ilen : olen, &params->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num);
+#elif defined(USE_NETTLE)
+  if(C_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
+    log_printf(ERROR, "failed to set cipher CTR: size doesn't fit");
+    return -1;
+  }
+  ctr_crypt(&params->ctx_, (nettle_crypt_func *)(aes_encrypt), AES_BLOCK_SIZE, params->ctr_.buf_, (ilen < olen) ? ilen : olen, out, in);
+#else  // USE_GCRYPT is the default
   err = gcry_cipher_setctr(params->handle_, params->ctr_.buf_, C_AESCTR_CTR_LENGTH);
   if(err) {
     log_printf(ERROR, "failed to set cipher CTR: %s", gcry_strerror(err));
@@ -321,16 +357,8 @@ int32_t cipher_aesctr_crypt(cipher_t* c, key_derivation_t* kd, key_derivation_di
     log_printf(ERROR, "failed to de/encrypt packet: %s", gcry_strerror(err));
     return -1;
   }
-#else
-  if(C_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
-    log_printf(ERROR, "failed to set cipher CTR: size don't fits");
-    return -1;
-  }
-  u_int32_t num = 0;
-  memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
-  AES_ctr128_encrypt(in, out, (ilen < olen) ? ilen : olen, &params->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num);
 #endif
 
-  return (ilen < olen) ? ilen : olen;  
+  return (ilen < olen) ? ilen : olen;
 }
 #endif