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-2009 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 as published by
21 * the Free Software Foundation, either version 3 of the License, or
24 * Anytun is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with anytun. If not, see <http://www.gnu.org/licenses/>.
35 #include "anytunError.h"
36 #include "keyDerivation.h"
37 #include "threadUtils.hpp"
38 #include "datatypes.h"
50 #include <openssl/sha.h>
55 void KeyDerivation::setRole(const role_t role)
57 WritersLock lock(mutex_);
59 cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: using role " << role_;
64 void KeyDerivation::calcMasterKey(std::string passphrase, u_int16_t length)
66 cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master key from passphrase";
68 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: bad master key length";
72 #ifndef USE_SSL_CRYPTO
73 if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA256)) {
75 if(length > SHA256_DIGEST_LENGTH) {
77 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: master key too long for passphrase algorithm";
81 #ifndef USE_SSL_CRYPTO
82 Buffer digest(gcry_md_get_algo_dlen(GCRY_MD_SHA256));
83 gcry_md_hash_buffer(GCRY_MD_SHA256, digest.getBuf(), passphrase.c_str(), passphrase.length());
85 Buffer digest(u_int32_t(SHA256_DIGEST_LENGTH));
86 SHA256(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
88 master_key_.setLength(length);
90 std::memcpy(master_key_.getBuf(), &digest.getBuf()[digest.getLength() - master_key_.getLength()], master_key_.getLength());
93 void KeyDerivation::calcMasterSalt(std::string passphrase, u_int16_t length)
95 cLog.msg(Log::PRIO_NOTICE) << "KeyDerivation: calculating master salt from passphrase";
97 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: bad master salt length";
101 #ifndef USE_SSL_CRYPTO
102 if(length > gcry_md_get_algo_dlen(GCRY_MD_SHA1)) {
104 if(length > SHA_DIGEST_LENGTH) {
106 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation: master key too long for passphrase algorithm";
110 #ifndef USE_SSL_CRYPTO
111 Buffer digest(gcry_md_get_algo_dlen(GCRY_MD_SHA1));
112 gcry_md_hash_buffer(GCRY_MD_SHA1, digest.getBuf(), passphrase.c_str(), passphrase.length());
114 Buffer digest(u_int32_t(SHA_DIGEST_LENGTH));
115 SHA1(reinterpret_cast<const unsigned char*>(passphrase.c_str()), passphrase.length(), digest.getBuf());
117 master_salt_.setLength(length);
119 std::memcpy(master_salt_.getBuf(), &digest.getBuf()[digest.getLength() - master_salt_.getLength()], master_salt_.getLength());
124 satp_prf_label_t KeyDerivation::convertLabel(kd_dir_t dir, satp_prf_label_t label)
128 if(dir == KD_OUTBOUND) {
129 if(role_ == ROLE_LEFT) return LABEL_LEFT_ENC;
130 if(role_ == ROLE_RIGHT) return LABEL_RIGHT_ENC;
133 if(role_ == ROLE_LEFT) return LABEL_RIGHT_ENC;
134 if(role_ == ROLE_RIGHT) return LABEL_LEFT_ENC;
139 if(dir == KD_OUTBOUND) {
140 if(role_ == ROLE_LEFT) return LABEL_LEFT_SALT;
141 if(role_ == ROLE_RIGHT) return LABEL_RIGHT_SALT;
144 if(role_ == ROLE_LEFT) return LABEL_RIGHT_SALT;
145 if(role_ == ROLE_RIGHT) return LABEL_LEFT_SALT;
150 if(dir == KD_OUTBOUND) {
151 if(role_ == ROLE_LEFT) return LABEL_LEFT_AUTH;
152 if(role_ == ROLE_RIGHT) return LABEL_RIGHT_AUTH;
155 if(role_ == ROLE_LEFT) return LABEL_RIGHT_AUTH;
156 if(role_ == ROLE_RIGHT) return LABEL_LEFT_AUTH;
165 //****** NullKeyDerivation ******
167 bool NullKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
169 std::memset(key.getBuf(), 0, key.getLength());
174 //****** AesIcmKeyDerivation ******
176 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH)
178 #ifndef USE_SSL_CRYPTO
179 for(int i=0; i<2; i++)
184 AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length) : KeyDerivation(key_length)
186 #ifndef USE_SSL_CRYPTO
187 for(int i=0; i<2; i++)
192 AesIcmKeyDerivation::~AesIcmKeyDerivation()
194 WritersLock lock(mutex_);
195 #ifndef USE_SSL_CRYPTO
196 for(int i=0; i<2; i++)
198 gcry_cipher_close(handle_[i]);
202 void AesIcmKeyDerivation::init(Buffer key, Buffer salt, std::string passphrase)
204 WritersLock lock(mutex_);
206 is_initialized_ = false;
207 #ifndef NO_PASSPHRASE
208 if(passphrase != "" && !key.getLength())
209 calcMasterKey(passphrase, key_length_/8);
211 master_key_ = SyncBuffer(key);
213 if(passphrase != "" && !salt.getLength())
214 calcMasterSalt(passphrase, SALT_LENGTH);
216 master_salt_ = SyncBuffer(salt);
218 master_key_ = SyncBuffer(key);
219 master_salt_ = SyncBuffer(salt);
225 void AesIcmKeyDerivation::updateMasterKey()
227 if(master_key_.getLength()*8 != key_length_) {
228 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: key lengths don't match";
232 if(master_salt_.getLength() != SALT_LENGTH) {
233 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: salt lengths don't match";
237 #ifndef USE_SSL_CRYPTO
239 switch(key_length_) {
240 case 128: algo = GCRY_CIPHER_AES128; break;
241 case 192: algo = GCRY_CIPHER_AES192; break;
242 case 256: algo = GCRY_CIPHER_AES256; break;
244 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_ << " Bits is not supported";
249 for(int i=0; i<2; i++) {
251 gcry_cipher_close(handle_[i]);
253 gcry_error_t err = gcry_cipher_open(&handle_[i], algo, GCRY_CIPHER_MODE_CTR, 0);
255 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << AnytunGpgError(err);
259 err = gcry_cipher_setkey(handle_[i], master_key_.getBuf(), master_key_.getLength());
261 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << AnytunGpgError(err);
266 for(int i=0; i<2; i++) {
267 int ret = AES_set_encrypt_key(master_key_.getBuf(), master_key_.getLength()*8, &aes_key_[i]);
269 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret << ")";
274 is_initialized_ = true;
277 std::string AesIcmKeyDerivation::printType()
279 ReadersLock lock(mutex_);
281 std::stringstream sstr;
282 sstr << "AesIcm" << key_length_ << "KeyDerivation";
286 bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr)
288 if(master_salt_.getLength() != SALT_LENGTH) {
289 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::calcCtr: salt lengths don't match";
292 std::memcpy(ctr_[dir].salt_.buf_, master_salt_.getBuf(), SALT_LENGTH);
293 ctr_[dir].salt_.zero_ = 0;
294 ctr_[dir].params_.label_ ^= SATP_PRF_LABEL_T_HTON(convertLabel(dir, label));
295 ctr_[dir].params_.seq_ ^= SEQ_NR_T_HTON(seq_nr);
300 bool AesIcmKeyDerivation::generate(kd_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, Buffer& key)
302 ReadersLock lock(mutex_);
307 if(!calcCtr(dir, label, seq_nr)) {
311 #ifndef USE_SSL_CRYPTO
312 gcry_error_t err = gcry_cipher_reset(handle_[dir]);
314 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to reset cipher: " << AnytunGpgError(err);
317 err = gcry_cipher_setctr(handle_[dir], ctr_[dir].buf_, CTR_LENGTH);
319 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to set CTR: " << AnytunGpgError(err);
323 std::memset(key.getBuf(), 0, key.getLength());
324 err = gcry_cipher_encrypt(handle_[dir], key, key.getLength(), NULL, 0);
326 cLog.msg(Log::PRIO_ERROR) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << AnytunGpgError(err);
329 if(CTR_LENGTH != AES_BLOCK_SIZE) {
330 cLog.msg(Log::PRIO_ERROR) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
333 unsigned int num = 0;
334 std::memset(ecount_buf_[dir], 0, AES_BLOCK_SIZE);
335 std::memset(key.getBuf(), 0, key.getLength());
336 AES_ctr128_encrypt(key.getBuf(), key.getBuf(), key.getLength(), &aes_key_[dir], ctr_[dir].buf_, ecount_buf_[dir], &num);