18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2007 <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This file implements an example authentication algorithm defined for 3GPP 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-AKA to be tested properly with real USIM cards. 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This implementations assumes that the r1..r5 and c1..c5 constants defined in 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * be AES (Rijndael). 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "milenage.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * milenage_f1 - Milenage f1 and f1* algorithms 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @opc: OPc = 128-bit value derived from OP and K 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @k: K = 128-bit subscriber key 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @_rand: RAND = 128-bit random challenge 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sqn: SQN = 48-bit sequence number 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @amf: AMF = 16-bit authentication management field 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 tmp1[16], tmp2[16], tmp3[16]; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[i] = _rand[i] ^ opc[i]; 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp1, tmp1)) 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(tmp2, sqn, 6); 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(tmp2 + 6, amf, 2); 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(tmp2 + 8, tmp2, 8); 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* XOR with TEMP = E_K(RAND XOR OP_C) */ 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp3[i] ^= tmp1[i]; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* XOR with c1 (= ..00, i.e., NOP) */ 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* f1 || f1* = E_K(tmp3) XOR OP_c */ 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp3, tmp1)) 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[i] ^= opc[i]; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mac_a) 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(mac_a, tmp1, 8); /* f1 */ 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mac_s) 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @opc: OPc = 128-bit value derived from OP and K 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @k: K = 128-bit subscriber key 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @_rand: RAND = 128-bit random challenge 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @res: Buffer for RES = 64-bit signed response (f2), or %NULL 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 tmp1[16], tmp2[16], tmp3[16]; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[i] = _rand[i] ^ opc[i]; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp1, tmp2)) 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* f2 and f5 */ 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* rotate by r2 (= 0, i.e., NOP) */ 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[i] = tmp2[i] ^ opc[i]; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[15] ^= 1; /* XOR c2 (= ..01) */ 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* f5 || f2 = E_K(tmp1) XOR OP_c */ 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp1, tmp3)) 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp3[i] ^= opc[i]; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res) 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(res, tmp3 + 8, 8); /* f2 */ 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ak) 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ak, tmp3, 6); /* f5 */ 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* f3 */ 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ck) { 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* rotate by r3 = 0x20 = 4 bytes */ 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[15] ^= 2; /* XOR c3 (= ..02) */ 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp1, ck)) 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ck[i] ^= opc[i]; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* f4 */ 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ik) { 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* rotate by r4 = 0x40 = 8 bytes */ 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[15] ^= 4; /* XOR c4 (= ..04) */ 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp1, ik)) 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ik[i] ^= opc[i]; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* f5* */ 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (akstar) { 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* rotate by r5 = 0x60 = 12 bytes */ 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 16; i++) 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp1[15] ^= 8; /* XOR c5 (= ..08) */ 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aes_128_encrypt_block(k, tmp1, tmp1)) 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 6; i++) 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt akstar[i] = tmp1[i] ^ opc[i]; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * milenage_generate - Generate AKA AUTN,IK,CK,RES 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @amf: AMF = 16-bit authentication management field 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @k: K = 128-bit subscriber key 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sqn: SQN = 48-bit sequence number 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @_rand: RAND = 128-bit random challenge 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @autn: Buffer for AUTN = 128-bit authentication token 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @res: Buffer for RES = 64-bit signed response (f2), or %NULL 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @res_len: Max length for res; set to used length or 0 on failure 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *ck, u8 *res, size_t *res_len) 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 mac_a[8], ak[6]; 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*res_len < 8) { 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *res_len = 0; 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *res_len = 0; 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *res_len = 8; 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* AUTN = (SQN ^ AK) || AMF || MAC */ 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 6; i++) 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt autn[i] = sqn[i] ^ ak[i]; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(autn + 6, amf, 2); 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(autn + 8, mac_a, 8); 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * milenage_auts - Milenage AUTS validation 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @k: K = 128-bit subscriber key 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @_rand: RAND = 128-bit random challenge 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auts: AUTS = 112-bit authentication token from client 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sqn: Buffer for SQN = 48-bit sequence number 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 = success (sqn filled), -1 on failure 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *sqn) 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 ak[6], mac_s[8]; 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 6; i++) 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sqn[i] = auts[i] ^ ak[i]; 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcmp(mac_s, auts + 6, 8) != 0) 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @k: K = 128-bit subscriber key 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @_rand: RAND = 128-bit random challenge 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sres: Buffer for SRES = 32-bit SRES 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @kc: Buffer for Kc = 64-bit Kc 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 res[8], ck[16], ik[16]; 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 8; i++) 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef GSM_MILENAGE_ALT_SRES 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(sres, res, 4); 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* GSM_MILENAGE_ALT_SRES */ 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 4; i++) 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sres[i] = res[i] ^ res[i + 4]; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* GSM_MILENAGE_ALT_SRES */ 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * milenage_generate - Generate AKA AUTN,IK,CK,RES 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @k: K = 128-bit subscriber key 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sqn: SQN = 48-bit sequence number 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @_rand: RAND = 128-bit random challenge 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @autn: AUTN = 128-bit authentication token 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @res: Buffer for RES = 64-bit signed response (f2), or %NULL 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @res_len: Variable that will be set to RES length 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @auts: 112-bit buffer for AUTS 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure, or -2 on synchronization failure 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *auts) 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 mac_a[8], ak[6], rx_sqn[6]; 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *amf; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *res_len = 8; 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* AUTN = (SQN ^ AK) || AMF || MAC */ 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 6; i++) 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rx_sqn[i] = autn[i] ^ ak[i]; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(rx_sqn, sqn, 6) <= 0) { 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 6; i++) 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auts[i] = sqn[i] ^ ak[i]; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -2; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt amf = autn + 6; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(mac_a, autn + 8, 8) != 0) { 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt autn + 8, 8); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 324