diff options
Diffstat (limited to 'src/keyDerivation.cpp')
-rw-r--r-- | src/keyDerivation.cpp | 255 |
1 files changed, 177 insertions, 78 deletions
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 |