blob: d223cb768edcc7f6a007c84f497be09520e9bc00 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*
Sylvain Munautf1d33442011-04-23 15:34:11 +02002 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
3 *
4 * All Rights Reserved
5 *
Harald Weltee08da972017-11-13 01:00:26 +09006 * SPDX-License-Identifier: GPL-2.0+
7 *
Sylvain Munautf1d33442011-04-23 15:34:11 +02008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Sylvain Munautf1d33442011-04-23 15:34:11 +020017 */
18
Harald Welte8cc27672017-10-16 16:00:36 +020019/*! \addtogroup a5
Sylvain Munaut2735ac42011-11-17 21:01:46 +010020 * @{
Harald Welte8cc27672017-10-16 16:00:36 +020021 * Osmocom GSM ciphering algorithm implementation
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020022 *
Harald Welte8cc27672017-10-16 16:00:36 +020023 * Full reimplementation of A5/1,2,3,4 (split and threadsafe).
24 *
25 * The logic behind the algorithm is taken from "A pedagogical implementation
26 * of the GSM A5/1 and A5/2 "voice privacy" encryption algorithms." by
27 * Marc Briceno, Ian Goldberg, and David Wagner.
28 */
Sylvain Munaut2735ac42011-11-17 21:01:46 +010029
Sylvain Munautc1e9be92012-12-06 08:23:02 +010030#include <errno.h>
Sylvain Munautf1d33442011-04-23 15:34:11 +020031#include <string.h>
Maxf8699ca2015-03-25 17:20:31 +010032#include <stdbool.h>
Sylvain Munautf1d33442011-04-23 15:34:11 +020033
34#include <osmocom/gsm/a5.h>
Maxf8699ca2015-03-25 17:20:31 +010035#include <osmocom/gsm/kasumi.h>
Maxceae1232016-06-27 18:12:49 +020036#include <osmocom/crypt/auth.h>
Sylvain Munautf1d33442011-04-23 15:34:11 +020037
Harald Weltee15ac062014-12-04 14:15:36 +010038/* Somme OS (like Nuttx) don't have ENOTSUP */
39#ifndef ENOTSUP
40#define ENOTSUP EINVAL
41#endif
42
Maxf8699ca2015-03-25 17:20:31 +010043/* ------------------------------------------------------------------------ */
44/* A5/3&4 */
45/* ------------------------------------------------------------------------ */
46
Neels Hofmeyr87e45502017-06-20 00:17:59 +020047/*! Generate a GSM A5/4 cipher stream
Maxf8699ca2015-03-25 17:20:31 +010048 * \param[in] key 16 byte array for the key (as received from the SIM)
49 * \param[in] fn Frame number
50 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
51 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
52 * \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
53 *
54 * Either (or both) of dl/ul should be NULL if not needed.
55 *
56 * Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
57 * with slight simplifications (CE hardcoded to 0).
58 */
59void
60_a5_4(const uint8_t *ck, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
61{
62 uint8_t i, gamma[32], uplink[15];
63 uint32_t fn_count = (fn_correct) ? osmo_a5_fn_count(fn) : fn;
64
65 if (ul) {
66 _kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 228);
67 for(i = 0; i < 15; i++) uplink[i] = (gamma[i + 14] << 2) + (gamma[i + 15] >> 6);
68 osmo_pbit2ubit(ul, uplink, 114);
69 }
70 if (dl) {
71 _kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 114);
72 osmo_pbit2ubit(dl, gamma, 114);
73 }
74}
75
Neels Hofmeyr87e45502017-06-20 00:17:59 +020076/*! Generate a GSM A5/3 cipher stream
Maxf8699ca2015-03-25 17:20:31 +010077 * \param[in] key 8 byte array for the key (as received from the SIM)
78 * \param[in] fn Frame number
79 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
80 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
81 * \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
82 *
83 * Either (or both) of dl/ul should be NULL if not needed.
84 *
85 * Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
86 * with slight simplifications (CE hardcoded to 0).
87 */
88void
89_a5_3(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
90{
91 uint8_t ck[16];
Maxceae1232016-06-27 18:12:49 +020092 osmo_c4(ck, key);
Maxf8699ca2015-03-25 17:20:31 +010093 /* internal function require 128 bit key so we expand by concatenating supplied 64 bit key */
94 _a5_4(ck, fn, dl, ul, fn_correct);
95}
96
Sylvain Munautf1d33442011-04-23 15:34:11 +020097/* ------------------------------------------------------------------------ */
98/* A5/1&2 common stuff */
99/* ------------------------------------------------------------------------ */
100
101#define A5_R1_LEN 19
102#define A5_R2_LEN 22
103#define A5_R3_LEN 23
104#define A5_R4_LEN 17 /* A5/2 only */
105
106#define A5_R1_MASK ((1<<A5_R1_LEN)-1)
107#define A5_R2_MASK ((1<<A5_R2_LEN)-1)
108#define A5_R3_MASK ((1<<A5_R3_LEN)-1)
109#define A5_R4_MASK ((1<<A5_R4_LEN)-1)
110
Sylvain Munaut2dafed52012-03-01 19:54:02 +0100111#define A5_R1_TAPS 0x072000 /* x^19 + x^18 + x^17 + x^14 + 1 */
112#define A5_R2_TAPS 0x300000 /* x^22 + x^21 + 1 */
113#define A5_R3_TAPS 0x700080 /* x^23 + x^22 + x^21 + x^8 + 1 */
114#define A5_R4_TAPS 0x010800 /* x^17 + x^12 + 1 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200115
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200116/*! Computes parity of a 32-bit word
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100117 * \param[in] x 32 bit word
118 * \return Parity bit (xor of all bits) as 0 or 1
119 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200120static inline uint32_t
121_a5_12_parity(uint32_t x)
122{
123 x ^= x >> 16;
124 x ^= x >> 8;
125 x ^= x >> 4;
Sylvain Munautad4a6a82011-11-20 08:46:56 +0100126 x &= 0xf;
127 return (0x6996 >> x) & 1;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200128}
129
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200130/*! Compute majority bit from 3 taps
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100131 * \param[in] v1 LFSR state ANDed with tap-bit
132 * \param[in] v2 LFSR state ANDed with tap-bit
133 * \param[in] v3 LFSR state ANDed with tap-bit
134 * \return The majority bit (0 or 1)
135 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200136static inline uint32_t
137_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
138{
139 return (!!v1 + !!v2 + !!v3) >= 2;
140}
141
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200142/*! Compute the next LFSR state
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100143 * \param[in] r Current state
144 * \param[in] mask LFSR mask
145 * \param[in] taps LFSR taps
146 * \return Next state
147 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200148static inline uint32_t
149_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
150{
151 return ((r << 1) & mask) | _a5_12_parity(r & taps);
152}
153
154
155/* ------------------------------------------------------------------------ */
156/* A5/1 */
157/* ------------------------------------------------------------------------ */
158
159#define A51_R1_CLKBIT 0x000100
160#define A51_R2_CLKBIT 0x000400
161#define A51_R3_CLKBIT 0x000400
162
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200163/*! GSM A5/1 Clocking function
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100164 * \param[in] r Register state
165 * \param[in] force Non-zero value disable conditional clocking
166 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200167static inline void
168_a5_1_clock(uint32_t r[], int force)
169{
170 int cb[3], maj;
171
172 cb[0] = !!(r[0] & A51_R1_CLKBIT);
173 cb[1] = !!(r[1] & A51_R2_CLKBIT);
174 cb[2] = !!(r[2] & A51_R3_CLKBIT);
175
176 maj = _a5_12_majority(cb[0], cb[1], cb[2]);
177
178 if (force || (maj == cb[0]))
179 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
180
181 if (force || (maj == cb[1]))
182 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
183
184 if (force || (maj == cb[2]))
185 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
186}
187
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200188/*! GSM A5/1 Output function
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100189 * \param[in] r Register state
190 * \return The A5/1 output function bit
191 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200192static inline uint8_t
193_a5_1_get_output(uint32_t r[])
194{
195 return (r[0] >> (A5_R1_LEN-1)) ^
196 (r[1] >> (A5_R2_LEN-1)) ^
197 (r[2] >> (A5_R3_LEN-1));
198}
199
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200200/*! Generate a GSM A5/1 cipher stream
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100201 * \param[in] key 8 byte array for the key (as received from the SIM)
202 * \param[in] fn Frame number
203 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
204 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
205 *
206 * Either (or both) of dl/ul can be NULL if not needed.
207 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200208void
Maxfdb3d8c2016-04-21 16:51:04 +0200209_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200210{
211 uint32_t r[3] = {0, 0, 0};
212 uint32_t fn_count;
213 uint32_t b;
214 int i;
215
216 /* Key load */
217 for (i=0; i<64; i++)
218 {
219 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
220
221 _a5_1_clock(r, 1);
222
223 r[0] ^= b;
224 r[1] ^= b;
225 r[2] ^= b;
226 }
227
228 /* Frame count load */
229 fn_count = osmo_a5_fn_count(fn);
230
231 for (i=0; i<22; i++)
232 {
233 b = (fn_count >> i) & 1;
234
235 _a5_1_clock(r, 1);
236
237 r[0] ^= b;
238 r[1] ^= b;
239 r[2] ^= b;
240 }
241
242 /* Mix */
243 for (i=0; i<100; i++)
244 {
245 _a5_1_clock(r, 0);
246 }
247
248 /* Output */
249 for (i=0; i<114; i++) {
250 _a5_1_clock(r, 0);
251 if (dl)
252 dl[i] = _a5_1_get_output(r);
253 }
254
255 for (i=0; i<114; i++) {
256 _a5_1_clock(r, 0);
257 if (ul)
258 ul[i] = _a5_1_get_output(r);
259 }
260}
261
Maxfdb3d8c2016-04-21 16:51:04 +0200262void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
263{
264 osmo_a5(1, key, fn, dl, ul);
265}
Sylvain Munautf1d33442011-04-23 15:34:11 +0200266
267/* ------------------------------------------------------------------------ */
268/* A5/2 */
269/* ------------------------------------------------------------------------ */
270
271#define A52_R4_CLKBIT0 0x000400
272#define A52_R4_CLKBIT1 0x000008
273#define A52_R4_CLKBIT2 0x000080
274
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200275/*! GSM A5/2 Clocking function
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100276 * \param[in] r Register state
277 * \param[in] force Non-zero value disable conditional clocking
278 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200279static inline void
280_a5_2_clock(uint32_t r[], int force)
281{
282 int cb[3], maj;
283
284 cb[0] = !!(r[3] & A52_R4_CLKBIT0);
285 cb[1] = !!(r[3] & A52_R4_CLKBIT1);
286 cb[2] = !!(r[3] & A52_R4_CLKBIT2);
287
288 maj = (cb[0] + cb[1] + cb[2]) >= 2;
289
290 if (force || (maj == cb[0]))
291 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
292
293 if (force || (maj == cb[1]))
294 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
295
296 if (force || (maj == cb[2]))
297 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
298
299 r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
300}
301
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200302/*! GSM A5/2 Output function
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100303 * \param[in] r Register state
304 * \return The A5/2 output function bit
305 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200306static inline uint8_t
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100307_a5_2_get_output(uint32_t r[])
Sylvain Munautf1d33442011-04-23 15:34:11 +0200308{
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100309 uint8_t b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200310
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100311 b = (r[0] >> (A5_R1_LEN-1)) ^
312 (r[1] >> (A5_R2_LEN-1)) ^
313 (r[2] >> (A5_R3_LEN-1)) ^
314 _a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^
315 _a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^
316 _a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200317
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100318 return b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200319}
320
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200321/*! Generate a GSM A5/1 cipher stream
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100322 * \param[in] key 8 byte array for the key (as received from the SIM)
323 * \param[in] fn Frame number
324 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
325 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
326 *
327 * Either (or both) of dl/ul can be NULL if not needed.
328 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200329void
Maxfdb3d8c2016-04-21 16:51:04 +0200330_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200331{
332 uint32_t r[4] = {0, 0, 0, 0};
333 uint32_t fn_count;
334 uint32_t b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200335 int i;
336
337 /* Key load */
338 for (i=0; i<64; i++)
339 {
340 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
341
342 _a5_2_clock(r, 1);
343
344 r[0] ^= b;
345 r[1] ^= b;
346 r[2] ^= b;
347 r[3] ^= b;
348 }
349
350 /* Frame count load */
351 fn_count = osmo_a5_fn_count(fn);
352
353 for (i=0; i<22; i++)
354 {
355 b = (fn_count >> i) & 1;
356
357 _a5_2_clock(r, 1);
358
359 r[0] ^= b;
360 r[1] ^= b;
361 r[2] ^= b;
362 r[3] ^= b;
363 }
364
365 r[0] |= 1 << 15;
366 r[1] |= 1 << 16;
367 r[2] |= 1 << 18;
368 r[3] |= 1 << 10;
369
370 /* Mix */
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100371 for (i=0; i<99; i++)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200372 {
373 _a5_2_clock(r, 0);
374 }
375
Sylvain Munautf1d33442011-04-23 15:34:11 +0200376 /* Output */
377 for (i=0; i<114; i++) {
378 _a5_2_clock(r, 0);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200379 if (dl)
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100380 dl[i] = _a5_2_get_output(r);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200381 }
382
383 for (i=0; i<114; i++) {
384 _a5_2_clock(r, 0);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200385 if (ul)
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100386 ul[i] = _a5_2_get_output(r);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200387 }
388}
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100389
Maxfdb3d8c2016-04-21 16:51:04 +0200390void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
391{
392 osmo_a5(2, key, fn, dl, ul);
393}
394
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200395/*! Main method to generate a A5/x cipher stream
Maxfdb3d8c2016-04-21 16:51:04 +0200396 * \param[in] n Which A5/x method to use
397 * \param[in] key 8 or 16 (for a5/4) byte array for the key (as received from the SIM)
398 * \param[in] fn Frame number
399 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
400 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
401 * \returns 0 for success, -ENOTSUP for invalid cipher selection.
402 *
403 * Currently A5/[0-4] are supported.
404 * Either (or both) of dl/ul can be NULL if not needed.
405 */
406int
407osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
408{
409 switch (n)
410 {
411 case 0:
412 if (dl)
413 memset(dl, 0x00, 114);
414 if (ul)
415 memset(ul, 0x00, 114);
416 break;
417
418 case 1:
419 _a5_1(key, fn, dl, ul);
420 break;
421
422 case 2:
423 _a5_2(key, fn, dl, ul);
424 break;
425
426 case 3:
427 _a5_3(key, fn, dl, ul, true);
428 break;
429
430 case 4:
431 _a5_4(key, fn, dl, ul, true);
432 break;
433
434 default:
435 /* a5/[5..7] not supported here/yet */
436 return -ENOTSUP;
437 }
438
439 return 0;
440}
441
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200442/*! @} */