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