1214501Srpaulo/* 2214501Srpaulo * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) 3214501Srpaulo * Copyright (c) 2006-2007 <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo * 8214501Srpaulo * This file implements an example authentication algorithm defined for 3GPP 9214501Srpaulo * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow 10214501Srpaulo * EAP-AKA to be tested properly with real USIM cards. 11214501Srpaulo * 12214501Srpaulo * This implementations assumes that the r1..r5 and c1..c5 constants defined in 13214501Srpaulo * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, 14214501Srpaulo * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to 15214501Srpaulo * be AES (Rijndael). 16214501Srpaulo */ 17214501Srpaulo 18214501Srpaulo#include "includes.h" 19214501Srpaulo 20214501Srpaulo#include "common.h" 21214501Srpaulo#include "crypto/aes_wrap.h" 22214501Srpaulo#include "milenage.h" 23214501Srpaulo 24214501Srpaulo 25214501Srpaulo/** 26214501Srpaulo * milenage_f1 - Milenage f1 and f1* algorithms 27214501Srpaulo * @opc: OPc = 128-bit value derived from OP and K 28214501Srpaulo * @k: K = 128-bit subscriber key 29214501Srpaulo * @_rand: RAND = 128-bit random challenge 30214501Srpaulo * @sqn: SQN = 48-bit sequence number 31214501Srpaulo * @amf: AMF = 16-bit authentication management field 32214501Srpaulo * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL 33214501Srpaulo * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL 34214501Srpaulo * Returns: 0 on success, -1 on failure 35214501Srpaulo */ 36214501Srpauloint milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, 37214501Srpaulo const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) 38214501Srpaulo{ 39214501Srpaulo u8 tmp1[16], tmp2[16], tmp3[16]; 40214501Srpaulo int i; 41214501Srpaulo 42214501Srpaulo /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ 43214501Srpaulo for (i = 0; i < 16; i++) 44214501Srpaulo tmp1[i] = _rand[i] ^ opc[i]; 45214501Srpaulo if (aes_128_encrypt_block(k, tmp1, tmp1)) 46214501Srpaulo return -1; 47214501Srpaulo 48214501Srpaulo /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ 49214501Srpaulo os_memcpy(tmp2, sqn, 6); 50214501Srpaulo os_memcpy(tmp2 + 6, amf, 2); 51214501Srpaulo os_memcpy(tmp2 + 8, tmp2, 8); 52214501Srpaulo 53214501Srpaulo /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ 54214501Srpaulo 55214501Srpaulo /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ 56214501Srpaulo for (i = 0; i < 16; i++) 57214501Srpaulo tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; 58214501Srpaulo /* XOR with TEMP = E_K(RAND XOR OP_C) */ 59214501Srpaulo for (i = 0; i < 16; i++) 60214501Srpaulo tmp3[i] ^= tmp1[i]; 61214501Srpaulo /* XOR with c1 (= ..00, i.e., NOP) */ 62214501Srpaulo 63214501Srpaulo /* f1 || f1* = E_K(tmp3) XOR OP_c */ 64214501Srpaulo if (aes_128_encrypt_block(k, tmp3, tmp1)) 65214501Srpaulo return -1; 66214501Srpaulo for (i = 0; i < 16; i++) 67214501Srpaulo tmp1[i] ^= opc[i]; 68214501Srpaulo if (mac_a) 69214501Srpaulo os_memcpy(mac_a, tmp1, 8); /* f1 */ 70214501Srpaulo if (mac_s) 71214501Srpaulo os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ 72214501Srpaulo return 0; 73214501Srpaulo} 74214501Srpaulo 75214501Srpaulo 76214501Srpaulo/** 77214501Srpaulo * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms 78214501Srpaulo * @opc: OPc = 128-bit value derived from OP and K 79214501Srpaulo * @k: K = 128-bit subscriber key 80214501Srpaulo * @_rand: RAND = 128-bit random challenge 81214501Srpaulo * @res: Buffer for RES = 64-bit signed response (f2), or %NULL 82214501Srpaulo * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL 83214501Srpaulo * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL 84214501Srpaulo * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL 85214501Srpaulo * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL 86214501Srpaulo * Returns: 0 on success, -1 on failure 87214501Srpaulo */ 88214501Srpauloint milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, 89214501Srpaulo u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) 90214501Srpaulo{ 91214501Srpaulo u8 tmp1[16], tmp2[16], tmp3[16]; 92214501Srpaulo int i; 93214501Srpaulo 94214501Srpaulo /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ 95214501Srpaulo for (i = 0; i < 16; i++) 96214501Srpaulo tmp1[i] = _rand[i] ^ opc[i]; 97214501Srpaulo if (aes_128_encrypt_block(k, tmp1, tmp2)) 98214501Srpaulo return -1; 99214501Srpaulo 100214501Srpaulo /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ 101214501Srpaulo /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ 102214501Srpaulo /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ 103214501Srpaulo /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ 104214501Srpaulo 105214501Srpaulo /* f2 and f5 */ 106214501Srpaulo /* rotate by r2 (= 0, i.e., NOP) */ 107214501Srpaulo for (i = 0; i < 16; i++) 108214501Srpaulo tmp1[i] = tmp2[i] ^ opc[i]; 109214501Srpaulo tmp1[15] ^= 1; /* XOR c2 (= ..01) */ 110214501Srpaulo /* f5 || f2 = E_K(tmp1) XOR OP_c */ 111214501Srpaulo if (aes_128_encrypt_block(k, tmp1, tmp3)) 112214501Srpaulo return -1; 113214501Srpaulo for (i = 0; i < 16; i++) 114214501Srpaulo tmp3[i] ^= opc[i]; 115214501Srpaulo if (res) 116214501Srpaulo os_memcpy(res, tmp3 + 8, 8); /* f2 */ 117214501Srpaulo if (ak) 118214501Srpaulo os_memcpy(ak, tmp3, 6); /* f5 */ 119214501Srpaulo 120214501Srpaulo /* f3 */ 121214501Srpaulo if (ck) { 122214501Srpaulo /* rotate by r3 = 0x20 = 4 bytes */ 123214501Srpaulo for (i = 0; i < 16; i++) 124214501Srpaulo tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; 125214501Srpaulo tmp1[15] ^= 2; /* XOR c3 (= ..02) */ 126214501Srpaulo if (aes_128_encrypt_block(k, tmp1, ck)) 127214501Srpaulo return -1; 128214501Srpaulo for (i = 0; i < 16; i++) 129214501Srpaulo ck[i] ^= opc[i]; 130214501Srpaulo } 131214501Srpaulo 132214501Srpaulo /* f4 */ 133214501Srpaulo if (ik) { 134214501Srpaulo /* rotate by r4 = 0x40 = 8 bytes */ 135214501Srpaulo for (i = 0; i < 16; i++) 136214501Srpaulo tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; 137214501Srpaulo tmp1[15] ^= 4; /* XOR c4 (= ..04) */ 138214501Srpaulo if (aes_128_encrypt_block(k, tmp1, ik)) 139214501Srpaulo return -1; 140214501Srpaulo for (i = 0; i < 16; i++) 141214501Srpaulo ik[i] ^= opc[i]; 142214501Srpaulo } 143214501Srpaulo 144214501Srpaulo /* f5* */ 145214501Srpaulo if (akstar) { 146214501Srpaulo /* rotate by r5 = 0x60 = 12 bytes */ 147214501Srpaulo for (i = 0; i < 16; i++) 148214501Srpaulo tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; 149214501Srpaulo tmp1[15] ^= 8; /* XOR c5 (= ..08) */ 150214501Srpaulo if (aes_128_encrypt_block(k, tmp1, tmp1)) 151214501Srpaulo return -1; 152214501Srpaulo for (i = 0; i < 6; i++) 153214501Srpaulo akstar[i] = tmp1[i] ^ opc[i]; 154214501Srpaulo } 155214501Srpaulo 156214501Srpaulo return 0; 157214501Srpaulo} 158214501Srpaulo 159214501Srpaulo 160214501Srpaulo/** 161214501Srpaulo * milenage_generate - Generate AKA AUTN,IK,CK,RES 162214501Srpaulo * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 163214501Srpaulo * @amf: AMF = 16-bit authentication management field 164214501Srpaulo * @k: K = 128-bit subscriber key 165214501Srpaulo * @sqn: SQN = 48-bit sequence number 166214501Srpaulo * @_rand: RAND = 128-bit random challenge 167214501Srpaulo * @autn: Buffer for AUTN = 128-bit authentication token 168214501Srpaulo * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL 169214501Srpaulo * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL 170214501Srpaulo * @res: Buffer for RES = 64-bit signed response (f2), or %NULL 171214501Srpaulo * @res_len: Max length for res; set to used length or 0 on failure 172214501Srpaulo */ 173214501Srpaulovoid milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, 174214501Srpaulo const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, 175214501Srpaulo u8 *ck, u8 *res, size_t *res_len) 176214501Srpaulo{ 177214501Srpaulo int i; 178214501Srpaulo u8 mac_a[8], ak[6]; 179214501Srpaulo 180214501Srpaulo if (*res_len < 8) { 181214501Srpaulo *res_len = 0; 182214501Srpaulo return; 183214501Srpaulo } 184214501Srpaulo if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || 185214501Srpaulo milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { 186214501Srpaulo *res_len = 0; 187214501Srpaulo return; 188214501Srpaulo } 189214501Srpaulo *res_len = 8; 190214501Srpaulo 191214501Srpaulo /* AUTN = (SQN ^ AK) || AMF || MAC */ 192214501Srpaulo for (i = 0; i < 6; i++) 193214501Srpaulo autn[i] = sqn[i] ^ ak[i]; 194214501Srpaulo os_memcpy(autn + 6, amf, 2); 195214501Srpaulo os_memcpy(autn + 8, mac_a, 8); 196214501Srpaulo} 197214501Srpaulo 198214501Srpaulo 199214501Srpaulo/** 200214501Srpaulo * milenage_auts - Milenage AUTS validation 201214501Srpaulo * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 202214501Srpaulo * @k: K = 128-bit subscriber key 203214501Srpaulo * @_rand: RAND = 128-bit random challenge 204214501Srpaulo * @auts: AUTS = 112-bit authentication token from client 205214501Srpaulo * @sqn: Buffer for SQN = 48-bit sequence number 206214501Srpaulo * Returns: 0 = success (sqn filled), -1 on failure 207214501Srpaulo */ 208214501Srpauloint milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, 209214501Srpaulo u8 *sqn) 210214501Srpaulo{ 211214501Srpaulo u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ 212214501Srpaulo u8 ak[6], mac_s[8]; 213214501Srpaulo int i; 214214501Srpaulo 215214501Srpaulo if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) 216214501Srpaulo return -1; 217214501Srpaulo for (i = 0; i < 6; i++) 218214501Srpaulo sqn[i] = auts[i] ^ ak[i]; 219214501Srpaulo if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || 220214501Srpaulo memcmp(mac_s, auts + 6, 8) != 0) 221214501Srpaulo return -1; 222214501Srpaulo return 0; 223214501Srpaulo} 224214501Srpaulo 225214501Srpaulo 226214501Srpaulo/** 227214501Srpaulo * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet 228214501Srpaulo * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 229214501Srpaulo * @k: K = 128-bit subscriber key 230214501Srpaulo * @_rand: RAND = 128-bit random challenge 231214501Srpaulo * @sres: Buffer for SRES = 32-bit SRES 232214501Srpaulo * @kc: Buffer for Kc = 64-bit Kc 233214501Srpaulo * Returns: 0 on success, -1 on failure 234214501Srpaulo */ 235214501Srpauloint gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) 236214501Srpaulo{ 237214501Srpaulo u8 res[8], ck[16], ik[16]; 238214501Srpaulo int i; 239214501Srpaulo 240214501Srpaulo if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) 241214501Srpaulo return -1; 242214501Srpaulo 243214501Srpaulo for (i = 0; i < 8; i++) 244214501Srpaulo kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; 245214501Srpaulo 246214501Srpaulo#ifdef GSM_MILENAGE_ALT_SRES 247214501Srpaulo os_memcpy(sres, res, 4); 248214501Srpaulo#else /* GSM_MILENAGE_ALT_SRES */ 249214501Srpaulo for (i = 0; i < 4; i++) 250214501Srpaulo sres[i] = res[i] ^ res[i + 4]; 251214501Srpaulo#endif /* GSM_MILENAGE_ALT_SRES */ 252214501Srpaulo return 0; 253214501Srpaulo} 254214501Srpaulo 255214501Srpaulo 256214501Srpaulo/** 257214501Srpaulo * milenage_generate - Generate AKA AUTN,IK,CK,RES 258214501Srpaulo * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 259214501Srpaulo * @k: K = 128-bit subscriber key 260214501Srpaulo * @sqn: SQN = 48-bit sequence number 261214501Srpaulo * @_rand: RAND = 128-bit random challenge 262214501Srpaulo * @autn: AUTN = 128-bit authentication token 263214501Srpaulo * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL 264214501Srpaulo * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL 265214501Srpaulo * @res: Buffer for RES = 64-bit signed response (f2), or %NULL 266214501Srpaulo * @res_len: Variable that will be set to RES length 267214501Srpaulo * @auts: 112-bit buffer for AUTS 268214501Srpaulo * Returns: 0 on success, -1 on failure, or -2 on synchronization failure 269214501Srpaulo */ 270214501Srpauloint milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, 271214501Srpaulo const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, 272214501Srpaulo u8 *auts) 273214501Srpaulo{ 274214501Srpaulo int i; 275214501Srpaulo u8 mac_a[8], ak[6], rx_sqn[6]; 276214501Srpaulo const u8 *amf; 277214501Srpaulo 278214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); 279214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); 280214501Srpaulo 281214501Srpaulo if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) 282214501Srpaulo return -1; 283214501Srpaulo 284214501Srpaulo *res_len = 8; 285214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); 286214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); 287214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); 288214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); 289214501Srpaulo 290214501Srpaulo /* AUTN = (SQN ^ AK) || AMF || MAC */ 291214501Srpaulo for (i = 0; i < 6; i++) 292214501Srpaulo rx_sqn[i] = autn[i] ^ ak[i]; 293214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); 294214501Srpaulo 295214501Srpaulo if (os_memcmp(rx_sqn, sqn, 6) <= 0) { 296214501Srpaulo u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ 297214501Srpaulo if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) 298214501Srpaulo return -1; 299214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); 300214501Srpaulo for (i = 0; i < 6; i++) 301214501Srpaulo auts[i] = sqn[i] ^ ak[i]; 302214501Srpaulo if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) 303214501Srpaulo return -1; 304214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); 305214501Srpaulo return -2; 306214501Srpaulo } 307214501Srpaulo 308214501Srpaulo amf = autn + 6; 309214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); 310214501Srpaulo if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) 311214501Srpaulo return -1; 312214501Srpaulo 313214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); 314214501Srpaulo 315214501Srpaulo if (os_memcmp(mac_a, autn + 8, 8) != 0) { 316214501Srpaulo wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); 317214501Srpaulo wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", 318214501Srpaulo autn + 8, 8); 319214501Srpaulo return -1; 320214501Srpaulo } 321214501Srpaulo 322214501Srpaulo return 0; 323214501Srpaulo} 324