diff options
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/anytun.cpp | 10 | ||||
-rw-r--r-- | src/authAlgo.cpp | 12 | ||||
-rw-r--r-- | src/authAlgo.h | 12 | ||||
-rw-r--r-- | src/cipher.cpp | 71 | ||||
-rw-r--r-- | src/cipher.h | 20 | ||||
-rw-r--r-- | src/cryptinit.hpp | 37 | ||||
-rw-r--r-- | src/keyDerivation.cpp | 255 | ||||
-rw-r--r-- | src/keyDerivation.h | 71 | ||||
-rw-r--r-- | src/mpi.cpp | 203 | ||||
-rw-r--r-- | src/mpi.h | 84 | ||||
-rw-r--r-- | src/threadUtils.hpp | 5 |
12 files changed, 334 insertions, 448 deletions
diff --git a/src/Makefile b/src/Makefile index 5dae026..64dd5b8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -55,7 +55,6 @@ OBJS = tunDevice.o \ cipher.o \ authAlgo.o \ keyDerivation.o \ - mpi.o \ cipherFactory.o \ authAlgoFactory.o \ keyDerivationFactory.o \ @@ -87,7 +86,6 @@ ANYCTROBJS = signalController.o \ ANYCONFOBJS = log.o \ buffer.o \ keyDerivation.o \ - mpi.o \ keyDerivationFactory.o \ networkAddress.o \ networkPrefix.o \ diff --git a/src/anytun.cpp b/src/anytun.cpp index e46731a..c0cb03b 100644 --- a/src/anytun.cpp +++ b/src/anytun.cpp @@ -169,13 +169,13 @@ void sender(void* p) } // encrypt packet - c->encrypt(conn.kd_, plain_packet, encrypted_packet, conn.seq_nr_, gOpt.getSenderId(), mux); + c->encrypt(conn.kd_, KD_OUTBOUND, plain_packet, encrypted_packet, conn.seq_nr_, gOpt.getSenderId(), mux); encrypted_packet.setHeader(conn.seq_nr_, gOpt.getSenderId(), mux); conn.seq_nr_++; // add authentication tag - a->generate(conn.kd_, encrypted_packet); + a->generate(conn.kd_, KD_OUTBOUND, encrypted_packet); try { @@ -276,7 +276,7 @@ void receiver(void* p) ConnectionParam & conn = cit->second; // check whether auth tag is ok or not - if(!a->checkTag(conn.kd_, encrypted_packet)) { + if(!a->checkTag(conn.kd_, KD_INBOUND, encrypted_packet)) { cLog.msg(Log::PRIO_NOTICE) << "wrong Authentication Tag!" << std::endl; continue; } @@ -302,7 +302,7 @@ void receiver(void* p) } // decrypt packet - c->decrypt(conn.kd_, encrypted_packet, plain_packet); + c->decrypt(conn.kd_, KD_INBOUND, encrypted_packet, plain_packet); // check payload_type if((param->dev.getType() == TYPE_TUN && plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN4 && @@ -418,10 +418,12 @@ int main(int argc, char* argv[]) ThreadParam p(dev, *src, *(new OptionConnectTo())); #ifndef NOCRYPT +#ifndef USE_SSL_CRYPTO // this must be called before any other libgcrypt call if(!initLibGCrypt()) return -1; #endif +#endif boost::thread senderThread(boost::bind(sender,&p)); #ifndef NOSIGNALCONTROLLER diff --git a/src/authAlgo.cpp b/src/authAlgo.cpp index 669308b..a0b9193 100644 --- a/src/authAlgo.cpp +++ b/src/authAlgo.cpp @@ -38,11 +38,11 @@ #include <cstring> //****** NullAuthAlgo ****** -void NullAuthAlgo::generate(KeyDerivation& kd, EncryptedPacket& packet) +void NullAuthAlgo::generate(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet) { } -bool NullAuthAlgo::checkTag(KeyDerivation& kd, EncryptedPacket& packet) +bool NullAuthAlgo::checkTag(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet) { return true; } @@ -74,13 +74,13 @@ Sha1AuthAlgo::~Sha1AuthAlgo() #endif } -void Sha1AuthAlgo::generate(KeyDerivation& kd, EncryptedPacket& packet) +void Sha1AuthAlgo::generate(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet) { packet.addAuthTag(); if(!packet.getAuthTagLength()) return; - bool result = kd.generate(LABEL_SATP_MSG_AUTH, packet.getSeqNr(), key_); + bool result = kd.generate(dir, LABEL_SATP_MSG_AUTH, packet.getSeqNr(), key_); if(result) { // a new key got generated #ifndef USE_SSL_CRYPTO gcry_error_t err = gcry_md_setkey(handle_, key_.getBuf(), key_.getLength()); @@ -118,13 +118,13 @@ void Sha1AuthAlgo::generate(KeyDerivation& kd, EncryptedPacket& packet) std::memcpy(&tag[packet.getAuthTagLength() - length], &hmac[DIGEST_LENGTH - length], length); } -bool Sha1AuthAlgo::checkTag(KeyDerivation& kd, EncryptedPacket& packet) +bool Sha1AuthAlgo::checkTag(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet) { packet.withAuthTag(true); if(!packet.getAuthTagLength()) return true; - bool result = kd.generate(LABEL_SATP_MSG_AUTH, packet.getSeqNr(), key_); + bool result = kd.generate(dir, LABEL_SATP_MSG_AUTH, packet.getSeqNr(), key_); if(result) { // a new key got generated #ifndef USE_SSL_CRYPTO gcry_error_t err = gcry_md_setkey(handle_, key_.getBuf(), key_.getLength()); diff --git a/src/authAlgo.h b/src/authAlgo.h index be8d158..5728426 100644 --- a/src/authAlgo.h +++ b/src/authAlgo.h @@ -55,13 +55,13 @@ public: * generate the mac * @param packet the packet to be authenticated */ - virtual void generate(KeyDerivation& kd, EncryptedPacket& packet) = 0; + virtual void generate(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet) = 0; /** * check the mac * @param packet the packet to be authenticated */ - virtual bool checkTag(KeyDerivation& kd, EncryptedPacket& packet) = 0; + virtual bool checkTag(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet) = 0; }; //****** NullAuthAlgo ****** @@ -69,8 +69,8 @@ public: class NullAuthAlgo : public AuthAlgo { public: - void generate(KeyDerivation& kd, EncryptedPacket& packet); - bool checkTag(KeyDerivation& kd, EncryptedPacket& packet); + void generate(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet); + bool checkTag(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet); }; #ifndef NOCRYPT @@ -83,8 +83,8 @@ public: Sha1AuthAlgo(); ~Sha1AuthAlgo(); - void generate(KeyDerivation& kd, EncryptedPacket& packet); - bool checkTag(KeyDerivation& kd, EncryptedPacket& packet); + void generate(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet); + bool checkTag(KeyDerivation& kd, kd_dir dir, EncryptedPacket& packet); static const u_int32_t DIGEST_LENGTH = 20; diff --git a/src/cipher.cpp b/src/cipher.cpp index 8db6256..3d86fc5 100644 --- a/src/cipher.cpp +++ b/src/cipher.cpp @@ -40,31 +40,31 @@ #include "cipher.h" #include "log.h" -void Cipher::encrypt(KeyDerivation& kd, PlainPacket & in, EncryptedPacket & out, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +void Cipher::encrypt(KeyDerivation& kd, kd_dir dir, PlainPacket & in, EncryptedPacket & out, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { - u_int32_t len = cipher(kd, in, in.getLength(), out.getPayload(), out.getPayloadLength(), seq_nr, sender_id, mux); + u_int32_t len = cipher(kd, dir, in, in.getLength(), out.getPayload(), out.getPayloadLength(), seq_nr, sender_id, mux); out.setSenderId(sender_id); out.setSeqNr(seq_nr); out.setMux(mux); out.setPayloadLength(len); } -void Cipher::decrypt(KeyDerivation& kd, EncryptedPacket & in, PlainPacket & out) +void Cipher::decrypt(KeyDerivation& kd, kd_dir dir, EncryptedPacket & in, PlainPacket & out) { - u_int32_t len = decipher(kd, in.getPayload() , in.getPayloadLength(), out, out.getLength(), in.getSeqNr(), in.getSenderId(), in.getMux()); + u_int32_t len = decipher(kd, dir, in.getPayload() , in.getPayloadLength(), out, out.getLength(), in.getSeqNr(), in.getSenderId(), in.getMux()); out.setLength(len); } //******* NullCipher ******* -u_int32_t NullCipher::cipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +u_int32_t NullCipher::cipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { std::memcpy(out, in, (ilen < olen) ? ilen : olen); return (ilen < olen) ? ilen : olen; } -u_int32_t NullCipher::decipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +u_int32_t NullCipher::decipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { std::memcpy(out, in, (ilen < olen) ? ilen : olen); return (ilen < olen) ? ilen : olen; @@ -118,21 +118,21 @@ AesIcmCipher::~AesIcmCipher() #endif } -u_int32_t AesIcmCipher::cipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +u_int32_t AesIcmCipher::cipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { - calc(kd, in, ilen, out, olen, seq_nr, sender_id, mux); + calc(kd, dir, in, ilen, out, olen, seq_nr, sender_id, mux); return (ilen < olen) ? ilen : olen; } -u_int32_t AesIcmCipher::decipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +u_int32_t AesIcmCipher::decipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { - calc(kd, in, ilen, out, olen, seq_nr, sender_id, mux); + calc(kd, dir, in, ilen, out, olen, seq_nr, sender_id, mux); return (ilen < olen) ? ilen : olen; } -void AesIcmCipher::calc_ctr(KeyDerivation& kd, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +void AesIcmCipher::calcCtr(KeyDerivation& kd, kd_dir dir, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { - kd.generate(LABEL_SATP_SALT, seq_nr, salt_); + kd.generate(dir, LABEL_SATP_SALT, seq_nr, salt_); #ifdef ANYTUN_02_COMPAT if(!salt_[int32_t(0)]) @@ -148,47 +148,36 @@ void AesIcmCipher::calc_ctr(KeyDerivation& kd, seq_nr_t seq_nr, sender_id_t send return; } -void AesIcmCipher::calc(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) +void AesIcmCipher::calc(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) { #ifndef USE_SSL_CRYPTO if(!handle_) return; #endif - bool result = kd.generate(LABEL_SATP_ENCRYPTION, seq_nr, key_); - if(result) { // a new key got generated + kd.generate(dir, LABEL_SATP_ENCRYPTION, seq_nr, key_); #ifdef USE_SSL_CRYPTO - int ret = AES_set_encrypt_key(key_.getBuf(), key_.getLength()*8, &aes_key_); - if(ret) { - char buf[STERROR_TEXT_MAX]; - buf[0] = 0; - cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher ssl key (code: " << ret << ")"; - return; - } + int ret = AES_set_encrypt_key(key_.getBuf(), key_.getLength()*8, &aes_key_); + if(ret) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher ssl key (code: " << ret << ")"; + return; + } #else - gcry_error_t err = gcry_cipher_setkey(handle_, key_.getBuf(), key_.getLength()); - if(err) { - char buf[STERROR_TEXT_MAX]; - buf[0] = 0; - cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher key: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); - return; - } - } // no new key got generated - else { - gcry_error_t err = gcry_cipher_reset(handle_); - if(err) { - char buf[STERROR_TEXT_MAX]; - buf[0] = 0; - cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to reset cipher: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); - return; - } -#endif + gcry_error_t err = gcry_cipher_setkey(handle_, key_.getBuf(), key_.getLength()); + if(err) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher key: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); + return; } +#endif - calc_ctr(kd, seq_nr, sender_id, mux); + calcCtr(kd, dir, seq_nr, sender_id, mux); #ifndef USE_SSL_CRYPTO - gcry_error_t err = gcry_cipher_setctr(handle_, ctr_.buf_, CTR_LENGTH); + err = gcry_cipher_setctr(handle_, ctr_.buf_, CTR_LENGTH); if(err) { char buf[STERROR_TEXT_MAX]; buf[0] = 0; diff --git a/src/cipher.h b/src/cipher.h index f930bc4..30bbeed 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -51,12 +51,12 @@ class Cipher public: virtual ~Cipher() {}; - void encrypt(KeyDerivation& kd, PlainPacket & in, EncryptedPacket & out, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); - void decrypt(KeyDerivation& kd, EncryptedPacket & in, PlainPacket & out); + void encrypt(KeyDerivation& kd, kd_dir dir, PlainPacket & in, EncryptedPacket & out, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + void decrypt(KeyDerivation& kd, kd_dir dir, EncryptedPacket & in, PlainPacket & out); protected: - virtual u_int32_t cipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) = 0; - virtual u_int32_t decipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) = 0; + virtual u_int32_t cipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) = 0; + virtual u_int32_t decipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux) = 0; }; //****** NullCipher ****** @@ -64,8 +64,8 @@ protected: class NullCipher : public Cipher { protected: - u_int32_t cipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); - u_int32_t decipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + u_int32_t cipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + u_int32_t decipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); }; #ifndef NOCRYPT @@ -83,14 +83,14 @@ public: static const u_int16_t SALT_LENGTH = 14; protected: - u_int32_t cipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); - u_int32_t decipher(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + u_int32_t cipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + u_int32_t decipher(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); private: void init(u_int16_t key_length = DEFAULT_KEY_LENGTH); - void calc_ctr(KeyDerivation& kd, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); - void calc(KeyDerivation& kd, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + void calcCtr(KeyDerivation& kd, kd_dir dir, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); + void calc(KeyDerivation& kd, kd_dir dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux); #ifndef USE_SSL_CRYPTO gcry_cipher_hd_t handle_; diff --git a/src/cryptinit.hpp b/src/cryptinit.hpp index 567a374..dd878cd 100644 --- a/src/cryptinit.hpp +++ b/src/cryptinit.hpp @@ -1,7 +1,39 @@ +/* + * anytun + * + * The secure anycast tunneling protocol (satp) defines a protocol used + * for communication between any combination of unicast and anycast + * 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 + * 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, + * Christian Pointner <satp@wirdorange.org> + * + * 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. + * + * Anytun is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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/>. + */ + #ifndef _CRYPTINIT_HPP #define _CRYPTINIT_HPP -#ifndef NOCRYPT +#ifndef NOCRYPT +#ifndef USE_SSL_CRYPTO // boost thread callbacks for libgcrypt #if defined(BOOST_HAS_PTHREADS) @@ -76,7 +108,8 @@ bool initLibGCrypt() cLog.msg(Log::PRIO_NOTICE) << "initLibGCrypt: libgcrypt init finished"; return true; } - #endif #endif +#endif + diff --git a/src/keyDerivation.cpp b/src/keyDerivation.cpp index 0bf74a7..459d6c9 100644 --- a/src/keyDerivation.cpp +++ b/src/keyDerivation.cpp @@ -34,142 +34,241 @@ #include "keyDerivation.h" #include "threadUtils.hpp" #include "datatypes.h" +#include "endian.h" #include <stdexcept> #include <iostream> +#include <sstream> #include <string> -#ifndef NOCRYPT -#include <gcrypt.h> -#include "mpi.h" -#endif - -void KeyDerivation::setLogKDRate(const u_int8_t log_rate) +void KeyDerivation::setLogKDRate(const int8_t log_rate) { - Lock lock(mutex_); - if( log_rate < 49 ) - ld_kdr_ = log_rate; + WritersLock lock(mutex_); + ld_kdr_ = log_rate; + if(ld_kdr_ > (int8_t)(sizeof(seq_nr_t) * 8)) + ld_kdr_ = sizeof(seq_nr_t) * 8; } //****** NullKeyDerivation ****** -bool NullKeyDerivation::generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key) +bool NullKeyDerivation::generate(kd_dir dir, satp_prf_label label, seq_nr_t seq_nr, Buffer& key) { - for(u_int32_t i=0; i < key.getLength(); ++i) key[i] = 0; + std::memset(key.getBuf(), 0, key.getLength()); return true; } #ifndef NOCRYPT //****** AesIcmKeyDerivation ****** +AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH) +{ +#ifndef USE_SSL_CRYPTO + handle_ = NULL; +#endif +} + +AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length) : KeyDerivation(key_length) +{ +#ifndef USE_SSL_CRYPTO + handle_ = NULL; +#endif +} + AesIcmKeyDerivation::~AesIcmKeyDerivation() { - Lock lock(mutex_); - if(cipher_) - gcry_cipher_close( cipher_ ); + WritersLock lock(mutex_); +#ifndef USE_SSL_CRYPTO + if(handle_) + gcry_cipher_close(handle_); +#endif +} + +void AesIcmKeyDerivation::init(Buffer key, Buffer salt) +{ + WritersLock lock(mutex_); + + master_salt_ = SyncBuffer(salt); + master_key_ = SyncBuffer(key); + + updateMasterKey(); } void AesIcmKeyDerivation::updateMasterKey() { - if(!cipher_) + if(master_key_.getLength()*8 != key_length_) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: key lengths don't match"; return; + } - gcry_error_t err = gcry_cipher_setkey( cipher_, master_key_.getBuf(), master_key_.getLength() ); - if( err ) { + if(master_salt_.getLength() != SALT_LENGTH) { char buf[STERROR_TEXT_MAX]; buf[0] = 0; - cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); + cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: salt lengths don't match"; + return; } -} -void AesIcmKeyDerivation::init(Buffer key, Buffer salt) -{ - Lock lock(mutex_); - if(cipher_) - gcry_cipher_close( cipher_ ); +#ifndef USE_SSL_CRYPTO + 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; + default: { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_ << " Bits is not supported"; + return; + } + } + + if(handle_) + gcry_cipher_close(handle_); + + gcry_error_t err = gcry_cipher_open(&handle_, algo, GCRY_CIPHER_MODE_CTR, 0); + if(err) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); + return; + } - // TODO: hardcoded size - gcry_error_t err = gcry_cipher_open( &cipher_, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0 ); - if( err ) { + err = gcry_cipher_setkey(handle_, master_key_.getBuf(), master_key_.getLength()); + if(err) { char buf[STERROR_TEXT_MAX]; buf[0] = 0; - cLog.msg(Log::PRIO_ERR) << "KeyDerivation::init: Failed to open cipher: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); + cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); return; } - - master_salt_ = SyncBuffer(salt); - master_key_ = SyncBuffer(key); +#else + int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_); + if(ret) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")"; + return; + } +#endif +} - updateMasterKey(); +std::string AesIcmKeyDerivation::printType() +{ + ReadersLock lock(mutex_); + + std::stringstream sstr; + sstr << "AesIcm" << key_length_ << "KeyDerivation"; + return sstr.str(); } -bool AesIcmKeyDerivation::generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key) +bool AesIcmKeyDerivation::calcCtr(kd_dir dir, seq_nr_t* r, satp_prf_label label, seq_nr_t seq_nr) { - Lock lock(mutex_); - if(!cipher_) - { - cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: cipher not opened"; - return false; - } + *r = 0; + if(ld_kdr_ >= 0) + *r = seq_nr >> ld_kdr_; - gcry_error_t err = gcry_cipher_reset( cipher_ ); - if( err ) { +// TODO: determine whether to generate a key or not +// if(key_store_[dir][label].key_.getBuf() && key_store_[dir][label].r_ == *r) { +// if(!(*r) || (seq_nr % (*r))) +// return false; +// } + + if(master_salt_.getLength() != SALT_LENGTH) { char buf[STERROR_TEXT_MAX]; buf[0] = 0; - cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to reset cipher: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); + cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::calcCtr: salt lengths don't match"; + return false; } + memcpy(ctr_.salt_.buf_, master_salt_.getBuf(), SALT_LENGTH); + ctr_.salt_.zero_ = 0; + ctr_.params_.label_ ^= label; + ctr_.params_.r_ ^= SEQ_NR_T_HTON(*r); - // see at: http://tools.ietf.org/html/rfc3711#section-4.3 - // * Let r = index DIV key_derivation_rate (with DIV as defined above). - // * Let key_id = <label> || r. - // * Let x = key_id XOR master_salt, where key_id and master_salt are - // aligned so that their least significant bits agree (right- - // alignment). - // - - Mpi r(48); // ld(kdr) <= 48 - if( ld_kdr_ == -1 ) // means key_derivation_rate = 0 - r = 0; // TODO: no new key should be generated if r == 0, except it is the first time - else - { - Mpi seq(32); - seq = seq_nr; - Mpi rate(48); - rate = 1; - rate = rate.mul2exp(ld_kdr_); - r = seq / rate; - } - // TODO: generate key only if index % r == 0, except it is the first time + return true; +} + +bool AesIcmKeyDerivation::generate(kd_dir dir, satp_prf_label label, seq_nr_t seq_nr, Buffer& key) +{ +// ReadersLock lock(mutex_); + WritersLock lock(mutex_); - Mpi key_id(128); // TODO: hardcoded size - Mpi l(128); // TODO: hardcoded size - l = label; - key_id = l.mul2exp(48) + r; + seq_nr_t r; + calcCtr(dir, &r, label, seq_nr); +// TODO: return stored key +// bool result = calcCtr(dir, &r, label, seq_nr); +// if(!result) { +// if(len > kd->key_store_[dir][label].key_.length_) { +// log_printf(WARNING, "stored (old) key for label 0x%02X is too short, filling with zeros", label); +// memset(key, 0, len); +// len = kd->key_store_[dir][label].key_.length_; +// } +// memcpy(key, kd->key_store_[dir][label].key_.buf_, len); +// return false; +// } - Mpi salt(master_salt_.getBuf(), master_salt_.getLength()); - Mpi x(128); // TODO: hardcoded size - x = key_id ^ salt; - size_t written; - u_int8_t *ctr_buf = x.mul2exp(16).getNewBuf(&written); // TODO: hardcoded size - err = gcry_cipher_setctr( cipher_ , ctr_buf, written ); - delete[] ctr_buf; +#ifndef USE_SSL_CRYPTO + gcry_error_t err = gcry_cipher_reset(handle_); + if(err) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to reset cipher: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); + } - if( err ) { + err = gcry_cipher_setctr(handle_, ctr_.buf_, CTR_LENGTH); + if(err) { char buf[STERROR_TEXT_MAX]; buf[0] = 0; cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to set CTR: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); return false; } - for(u_int32_t i=0; i < key.getLength(); ++i) key[i] = 0; - err = gcry_cipher_encrypt( cipher_, key, key.getLength(), NULL, 0); - if( err ) { + std::memset(key.getBuf(), 0, key.getLength()); + err = gcry_cipher_encrypt(handle_, key, key.getLength(), NULL, 0); + if(err) { char buf[STERROR_TEXT_MAX]; buf[0] = 0; cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << gpg_strerror_r(err, buf, STERROR_TEXT_MAX); } return true; +#else + if(CTR_LENGTH != AES_BLOCK_SIZE) { + char buf[STERROR_TEXT_MAX]; + buf[0] = 0; + cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher CTR: size don't fits"; + return false; + } + u_int32_t num = 0; + std::memset(ecount_buf_, 0, AES_BLOCK_SIZE); + std::memset(key.getBuf(), 0, key.getLength()); + AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_, ctr_.buf_, ecount_buf_, &num); +#endif + +// TODO: store key if key derivation rate is != 0 +// if(!ld_kdr_) +// return true; + +// if(!kd->key_store_[dir][label].key_.buf_) { +// kd->key_store_[dir][label].key_.length_ = 0; +// kd->key_store_[dir][label].key_.buf_ = malloc(len); +// if(!kd->key_store_[dir][label].key_.buf_) +// return -2; + +// kd->key_store_[dir][label].key_.length_ = len; +// } +// else if(kd->key_store_[dir][label].key_.length_ < len) { +// u_int8_t* tmp = realloc(kd->key_store_[dir][label].key_.buf_, len); +// if(!tmp) +// return -2; + +// kd->key_store_[dir][label].key_.buf_ = tmp; +// kd->key_store_[dir][label].key_.length_ = len; +// } + +// memcpy(kd->key_store_[dir][label].key_.buf_, key, len); +// kd->key_store_[dir][label].r_ = r; + + return true; } #endif diff --git a/src/keyDerivation.h b/src/keyDerivation.h index 6dd8080..6b20983 100644 --- a/src/keyDerivation.h +++ b/src/keyDerivation.h @@ -38,7 +38,11 @@ #include "syncBuffer.h" #ifndef NOCRYPT +#ifndef USE_SSL_CRYPTO #include <gcrypt.h> +#else +#include <openssl/aes.h> +#endif #endif #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> @@ -50,19 +54,24 @@ typedef enum { LABEL_SATP_SALT = 0x02, } satp_prf_label; +typedef enum { + KD_INBOUND = 0, + KD_OUTBOUND = 1 +} kd_dir; class KeyDerivation { public: - KeyDerivation() : ld_kdr_(0), master_salt_(0), master_key_(0) {}; + KeyDerivation() : ld_kdr_(0), key_length_(0), master_salt_(0), master_key_(0) {}; + KeyDerivation(u_int16_t key_length) : ld_kdr_(0), key_length_(key_length), master_salt_(0), master_key_(0) {}; virtual ~KeyDerivation() {}; - void setLogKDRate(const u_int8_t ld_rate); + void setLogKDRate(const int8_t ld_rate); virtual void init(Buffer key, Buffer salt) = 0; - virtual bool generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key) = 0; + virtual bool generate(kd_dir dir, satp_prf_label label, seq_nr_t seq_nr, Buffer& key) = 0; - virtual std::string printType() { return "KeyDerivation"; }; + virtual std::string printType() { return "GenericKeyDerivation"; }; protected: virtual void updateMasterKey() = 0; @@ -72,18 +81,20 @@ protected: template<class Archive> void serialize(Archive & ar, const unsigned int version) { - Lock lock(mutex_); + WritersLock lock(mutex_); ar & ld_kdr_; + ar & key_length_; ar & master_salt_; ar & master_key_; updateMasterKey(); } int8_t ld_kdr_; // ld(key_derivation_rate) + u_int16_t key_length_; SyncBuffer master_salt_; SyncBuffer master_key_; - Mutex mutex_; + SharedMutex mutex_; }; BOOST_IS_ABSTRACT(KeyDerivation) @@ -97,7 +108,7 @@ public: ~NullKeyDerivation() {}; void init(Buffer key, Buffer salt) {}; - bool generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key); + bool generate(kd_dir dir, satp_prf_label label, seq_nr_t seq_nr, Buffer& key); std::string printType() { return "NullKeyDerivation"; }; @@ -119,17 +130,24 @@ private: class AesIcmKeyDerivation : public KeyDerivation { public: - AesIcmKeyDerivation() : cipher_(NULL) {}; + AesIcmKeyDerivation(); + AesIcmKeyDerivation(u_int16_t key_length); ~AesIcmKeyDerivation(); - + + static const u_int16_t DEFAULT_KEY_LENGTH = 128; + static const u_int16_t CTR_LENGTH = 16; + static const u_int16_t SALT_LENGTH = 14; + void init(Buffer key, Buffer salt); - bool generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key); + bool generate(kd_dir dir, satp_prf_label label, seq_nr_t seq_nr, Buffer& key); - std::string printType() { return "AesIcmKeyDerivation"; }; + std::string printType(); private: void updateMasterKey(); + bool calcCtr(kd_dir dir, seq_nr_t* r, satp_prf_label label, seq_nr_t seq_nr); + friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version) @@ -137,7 +155,36 @@ private: ar & boost::serialization::base_object<KeyDerivation>(*this); } - gcry_cipher_hd_t cipher_; +#ifndef USE_SSL_CRYPTO + gcry_cipher_hd_t handle_; +#else + AES_KEY aes_key_; + u_int8_t ecount_buf_[AES_BLOCK_SIZE]; +#endif + + union __attribute__((__packed__)) key_derivation_aesctr_ctr_union { + u_int8_t buf_[CTR_LENGTH]; + struct __attribute__ ((__packed__)) { + u_int8_t buf_[SALT_LENGTH]; + u_int16_t zero_; + } salt_; +#ifndef ANYTUN_02_COMPAT + struct __attribute__((__packed__)) { + u_int8_t fill_[SALT_LENGTH - sizeof(u_int8_t) - sizeof(seq_nr_t)]; + u_int8_t label_; + seq_nr_t r_; + u_int16_t zero_; + } params_; +#else + struct __attribute__((__packed__)) { + u_int8_t fill_[SALT_LENGTH - sizeof(u_int8_t) - 2 - sizeof(seq_nr_t)]; + u_int8_t label_; + u_int8_t r_fill_[2]; + seq_nr_t r_; + u_int16_t zero_; + } params_; +#endif + } ctr_; }; #endif diff --git a/src/mpi.cpp b/src/mpi.cpp deleted file mode 100644 index 0a240fd..0000000 --- a/src/mpi.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * anytun - * - * The secure anycast tunneling protocol (satp) defines a protocol used - * for communication between any combination of unicast and anycast - * 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 - * 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, - * Christian Pointner <satp@wirdorange.org> - * - * 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. - * - * Anytun is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * 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/>. - */ - -#include "mpi.h" - -#include "datatypes.h" -#include "cipher.h" - -#include <stdexcept> -#include <gcrypt.h> - -#include <iostream> -#include <cstring> - -Mpi::Mpi() : val_(NULL) -{ - val_ = gcry_mpi_set_ui(NULL, 0); - if(!val_) - throw std::bad_alloc(); -} - -Mpi::Mpi(u_int8_t length) : val_(NULL) -{ - val_ = gcry_mpi_new(length); - if(!val_) - throw std::bad_alloc(); -} - -Mpi::Mpi(const Mpi &src) : val_(NULL) -{ - val_ = gcry_mpi_copy(src.val_); - if(!val_) - throw std::bad_alloc(); -} - -Mpi::Mpi(const u_int8_t* src, u_int32_t len) : val_(NULL) -{ - u_int8_t* src_cpy = new u_int8_t[len+1]; - if(!src_cpy) - throw std::bad_alloc(); - - u_int8_t* buf = src_cpy; - u_int32_t buf_len = len; - if(src[0] & 0x80) // this would be a negative number, scan can't handle this :( - { - src_cpy[0] = 0; - buf++; - buf_len++; - } - std::memcpy(buf, src, len); - - gcry_mpi_scan( &val_, GCRYMPI_FMT_STD, src_cpy, buf_len, NULL ); - delete[] src_cpy; - if(!val_) - throw std::bad_alloc(); -} - -Mpi::~Mpi() -{ - gcry_mpi_release( val_ ); -} - - -void Mpi::operator=(const Mpi &src) -{ - gcry_mpi_release( val_ ); - val_ = gcry_mpi_copy(src.val_); - if(!val_) - throw std::bad_alloc(); -} - -void Mpi::operator=(const u_int32_t src) -{ - gcry_mpi_release( val_ ); - val_ = gcry_mpi_set_ui(NULL, src); - if(!val_) - throw std::bad_alloc(); -} - -Mpi Mpi::operator+(const Mpi &b) const -{ - Mpi res; - gcry_mpi_add(res.val_, val_, b.val_); - return res; -} - -Mpi Mpi::operator+(const u_int32_t &b) const -{ - Mpi res; - gcry_mpi_add_ui(res.val_, val_, b); - return res; -} - -Mpi Mpi::operator*(const u_int32_t n) const -{ - Mpi res; - gcry_mpi_mul_ui(res.val_, val_, n); - return res; -} - -Mpi Mpi::operator/(const Mpi &b) const -{ - Mpi res; - gcry_mpi_div(res.val_, NULL, val_, b.val_, 0); - return res; -} - -//TODO: this is outstandingly ugly!!!!!!!! -Mpi Mpi::operator^(const Mpi &b) const -{ - u_int32_t a_len = gcry_mpi_get_nbits(val_); - u_int32_t b_len = gcry_mpi_get_nbits(b.val_); - - Mpi res = (a_len >= b_len) ? Mpi(*this) : Mpi(b); - - for(u_int32_t i=0; i<a_len && i<b_len; i++) { - if(gcry_mpi_test_bit(val_, i) ^ gcry_mpi_test_bit(b.val_, i)) - gcry_mpi_set_bit(res.val_, i); - else - gcry_mpi_clear_bit(res.val_, i); - } - return res; -} - -Mpi Mpi::mul2exp(u_int32_t e) const -{ - Mpi res; - gcry_mpi_mul_2exp( res.val_, val_, e ); - return res; -} - -//TODO: problem, seems as gcry_mpi_(a)print doesn't work for mpi values of '0' -u_int8_t* Mpi::getNewBuf(size_t* written) const -{ - u_int8_t* res_cpy; - gcry_mpi_aprint( GCRYMPI_FMT_STD, &res_cpy, written, val_ ); - if(!res_cpy) - throw std::bad_alloc(); - - u_int8_t* buf = res_cpy; - if(*written > 1 && ! (res_cpy[0])) // positive number with highestBit set - { - buf++; - (*written)--; - } - - u_int8_t* res = new u_int8_t[*written]; - if(!res) - throw std::bad_alloc(); - - std::memcpy(res, buf, *written); - - gcry_free(res_cpy); - - return res; -} - -//TODO: why does this not work ????? -std::string Mpi::getHexDump() const -{ -// u_int8_t *buf; -// u_int32_t len; -// gcry_mpi_aprint( GCRYMPI_FMT_HEX, &buf, &len, val_ ); -// std::string res(buf, len); -// delete[] buf; - - gcry_mpi_dump( val_ ); - std::string res("\n"); - return res; -} - -u_int32_t Mpi::getLength() const -{ - return gcry_mpi_get_nbits( val_ ); -} diff --git a/src/mpi.h b/src/mpi.h deleted file mode 100644 index d85be2f..0000000 --- a/src/mpi.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * anytun - * - * The secure anycast tunneling protocol (satp) defines a protocol used - * for communication between any combination of unicast and anycast - * 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 - * 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, - * Christian Pointner <satp@wirdorange.org> - * - * 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. - * - * Anytun is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * 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/>. - */ - -#ifndef _MPI_H_ -#define _MPI_H_ - -#include "datatypes.h" -#include "buffer.h" - -#include <gcrypt.h> - - -/** - * This class is a wrapper for the libgcrypt multi precision integer library [1] - * [1] http://www.gnupg.org/documentation/manuals/gcrypt/MPI-library.html - * - */ - -class Mpi -{ -public: - Mpi(); - virtual ~Mpi(); - Mpi(u_int8_t length); - Mpi(const Mpi &src); - Mpi(const u_int8_t * src, u_int32_t len); - - void operator=(const Mpi &src); - void operator=(u_int32_t src); - Mpi operator+(const Mpi &b) const; - Mpi operator+(const u_int32_t &b) const; - Mpi operator*(const u_int32_t n) const; - Mpi operator/(const Mpi &b) const; - - Mpi operator^(const Mpi &b) const; - - Mpi mul2exp(u_int32_t e) const; // value * 2^e - - /** - * returns a new[] u_int8_t* buffer with the MPI value in the - * GCRYMPI_FMT_STD (2-complement stored without a length header).<br> - * you have to delete it by hand with delete[]! - * @param buf_len size of the new buffer that is returned - * @return a byte buffer of size buf_len - */ - u_int8_t *getNewBuf(size_t* written) const; - std::string getHexDump() const; - u_int32_t getLength() const; - -protected: - gcry_mpi_t val_; -}; - - - -#endif diff --git a/src/threadUtils.hpp b/src/threadUtils.hpp index 960e757..85500c1 100644 --- a/src/threadUtils.hpp +++ b/src/threadUtils.hpp @@ -30,12 +30,17 @@ */ #include <boost/thread.hpp> #include <boost/thread/mutex.hpp> +#include <boost/thread/shared_mutex.hpp> #include "datatypes.h" #ifndef __THREADUTILS__ #define __THREADUTILS__ typedef boost::mutex::scoped_lock Lock; typedef boost::mutex Mutex; +typedef boost::shared_mutex SharedMutex; +typedef boost::shared_lock<SharedMutex> ReadersLock; +typedef boost::unique_lock<SharedMutex> WritersLock; + class Semaphore { public: |