diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | buffer.cpp | 74 | ||||
-rw-r--r-- | buffer.h | 13 | ||||
-rw-r--r-- | cypher.cpp | 196 | ||||
-rw-r--r-- | cypher.h | 21 | ||||
-rw-r--r-- | keyDerivation.cpp | 113 | ||||
-rw-r--r-- | keyDerivation.h | 16 | ||||
-rw-r--r-- | tunDevice.cpp | 2 | ||||
-rw-r--r-- | tunDevice.h | 2 |
10 files changed, 273 insertions, 169 deletions
@@ -3,7 +3,7 @@ CFLAGS = -g -Wall C++ = g++ CCFLAGS = -g -Wall LD = g++ -LDFLAGS = -g -O2 -ldl -lpthread -lsrtp -lgcrypt +LDFLAGS = -g -Wall -O2 -ldl -lpthread -lsrtp -lgcrypt OPENVPNDEPS = openvpn/tun.o \ openvpn/error.o \ @@ -97,6 +97,8 @@ anytun.o: anytun.cpp clean: rm -f *.o rm -f $(EXECUTABLE) + rm -f -r doc/html/* + rm -f -r doc/latex/* doxygen: doxygen Doxyfile @@ -2,6 +2,7 @@ Building ======== * install libSRTP (as seen below) +* install libgcrypt * install libgcrypt11-dev * ./configure * make @@ -87,6 +87,43 @@ void Buffer::operator=(const Buffer &src) length_ = 0; } +void Buffer::operator=(const seq_nr_t &src) +{ + if(buf_) + delete[] buf_; + + length_ = sizeof(src); + + buf_ = new u_int8_t[length_]; + + if( buf_ ) + { + for( u_int32_t index = 0; index <= length_; index++ ) + buf_[index] = (src>>index) & 0xFF; + } + else + length_ = 0; +} + + +void Buffer::operator=(const sender_id_t &src) +{ + if(buf_) + delete[] buf_; + + length_ = sizeof(src); + + buf_ = new u_int8_t[length_]; + + if( buf_ ) + { + for( u_int32_t index = 0; index <= length_; index++ ) + buf_[index] = (src>>index) & 0xFF; + } + else + length_ = 0; +} + u_int32_t Buffer::resizeFront(u_int32_t new_length) { if(length_ == new_length) @@ -171,7 +208,42 @@ void Buffer::printHexDump() const for( u_int32_t index = 0; index < length_; index++ ) { - std::sprintf(text, "%#x", buf_[index]); + std::sprintf(text, "%#4x", buf_[index]); std::cout << text << " "; + if( ((index+1) % 10) == 0 ) + std::cout << std::endl; } } + +Buffer Buffer::operator^(const Buffer &xor_by) const +{ + Buffer res(length_); + if( xor_by.getLength() > length_ ) + throw std::out_of_range("buffer::operator^ const"); + + for( u_int32_t index = 0; index < xor_by.getLength(); index++ ) + res[index] = buf_[index] ^ xor_by[index]; + + return res; +} + +Buffer Buffer::leftByteShift(u_int32_t width) const +{ + Buffer res(length_+width); + + for( u_int32_t index = 0; index < length_; index++ ) + res[index+width] = buf_[index]; + + return res; +} + +Buffer Buffer::rightByteShift(u_int32_t width) const +{ + Buffer res(length_); + + for( u_int32_t index = 0; index < length_-width; index++ ) + res[index] = buf_[index+width]; + + return res; +} + @@ -45,6 +45,13 @@ public: virtual ~Buffer(); Buffer(const Buffer &src); void operator=(const Buffer &src); + void operator=(const seq_nr_t &src); + void operator=(const sender_id_t &src); + + // math operations to calculate IVs and keys + virtual Buffer operator^(const Buffer &xor_by) const; + virtual Buffer leftByteShift(u_int32_t width) const; + virtual Buffer rightByteShift(u_int32_t width) const; u_int32_t resizeFront(u_int32_t new_length); u_int32_t resizeBack(u_int32_t new_length); @@ -54,12 +61,12 @@ public: u_int8_t operator[](u_int32_t index) const; void printHexDump() const; -protected: operator u_int8_t*(); // just for write/read tun and packetSource +protected: friend class TunDevice; friend class UDPPacketSource; - friend class AesIcmCypher; - friend class KeyDerivation; // +// friend class AesIcmCypher; +// friend class KeyDerivation; // u_int8_t *buf_; u_int32_t length_; @@ -29,15 +29,15 @@ */ #include <stdexcept> -#include <vector> #include <iostream> +#include <string> #include "cypher.h" #include "keyDerivation.h" extern "C" { -#include <srtp/crypto_kernel.h> +#include <gcrypt.h> } void Cypher::cypher(Buffer& buf, seq_nr_t seq_nr, sender_id_t sender_id) @@ -65,129 +65,109 @@ Buffer NullCypher::getBitStream(u_int32_t length, seq_nr_t seq_nr, sender_id_t s } +const char* AesIcmCypher::MIN_GCRYPT_VERSION = "1.2.3"; +bool AesIcmCypher::gcrypt_initialized_ = false; + + +AesIcmCypher::AesIcmCypher() : salt_(Buffer(14)) +{ + gcry_error_t err; + if( !gcry_check_version( MIN_GCRYPT_VERSION ) ) + { + std::cerr << "Invalid Version of libgcrypt, should be >= "; + std::cerr << MIN_GCRYPT_VERSION << std::endl; + return; + } + + if( !gcrypt_initialized_ ) + { + /* Allocate a pool of secure memory. This also drops priviliges + on some systems. */ + err = gcry_control(GCRYCTL_INIT_SECMEM, GCRYPT_SEC_MEM, 0); + if( err ) + { + std::cerr << "Failed to allocate " << GCRYPT_SEC_MEM << "bytes of secure memory: "; + std::cerr << gpg_strerror( err ) << std::endl; + return; + } + gcrypt_initialized_ = true; + } + + /* Tell Libgcrypt that initialization has completed. */ + err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED); + if( err ) + { + std::cerr << "Failed to finish the initialization of libgcrypt"; + std::cerr << gpg_strerror( err ) << std::endl; + return; + } + + gcry_cipher_open( &cipher_, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0 ); + + std::cout << "Keysize: " << gcry_cipher_get_algo_keylen( GCRY_CIPHER_AES128 ) << std::endl; +} + + +AesIcmCypher::~AesIcmCypher() +{ + gcry_cipher_close( cipher_ ); +} + + void AesIcmCypher::setKey(Buffer key) { - key_ = key; + gcry_error_t err; + err = gcry_cipher_setkey( cipher_, key.getBuf(), 16 ); + if( err ) + std::cerr << "Failed to set cipher key: " << gpg_strerror( err ) << std::endl; } void AesIcmCypher::setSalt(Buffer salt) { - salt = salt; + salt_ = salt; } Buffer AesIcmCypher::getBitStream(u_int32_t length, seq_nr_t seq_nr, sender_id_t sender_id) { + gcry_error_t err; + Buffer buf(length); - extern cipher_type_t aes_icm; - err_status_t status = err_status_ok; - cipher_t* cipher = NULL; - v128_t iv, sid, seq, salt; - - v128_set_to_zero(&iv); - v128_set_to_zero(&sid); - v128_set_to_zero(&seq); - v128_set_to_zero(&salt); - - // allocate cipher - // FIXXME: why we do not can do this??? -// status = cipher_type_alloc(&aes_icm, &cipher, key_.getLength()); - status = cipher_type_alloc(&aes_icm, &cipher, 30); - if( status ) + +// // set IV +// // where the 128-bit integer value IV SHALL be defined by the SSRC, the +// // SRTP packet index i, and the SRTP session salting key k_s, as below. +// // +// // IV = (k_s * 2^16) XOR (SSRC * 2^64) XOR (i * 2^16) +// // sizeof(k_s) = 112 bit, random + + Buffer iv(16), seq, sid; + + sid = sender_id; + seq = seq_nr; + + iv = (salt_.leftByteShift(2) ^ sid.leftByteShift(8)) ^ sid.leftByteShift(2); + + err = gcry_cipher_setiv( cipher_, iv.getBuf(), 0 ); + if( err ) + { + std::cerr << "Failed to set cipher IV: " << gpg_strerror( err ) << std::endl; return Buffer(0); + } + + err = gcry_cipher_reset( cipher_ ); + if( err ) + { + std::cerr << "Failed to reset cipher: " << gpg_strerror( err ) << std::endl; + return Buffer(0); + } - // init cipher - status = cipher_init(cipher, key_.getBuf(), direction_any); - if( status ) + err = gcry_cipher_encrypt( cipher_, buf, buf.getLength(), 0, 0 ); + if( err ) { - cipher_dealloc(cipher); + std::cerr << "Failed to generate cipher bitstream: " << gpg_strerror( err ) << std::endl; return Buffer(0); } - // set IV - // where the 128-bit integer value IV SHALL be defined by the SSRC, the - // SRTP packet index i, and the SRTP session salting key k_s, as below. - // - // IV = (k_s * 2^16) XOR (SSRC * 2^64) XOR (i * 2^16) - // sizeof(k_s) = 112 bit, random - - seq.v64[0] = seq_nr; - sid.v64[0] = sender_id; - v128_copy_octet_string(&salt, salt_.getBuf()); - v128_left_shift(&salt, 16); - v128_left_shift(&sid, 64); - v128_left_shift(&seq, 16); - - v128_xor(&iv, &salt, &sid); - v128_xor(&iv, &iv, &seq); - - status = cipher_set_iv(cipher, &iv); - if( status ) - cipher_dealloc(cipher); - - status = cipher_output(cipher, buf, length); - status = cipher_dealloc(cipher); return buf; } -// -//void AesIcmCypher::cypher(Buffer& buf, seq_nr_t seq_nr, sender_id_t sender_id) -//{ -// extern cipher_type_t aes_icm; -// err_status_t status = err_status_ok; -// cipher_t* cipher = NULL; -// uint32_t length = 0; -// v128_t iv, sid, seq, salt; -// -// v128_set_to_zero(&iv); -// v128_set_to_zero(&sid); -// v128_set_to_zero(&seq); -// v128_set_to_zero(&salt); -// -// std::cout << "AesIcmCypher::cypher called" << std::endl; -// // allocate cipher -// // FIXXME: why we do not can do this??? -//// status = cipher_type_alloc(&aes_icm, &cipher, key_.getLength()); -// status = cipher_type_alloc(&aes_icm, &cipher, 30); -// if( status ) -// return; -// -// // init cipher -// status = cipher_init(cipher, key_.getBuf(), direction_any); -// if( status ) -// { -// cipher_dealloc(cipher); -// return; -// } -// -// // set IV -// // where the 128-bit integer value IV SHALL be defined by the SSRC, the -// // SRTP packet index i, and the SRTP session salting key k_s, as below. -// // -// // IV = (k_s * 2^16) XOR (SSRC * 2^64) XOR (i * 2^16) -// // sizeof(k_s) = 112 bit, random -// -//// iv.v32[0] ^= 0; -//// iv.v32[1] ^= sender_id; -//// iv.v32[2] ^= (seq_nr >> 16); -//// iv.v32[3] ^= (seq_nr << 16); -// -// seq.v64[0] = seq_nr; -// sid.v64[0] = sender_id; -// v128_copy_octet_string(&salt, salt_.getBuf()); -// v128_left_shift(&salt, 16); -// v128_left_shift(&sid, 64); -// v128_left_shift(&seq, 16); -// -// v128_xor(&iv, &salt, &sid); -// v128_xor(&iv, &iv, &seq); -// -// status = cipher_set_iv(cipher, &iv); -// if( status ) -// cipher_dealloc(cipher); -// -// length = buf.getLength(); -// -// status = cipher_encrypt(cipher, buf, &length); -// status = cipher_dealloc(cipher); -//} -// @@ -31,9 +31,15 @@ #ifndef _CYPHER_H_ #define _CYPHER_H_ + + #include "datatypes.h" #include "buffer.h" +extern "C" { +#include <gcrypt.h> +} + class Cypher { @@ -59,17 +65,22 @@ protected: class AesIcmCypher : public Cypher { public: - AesIcmCypher() : key_(Buffer(0)), salt_(Buffer(14)) {}; + AesIcmCypher(); + ~AesIcmCypher(); void setKey(Buffer key); void setSalt(Buffer salt); -// void cypher(Buffer& buf, seq_nr_t seq_nr, sender_id_t sender_id); + + static const char* MIN_GCRYPT_VERSION; + static const u_int32_t GCRYPT_SEC_MEM = 16384; // 16k secure memory protected: - Buffer getBitStream(u_int32_t length, seq_nr_t seq_nr, sender_id_t sender_id); + Buffer getBitStream(u_int32_t length, seq_nr_t seq_nr, sender_id_t sender_id); + gcry_cipher_hd_t cipher_; + Buffer salt_; private: - Buffer key_; - Buffer salt_; // size: 112 bit + static bool gcrypt_initialized_; }; + #endif diff --git a/keyDerivation.cpp b/keyDerivation.cpp index 95b94d2..f8e3c55 100644 --- a/keyDerivation.cpp +++ b/keyDerivation.cpp @@ -31,82 +31,109 @@ #include "keyDerivation.h" +#include <stdexcept> +#include <iostream> +#include <string> + extern "C" { -#include <srtp/crypto_kernel.h> +#include <gcrypt.h> } -err_status_t KeyDerivation::init(Buffer key, Buffer salt) +const char* KeyDerivation::MIN_GCRYPT_VERSION = "1.2.3"; + +void KeyDerivation::init(Buffer key, Buffer salt) { - extern cipher_type_t aes_icm; - err_status_t status = err_status_ok; + gcry_error_t err; + if( !gcry_check_version( MIN_GCRYPT_VERSION ) ) + { + std::cerr << "Invalid Version of libgcrypt, should be >= " << MIN_GCRYPT_VERSION << std::endl; + return; + } - salt_ = salt; + /* Allocate a pool of 16k secure memory. This also drops priviliges + * on some systems. */ + err = gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0); + if( err ) + { + std::cerr << "Failed to allocate 16k secure memory: " << gpg_strerror( err ) << std::endl; + return; + } - // allocate cipher - // FIXXME: why we do not can do this?? -// status = cipher_type_alloc(&aes_icm, &cipher_, key.getLength()); - status = cipher_type_alloc(&aes_icm, &cipher_, 30); - if( status ) - return status; + /* Tell Libgcrypt that initialization has completed. */ + err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED); + if( err ) + { + std::cerr << "Failed to finish the initialization of libgcrypt" << gpg_strerror( err ) << std::endl; + return; + } - // init cipher - status = cipher_init(cipher_, key.getBuf(), direction_any); - if( status ) - cipher_dealloc(cipher_); + err = gcry_cipher_open( &cipher_, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0 ); + if( err ) + { + std::cerr << "Failed to open cipher: " << gpg_strerror( err ) << std::endl; + return; + } - return status; } -err_status_t KeyDerivation::setLogKDRate(const uint8_t log_rate) +void KeyDerivation::setLogKDRate(const uint8_t log_rate) { if( log_rate < 49 ) - { ld_kdr_ = log_rate; - return err_status_ok; - } - return err_status_bad_param; } -err_status_t KeyDerivation::generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key, uint32_t length) +void KeyDerivation::generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key, u_int32_t length) { - err_status_t status = err_status_ok; - v128_t iv, salt, key_id; - uint8_t r = 0; + gcry_error_t err; + u_int8_t r = 0; + Buffer iv(16); + + u_int8_t tmp_key_id[16]; - v128_set_to_zero(&iv); - v128_set_to_zero(&salt); - v128_set_to_zero(&key_id); + // 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). + // - // look at: http://tools.ietf.org/html/rfc3711#section-4.3 if( ld_kdr_ == -1 ) // means key_derivation_rate = 0 r = 0; else // FIXXME: kdr can be greater than 2^32 (= 2^48) r = seq_nr / ( 0x01 << ld_kdr_ ); - key_id.v32[0] = (label << 8); - key_id.v32[0] += r; - v128_copy_octet_string(&salt, salt_.getBuf()); - v128_xor(&iv, &salt, &key_id); - status = cipher_set_iv(cipher_, &iv); - if( status ) + // FIXXME: why i cant access key_id via operator []? + for(u_int8_t i=0; i<sizeof(tmp_key_id); i++) + tmp_key_id[i] = 0x00; + + tmp_key_id[0] = r; + tmp_key_id[1] = label; + + Buffer key_id(tmp_key_id, 16); + + iv = key_id ^ salt_; + + err = gcry_cipher_reset( cipher_ ); + if( err ) { - KeyDerivation::clear(); - return status; + std::cerr << "Failed to reset cipher: " << gpg_strerror( err ) << std::endl; } - /* generate keystream output */ - status = cipher_output(cipher_, key, length); - - return status; + err = gcry_cipher_encrypt( cipher_, key, key.getLength(), 0, 0 ); + if( err ) + { + std::cerr << "Failed to generate cipher bitstream: " << gpg_strerror( err ) << std::endl; + } } -err_status_t KeyDerivation::clear() +void KeyDerivation::clear() { - return cipher_dealloc(cipher_); + gcry_cipher_close( cipher_ ); } diff --git a/keyDerivation.h b/keyDerivation.h index c65df0e..a0c1a01 100644 --- a/keyDerivation.h +++ b/keyDerivation.h @@ -36,7 +36,7 @@ extern "C" { - #include <srtp/crypto_kernel.h> + #include <gcrypt.h> } @@ -52,16 +52,20 @@ public: KeyDerivation() : ld_kdr_(-1), cipher_(NULL) {}; virtual ~KeyDerivation() {}; - err_status_t init(Buffer key, Buffer salt); - err_status_t setLogKDRate(const uint8_t ld_rate); - err_status_t generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key, uint32_t length); - err_status_t clear(); + void init(Buffer key, Buffer salt); + void setLogKDRate(const u_int8_t ld_rate); + void generate(satp_prf_label label, seq_nr_t seq_nr, Buffer& key, u_int32_t length); + void clear(); + protected: int8_t ld_kdr_; // ld(key_derivation_rate) Buffer salt_; + static const char* MIN_GCRYPT_VERSION; - cipher_t* cipher_; + gcry_cipher_hd_t cipher_; }; + #endif + diff --git a/tunDevice.cpp b/tunDevice.cpp index 40d0f9d..81f4cbb 100644 --- a/tunDevice.cpp +++ b/tunDevice.cpp @@ -153,7 +153,7 @@ u_int32_t TunDevice::getType() return TYPE_UNDEF; } -char* TunDevice::getTypeString() +const char* TunDevice::getTypeString() { if(!dev_) return NULL; diff --git a/tunDevice.h b/tunDevice.h index 8be2050..7e4493c 100644 --- a/tunDevice.h +++ b/tunDevice.h @@ -53,7 +53,7 @@ public: char* getActualName(); u_int32_t getType(); - char* getTypeString(); + const char* getTypeString(); private: void operator=(const TunDevice &src); |