140 lines
3.1 KiB
C
140 lines
3.1 KiB
C
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include <gmp.h>
|
|
#include <nettle/hmac.h>
|
|
|
|
#include "auc.h"
|
|
|
|
uint8_t opc[16] = {
|
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
|
|
};
|
|
|
|
/*
|
|
* @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);
|
|
|
|
SetOPc(opc);
|
|
|
|
/* 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];
|
|
int i;
|
|
|
|
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("AK : ", ak, 6);
|
|
print_buffer("RAND : ", vector->rand, 16);
|
|
|
|
/* Compute XRES, CK, IK, AK */
|
|
f2345(key, vector->rand, vector->xres, ck, ik, ak);
|
|
|
|
/* AUTN = SQN ^ AK || AMF || MAC */
|
|
generate_autn(sqn, ak, amf, mac_a, vector->autn);
|
|
|
|
print_buffer("XRES : ", vector->xres, 8);
|
|
|
|
derive_kasme(ck, ik, plmn, sqn, ak, vector->kasme);
|
|
print_buffer("KASME : ", vector->kasme, 32);
|
|
|
|
return 0;
|
|
}
|