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/>.
34 #include "keyDerivation.h"
35 #include "threadUtils.hpp"
36 #include "datatypes.h"
45 #include <openssl/sha.h>
48 void KeyDerivation::setLogKDRate(const int8_t log_rate
)
50 WritersLock
lock(mutex_
);
52 if(ld_kdr_
> (int8_t)(sizeof(seq_nr_t
) * 8))
53 ld_kdr_
= sizeof(seq_nr_t
) * 8;
57 void KeyDerivation::calcMasterKey(std::string passphrase
, u_int16_t length
)
59 cLog
.msg(Log::PRIO_NOTICE
) << "KeyDerivation: calculating master key from passphrase";
61 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation: bad master key length";
65 #ifndef USE_SSL_CRYPTO
66 if(length
> gcry_md_get_algo_dlen(GCRY_MD_SHA256
)) {
68 if(length
> SHA256_DIGEST_LENGTH
) {
70 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation: master key too long for passphrase algorithm";
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());
78 Buffer
digest(u_int32_t(SHA256_DIGEST_LENGTH
));
79 SHA256(reinterpret_cast<const unsigned char*>(passphrase
.c_str()), passphrase
.length(), digest
.getBuf());
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";
90 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation: bad master salt length";
94 #ifndef USE_SSL_CRYPTO
95 if(length
> gcry_md_get_algo_dlen(GCRY_MD_SHA1
)) {
97 if(length
> SHA_DIGEST_LENGTH
) {
99 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation: master key too long for passphrase algorithm";
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());
107 Buffer
digest(u_int32_t(SHA_DIGEST_LENGTH
));
108 SHA1(reinterpret_cast<const unsigned char*>(passphrase
.c_str()), passphrase
.length(), digest
.getBuf());
110 master_salt_
.setLength(length
);
112 memcpy(master_salt_
.getBuf(), &digest
.getBuf()[digest
.getLength() - master_salt_
.getLength()], master_salt_
.getLength());
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());
125 //****** AesIcmKeyDerivation ******
127 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH
)
129 #ifndef USE_SSL_CRYPTO
130 for(int i
=0; i
<2; i
++)
135 AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length
) : KeyDerivation(key_length
)
137 #ifndef USE_SSL_CRYPTO
138 for(int i
=0; i
<2; i
++)
143 AesIcmKeyDerivation::~AesIcmKeyDerivation()
145 WritersLock
lock(mutex_
);
146 #ifndef USE_SSL_CRYPTO
147 for(int i
=0; i
<2; i
++)
149 gcry_cipher_close(handle_
[i
]);
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);
162 master_key_
= SyncBuffer(key
);
164 if(passphrase
!= "" && !salt
.getLength())
165 calcMasterSalt(passphrase
, SALT_LENGTH
);
167 master_salt_
= SyncBuffer(salt
);
169 master_key_
= SyncBuffer(key
);
170 master_salt_
= SyncBuffer(salt
);
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";
183 if(master_salt_
.getLength() != SALT_LENGTH
) {
184 cLog
.msg(Log::PRIO_CRIT
) << "KeyDerivation::updateMasterKey: salt lengths don't match";
188 #ifndef USE_SSL_CRYPTO
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;
195 cLog
.msg(Log::PRIO_CRIT
) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_
<< " Bits is not supported";
200 for(int i
=0; i
<2; i
++) {
202 gcry_cipher_close(handle_
[i
]);
204 gcry_error_t err
= gcry_cipher_open(&handle_
[i
], algo
, GCRY_CIPHER_MODE_CTR
, 0);
206 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << LogGpgError(err
);
210 err
= gcry_cipher_setkey(handle_
[i
], master_key_
.getBuf(), master_key_
.getLength());
212 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << LogGpgError(err
);
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
]);
220 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret
<< ")";
225 is_initialized_
= true;
228 std::string
AesIcmKeyDerivation::printType()
230 ReadersLock
lock(mutex_
);
232 std::stringstream sstr
;
233 sstr
<< "AesIcm" << key_length_
<< "KeyDerivation";
237 bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir
, seq_nr_t
* r
, satp_prf_label_t label
, seq_nr_t seq_nr
)
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
)))
248 if(master_salt_
.getLength() != SALT_LENGTH
) {
249 cLog
.msg(Log::PRIO_CRIT
) << "KeyDerivation::calcCtr: salt lengths don't match";
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
);
260 bool AesIcmKeyDerivation::generate(kd_dir_t dir
, satp_prf_label_t label
, seq_nr_t seq_nr
, Buffer
& key
)
262 ReadersLock
lock(mutex_
);
268 calcCtr(dir
, &r
, label
, seq_nr
);
269 bool result
= calcCtr(dir
, &r
, label
, seq_nr
);
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
);
281 #ifndef USE_SSL_CRYPTO
282 gcry_error_t err
= gcry_cipher_reset(handle_
[dir
]);
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
);
289 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::generate: Failed to set CTR: " << LogGpgError(err
);
293 std::memset(key
.getBuf(), 0, key
.getLength());
294 err
= gcry_cipher_encrypt(handle_
[dir
], key
, key
.getLength(), NULL
, 0);
296 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << LogGpgError(err
);
300 if(CTR_LENGTH
!= AES_BLOCK_SIZE
) {
301 cLog
.msg(Log::PRIO_ERR
) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
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
);
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
;