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) ||
220c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	    os_memcmp_const(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
315c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(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