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
))
140 str
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 3);
141 for (i
= 0; i
< 3; i
++)
143 if (!this->prf
->get_bytes(this->prf
, chunk_empty
,
144 str
.ptr
+ str
.len
/ 3 * i
))
151 k_encr
= chunk_create(str
.ptr
, KENCR_LEN
);
152 k_auth
= chunk_create(str
.ptr
+ KENCR_LEN
, KAUTH_LEN
);
153 DBG3(DBG_LIB
, "K_encr %B\nK_auth %B\nMSK %B", &k_encr
, &k_auth
, &msk
);
155 if (!this->signer
->set_key(this->signer
, k_auth
) ||
156 !this->crypter
->set_key(this->crypter
, k_encr
))
162 *msk
= chunk_clone(chunk_create(str
.ptr
+ KENCR_LEN
+ KAUTH_LEN
, MSK_LEN
));
164 call_hook(this, k_encr
, k_auth
);
166 this->derived
= TRUE
;
170 METHOD(simaka_crypto_t
, derive_keys_reauth
, bool,
171 private_simaka_crypto_t
*this, chunk_t mk
)
173 chunk_t str
, k_encr
, k_auth
;
176 /* K_encr | K_auth = prf() | prf() */
177 if (!this->prf
->set_key(this->prf
, mk
))
181 str
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 2);
182 for (i
= 0; i
< 2; i
++)
184 if (!this->prf
->get_bytes(this->prf
, chunk_empty
,
185 str
.ptr
+ str
.len
/ 2 * i
))
190 k_encr
= chunk_create(str
.ptr
, KENCR_LEN
);
191 k_auth
= chunk_create(str
.ptr
+ KENCR_LEN
, KAUTH_LEN
);
192 DBG3(DBG_LIB
, "K_encr %B\nK_auth %B", &k_encr
, &k_auth
);
194 if (!this->signer
->set_key(this->signer
, k_auth
) ||
195 !this->crypter
->set_key(this->crypter
, k_encr
))
200 call_hook(this, k_encr
, k_auth
);
202 this->derived
= TRUE
;
206 METHOD(simaka_crypto_t
, derive_keys_reauth_msk
, bool,
207 private_simaka_crypto_t
*this, identification_t
*id
, chunk_t counter
,
208 chunk_t nonce_s
, chunk_t mk
, chunk_t
*msk
)
210 char xkey
[HASH_SIZE_SHA1
];
214 if (!this->hasher
->get_hash(this->hasher
, id
->get_encoding(id
), NULL
) ||
215 !this->hasher
->get_hash(this->hasher
, counter
, NULL
) ||
216 !this->hasher
->get_hash(this->hasher
, nonce_s
, NULL
) ||
217 !this->hasher
->get_hash(this->hasher
, mk
, xkey
))
222 /* MSK | EMSK = prf() | prf() | prf() | prf() */
223 if (!this->prf
->set_key(this->prf
, chunk_create(xkey
, sizeof(xkey
))))
227 str
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 2);
228 for (i
= 0; i
< 2; i
++)
230 if (!this->prf
->get_bytes(this->prf
, chunk_empty
,
231 str
.ptr
+ str
.len
/ 2 * i
))
236 *msk
= chunk_clone(chunk_create(str
.ptr
, MSK_LEN
));
237 DBG3(DBG_LIB
, "MSK %B", msk
);
242 METHOD(simaka_crypto_t
, clear_keys
, void,
243 private_simaka_crypto_t
*this)
245 this->derived
= FALSE
;
248 METHOD(simaka_crypto_t
, destroy
, void,
249 private_simaka_crypto_t
*this)
251 DESTROY_IF(this->rng
);
252 DESTROY_IF(this->hasher
);
253 DESTROY_IF(this->prf
);
254 DESTROY_IF(this->signer
);
255 DESTROY_IF(this->crypter
);
262 simaka_crypto_t
*simaka_crypto_create(eap_type_t type
)
264 private_simaka_crypto_t
*this;
268 .get_signer
= _get_signer
,
269 .get_crypter
= _get_crypter
,
271 .derive_keys_full
= _derive_keys_full
,
272 .derive_keys_reauth
= _derive_keys_reauth
,
273 .derive_keys_reauth_msk
= _derive_keys_reauth_msk
,
274 .clear_keys
= _clear_keys
,
278 .rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
),
279 .hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
),
280 .prf
= lib
->crypto
->create_prf(lib
->crypto
, PRF_FIPS_SHA1_160
),
281 .signer
= lib
->crypto
->create_signer(lib
->crypto
, AUTH_HMAC_SHA1_128
),
282 .crypter
= lib
->crypto
->create_crypter(lib
->crypto
, ENCR_AES_CBC
, 16),
284 if (!this->rng
|| !this->hasher
|| !this->prf
||
285 !this->signer
|| !this->crypter
)
287 DBG1(DBG_LIB
, "unable to use %N, missing algorithms",
288 eap_type_names
, type
);
292 return &this->public;