Imported Upstream version 0.3.5
[anytun.git] / src / keyDerivation.cpp
index 17d2a7c..780a51c 100644 (file)
@@ -6,12 +6,12 @@
  *  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-2009 Othmar Gsenger, Erwin Nindl,
+ *  Copyright (C) 2007-2014 Markus Grüneis, Othmar Gsenger, Erwin Nindl,
  *                          Christian Pointner <satp@wirdorange.org>
  *
  *  This file is part of Anytun.
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.
+ *  along with Anytun.  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.
  */
 
 
 
 #ifndef NO_CRYPT
 #ifndef NO_PASSPHRASE
-#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
+
 #endif
 #endif
 
@@ -69,21 +88,29 @@ void KeyDerivation::calcMasterKey(std::string passphrase, uint16_t length)
     return;
   }
 
-#ifndef USE_SSL_CRYPTO
-  if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA256)) {
-#else
+#if defined(USE_SSL_CRYPTO)
   if(length > SHA256_DIGEST_LENGTH) {
+#elif defined(USE_NETTLE)
+  if(length > SHA256_DIGEST_SIZE) {
+#else  // USE_GCRYPT is the default
+  if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA256)) {
 #endif
     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: master key too long for passphrase algorithm";
     return;
   }
 
-#ifndef USE_SSL_CRYPTO
-  Buffer digest(static_cast<uint32_t>(gcry_md_get_algo_dlen(GCRY_MD_SHA256)));
-  gcry_md_hash_buffer(GCRY_MD_SHA256, digest.getBuf(), passphrase.c_str(), passphrase.length());
-#else
+#if defined(USE_SSL_CRYPTO)
   Buffer digest(uint32_t(SHA256_DIGEST_LENGTH));
   SHA256(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
+#elif defined(USE_NETTLE)
+  Buffer digest(uint32_t(SHA256_DIGEST_SIZE));
+  struct sha256_ctx ctx;
+  sha256_init(&ctx);
+  sha256_update(&ctx, passphrase.length(), reinterpret_cast<const unsigned char*>(passphrase.c_str()));
+  sha256_digest(&ctx, digest.getLength(), digest.getBuf());
+#else  // USE_GCRYPT is the default
+  Buffer digest(static_cast<uint32_t>(gcry_md_get_algo_dlen(GCRY_MD_SHA256)));
+  gcry_md_hash_buffer(GCRY_MD_SHA256, digest.getBuf(), passphrase.c_str(), passphrase.length());
 #endif
   master_key_.setLength(length);
 
@@ -98,21 +125,29 @@ void KeyDerivation::calcMasterSalt(std::string passphrase, uint16_t length)
     return;
   }
 
-#ifndef USE_SSL_CRYPTO
-  if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA1)) {
-#else
+#if defined(USE_SSL_CRYPTO)
   if(length > SHA_DIGEST_LENGTH) {
+#elif defined(USE_NETTLE)
+  if(length > SHA1_DIGEST_SIZE) {
+#else  // USE_GCRYPT is the default
+  if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA1)) {
 #endif
     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: master key too long for passphrase algorithm";
     return;
   }
 
-#ifndef USE_SSL_CRYPTO
-  Buffer digest(static_cast<uint32_t>(gcry_md_get_algo_dlen(GCRY_MD_SHA1)));
-  gcry_md_hash_buffer(GCRY_MD_SHA1, digest.getBuf(), passphrase.c_str(), passphrase.length());
-#else
+#if defined(USE_SSL_CRYPTO)
   Buffer digest(uint32_t(SHA_DIGEST_LENGTH));
   SHA1(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
+#elif defined(USE_NETTLE)
+  Buffer digest(uint32_t(SHA1_DIGEST_SIZE));
+  struct sha1_ctx ctx;
+  sha1_init(&ctx);
+  sha1_update(&ctx, passphrase.length(), reinterpret_cast<const unsigned char*>(passphrase.c_str()));
+  sha1_digest(&ctx, digest.getLength(), digest.getBuf());
+#else  // USE_GCRYPT is the default
+  Buffer digest(static_cast<uint32_t>(gcry_md_get_algo_dlen(GCRY_MD_SHA1)));
+  gcry_md_hash_buffer(GCRY_MD_SHA1, digest.getBuf(), passphrase.c_str(), passphrase.length());
 #endif
   master_salt_.setLength(length);
 
@@ -172,7 +207,7 @@ bool NullKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t
 
 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH)
 {
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_GCRYPT)
   for(int i=0; i<2; i++) {
     handle_[i] = NULL;
   }
@@ -181,7 +216,7 @@ AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH)
 
 AesIcmKeyDerivation::AesIcmKeyDerivation(uint16_t key_length) : KeyDerivation(key_length)
 {
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_GCRYPT)
   for(int i=0; i<2; i++) {
     handle_[i] = NULL;
   }
@@ -191,7 +226,7 @@ AesIcmKeyDerivation::AesIcmKeyDerivation(uint16_t key_length) : KeyDerivation(ke
 AesIcmKeyDerivation::~AesIcmKeyDerivation()
 {
   WritersLock lock(mutex_);
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_GCRYPT)
   for(int i=0; i<2; i++)
     if(handle_[i]) {
       gcry_cipher_close(handle_[i]);
@@ -236,7 +271,19 @@ void AesIcmKeyDerivation::updateMasterKey()
     return;
   }
 
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  for(int i=0; i<2; i++) {
+    int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_[i]);
+    if(ret) {
+      cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")";
+      return;
+    }
+  }
+#elif defined(USE_NETTLE)
+  for(int i=0; i<2; i++) {
+    aes_set_encrypt_key(&(ctx_[i]), master_key_.getLength(), master_key_.getBuf());
+  }
+#else  // USE_GCRYPT is the default
   int algo;
   switch(key_length_) {
   case 128:
@@ -271,14 +318,6 @@ void AesIcmKeyDerivation::updateMasterKey()
       return;
     }
   }
-#else
-  for(int i=0; i<2; i++) {
-    int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_[i]);
-    if(ret) {
-      cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")";
-      return;
-    }
-  }
 #endif
   is_initialized_ = true;
 }
@@ -318,7 +357,23 @@ bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_
     return false;
   }
 
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+  if(CTR_LENGTH != AES_BLOCK_SIZE) {
+    cLog.msg(Log::PRIO_ERROR) << "AesIcmCipher: Failed to set cipher CTR: size doesn't fit";
+    return false;
+  }
+  unsigned int num = 0;
+  std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE);
+  std::memset(key.getBuf(), 0, key.getLength());
+  AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num);
+#elif defined(USE_NETTLE)
+  if(CTR_LENGTH != AES_BLOCK_SIZE) {
+    cLog.msg(Log::PRIO_ERROR) << "AesIcmCipher: Failed to set cipher CTR: size doesn't fit";
+    return false;
+  }
+  std::memset(key.getBuf(), 0, key.getLength());
+  ctr_crypt(&(ctx_[dir]), (nettle_crypt_func *)(aes_encrypt), AES_BLOCK_SIZE, ctr_[dir].buf_, key.getLength(), key.getBuf(), key.getBuf());
+#else  // USE_GCRYPT is the default
   gcry_error_t err = gcry_cipher_reset(handle_[dir]);
   if(err) {
     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to reset cipher: " << AnytunGpgError(err);
@@ -335,15 +390,6 @@ bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_
   if(err) {
     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << AnytunGpgError(err);
   }
-#else
-  if(CTR_LENGTH != AES_BLOCK_SIZE) {
-    cLog.msg(Log::PRIO_ERROR) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
-    return false;
-  }
-  unsigned int num = 0;
-  std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE);
-  std::memset(key.getBuf(), 0, key.getLength());
-  AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num);
 #endif
 
   return true;