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"
44 void KeyDerivation::setLogKDRate(const int8_t log_rate
)
46 WritersLock
lock(mutex_
);
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());
61 //****** AesIcmKeyDerivation ******
63 AesIcmKeyDerivation::AesIcmKeyDerivation() : KeyDerivation(DEFAULT_KEY_LENGTH
)
65 #ifndef USE_SSL_CRYPTO
66 for(int i
=0; i
<2; i
++)
71 AesIcmKeyDerivation::AesIcmKeyDerivation(u_int16_t key_length
) : KeyDerivation(key_length
)
73 #ifndef USE_SSL_CRYPTO
74 for(int i
=0; i
<2; i
++)
79 AesIcmKeyDerivation::~AesIcmKeyDerivation()
81 WritersLock
lock(mutex_
);
82 #ifndef USE_SSL_CRYPTO
83 for(int i
=0; i
<2; i
++)
85 gcry_cipher_close(handle_
[i
]);
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
);
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";
107 if(master_salt_
.getLength() != SALT_LENGTH
) {
108 cLog
.msg(Log::PRIO_CRIT
) << "KeyDerivation::updateMasterKey: salt lengths don't match";
112 #ifndef USE_SSL_CRYPTO
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;
119 cLog
.msg(Log::PRIO_CRIT
) << "KeyDerivation::updateMasterKey: cipher key length of " << key_length_
<< " Bits is not supported";
124 for(int i
=0; i
<2; i
++) {
126 gcry_cipher_close(handle_
[i
]);
128 gcry_error_t err
= gcry_cipher_open(&handle_
[i
], algo
, GCRY_CIPHER_MODE_CTR
, 0);
130 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::updateMasterKey: Failed to open cipher: " << LogGpgError(err
);
134 err
= gcry_cipher_setkey(handle_
[i
], master_key_
.getBuf(), master_key_
.getLength());
136 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::updateMasterKey: Failed to set cipher key: " << LogGpgError(err
);
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
]);
144 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::updateMasterKey: Failed to set ssl key (code: " << ret
<< ")";
149 is_initialized_
= true;
152 std::string
AesIcmKeyDerivation::printType()
154 ReadersLock
lock(mutex_
);
156 std::stringstream sstr
;
157 sstr
<< "AesIcm" << key_length_
<< "KeyDerivation";
161 bool AesIcmKeyDerivation::calcCtr(kd_dir_t dir
, seq_nr_t
* r
, satp_prf_label_t label
, seq_nr_t seq_nr
)
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
)))
172 if(master_salt_
.getLength() != SALT_LENGTH
) {
173 cLog
.msg(Log::PRIO_CRIT
) << "KeyDerivation::calcCtr: salt lengths don't match";
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
);
184 bool AesIcmKeyDerivation::generate(kd_dir_t dir
, satp_prf_label_t label
, seq_nr_t seq_nr
, Buffer
& key
)
186 ReadersLock
lock(mutex_
);
192 calcCtr(dir
, &r
, label
, seq_nr
);
193 bool result
= calcCtr(dir
, &r
, label
, seq_nr
);
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
);
205 #ifndef USE_SSL_CRYPTO
206 gcry_error_t err
= gcry_cipher_reset(handle_
[dir
]);
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
);
213 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::generate: Failed to set CTR: " << LogGpgError(err
);
217 std::memset(key
.getBuf(), 0, key
.getLength());
218 err
= gcry_cipher_encrypt(handle_
[dir
], key
, key
.getLength(), NULL
, 0);
220 cLog
.msg(Log::PRIO_ERR
) << "KeyDerivation::generate: Failed to generate cipher bitstream: " << LogGpgError(err
);
224 if(CTR_LENGTH
!= AES_BLOCK_SIZE
) {
225 cLog
.msg(Log::PRIO_ERR
) << "AesIcmCipher: Failed to set cipher CTR: size don't fits";
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
);
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
;