added passphrase support to key derivation
[anytun.git] / src / keyDerivation.cpp
blob48db03436d5eb2c8ebdde48df29a052584b8cb58
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 #ifdef USE_SSL_CRYPTO
45 #include <openssl/sha.h>
46 #endif
48 void KeyDerivation::setLogKDRate(const int8_t log_rate)
50 WritersLock lock(mutex_);
51 ld_kdr_ = log_rate;
52 if(ld_kdr_ > (int8_t)(sizeof(seq_nr_t) * 8))
53 ld_kdr_ = sizeof(seq_nr_t) * 8;
56 #ifndef NO_PASSPHRASE
57 void KeyDerivation::calcMasterKey(std::string passphrase, u_int16_t length)
59 cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master key from passphrase";
60 if(!length) {
61 cLog.msg(Log::PRIO_ERR) << "KeyDerivation: bad master key length";
62 return;
65 #ifndef USE_SSL_CRYPTO
66 if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA256)) {
67 #else
68 if(length > SHA256_DIGEST_LENGTH) {
69 #endif
70 cLog.msg(Log::PRIO_ERR) << "KeyDerivation: master key too long for passphrase algorithm";
71 return;
74 #ifndef USE_SSL_CRYPTO
75 Buffer digest(gcry_md_get_algo_dlen(GCRY_MD_SHA256));
76 gcry_md_hash_buffer(GCRY_MD_SHA256, digest.getBuf(), passphrase.c_str(), passphrase.length());
77 #else
78 Buffer digest(u_int32_t(SHA256_DIGEST_LENGTH));
79 SHA256(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
80 #endif
81 master_key_.setLength(length);
83 memcpy(master_key_.getBuf(), &digest.getBuf()[digest.getLength() - master_key_.getLength()], master_key_.getLength());
86 void KeyDerivation::calcMasterSalt(std::string passphrase, u_int16_t length)
88 cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master salt from passphrase";
89 if(!length) {
90 cLog.msg(Log::PRIO_ERR) << "KeyDerivation: bad master salt length";
91 return;
94 #ifndef USE_SSL_CRYPTO
95 if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA1)) {
96 #else
97 if(length > SHA_DIGEST_LENGTH) {
98 #endif
99 cLog.msg(Log::PRIO_ERR) << "KeyDerivation: master key too long for passphrase algorithm";
100 return;
103 #ifndef USE_SSL_CRYPTO
104 Buffer digest(gcry_md_get_algo_dlen(GCRY_MD_SHA1));
105 gcry_md_hash_buffer(GCRY_MD_SHA1, digest.getBuf(), passphrase.c_str(), passphrase.length());
106 #else
107 Buffer digest(u_int32_t(SHA_DIGEST_LENGTH));
108 SHA1(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
109 #endif
110 master_salt_.setLength(length);
112 memcpy(master_salt_.getBuf(), &digest.getBuf()[digest.getLength() - master_salt_.getLength()], master_salt_.getLength());
114 #endif
116 //****** NullKeyDerivation ******
118 bool NullKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
120 std::memset(key.getBuf(), 0, key.getLength());
121 return true;
124 #ifndef NOCRYPT
125 //****** AesIcmKeyDerivation ******
127 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH)
129 #ifndef USE_SSL_CRYPTO
130 for(int i=0; i<2; i++)
131 handle_[i] = NULL;
132 #endif
135 AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length) : KeyDerivation(key_length)
137 #ifndef USE_SSL_CRYPTO
138 for(int i=0; i<2; i++)
139 handle_[i] = NULL;
140 #endif
143 AesIcmKeyDerivation::~AesIcmKeyDerivation()
145 WritersLock lock(mutex_);
146 #ifndef USE_SSL_CRYPTO
147 for(int i=0; i<2; i++)
148 if(handle_[i])
149 gcry_cipher_close(handle_[i]);
150 #endif
153 void AesIcmKeyDerivation::init(Buffer key, Buffer salt, std::string passphrase)
155 WritersLock lock(mutex_);
157 is_initialized_ = false;
158 #ifndef NO_PASSPHRASE
159 if(passphrase != "" && !key.getLength())
160 calcMasterKey(passphrase, key_length_/8);
161 else
162 master_key_ = SyncBuffer(key);
164 if(passphrase != "" && !salt.getLength())
165 calcMasterSalt(passphrase, SALT_LENGTH);
166 else
167 master_salt_ = SyncBuffer(salt);
168 #else
169 master_key_ = SyncBuffer(key);
170 master_salt_ = SyncBuffer(salt);
171 #endif
173 updateMasterKey();
176 void AesIcmKeyDerivation::updateMasterKey()
178 if(master_key_.getLength()*8 != key_length_) {
179 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: key lengths don't match";
180 return;
183 if(master_salt_.getLength() != SALT_LENGTH) {
184 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: salt lengths don't match";
185 return;
188 #ifndef USE_SSL_CRYPTO
189 int algo;
190 switch(key_length_) {
191 case 128: algo = GCRY_CIPHER_AES128; break;
192 case 192: algo = GCRY_CIPHER_AES192; break;
193 case 256: algo = GCRY_CIPHER_AES256; break;
194 default: {
195 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_ << " Bits is not supported";
196 return;
200 for(int i=0; i<2; i++) {
201 if(handle_[i])
202 gcry_cipher_close(handle_[i]);
204 gcry_error_t err = gcry_cipher_open(&handle_[i], algo, GCRY_CIPHER_MODE_CTR, 0);
205 if(err) {
206 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << LogGpgError(err);
207 return;
210 err = gcry_cipher_setkey(handle_[i], master_key_.getBuf(), master_key_.getLength());
211 if(err) {
212 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << LogGpgError(err);
213 return;
216 #else
217 for(int i=0; i<2; i++) {
218 int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_[i]);
219 if(ret) {
220 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")";
221 return;
224 #endif
225 is_initialized_ = true;
228 std::string AesIcmKeyDerivation::printType()
230 ReadersLock lock(mutex_);
232 std::stringstream sstr;
233 sstr << "AesIcm" << key_length_ << "KeyDerivation";
234 return sstr.str();
237 bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir, seq_nr_t* r, satp_prf_label_t label, seq_nr_t seq_nr)
239 *r = 0;
240 if(ld_kdr_ >= 0)
241 *r = seq_nr >> ld_kdr_;
243 if(key_store_[dir][label].key_.getLength() && key_store_[dir][label].r_ == *r) {
244 if(!(*r) || (seq_nr % (*r)))
245 return false;
248 if(master_salt_.getLength() != SALT_LENGTH) {
249 cLog.msg(Log::PRIO_CRIT) << "KeyDerivation::calcCtr: salt lengths don't match";
250 return false;
252 memcpy(ctr_[dir].salt_.buf_, master_salt_.getBuf(), SALT_LENGTH);
253 ctr_[dir].salt_.zero_ = 0;
254 ctr_[dir].params_.label_ ^= label;
255 ctr_[dir].params_.r_ ^= SEQ_NR_T_HTON(*r);
257 return true;
260 bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
262 ReadersLock lock(mutex_);
264 if(!is_initialized_)
265 return false;
267 seq_nr_t r;
268 calcCtr(dir, &r, label, seq_nr);
269 bool result = calcCtr(dir, &r, label, seq_nr);
270 if(!result) {
271 u_int32_t len = key.getLength();
272 if(len > key_store_[dir][label].key_.getLength()) {
273 cLog.msg(Log::PRIO_WARNING) << "KeyDerivation::generate: stored (old) key for label " << label << " is too short, filling with zeros";
274 std::memset(key.getBuf(), 0, len);
275 len = key_store_[dir][label].key_.getLength();
277 std::memcpy(key.getBuf(), key_store_[dir][label].key_.getBuf(), len);
278 return false;
281 #ifndef USE_SSL_CRYPTO
282 gcry_error_t err = gcry_cipher_reset(handle_[dir]);
283 if(err) {
284 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to reset cipher: " << LogGpgError(err);
287 err = gcry_cipher_setctr(handle_[dir], ctr_[dir].buf_, CTR_LENGTH);
288 if(err) {
289 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to set CTR: " << LogGpgError(err);
290 return false;
293 std::memset(key.getBuf(), 0, key.getLength());
294 err = gcry_cipher_encrypt(handle_[dir], key, key.getLength(), NULL, 0);
295 if(err) {
296 cLog.msg(Log::PRIO_ERR) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << LogGpgError(err);
298 return true;
299 #else
300 if(CTR_LENGTH != AES_BLOCK_SIZE) {
301 cLog.msg(Log::PRIO_ERR) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
302 return false;
304 unsigned int num = 0;
305 std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE);
306 std::memset(key.getBuf(), 0, key.getLength());
307 AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num);
308 #endif
310 if(!ld_kdr_)
311 return true;
313 if(key_store_[dir][label].key_.getLength() < key.getLength()) {
314 key_store_[dir][label].key_.setLength(key.getLength());
317 std::memcpy(key_store_[dir][label].key_.getBuf(), key.getBuf(), key.getLength());
318 key_store_[dir][label].r_ = r;
320 return true;
322 #endif