Imported Upstream version 0.3.5
[debian/uanytun.git] / src / key_derivation.c
index a01695b..f2d8548 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"
 
 #include "key_derivation.h"
 
-#ifdef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
 #include <openssl/sha.h>
+#elif defined(USE_NETTLE)
+#include <nettle/sha1.h>
+#include <nettle/sha2.h>
+#include <nettle/ctr.h>
 #endif
 
 #include "log.h"
@@ -48,7 +65,7 @@
 
 int key_derivation_init(key_derivation_t* kd, const char* type, role_t role, const char* passphrase, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len)
 {
-  if(!kd) 
+  if(!kd)
     return -1;
 
   kd->role_ = role;
@@ -62,7 +79,7 @@ int key_derivation_init(key_derivation_t* kd, const char* type, role_t role, con
     if(type[7] == 0) {
       kd->key_length_ = KD_AESCTR_DEFAULT_KEY_LENGTH;
     }
-    else if(type[7] != '-') 
+    else if(type[7] != '-')
       return -1;
     else {
       const char* tmp = &type[8];
@@ -127,7 +144,7 @@ int key_derivation_generate_master_key(key_derivation_t* kd, const char* passphr
   if(kd->master_key_.buf_) {
     log_printf(WARNING, "master key and passphrase provided, ignoring passphrase");
     return 0;
-  }    
+  }
   log_printf(NOTICE, "using passphrase to generate master key");
 
   if(!key_length || (key_length % 8)) {
@@ -135,30 +152,39 @@ int key_derivation_generate_master_key(key_derivation_t* kd, const char* passphr
     return -1;
   }
 
-#ifndef USE_SSL_CRYPTO
-  if(key_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA256) * 8)) {
-#else
+#if defined(USE_SSL_CRYPTO)
   if(key_length > (SHA256_DIGEST_LENGTH * 8)) {
+#elif defined(USE_NETTLE)
+  if(key_length > (SHA256_DIGEST_SIZE * 8)) {
+#else  // USE_GCRYPT is the default
+  if(key_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA256) * 8)) {
 #endif
     log_printf(ERROR, "master key too long for passphrase algorithm");
     return -1;
   }
 
   buffer_t digest;
-#ifndef USE_SSL_CRYPTO
-  digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
-#else
+#if defined(USE_SSL_CRYPTO)
   digest.length_ = SHA256_DIGEST_LENGTH;
+#elif defined(USE_NETTLE)
+  digest.length_ = SHA256_DIGEST_SIZE;
+#else  // USE_GCRYPT is the default
+  digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
 #endif
   digest.buf_ = malloc(digest.length_);
   if(!digest.buf_)
     return -2;
 
 
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  SHA256((const u_int8_t*)passphrase, strlen(passphrase), digest.buf_);
+#elif defined(USE_NETTLE)
+  struct sha256_ctx ctx;
+  sha256_init(&ctx);
+  sha256_update(&ctx, strlen(passphrase), (const u_int8_t*)passphrase);
+  sha256_digest(&ctx, digest.length_, digest.buf_);
+#else  // USE_GCRYPT is the default
   gcry_md_hash_buffer(GCRY_MD_SHA256, digest.buf_, passphrase, strlen(passphrase));
-#else
-  SHA256(passphrase, strlen(passphrase), digest.buf_);
 #endif
 
   kd->master_key_.length_ = key_length/8;
@@ -183,7 +209,7 @@ int key_derivation_generate_master_salt(key_derivation_t* kd, const char* passph
   if(kd->master_salt_.buf_) {
     log_printf(WARNING, "master salt and passphrase provided, ignoring passphrase");
     return 0;
-  }    
+  }
   log_printf(NOTICE, "using passphrase to generate master salt");
 
   if(!salt_length || (salt_length % 8)) {
@@ -191,29 +217,38 @@ int key_derivation_generate_master_salt(key_derivation_t* kd, const char* passph
     return -1;
   }
 
-#ifndef USE_SSL_CRYPTO
-  if(salt_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA1) * 8)) {
-#else
+#if defined(USE_SSL_CRYPTO)
   if(salt_length > (SHA_DIGEST_LENGTH * 8)) {
+#elif defined(USE_NETTLE)
+  if(salt_length > (SHA1_DIGEST_SIZE * 8)) {
+#else  // USE_GCRYPT is the default
+  if(salt_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA1) * 8)) {
 #endif
     log_printf(ERROR, "master salt too long for passphrase algorithm");
     return -1;
   }
 
   buffer_t digest;
-#ifndef USE_SSL_CRYPTO
-  digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
-#else
+#if defined(USE_SSL_CRYPTO)
   digest.length_ = SHA_DIGEST_LENGTH;
+#elif defined(USE_NETTLE)
+  digest.length_ = SHA1_DIGEST_SIZE;
+#else  // USE_GCRYPT is the default
+  digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
 #endif
   digest.buf_ = malloc(digest.length_);
   if(!digest.buf_)
     return -2;
 
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  SHA1((const u_int8_t*)passphrase, strlen(passphrase), digest.buf_);
+#elif defined(USE_NETTLE)
+  struct sha1_ctx ctx;
+  sha1_init(&ctx);
+  sha1_update(&ctx, strlen(passphrase), (const u_int8_t*)passphrase);
+  sha1_digest(&ctx, digest.length_, digest.buf_);
+#else  // USE_GCRYPT is the default
   gcry_md_hash_buffer(GCRY_MD_SHA1, digest.buf_, passphrase, strlen(passphrase));
-#else
-  SHA1(passphrase, strlen(passphrase), digest.buf_);
 #endif
 
   kd->master_salt_.length_ = salt_length/8;
@@ -247,7 +282,7 @@ void key_derivation_close(key_derivation_t* kd)
 
 int key_derivation_generate(key_derivation_t* kd, key_derivation_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len)
 {
-  if(!kd || !key) 
+  if(!kd || !key)
     return -1;
 
   if(label >= LABEL_NIL) {
@@ -330,7 +365,7 @@ int key_derivation_aesctr_init(key_derivation_t* kd, const char* passphrase)
     return -2;
 
   key_derivation_aesctr_param_t* params = kd->params_;
-#ifndef USE_SSL_CRYPTO
+#ifdef USE_GCRYPT
   params->handle_ = 0;
 #endif
 
@@ -345,7 +380,15 @@ int key_derivation_aesctr_init(key_derivation_t* kd, const char* passphrase)
   }
 #endif
 
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  int ret = AES_set_encrypt_key(kd->master_key_.buf_, kd->master_key_.length_*8, &params->aes_key_);
+  if(ret) {
+    log_printf(ERROR, "failed to set key derivation ssl aes-key (code: %d)", ret);
+    return -1;
+  }
+#elif defined(USE_NETTLE)
+  aes_set_encrypt_key(&params->ctx_, kd->master_key_.length_, kd->master_key_.buf_);
+#else  // USE_GCRYPT is the default
   int algo;
   switch(kd->key_length_) {
   case 128: algo = GCRY_CIPHER_AES128; break;
@@ -361,19 +404,13 @@ int key_derivation_aesctr_init(key_derivation_t* kd, const char* passphrase)
   if(err) {
     log_printf(ERROR, "failed to open key derivation cipher: %s", gcry_strerror(err));
     return -1;
-  } 
+  }
 
   err = gcry_cipher_setkey(params->handle_, kd->master_key_.buf_, kd->master_key_.length_);
   if(err) {
     log_printf(ERROR, "failed to set key derivation key: %s", gcry_strerror(err));
     return -1;
   }
-#else
-  int ret = AES_set_encrypt_key(kd->master_key_.buf_, kd->master_key_.length_*8, &params->aes_key_);
-  if(ret) {
-    log_printf(ERROR, "failed to set key derivation ssl aes-key (code: %d)", ret);
-    return -1;
-  }
 #endif
 
   return 0;
@@ -385,9 +422,8 @@ void key_derivation_aesctr_close(key_derivation_t* kd)
     return;
 
   if(kd->params_) {
+#ifdef USE_GCRYPT
     key_derivation_aesctr_param_t* params = kd->params_;
-
-#ifndef USE_SSL_CRYPTO
     if(params->handle_)
       gcry_cipher_close(params->handle_);
 #endif
@@ -429,7 +465,23 @@ int key_derivation_aesctr_generate(key_derivation_t* kd, key_derivation_dir_t di
     return -1;
   }
 
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  if(KD_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
+    log_printf(ERROR, "failed to set key derivation CTR: size don't fits");
+    return -1;
+  }
+  u_int32_t num = 0;
+  memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
+  memset(key, 0, len);
+  AES_ctr128_encrypt(key, key, len, &params->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num);
+#elif defined(USE_NETTLE)
+  if(KD_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
+    log_printf(ERROR, "failed to set cipher CTR: size doesn't fit");
+    return -1;
+  }
+  memset(key, 0, len);
+  ctr_crypt(&params->ctx_, (nettle_crypt_func *)(aes_encrypt), AES_BLOCK_SIZE, params->ctr_.buf_, len, key, key);
+#else  // USE_GCRYPT is the default
   gcry_error_t err = gcry_cipher_reset(params->handle_);
   if(err) {
     log_printf(ERROR, "failed to reset key derivation cipher: %s", gcry_strerror(err));
@@ -448,16 +500,7 @@ int key_derivation_aesctr_generate(key_derivation_t* kd, key_derivation_dir_t di
     log_printf(ERROR, "failed to generate key derivation bitstream: %s", gcry_strerror(err));
     return -1;
   }
-#else
-  if(KD_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
-    log_printf(ERROR, "failed to set key derivation CTR: size don't fits");
-    return -1;
-  }
-  u_int32_t num = 0;
-  memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
-  memset(key, 0, len);
-  AES_ctr128_encrypt(key, key, len, &params->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num);
 #endif
-  
+
   return 0;
 }