blob: c044a377217e3151b826c1225cc8dafa1f90abe2 [file] [log] [blame]
Harald Welte8bd9d5d2023-05-28 09:36:50 +02001/* (C) 2023 by Harald Welte <laforge@osmocom.org>
2 *
3 * All Rights Reserved
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <stdint.h>
19#include <string.h>
20#include <string.h>
21#include <errno.h>
22
23#include <osmocom/core/utils.h>
24
25#include "KeccakP-1600-3gpp.h"
26
27/* TUAK authentication algorithm
28 * as proposed by 3GPP as an alternative to Milenage
29 * algorithm based on SHA-3 (more exactly its KeccakP-1600 permutation)
30 * see 3GPP TS 35.231, 232 and 233 */
31
32static unsigned int g_keccak_iterations = 1;
33static const char algoname[] = "TUAK1.0";
34const uint8_t zero16[16] = { 0, };
35
36void tuak_set_keccak_iterations(unsigned int i)
37{
38 g_keccak_iterations = i;
39}
40
41/* append data from 'input' to 'buf' at 'idx', reversing byte order */
42#define PUSH_DATA(buf, idx, input, nbytes) \
43 for (int i = nbytes-1; i >= 0; i--) { \
44 buf[idx++] = input[i]; \
45 }
46
47/* like memcpy(), but reversing they order of bytes */
48void memcpy_reverse(uint8_t *dst, const uint8_t *src, size_t len)
49{
50 for (size_t i = 0; i < len; i++)
51 dst[i] = src[len-i-1];
52}
53
54static void tuak_core(uint8_t buf[200], const uint8_t *opc, uint8_t instance, const uint8_t *_rand,
55 const uint8_t *amf, const uint8_t *sqn, const uint8_t *k, uint8_t k_len_bytes,
56 unsigned int keccac_iterations)
57{
58 unsigned int idx = 0;
59
60 PUSH_DATA(buf, idx, opc, 32);
61 buf[idx++] = instance;
62 PUSH_DATA(buf, idx, algoname, strlen(algoname)); /* without trailing NUL */
63 PUSH_DATA(buf, idx, _rand, 16);
64 PUSH_DATA(buf, idx, amf, 2);
65 PUSH_DATA(buf, idx, sqn, 6);
66 PUSH_DATA(buf, idx, k, k_len_bytes);
67 memset(buf+idx, 0, 32-k_len_bytes); idx += 32-k_len_bytes;
68 buf[idx++] = 0x1f;
69 memset(buf+idx, 0, 38); idx += 38;
70 buf[idx++] = 0x80;
71 memset(buf+idx, 0, 64); idx += 64;
72 OSMO_ASSERT(idx == 200);
73
74 for (unsigned int i = 0; i < keccac_iterations; i++)
75 Keccak_f_64((uint64_t *) buf);
76}
77
78/**
79 * tuak_f1 - TUAK f1 algorithm
80 * @opc: OPc = 256-bit value derived from OP and K
81 * @k: K = 128-bit or 256-bit subscriber key
82 * @_rand: RAND = 128-bit random challenge
83 * @sqn: SQN = 48-bit sequence number
84 * @amf: AMF = 16-bit authentication management field
85 * @mac_a: Buffer for MAC-A = 64/128/256-bit network authentication code
86 * Returns: 0 on success, -1 on failure
87 */
88int tuak_f1(const uint8_t *opc, const uint8_t *k, uint8_t k_len_bytes, const uint8_t *_rand,
89 const uint8_t *sqn, const uint8_t *amf, uint8_t *mac_a, uint8_t mac_a_len_bytes,
90 unsigned int keccac_iterations)
91{
92 uint8_t buf[200];
93 uint8_t instance = 0x00;
94
95 switch (mac_a_len_bytes) {
96 case 8:
97 instance |= 0x08;
98 break;
99 case 16:
100 instance |= 0x10;
101 break;
102 case 32:
103 instance |= 0x20;
104 break;
105 default:
106 return -EINVAL;
107 }
108
109 switch (k_len_bytes) {
110 case 16:
111 break;
112 case 32:
113 instance |= 0x01;
114 break;
115 default:
116 return -EINVAL;
117 }
118
119 tuak_core(buf, opc, instance, _rand, amf, sqn, k, k_len_bytes, keccac_iterations);
120
121 memcpy_reverse(mac_a, buf, mac_a_len_bytes);
122
123 return 0;
124}
125
126/**
127 * tuak_f1star - TUAK f1* algorithm
128 * @opc: OPc = 256-bit value derived from OP and K
129 * @k: K = 128-bit or 256-bit subscriber key
130 * @_rand: RAND = 128-bit random challenge
131 * @sqn: SQN = 48-bit sequence number
132 * @amf: AMF = 16-bit authentication management field
133 * @mac_s: Buffer for MAC-S = 64/128/256-bit resync authentication code
134 * Returns: 0 on success, -1 on failure
135 */
136int tuak_f1star(const uint8_t *opc, const uint8_t *k, uint8_t k_len_bytes, const uint8_t *_rand,
137 const uint8_t *sqn, const uint8_t *amf, uint8_t *mac_s, uint8_t mac_s_len_bytes,
138 unsigned int keccac_iterations)
139{
140 uint8_t buf[200];
141 uint8_t instance = 0x80;
142
143 switch (mac_s_len_bytes) {
144 case 8:
145 instance |= 0x08;
146 break;
147 case 16:
148 instance |= 0x10;
149 break;
150 case 32:
151 instance |= 0x20;
152 break;
153 default:
154 return -EINVAL;
155 }
156
157 switch (k_len_bytes) {
158 case 16:
159 break;
160 case 32:
161 instance |= 0x01;
162 break;
163 default:
164 return -EINVAL;
165 }
166
167 tuak_core(buf, opc, instance, _rand, amf, sqn, k, k_len_bytes, keccac_iterations);
168
169 memcpy_reverse(mac_s, buf, mac_s_len_bytes);
170
171 return 0;
172}
173
174/**
175 * tuak_f2345 - TUAK f2, f3, f4, f5, algorithms
176 * @opc: OPc = 256-bit value derived from OP and K
177 * @k: K = 128/256-bit subscriber key
178 * @_rand: RAND = 128-bit random challenge
179 * @res: Buffer for RES = 32/64/128/256-bit signed response (f2), or %NULL
180 * @ck: Buffer for CK = 128/256-bit confidentiality key (f3), or %NULL
181 * @ik: Buffer for IK = 128/256-bit integrity key (f4), or %NULL
182 * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
183 * Returns: 0 on success, -1 on failure
184 */
185int tuak_f2345(const uint8_t *opc, const uint8_t *k, uint8_t k_len_bytes,
186 const uint8_t *_rand, uint8_t *res, uint8_t res_len_bytes,
187 uint8_t *ck, uint8_t ck_len_bytes,
188 uint8_t *ik, uint8_t ik_len_bytes, uint8_t *ak, unsigned int keccac_iterations)
189{
190 uint8_t buf[200];
191 uint8_t instance = 0x40;
192
193 switch (res_len_bytes) {
194 case 4:
195 break;
196 case 8:
197 instance |= 0x08;
198 break;
199 case 16:
200 instance |= 0x10;
201 break;
202 case 32:
203 instance |= 0x20;
204 break;
205 default:
206 return -EINVAL;
207 }
208
209 switch (ck_len_bytes) {
210 case 16:
211 break;
212 case 32:
213 instance |= 0x04;
214 break;
215 default:
216 return -EINVAL;
217 }
218
219 switch (ik_len_bytes) {
220 case 16:
221 break;
222 case 32:
223 instance |= 0x02;
224 break;
225 default:
226 return -EINVAL;
227 }
228
229 switch (k_len_bytes) {
230 case 16:
231 break;
232 case 32:
233 instance |= 0x01;
234 break;
235 default:
236 return -EINVAL;
237 }
238
239 tuak_core(buf, opc, instance, _rand, zero16, zero16, k, k_len_bytes, keccac_iterations);
240
241 if (res)
242 memcpy_reverse(res, buf, res_len_bytes);
243
244 if (ck)
245 memcpy_reverse(ck, buf + 32, ck_len_bytes);
246
247 if (ik)
248 memcpy_reverse(ik, buf + 64, ik_len_bytes);
249
250 if (ak)
251 memcpy_reverse(ak, buf + 96, 6);
252
253 return 0;
254}
255
256/**
257 * tuak_f5star - TUAK f5* algorithm
258 * @opc: OPc = 256-bit value derived from OP and K
259 * @k: K = 128/256-bit subscriber key
260 * @_rand: RAND = 128-bit random challenge
261 * @ak: Buffer for AK = 48-bit anonymity key (f5)
262 * Returns: 0 on success, -1 on failure
263 */
264int tuak_f5star(const uint8_t *opc, const uint8_t *k, uint8_t k_len_bytes,
265 const uint8_t *_rand, uint8_t *ak, unsigned int keccac_iterations)
266{
267 uint8_t buf[200];
268 uint8_t instance = 0xc0;
269
270 switch (k_len_bytes) {
271 case 16:
272 break;
273 case 32:
274 instance += 1;
275 break;
276 default:
277 return -EINVAL;
278 }
279
280 tuak_core(buf, opc, instance, _rand, zero16, zero16, k, k_len_bytes, keccac_iterations);
281
282 memcpy_reverse(ak, buf + 96, 6);
283
284 return 0;
285}
286
287/**
288 * tuak_generate - Generate AKA AUTN,IK,CK,RES
289 * @opc: OPc = 256-bit operator variant algorithm configuration field (encr.)
290 * @amf: AMF = 16-bit authentication management field
291 * @k: K = 128/256-bit subscriber key
292 * @sqn: SQN = 48-bit sequence number
293 * @_rand: RAND = 128-bit random challenge
294 * @autn: Buffer for AUTN = 128-bit authentication token
295 * @ik: Buffer for IK = 128/256-bit integrity key (f4), or %NULL
296 * @ck: Buffer for CK = 128/256-bit confidentiality key (f3), or %NULL
297 * @res: Buffer for RES = 32/64/128-bit signed response (f2), or %NULL
298 * @res_len: Max length for res; set to used length or 0 on failure
299 */
300void tuak_generate(const uint8_t *opc, const uint8_t *amf, const uint8_t *k, uint8_t k_len_bytes,
301 const uint8_t *sqn, const uint8_t *_rand, uint8_t *autn, uint8_t *ik,
302 uint8_t *ck, uint8_t *res, size_t *res_len)
303{
304 int i;
305 uint8_t mac_a[8], ak[6];
306
307 if (*res_len < 4) {
308 *res_len = 0;
309 return;
310 }
311 if (tuak_f1(opc, k, k_len_bytes, _rand, sqn, amf, mac_a, sizeof(mac_a), g_keccak_iterations) ||
312 tuak_f2345(opc, k, k_len_bytes, _rand, res, *res_len, ck, 16, ik, 16, ak, g_keccak_iterations)) {
313 *res_len = 0;
314 return;
315 }
316
317 /* AUTN = (SQN ^ AK) || AMF || MAC */
318 for (i = 0; i < 6; i++)
319 autn[i] = sqn[i] ^ ak[i];
320 memcpy(autn + 6, amf, 2);
321 memcpy(autn + 8, mac_a, 8);
322}
323
324
325/**
326 * tuak_auts - Milenage AUTS validation
327 * @opc: OPc = 256-bit operator variant algorithm configuration field (encr.)
328 * @k: K = 128/256-bit subscriber key
329 * @_rand: RAND = 128-bit random challenge
330 * @auts: AUTS = 112-bit authentication token from client
331 * @sqn: Buffer for SQN = 48-bit sequence number
332 * Returns: 0 = success (sqn filled), -1 on failure
333 */
334int tuak_auts(const uint8_t *opc, const uint8_t *k, uint8_t k_len_bytes,
335 const uint8_t *_rand, const uint8_t *auts, uint8_t *sqn)
336{
337 uint8_t amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
338 uint8_t ak[6], mac_s[8];
339 int i;
340
341 if (tuak_f5star(opc, k, k_len_bytes, _rand, ak, g_keccak_iterations))
342 return -1;
343 for (i = 0; i < 6; i++)
344 sqn[i] = auts[i] ^ ak[i];
345 if (tuak_f1star(opc, k, k_len_bytes, _rand, sqn, amf, mac_s, 8, g_keccak_iterations) ||
346 memcmp(mac_s, auts + 6, 8) != 0)
347 return -1;
348 return 0;
349}
350
351int tuak_opc_gen(uint8_t *opc, const uint8_t *k, uint8_t k_len_bytes, const uint8_t *op)
352{
353 uint8_t buf[200];
354 uint8_t instance;
355
356 switch (k_len_bytes) {
357 case 16:
358 instance = 0x00;
359 break;
360 case 32:
361 instance = 0x01;
362 break;
363 default:
364 return -EINVAL;
365 }
366
367 tuak_core(buf, op, instance, zero16, zero16, zero16, k, k_len_bytes, g_keccak_iterations);
368
369 memcpy_reverse(opc, buf, 32);
370
371 return 0;
372}