2 * Copyright (C) 2009-2011 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "simaka_crypto.h"
18 #include "simaka_manager.h"
22 /** length of the k_encr key */
24 /** length of the k_auth key */
26 /** length of the MSK */
28 /** length of the EMSK */
31 typedef struct private_simaka_crypto_t private_simaka_crypto_t
;
34 * Private data of an simaka_crypto_t object.
36 struct private_simaka_crypto_t
{
39 * Public simaka_crypto_t interface.
41 simaka_crypto_t
public;
44 * EAP type this crypto is used, SIM or AKA
49 * signer to create/verify AT_MAC
54 * crypter to encrypt/decrypt AT_ENCR_DATA
59 * hasher used in key derivation
64 * PRF function used in key derivation
69 * Random number generator to generate nonces
74 * Have k_encr/k_auth been derived?
79 METHOD(simaka_crypto_t
, get_signer
, signer_t
*,
80 private_simaka_crypto_t
*this)
82 return this->derived ?
this->signer
: NULL
;
85 METHOD(simaka_crypto_t
, get_crypter
, crypter_t
*,
86 private_simaka_crypto_t
*this)
88 return this->derived ?
this->crypter
: NULL
;
91 METHOD(simaka_crypto_t
, get_rng
, rng_t
*,
92 private_simaka_crypto_t
*this)
98 * Call SIM/AKA key hook
100 static void call_hook(private_simaka_crypto_t
*this, chunk_t encr
, chunk_t auth
)
102 simaka_manager_t
*mgr
;
107 mgr
= lib
->get(lib
, "sim-manager");
110 mgr
= lib
->get(lib
, "aka-manager");
115 mgr
->key_hook(mgr
, encr
, auth
);
118 METHOD(simaka_crypto_t
, derive_keys_full
, bool,
119 private_simaka_crypto_t
*this, identification_t
*id
,
120 chunk_t data
, chunk_t
*mk
, chunk_t
*msk
)
122 chunk_t str
, k_encr
, k_auth
;
125 /* For SIM: MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version)
126 * For AKA: MK = SHA1(Identity|IK|CK) */
127 if (!this->hasher
->get_hash(this->hasher
, id
->get_encoding(id
), NULL
) ||
128 !this->hasher
->allocate_hash(this->hasher
, data
, mk
))
132 DBG3(DBG_LIB
, "MK %B", mk
);
134 /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() */
135 if (this->prf
->set_key(this->prf
, *mk
))
139 str
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 3);
140 for (i
= 0; i
< 3; i
++)
142 if (!this->prf
->get_bytes(this->prf
, chunk_empty
,
143 str
.ptr
+ str
.len
/ 3 * i
))
150 k_encr
= chunk_create(str
.ptr
, KENCR_LEN
);
151 k_auth
= chunk_create(str
.ptr
+ KENCR_LEN
, KAUTH_LEN
);
152 DBG3(DBG_LIB
, "K_encr %B\nK_auth %B\nMSK %B", &k_encr
, &k_auth
, &msk
);
154 if (!this->signer
->set_key(this->signer
, k_auth
) ||
155 !this->crypter
->set_key(this->crypter
, k_encr
))
161 *msk
= chunk_create(str
.ptr
+ KENCR_LEN
+ KAUTH_LEN
, MSK_LEN
);
163 call_hook(this, k_encr
, k_auth
);
165 this->derived
= TRUE
;
169 METHOD(simaka_crypto_t
, derive_keys_reauth
, bool,
170 private_simaka_crypto_t
*this, chunk_t mk
)
172 chunk_t str
, k_encr
, k_auth
;
175 /* K_encr | K_auth = prf() | prf() */
176 if (!this->prf
->set_key(this->prf
, mk
))
180 str
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 2);
181 for (i
= 0; i
< 2; i
++)
183 if (!this->prf
->get_bytes(this->prf
, chunk_empty
,
184 str
.ptr
+ str
.len
/ 2 * i
))
189 k_encr
= chunk_create(str
.ptr
, KENCR_LEN
);
190 k_auth
= chunk_create(str
.ptr
+ KENCR_LEN
, KAUTH_LEN
);
191 DBG3(DBG_LIB
, "K_encr %B\nK_auth %B", &k_encr
, &k_auth
);
193 if (!this->signer
->set_key(this->signer
, k_auth
) ||
194 !this->crypter
->set_key(this->crypter
, k_encr
))
199 call_hook(this, k_encr
, k_auth
);
201 this->derived
= TRUE
;
205 METHOD(simaka_crypto_t
, derive_keys_reauth_msk
, bool,
206 private_simaka_crypto_t
*this, identification_t
*id
, chunk_t counter
,
207 chunk_t nonce_s
, chunk_t mk
, chunk_t
*msk
)
209 char xkey
[HASH_SIZE_SHA1
];
213 if (!this->hasher
->get_hash(this->hasher
, id
->get_encoding(id
), NULL
) ||
214 !this->hasher
->get_hash(this->hasher
, counter
, NULL
) ||
215 !this->hasher
->get_hash(this->hasher
, nonce_s
, NULL
) ||
216 !this->hasher
->get_hash(this->hasher
, mk
, xkey
))
221 /* MSK | EMSK = prf() | prf() | prf() | prf() */
222 if (!this->prf
->set_key(this->prf
, chunk_create(xkey
, sizeof(xkey
))))
226 str
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 2);
227 for (i
= 0; i
< 2; i
++)
229 if (!this->prf
->get_bytes(this->prf
, chunk_empty
,
230 str
.ptr
+ str
.len
/ 2 * i
))
235 *msk
= chunk_create(str
.ptr
, MSK_LEN
);
236 DBG3(DBG_LIB
, "MSK %B", msk
);
241 METHOD(simaka_crypto_t
, clear_keys
, void,
242 private_simaka_crypto_t
*this)
244 this->derived
= FALSE
;
247 METHOD(simaka_crypto_t
, destroy
, void,
248 private_simaka_crypto_t
*this)
250 DESTROY_IF(this->rng
);
251 DESTROY_IF(this->hasher
);
252 DESTROY_IF(this->prf
);
253 DESTROY_IF(this->signer
);
254 DESTROY_IF(this->crypter
);
261 simaka_crypto_t
*simaka_crypto_create(eap_type_t type
)
263 private_simaka_crypto_t
*this;
267 .get_signer
= _get_signer
,
268 .get_crypter
= _get_crypter
,
270 .derive_keys_full
= _derive_keys_full
,
271 .derive_keys_reauth
= _derive_keys_reauth
,
272 .derive_keys_reauth_msk
= _derive_keys_reauth_msk
,
273 .clear_keys
= _clear_keys
,
277 .rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
),
278 .hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
),
279 .prf
= lib
->crypto
->create_prf(lib
->crypto
, PRF_FIPS_SHA1_160
),
280 .signer
= lib
->crypto
->create_signer(lib
->crypto
, AUTH_HMAC_SHA1_128
),
281 .crypter
= lib
->crypto
->create_crypter(lib
->crypto
, ENCR_AES_CBC
, 16),
283 if (!this->rng
|| !this->hasher
|| !this->prf
||
284 !this->signer
|| !this->crypter
)
286 DBG1(DBG_LIB
, "unable to use %N, missing algorithms",
287 eap_type_names
, type
);
291 return &this->public;