added initialized flag to key derivation
[anytun.git] / src / keyDerivation.cpp
blob5b4f7a648e17bd2382033a0903ac2d4e93412381
1 /*
2 * anytun
4 * The secure anycast tunneling protocol (satp) defines a protocol used
5 * for communication between any combination of unicast and anycast
6 * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel
7 * mode and allows tunneling of every ETHER TYPE protocol (e.g.
8 * ethernet, ip, arp ...). satp directly includes cryptography and
9 * message authentication based on the methodes used by SRTP. It is
10 * intended to deliver a generic, scaleable and secure solution for
11 * tunneling and relaying of packets of any protocol.
14 * Copyright (C) 2007-2008 Othmar Gsenger, Erwin Nindl,
15 * Christian Pointner <satp@wirdorange.org>
17 * This file is part of Anytun.
19 * Anytun is free software: you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License version 3 as
21 * published by the Free Software Foundation.
23 * Anytun is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with anytun. If not, see <http://www.gnu.org/licenses/>.
33 #include "log.h"
34 #include "keyDerivation.h"
35 #include "threadUtils.hpp"
36 #include "datatypes.h"
37 #include "endian.h"
39 #include <stdexcept>
40 #include <iostream>
41 #include <sstream>
42 #include <string>
44 void KeyDerivation::setLogKDRate(const int8_t log_rate)
46 WritersLock lock(mutex_);
47 ld_kdr_ = log_rate;
48 if(ld_kdr_ > (int8_t)(sizeof(seq_nr_t) * 8))
49 ld_kdr_ = sizeof(seq_nr_t) * 8;
52 //****** NullKeyDerivation ******
54 bool NullKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
56 std::memset(key.getBuf(), 0, key.getLength());
57 return true;
60 #ifndef NOCRYPT
61 //****** AesIcmKeyDerivation ******
63 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH)
65 #ifndef USE_SSL_CRYPTO
66 for(int i=0; i<2; i++)
67 handle_[i] = NULL;
68 #endif
71 AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length) : KeyDerivation(key_length)
73 #ifndef USE_SSL_CRYPTO
74 for(int i=0; i<2; i++)
75 handle_[i] = NULL;
76 #endif
79 AesIcmKeyDerivation::~AesIcmKeyDerivation()
81 WritersLock lock(mutex_);
82 #ifndef USE_SSL_CRYPTO
83 for(int i=0; i<2; i++)
84 if(handle_[i])
85 gcry_cipher_close(handle_[i]);
86 #endif
89 void AesIcmKeyDerivation::init(Buffer key, Buffer salt)
91 WritersLock lock(mutex_);
93 is_initialized_ = false;
94 master_salt_ = SyncBuffer(salt);
95 master_key_ = SyncBuffer(key);
97 updateMasterKey();
100 void AesIcmKeyDerivation::updateMasterKey()
102 if(master_key_.getLength()*8 != key_length_) {
103 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: key lengths don't match";
104 return;
107 if(master_salt_.getLength() != SALT_LENGTH) {
108 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: salt lengths don't match";
109 return;
112 #ifndef USE_SSL_CRYPTO
113 int algo;
114 switch(key_length_) {
115 case 128: algo = GCRY_CIPHER_AES128; break;
116 case 192: algo = GCRY_CIPHER_AES192; break;
117 case 256: algo = GCRY_CIPHER_AES256; break;
118 default: {
119 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_ << " Bits is not supported";
120 return;
124 for(int i=0; i<2; i++) {
125 if(handle_[i])
126 gcry_cipher_close(handle_[i]);
128 gcry_error_t err = gcry_cipher_open(&handle_[i], algo, GCRY_CIPHER_MODE_CTR, 0);
129 if(err) {
130 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << LogGpgError(err);
131 return;
134 err = gcry_cipher_setkey(handle_[i], master_key_.getBuf(), master_key_.getLength());
135 if(err) {
136 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << LogGpgError(err);
137 return;
140 #else
141 for(int i=0; i<2; i++) {
142 int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_[i]);
143 if(ret) {
144 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")";
145 return;
148 #endif
149 is_initialized_ = true;
152 std::string AesIcmKeyDerivation::printType()
154 ReadersLock lock(mutex_);
156 std::stringstream sstr;
157 sstr << "AesIcm" << key_length_ << "KeyDerivation";
158 return sstr.str();
161 bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir, seq_nr_t* r, satp_prf_label_t label, seq_nr_t seq_nr)
163 *r = 0;
164 if(ld_kdr_ >= 0)
165 *r = seq_nr >> ld_kdr_;
167 if(key_store_[dir][label].key_.getLength() && key_store_[dir][label].r_ == *r) {
168 if(!(*r) || (seq_nr % (*r)))
169 return false;
172 if(master_salt_.getLength() != SALT_LENGTH) {
173 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::calcCtr: salt lengths don't match";
174 return false;
176 memcpy(ctr_[dir].salt_.buf_, master_salt_.getBuf(), SALT_LENGTH);
177 ctr_[dir].salt_.zero_ = 0;
178 ctr_[dir].params_.label_ ^= label;
179 ctr_[dir].params_.r_ ^= SEQ_NR_T_HTON(*r);
181 return true;
184 bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
186 ReadersLock lock(mutex_);
188 if(!is_initialized_)
189 return false;
191 seq_nr_t r;
192 calcCtr(dir, &r, label, seq_nr);
193 bool result = calcCtr(dir, &r, label, seq_nr);
194 if(!result) {
195 u_int32_t len = key.getLength();
196 if(len > key_store_[dir][label].key_.getLength()) {
197 cLog.msg(Log::PRIO_WARNING) << "KeyDerivation::generate: stored (old) key for label " << label << " is too short, filling with zeros";
198 std::memset(key.getBuf(), 0, len);
199 len = key_store_[dir][label].key_.getLength();
201 std::memcpy(key.getBuf(), key_store_[dir][label].key_.getBuf(), len);
202 return false;
205 #ifndef USE_SSL_CRYPTO
206 gcry_error_t err = gcry_cipher_reset(handle_[dir]);
207 if(err) {
208 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to reset cipher: " << LogGpgError(err);
211 err = gcry_cipher_setctr(handle_[dir], ctr_[dir].buf_, CTR_LENGTH);
212 if(err) {
213 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to set CTR: " << LogGpgError(err);
214 return false;
217 std::memset(key.getBuf(), 0, key.getLength());
218 err = gcry_cipher_encrypt(handle_[dir], key, key.getLength(), NULL, 0);
219 if(err) {
220 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << LogGpgError(err);
222 return true;
223 #else
224 if(CTR_LENGTH != AES_BLOCK_SIZE) {
225 cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
226 return false;
228 u_int32_t num = 0;
229 std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE);
230 std::memset(key.getBuf(), 0, key.getLength());
231 AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num);
232 #endif
234 if(!ld_kdr_)
235 return true;
237 if(key_store_[dir][label].key_.getLength() < key.getLength()) {
238 key_store_[dir][label].key_.setLength(key.getLength());
241 std::memcpy(key_store_[dir][label].key_.getBuf(), key.getBuf(), key.getLength());
242 key_store_[dir][label].r_ = r;
244 return true;
246 #endif