Imported Upstream version 0.3
[anytun.git] / src / keyDerivation.cpp
1 /*
2  *  anytun
3  *
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.
12  *
13  *
14  *  Copyright (C) 2007-2008 Othmar Gsenger, Erwin Nindl, 
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
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.
22  *
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.
27  *
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/>.
30  */
31
32
33 #include "log.h"
34 #include "anytunError.h"
35 #include "keyDerivation.h"
36 #include "threadUtils.hpp"
37 #include "datatypes.h"
38 #include "endian.h"
39
40 #include <stdexcept>
41 #include <iostream>
42 #include <sstream>
43 #include <string>
44
45 #ifndef NO_CRYPT
46 #ifndef NO_PASSPHRASE
47 #ifdef USE_SSL_CRYPTO
48 #include <openssl/sha.h>
49 #endif
50 #endif
51 #endif
52
53 void KeyDerivation::setRole(const role_t role)
54 {
55   WritersLock lock(mutex_);
56   role_ = role;
57   cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: using role " << role_;
58 }
59
60 #ifndef NO_CRYPT
61 #ifndef NO_PASSPHRASE
62 void KeyDerivation::calcMasterKey(std::string passphrase, u_int16_t length)
63 {
64   cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master key from passphrase";
65   if(!length) {
66     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: bad master key length";
67     return;
68   }
69
70 #ifndef USE_SSL_CRYPTO
71   if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA256)) {
72 #else
73   if(length > SHA256_DIGEST_LENGTH) {
74 #endif
75     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: master key too long for passphrase algorithm";
76     return;
77   }
78
79 #ifndef USE_SSL_CRYPTO
80   Buffer digest(gcry_md_get_algo_dlen(GCRY_MD_SHA256));
81   gcry_md_hash_buffer(GCRY_MD_SHA256, digest.getBuf(), passphrase.c_str(), passphrase.length());
82 #else
83   Buffer digest(u_int32_t(SHA256_DIGEST_LENGTH));
84   SHA256(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
85 #endif
86   master_key_.setLength(length);
87
88   memcpy(master_key_.getBuf(), &digest.getBuf()[digest.getLength() - master_key_.getLength()], master_key_.getLength());
89 }
90
91 void KeyDerivation::calcMasterSalt(std::string passphrase, u_int16_t length)
92 {
93   cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master salt from passphrase";
94   if(!length) {
95     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: bad master salt length";
96     return;
97   }
98
99 #ifndef USE_SSL_CRYPTO
100   if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA1)) {
101 #else
102   if(length > SHA_DIGEST_LENGTH) {
103 #endif
104     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: master key too long for passphrase algorithm";
105     return;
106   }
107
108 #ifndef USE_SSL_CRYPTO
109   Buffer digest(gcry_md_get_algo_dlen(GCRY_MD_SHA1));
110   gcry_md_hash_buffer(GCRY_MD_SHA1, digest.getBuf(), passphrase.c_str(), passphrase.length());
111 #else
112   Buffer digest(u_int32_t(SHA_DIGEST_LENGTH));
113   SHA1(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
114 #endif
115   master_salt_.setLength(length);
116
117   memcpy(master_salt_.getBuf(), &digest.getBuf()[digest.getLength() - master_salt_.getLength()], master_salt_.getLength());
118 }
119 #endif
120 #endif
121
122 satp_prf_label_t KeyDerivation::convertLabel(kd_dir_t dir, satp_prf_label_t label)
123 {
124   switch(label) {
125   case LABEL_ENC: {
126     if(dir == KD_OUTBOUND) {
127       if(role_ == ROLE_LEFT) return LABEL_LEFT_ENC;
128       if(role_ == ROLE_RIGHT) return LABEL_RIGHT_ENC;
129     }
130     else {
131       if(role_ == ROLE_LEFT) return LABEL_RIGHT_ENC;
132       if(role_ == ROLE_RIGHT) return LABEL_LEFT_ENC;
133     }
134     break;
135   }
136   case LABEL_SALT: {
137     if(dir == KD_OUTBOUND) {
138       if(role_ == ROLE_LEFT) return LABEL_LEFT_SALT;
139       if(role_ == ROLE_RIGHT) return LABEL_RIGHT_SALT;
140     }
141     else {
142       if(role_ == ROLE_LEFT) return LABEL_RIGHT_SALT;
143       if(role_ == ROLE_RIGHT) return LABEL_LEFT_SALT;
144     }
145     break;
146   }
147   case LABEL_AUTH: {
148     if(dir == KD_OUTBOUND) {
149       if(role_ == ROLE_LEFT) return LABEL_LEFT_AUTH;
150       if(role_ == ROLE_RIGHT) return LABEL_RIGHT_AUTH;
151     }
152     else {
153       if(role_ == ROLE_LEFT) return LABEL_RIGHT_AUTH;
154       if(role_ == ROLE_RIGHT) return LABEL_LEFT_AUTH;
155     }
156     break;
157   }
158   }
159
160   return label;
161 }
162
163 //****** NullKeyDerivation ******
164
165 bool NullKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
166 {
167   std::memset(key.getBuf(), 0, key.getLength());
168   return true;
169 }
170
171 #ifndef NO_CRYPT
172 //****** AesIcmKeyDerivation ******
173
174 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH) 
175 {
176 #ifndef USE_SSL_CRYPTO
177   for(int i=0; i<2; i++)
178     handle_[i] = NULL;
179 #endif
180 }
181
182 AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length) : KeyDerivation(key_length) 
183 {
184 #ifndef USE_SSL_CRYPTO
185   for(int i=0; i<2; i++)
186     handle_[i] = NULL;
187 #endif
188 }
189
190 AesIcmKeyDerivation::~AesIcmKeyDerivation()
191 {
192   WritersLock lock(mutex_);
193 #ifndef USE_SSL_CRYPTO
194   for(int i=0; i<2; i++)
195     if(handle_[i])
196       gcry_cipher_close(handle_[i]);
197 #endif
198 }
199
200 void AesIcmKeyDerivation::init(Buffer key, Buffer salt, std::string passphrase)
201 {
202   WritersLock lock(mutex_);
203
204   is_initialized_ = false;
205 #ifndef NO_PASSPHRASE
206   if(passphrase != "" && !key.getLength())
207     calcMasterKey(passphrase, key_length_/8);
208   else
209     master_key_ = SyncBuffer(key);
210   
211   if(passphrase != "" && !salt.getLength())
212     calcMasterSalt(passphrase, SALT_LENGTH);
213   else
214     master_salt_ = SyncBuffer(salt);
215 #else
216   master_key_ = SyncBuffer(key);
217   master_salt_ = SyncBuffer(salt);
218 #endif
219
220   updateMasterKey();
221 }
222
223 void AesIcmKeyDerivation::updateMasterKey()
224 {
225   if(master_key_.getLength()*8 != key_length_) {
226     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: key lengths don't match";
227     return;
228   }
229
230   if(master_salt_.getLength() != SALT_LENGTH) {
231     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: salt lengths don't match";
232     return;
233   }
234
235 #ifndef USE_SSL_CRYPTO
236   int algo;
237   switch(key_length_) {
238   case 128: algo = GCRY_CIPHER_AES128; break;
239   case 192: algo = GCRY_CIPHER_AES192; break;
240   case 256: algo = GCRY_CIPHER_AES256; break;
241   default: {
242     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_ << " Bits is not supported";
243     return;
244   }
245   }
246
247   for(int i=0; i<2; i++) {
248     if(handle_[i])
249       gcry_cipher_close(handle_[i]);
250     
251     gcry_error_t err = gcry_cipher_open(&handle_[i], algo, GCRY_CIPHER_MODE_CTR, 0);
252     if(err) {
253       cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << AnytunGpgError(err);
254       return;
255     } 
256     
257     err = gcry_cipher_setkey(handle_[i], master_key_.getBuf(), master_key_.getLength());
258     if(err) {
259       cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << AnytunGpgError(err);
260       return;
261     }
262   }
263 #else
264   for(int i=0; i<2; i++) {
265     int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_[i]);
266     if(ret) {
267       cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")";
268       return;
269     }
270   }
271 #endif
272   is_initialized_ = true;
273 }
274
275 std::string AesIcmKeyDerivation::printType() 
276 {
277   ReadersLock lock(mutex_);
278
279   std::stringstream sstr;
280   sstr << "AesIcm" << key_length_ << "KeyDerivation";
281   return sstr.str();
282 }
283
284 bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr)
285 {
286   if(master_salt_.getLength() != SALT_LENGTH) {
287     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::calcCtr: salt lengths don't match";
288     return false;
289   }
290   memcpy(ctr_[dir].salt_.buf_, master_salt_.getBuf(), SALT_LENGTH);
291   ctr_[dir].salt_.zero_ = 0;
292   ctr_[dir].params_.label_ ^= SATP_PRF_LABEL_T_HTON(convertLabel(dir, label));
293   ctr_[dir].params_.seq_ ^= SEQ_NR_T_HTON(seq_nr);
294
295   return true;
296 }
297
298 bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key) 
299 {
300   ReadersLock lock(mutex_);
301
302   if(!is_initialized_)
303     return false;
304
305   if(!calcCtr(dir, label, seq_nr)) {
306     return false;
307   }
308  
309 #ifndef USE_SSL_CRYPTO
310   gcry_error_t err = gcry_cipher_reset(handle_[dir]);
311   if(err) {
312     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to reset cipher: " << AnytunGpgError(err);
313   }
314
315   err = gcry_cipher_setctr(handle_[dir], ctr_[dir].buf_, CTR_LENGTH);
316   if(err) {
317     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to set CTR: " << AnytunGpgError(err);
318     return false;
319   }
320
321   std::memset(key.getBuf(), 0, key.getLength());
322   err = gcry_cipher_encrypt(handle_[dir], key, key.getLength(), NULL, 0);
323   if(err) {
324     cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << AnytunGpgError(err);
325   }
326 #else
327   if(CTR_LENGTH != AES_BLOCK_SIZE) {
328     cLog.msg(Log::PRIO_ERROR) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
329     return false;
330   }
331   unsigned int num = 0;
332   std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE);
333   std::memset(key.getBuf(), 0, key.getLength());
334   AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num);
335 #endif
336   
337   return true;
338 }
339 #endif
340