X-Git-Url: https://git.syn-net.org/debian/?a=blobdiff_plain;f=src%2FkeyDerivation.cpp;h=812dc4414853f40d8dfc658c3ff9a6f04bb07add;hb=59f70c469910fe88a529c043ab0364ca5f8918b9;hp=cdf6368fe44ccf9c90dd6abbe4b9c484a0aa2b9e;hpb=058ae090a970436caec3b3059e9e18b310dd6b0d;p=anytun.git diff --git a/src/keyDerivation.cpp b/src/keyDerivation.cpp index cdf6368..812dc44 100644 --- a/src/keyDerivation.cpp +++ b/src/keyDerivation.cpp @@ -6,19 +6,20 @@ * 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-2008 Othmar Gsenger, Erwin Nindl, + * Copyright (C) 2007-2014 Markus Grüneis, Othmar Gsenger, Erwin Nindl, * Christian Pointner * * This file is part of Anytun. * * Anytun is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. * * Anytun is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,7 +27,20 @@ * 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 . + * along with Anytun. If not, see . + * + * 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. */ @@ -41,12 +55,21 @@ #include #include #include +#include #ifndef NO_CRYPT #ifndef NO_PASSPHRASE -#ifdef USE_SSL_CRYPTO + +#if defined(USE_SSL_CRYPTO) +#include #include +#include +#elif defined(USE_NETTLE) +#include +#include +#include #endif + #endif #endif @@ -59,7 +82,7 @@ void KeyDerivation::setRole(const role_t role) #ifndef NO_CRYPT #ifndef NO_PASSPHRASE -void KeyDerivation::calcMasterKey(std::string passphrase, u_int16_t length) +void KeyDerivation::calcMasterKey(std::string passphrase, uint16_t length) { cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master key from passphrase"; if(!length) { @@ -67,28 +90,36 @@ void KeyDerivation::calcMasterKey(std::string passphrase, u_int16_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(gcry_md_get_algo_dlen(GCRY_MD_SHA256)); - gcry_md_hash_buffer(GCRY_MD_SHA256, digest.getBuf(), passphrase.c_str(), passphrase.length()); -#else - Buffer digest(u_int32_t(SHA256_DIGEST_LENGTH)); +#if defined(USE_SSL_CRYPTO) + Buffer digest(uint32_t(SHA256_DIGEST_LENGTH)); SHA256(reinterpret_cast(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(passphrase.c_str())); + sha256_digest(&ctx, digest.getLength(), digest.getBuf()); +#else // USE_GCRYPT is the default + Buffer digest(static_cast(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); - memcpy(master_key_.getBuf(), &digest.getBuf()[digest.getLength() - master_key_.getLength()], master_key_.getLength()); + std::memcpy(master_key_.getBuf(), &digest.getBuf()[digest.getLength() - master_key_.getLength()], master_key_.getLength()); } -void KeyDerivation::calcMasterSalt(std::string passphrase, u_int16_t length) +void KeyDerivation::calcMasterSalt(std::string passphrase, uint16_t length) { cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master salt from passphrase"; if(!length) { @@ -96,25 +127,33 @@ void KeyDerivation::calcMasterSalt(std::string passphrase, u_int16_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(gcry_md_get_algo_dlen(GCRY_MD_SHA1)); - gcry_md_hash_buffer(GCRY_MD_SHA1, digest.getBuf(), passphrase.c_str(), passphrase.length()); -#else - Buffer digest(u_int32_t(SHA_DIGEST_LENGTH)); +#if defined(USE_SSL_CRYPTO) + Buffer digest(uint32_t(SHA_DIGEST_LENGTH)); SHA1(reinterpret_cast(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(passphrase.c_str())); + sha1_digest(&ctx, digest.getLength(), digest.getBuf()); +#else // USE_GCRYPT is the default + Buffer digest(static_cast(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); - memcpy(master_salt_.getBuf(), &digest.getBuf()[digest.getLength() - master_salt_.getLength()], master_salt_.getLength()); + std::memcpy(master_salt_.getBuf(), &digest.getBuf()[digest.getLength() - master_salt_.getLength()], master_salt_.getLength()); } #endif #endif @@ -124,34 +163,31 @@ satp_prf_label_t KeyDerivation::convertLabel(kd_dir_t dir, satp_prf_label_t labe switch(label) { case LABEL_ENC: { if(dir == KD_OUTBOUND) { - if(role_ == ROLE_LEFT) return LABEL_LEFT_ENC; - if(role_ == ROLE_RIGHT) return LABEL_RIGHT_ENC; - } - else { - if(role_ == ROLE_LEFT) return LABEL_RIGHT_ENC; - if(role_ == ROLE_RIGHT) return LABEL_LEFT_ENC; + if(role_ == ROLE_LEFT) { return LABEL_LEFT_ENC; } + if(role_ == ROLE_RIGHT) { return LABEL_RIGHT_ENC; } + } else { + if(role_ == ROLE_LEFT) { return LABEL_RIGHT_ENC; } + if(role_ == ROLE_RIGHT) { return LABEL_LEFT_ENC; } } break; } case LABEL_SALT: { if(dir == KD_OUTBOUND) { - if(role_ == ROLE_LEFT) return LABEL_LEFT_SALT; - if(role_ == ROLE_RIGHT) return LABEL_RIGHT_SALT; - } - else { - if(role_ == ROLE_LEFT) return LABEL_RIGHT_SALT; - if(role_ == ROLE_RIGHT) return LABEL_LEFT_SALT; + if(role_ == ROLE_LEFT) { return LABEL_LEFT_SALT; } + if(role_ == ROLE_RIGHT) { return LABEL_RIGHT_SALT; } + } else { + if(role_ == ROLE_LEFT) { return LABEL_RIGHT_SALT; } + if(role_ == ROLE_RIGHT) { return LABEL_LEFT_SALT; } } break; } case LABEL_AUTH: { if(dir == KD_OUTBOUND) { - if(role_ == ROLE_LEFT) return LABEL_LEFT_AUTH; - if(role_ == ROLE_RIGHT) return LABEL_RIGHT_AUTH; - } - else { - if(role_ == ROLE_LEFT) return LABEL_RIGHT_AUTH; - if(role_ == ROLE_RIGHT) return LABEL_LEFT_AUTH; + if(role_ == ROLE_LEFT) { return LABEL_LEFT_AUTH; } + if(role_ == ROLE_RIGHT) { return LABEL_RIGHT_AUTH; } + } else { + if(role_ == ROLE_LEFT) { return LABEL_RIGHT_AUTH; } + if(role_ == ROLE_RIGHT) { return LABEL_LEFT_AUTH; } } break; } @@ -171,29 +207,32 @@ bool NullKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t #ifndef NO_CRYPT //****** AesIcmKeyDerivation ****** -AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH) +AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH) { -#ifndef USE_SSL_CRYPTO - for(int i=0; i<2; i++) +#if defined(USE_GCRYPT) + for(int i=0; i<2; i++) { handle_[i] = NULL; + } #endif } -AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length) : KeyDerivation(key_length) +AesIcmKeyDerivation::AesIcmKeyDerivation(uint16_t key_length) : KeyDerivation(key_length) { -#ifndef USE_SSL_CRYPTO - for(int i=0; i<2; i++) +#if defined(USE_GCRYPT) + for(int i=0; i<2; i++) { handle_[i] = NULL; + } #endif } AesIcmKeyDerivation::~AesIcmKeyDerivation() { WritersLock lock(mutex_); -#ifndef USE_SSL_CRYPTO +#if defined(USE_GCRYPT) for(int i=0; i<2; i++) - if(handle_[i]) + if(handle_[i]) { gcry_cipher_close(handle_[i]); + } #endif } @@ -203,15 +242,17 @@ void AesIcmKeyDerivation::init(Buffer key, Buffer salt, std::string passphrase) is_initialized_ = false; #ifndef NO_PASSPHRASE - if(passphrase != "" && !key.getLength()) + if(passphrase != "" && !key.getLength()) { calcMasterKey(passphrase, key_length_/8); - else + } else { master_key_ = SyncBuffer(key); - - if(passphrase != "" && !salt.getLength()) + } + + if(passphrase != "" && !salt.getLength()) { calcMasterSalt(passphrase, SALT_LENGTH); - else + } else { master_salt_ = SyncBuffer(salt); + } #else master_key_ = SyncBuffer(key); master_salt_ = SyncBuffer(salt); @@ -232,12 +273,30 @@ 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: algo = GCRY_CIPHER_AES128; break; - case 192: algo = GCRY_CIPHER_AES192; break; - case 256: algo = GCRY_CIPHER_AES256; break; + case 128: + algo = GCRY_CIPHER_AES128; + break; + case 192: + algo = GCRY_CIPHER_AES192; + break; + case 256: + algo = GCRY_CIPHER_AES256; + break; default: { cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_ << " Bits is not supported"; return; @@ -245,34 +304,27 @@ void AesIcmKeyDerivation::updateMasterKey() } for(int i=0; i<2; i++) { - if(handle_[i]) + if(handle_[i]) { gcry_cipher_close(handle_[i]); - + } + gcry_error_t err = gcry_cipher_open(&handle_[i], algo, GCRY_CIPHER_MODE_CTR, 0); if(err) { cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << AnytunGpgError(err); return; - } - + } + err = gcry_cipher_setkey(handle_[i], master_key_.getBuf(), master_key_.getLength()); if(err) { cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << AnytunGpgError(err); 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; } -std::string AesIcmKeyDerivation::printType() +std::string AesIcmKeyDerivation::printType() { ReadersLock lock(mutex_); @@ -287,7 +339,7 @@ bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir, satp_prf_label_t label, seq_nr_t cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::calcCtr: salt lengths don't match"; return false; } - memcpy(ctr_[dir].salt_.buf_, master_salt_.getBuf(), SALT_LENGTH); + std::memcpy(ctr_[dir].salt_.buf_, master_salt_.getBuf(), SALT_LENGTH); ctr_[dir].salt_.zero_ = 0; ctr_[dir].params_.label_ ^= SATP_PRF_LABEL_T_HTON(convertLabel(dir, label)); ctr_[dir].params_.seq_ ^= SEQ_NR_T_HTON(seq_nr); @@ -295,18 +347,35 @@ bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir, satp_prf_label_t label, seq_nr_t return true; } -bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key) +bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key) { ReadersLock lock(mutex_); - if(!is_initialized_) + if(!is_initialized_) { return false; + } if(!calcCtr(dir, 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(key.getBuf(), 0, key.getLength()); + std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE); + CRYPTO_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num, (block128_f)AES_encrypt); +#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); @@ -323,17 +392,8 @@ 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; } #endif