/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include "auc.h"
#include "hss_config.h"
#define DEBUG_AUC_KDF 1
extern hss_config_t hss_config;
uint8_t opc[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t op[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*
* @param key the input key
* @param key_len length of the key
* @param s string for key derivation as defined in 3GPP TS.33401 Annex A
* @param s_len length of s
* @param out buffer to place the output of kdf
* @param ou_len expected length for the output key
*/
inline
void kdf(uint8_t *key, uint16_t key_len, uint8_t *s, uint16_t s_len, uint8_t *out,
uint16_t out_len)
{
struct hmac_sha256_ctx ctx;
memset(&ctx, 0, sizeof(ctx));
hmac_sha256_set_key(&ctx, key_len, key);
hmac_sha256_update(&ctx, s_len, s);
hmac_sha256_digest(&ctx, out_len, out);
}
/*
* Derive the Kasme using the KDF (key derive function).
* See 3GPP TS.33401 Annex A.2
* The input String S to the KDF is composed of 14 bytes:
* FC = 0x10
* P0 = SN id = PLMN
* L0 = length(SN id) = 0x00 0x03
* P1 = SQN xor AK
* L1 = length(P1) = 0x00 0x06
*/
inline
void derive_kasme(uint8_t ck[16], uint8_t ik[16], uint8_t plmn[3], uint8_t sqn[6],
uint8_t ak[6], uint8_t *kasme)
{
uint8_t s[14];
int i;
uint8_t key[32];
/* The input key is equal to the concatenation of CK and IK */
memcpy(&key[0], ck, 16);
memcpy(&key[16], ik, 16);
if (hss_config.valid_opc == 0) {
SetOP(hss_config.operator_key);
}
/* FC */
s[0] = 0x10;
/* SN id is composed of MCC and MNC
* Octets:
* 1 MCC digit 2 | MCC digit 1
* 2 MNC digit 3 | MCC digit 3
* 3 MNC digit 2 | MNC digit 1
*/
memcpy(&s[1], plmn, 3);
/* L0 */
s[4] = 0x00;
s[5] = 0x03;
/* P1 */
for (i = 0; i < 6; i++) {
s[6 + i] = sqn[i] ^ ak[i];
}
/* L1 */
s[12] = 0x00;
s[13] = 0x06;
#if defined(DEBUG_AUC_KDF)
for (i = 0; i < 32; i++)
printf("0x%02x ", key[i]);
printf("\n");
for (i = 0; i < 14; i++)
printf("0x%02x ", s[i]);
printf("\n");
#endif
kdf(key, 32, s, 14, kasme, 32);
}
int generate_vector(uint64_t imsi, uint8_t key[16], uint8_t plmn[3],
uint8_t sqn[6], auc_vector_t *vector)
{
/* in E-UTRAN an authentication vector is composed of:
* - RAND
* - XRES
* - AUTN
* - KASME
*/
uint8_t amf[] = { 0x80, 0x00 };
uint8_t mac_a[8];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
if (vector == NULL) {
return EINVAL;
}
/* Compute MAC */
f1(key, vector->rand, sqn, amf, mac_a);
print_buffer("MAC_A : ", mac_a, 8);
print_buffer("SQN : ", sqn, 6);
print_buffer("RAND : ", vector->rand, 16);
/* Compute XRES, CK, IK, AK */
f2345(key, vector->rand, vector->xres, ck, ik, ak);
print_buffer("AK : ", ak, 6);
print_buffer("CK : ", ck, 16);
print_buffer("IK : ", ik, 16);
print_buffer("XRES : ", vector->xres, 8);
/* AUTN = SQN ^ AK || AMF || MAC */
generate_autn(sqn, ak, amf, mac_a, vector->autn);
print_buffer("AUTN : ", vector->autn, 16);
derive_kasme(ck, ik, plmn, sqn, ak, vector->kasme);
print_buffer("KASME : ", vector->kasme, 32);
return 0;
}