#pragma once /** * @file src/modules/rlm_wimax/milenage.h * @brief 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) * * This file implements an example authentication algorithm defined for 3GPP * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow * EAP-AKA to be tested properly with real USIM cards. * * This implementations assumes that the r1..r5 and c1..c5 constants defined in * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to * be AES (Rijndael). * * This software may be distributed under the terms of the BSD license. * See README for more details. * * @copyright 2017 The FreeRADIUS server project * @copyright 2006-2007 (j@w1.fi) */ #include /* * Inputs */ #define MILENAGE_KI_SIZE 16 //!< Subscriber key. #define MILENAGE_OP_SIZE 16 //!< Operator code (unique to the operator) #define MILENAGE_OPC_SIZE 16 //!< Derived operator code (unique to the operator and subscriber). #define MILENAGE_AMF_SIZE 2 //!< Authentication management field. #define MILENAGE_SQN_SIZE 6 //!< Sequence number. #define MILENAGE_RAND_SIZE 16 //!< Random challenge. /* * UMTS Outputs */ #define MILENAGE_AK_SIZE 6 //!< Anonymisation key. #define MILENAGE_AUTN_SIZE 16 //!< Network authentication key. #define MILENAGE_IK_SIZE 16 //!< Integrity key. #define MILENAGE_CK_SIZE 16 //!< Ciphering key. #define MILENAGE_RES_SIZE 8 #define MILENAGE_AUTS_SIZE 14 /* * GSM (COMP128-4) outputs */ #define MILENAGE_SRES_SIZE 4 #define MILENAGE_KC_SIZE 8 /** Copy a 48bit value from a 64bit integer into a uint8_t buff in big endian byte order * * There may be fast ways of doing this, but this is the *correct* * way, and does not make assumptions about how integers are laid * out in memory. * * @param[out] out 6 byte butter to store value. * @param[in] i integer value. * @return pointer to out. */ static inline uint8_t *uint48_to_buff(uint8_t out[6], uint64_t i) { out[0] = (i & 0xff0000000000) >> 40; out[1] = (i & 0x00ff00000000) >> 32; out[2] = (i & 0x0000ff000000) >> 24; out[3] = (i & 0x000000ff0000) >> 16; out[4] = (i & 0x00000000ff00) >> 8; out[5] = (i & 0x0000000000ff); return out; } /** Convert a 48bit big endian value into a unsigned 64bit integer * */ static inline uint64_t uint48_from_buff(uint8_t const in[6]) { uint64_t i = 0; i |= ((uint64_t)in[0]) << 40; i |= ((uint64_t)in[1]) << 32; i |= ((uint32_t)in[2]) << 24; i |= ((uint32_t)in[3]) << 16; i |= ((uint16_t)in[4]) << 8; i |= in[5]; return i; } int milenage_opc_generate(uint8_t opc[MILENAGE_OPC_SIZE], uint8_t const op[MILENAGE_OP_SIZE], uint8_t const ki[MILENAGE_KI_SIZE]); int milenage_umts_generate(uint8_t autn[MILENAGE_AUTN_SIZE], uint8_t ik[MILENAGE_IK_SIZE], uint8_t ck[MILENAGE_CK_SIZE], uint8_t ak[MILENAGE_AK_SIZE], uint8_t res[MILENAGE_RES_SIZE], uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const amf[MILENAGE_AMF_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint64_t sqn, uint8_t const rand[MILENAGE_RAND_SIZE]); int milenage_auts(uint64_t *sqn, uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint8_t const rand[MILENAGE_RAND_SIZE], uint8_t const auts[MILENAGE_AUTS_SIZE]); void milenage_gsm_from_umts(uint8_t sres[MILENAGE_SRES_SIZE], uint8_t kc[MILENAGE_KC_SIZE], uint8_t const ik[MILENAGE_IK_SIZE], uint8_t const ck[MILENAGE_CK_SIZE], uint8_t const res[MILENAGE_RES_SIZE]); int milenage_gsm_generate(uint8_t sres[MILENAGE_SRES_SIZE], uint8_t kc[MILENAGE_KC_SIZE], uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint8_t const rand[MILENAGE_RAND_SIZE]); int milenage_check(uint8_t ik[MILENAGE_IK_SIZE], uint8_t ck[MILENAGE_CK_SIZE], uint8_t res[MILENAGE_RES_SIZE], uint8_t auts[MILENAGE_AUTS_SIZE], uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint64_t sqn, uint8_t const rand[MILENAGE_RAND_SIZE], uint8_t const autn[MILENAGE_AUTN_SIZE]);