blob: d0c7c5f5294901f3d14b56d1e7a7e5f438d2bb77 [file] [log] [blame]
Sylvain Munautf1d33442011-04-23 15:34:11 +02001/*
2 * a5.c
3 *
4 * Full reimplementation of A5/1,2 (split and threadsafe)
5 *
6 * The logic behind the algorithm is taken from "A pedagogical implementation
7 * of the GSM A5/1 and A5/2 "voice privacy" encryption algorithms." by
8 * Marc Briceno, Ian Goldberg, and David Wagner.
9 *
10 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
11 *
12 * All Rights Reserved
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 */
28
Sylvain Munaut2735ac42011-11-17 21:01:46 +010029/*! \addtogroup a5
30 * @{
31 */
32
33/*! \file gsm/a5.c
34 * \brief Osmocom GSM A5 ciphering algorithm implementation
35 */
36
Sylvain Munautc1e9be92012-12-06 08:23:02 +010037#include <errno.h>
Sylvain Munautf1d33442011-04-23 15:34:11 +020038#include <string.h>
Maxf8699ca2015-03-25 17:20:31 +010039#include <stdbool.h>
Sylvain Munautf1d33442011-04-23 15:34:11 +020040
41#include <osmocom/gsm/a5.h>
Maxf8699ca2015-03-25 17:20:31 +010042#include <osmocom/gsm/kasumi.h>
Sylvain Munautf1d33442011-04-23 15:34:11 +020043
Harald Weltee15ac062014-12-04 14:15:36 +010044/* Somme OS (like Nuttx) don't have ENOTSUP */
45#ifndef ENOTSUP
46#define ENOTSUP EINVAL
47#endif
48
Maxf8699ca2015-03-25 17:20:31 +010049/* ------------------------------------------------------------------------ */
50/* A5/3&4 */
51/* ------------------------------------------------------------------------ */
52
53/*! \brief Generate a GSM A5/4 cipher stream
54 * \param[in] key 16 byte array for the key (as received from the SIM)
55 * \param[in] fn Frame number
56 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
57 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
58 * \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
59 *
60 * Either (or both) of dl/ul should be NULL if not needed.
61 *
62 * Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
63 * with slight simplifications (CE hardcoded to 0).
64 */
65void
66_a5_4(const uint8_t *ck, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
67{
68 uint8_t i, gamma[32], uplink[15];
69 uint32_t fn_count = (fn_correct) ? osmo_a5_fn_count(fn) : fn;
70
71 if (ul) {
72 _kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 228);
73 for(i = 0; i < 15; i++) uplink[i] = (gamma[i + 14] << 2) + (gamma[i + 15] >> 6);
74 osmo_pbit2ubit(ul, uplink, 114);
75 }
76 if (dl) {
77 _kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 114);
78 osmo_pbit2ubit(dl, gamma, 114);
79 }
80}
81
82/*! \brief Generate a GSM A5/3 cipher stream
83 * \param[in] key 8 byte array for the key (as received from the SIM)
84 * \param[in] fn Frame number
85 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
86 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
87 * \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
88 *
89 * Either (or both) of dl/ul should be NULL if not needed.
90 *
91 * Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
92 * with slight simplifications (CE hardcoded to 0).
93 */
94void
95_a5_3(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
96{
97 uint8_t ck[16];
98 memcpy(ck, key, 8);
99 memcpy(ck + 8, key, 8);
100 /* internal function require 128 bit key so we expand by concatenating supplied 64 bit key */
101 _a5_4(ck, fn, dl, ul, fn_correct);
102}
103
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100104/*! \brief Main method to generate a A5/x cipher stream
105 * \param[in] n Which A5/x method to use
Maxf8699ca2015-03-25 17:20:31 +0100106 * \param[in] key 8 or 16 (for a5/4) byte array for the key (as received from the SIM)
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100107 * \param[in] fn Frame number
108 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
109 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
Sylvain Munautc1e9be92012-12-06 08:23:02 +0100110 * \returns 0 for success, -ENOTSUP for invalid cipher selection.
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100111 *
Maxf8699ca2015-03-25 17:20:31 +0100112 * Currently A5/[0-4] are supported.
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100113 * Either (or both) of dl/ul can be NULL if not needed.
114 */
Sylvain Munautc1e9be92012-12-06 08:23:02 +0100115int
Sylvain Munaut3e387cb2011-11-17 19:45:42 +0100116osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200117{
118 switch (n)
119 {
120 case 0:
121 if (dl)
122 memset(dl, 0x00, 114);
123 if (ul)
124 memset(ul, 0x00, 114);
125 break;
126
127 case 1:
128 osmo_a5_1(key, fn, dl, ul);
129 break;
130
131 case 2:
132 osmo_a5_2(key, fn, dl, ul);
133 break;
134
Maxf8699ca2015-03-25 17:20:31 +0100135 case 3:
136 _a5_3(key, fn, dl, ul, true);
137 break;
138
139 case 4:
140 _a5_4(key, fn, dl, ul, true);
141 break;
142
Sylvain Munautf1d33442011-04-23 15:34:11 +0200143 default:
Maxf8699ca2015-03-25 17:20:31 +0100144 /* a5/[5..7] not supported here/yet */
Sylvain Munautc1e9be92012-12-06 08:23:02 +0100145 return -ENOTSUP;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200146 }
Sylvain Munautc1e9be92012-12-06 08:23:02 +0100147
148 return 0;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200149}
150
151
152/* ------------------------------------------------------------------------ */
153/* A5/1&2 common stuff */
154/* ------------------------------------------------------------------------ */
155
156#define A5_R1_LEN 19
157#define A5_R2_LEN 22
158#define A5_R3_LEN 23
159#define A5_R4_LEN 17 /* A5/2 only */
160
161#define A5_R1_MASK ((1<<A5_R1_LEN)-1)
162#define A5_R2_MASK ((1<<A5_R2_LEN)-1)
163#define A5_R3_MASK ((1<<A5_R3_LEN)-1)
164#define A5_R4_MASK ((1<<A5_R4_LEN)-1)
165
Sylvain Munaut2dafed52012-03-01 19:54:02 +0100166#define A5_R1_TAPS 0x072000 /* x^19 + x^18 + x^17 + x^14 + 1 */
167#define A5_R2_TAPS 0x300000 /* x^22 + x^21 + 1 */
168#define A5_R3_TAPS 0x700080 /* x^23 + x^22 + x^21 + x^8 + 1 */
169#define A5_R4_TAPS 0x010800 /* x^17 + x^12 + 1 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200170
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100171/*! \brief Computes parity of a 32-bit word
172 * \param[in] x 32 bit word
173 * \return Parity bit (xor of all bits) as 0 or 1
174 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200175static inline uint32_t
176_a5_12_parity(uint32_t x)
177{
178 x ^= x >> 16;
179 x ^= x >> 8;
180 x ^= x >> 4;
Sylvain Munautad4a6a82011-11-20 08:46:56 +0100181 x &= 0xf;
182 return (0x6996 >> x) & 1;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200183}
184
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100185/*! \brief Compute majority bit from 3 taps
186 * \param[in] v1 LFSR state ANDed with tap-bit
187 * \param[in] v2 LFSR state ANDed with tap-bit
188 * \param[in] v3 LFSR state ANDed with tap-bit
189 * \return The majority bit (0 or 1)
190 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200191static inline uint32_t
192_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
193{
194 return (!!v1 + !!v2 + !!v3) >= 2;
195}
196
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100197/*! \brief Compute the next LFSR state
198 * \param[in] r Current state
199 * \param[in] mask LFSR mask
200 * \param[in] taps LFSR taps
201 * \return Next state
202 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200203static inline uint32_t
204_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
205{
206 return ((r << 1) & mask) | _a5_12_parity(r & taps);
207}
208
209
210/* ------------------------------------------------------------------------ */
211/* A5/1 */
212/* ------------------------------------------------------------------------ */
213
214#define A51_R1_CLKBIT 0x000100
215#define A51_R2_CLKBIT 0x000400
216#define A51_R3_CLKBIT 0x000400
217
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100218/*! \brief GSM A5/1 Clocking function
219 * \param[in] r Register state
220 * \param[in] force Non-zero value disable conditional clocking
221 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200222static inline void
223_a5_1_clock(uint32_t r[], int force)
224{
225 int cb[3], maj;
226
227 cb[0] = !!(r[0] & A51_R1_CLKBIT);
228 cb[1] = !!(r[1] & A51_R2_CLKBIT);
229 cb[2] = !!(r[2] & A51_R3_CLKBIT);
230
231 maj = _a5_12_majority(cb[0], cb[1], cb[2]);
232
233 if (force || (maj == cb[0]))
234 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
235
236 if (force || (maj == cb[1]))
237 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
238
239 if (force || (maj == cb[2]))
240 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
241}
242
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100243/*! \brief GSM A5/1 Output function
244 * \param[in] r Register state
245 * \return The A5/1 output function bit
246 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200247static inline uint8_t
248_a5_1_get_output(uint32_t r[])
249{
250 return (r[0] >> (A5_R1_LEN-1)) ^
251 (r[1] >> (A5_R2_LEN-1)) ^
252 (r[2] >> (A5_R3_LEN-1));
253}
254
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100255/*! \brief Generate a GSM A5/1 cipher stream
256 * \param[in] key 8 byte array for the key (as received from the SIM)
257 * \param[in] fn Frame number
258 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
259 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
260 *
261 * Either (or both) of dl/ul can be NULL if not needed.
262 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200263void
Sylvain Munaut3e387cb2011-11-17 19:45:42 +0100264osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200265{
266 uint32_t r[3] = {0, 0, 0};
267 uint32_t fn_count;
268 uint32_t b;
269 int i;
270
271 /* Key load */
272 for (i=0; i<64; i++)
273 {
274 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
275
276 _a5_1_clock(r, 1);
277
278 r[0] ^= b;
279 r[1] ^= b;
280 r[2] ^= b;
281 }
282
283 /* Frame count load */
284 fn_count = osmo_a5_fn_count(fn);
285
286 for (i=0; i<22; i++)
287 {
288 b = (fn_count >> i) & 1;
289
290 _a5_1_clock(r, 1);
291
292 r[0] ^= b;
293 r[1] ^= b;
294 r[2] ^= b;
295 }
296
297 /* Mix */
298 for (i=0; i<100; i++)
299 {
300 _a5_1_clock(r, 0);
301 }
302
303 /* Output */
304 for (i=0; i<114; i++) {
305 _a5_1_clock(r, 0);
306 if (dl)
307 dl[i] = _a5_1_get_output(r);
308 }
309
310 for (i=0; i<114; i++) {
311 _a5_1_clock(r, 0);
312 if (ul)
313 ul[i] = _a5_1_get_output(r);
314 }
315}
316
317
318/* ------------------------------------------------------------------------ */
319/* A5/2 */
320/* ------------------------------------------------------------------------ */
321
322#define A52_R4_CLKBIT0 0x000400
323#define A52_R4_CLKBIT1 0x000008
324#define A52_R4_CLKBIT2 0x000080
325
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100326/*! \brief GSM A5/2 Clocking function
327 * \param[in] r Register state
328 * \param[in] force Non-zero value disable conditional clocking
329 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200330static inline void
331_a5_2_clock(uint32_t r[], int force)
332{
333 int cb[3], maj;
334
335 cb[0] = !!(r[3] & A52_R4_CLKBIT0);
336 cb[1] = !!(r[3] & A52_R4_CLKBIT1);
337 cb[2] = !!(r[3] & A52_R4_CLKBIT2);
338
339 maj = (cb[0] + cb[1] + cb[2]) >= 2;
340
341 if (force || (maj == cb[0]))
342 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
343
344 if (force || (maj == cb[1]))
345 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
346
347 if (force || (maj == cb[2]))
348 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
349
350 r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
351}
352
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100353/*! \brief GSM A5/2 Output function
354 * \param[in] r Register state
355 * \return The A5/2 output function bit
356 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200357static inline uint8_t
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100358_a5_2_get_output(uint32_t r[])
Sylvain Munautf1d33442011-04-23 15:34:11 +0200359{
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100360 uint8_t b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200361
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100362 b = (r[0] >> (A5_R1_LEN-1)) ^
363 (r[1] >> (A5_R2_LEN-1)) ^
364 (r[2] >> (A5_R3_LEN-1)) ^
365 _a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^
366 _a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^
367 _a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200368
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100369 return b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200370}
371
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100372/*! \brief Generate a GSM A5/1 cipher stream
373 * \param[in] key 8 byte array for the key (as received from the SIM)
374 * \param[in] fn Frame number
375 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
376 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
377 *
378 * Either (or both) of dl/ul can be NULL if not needed.
379 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200380void
Sylvain Munaut3e387cb2011-11-17 19:45:42 +0100381osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200382{
383 uint32_t r[4] = {0, 0, 0, 0};
384 uint32_t fn_count;
385 uint32_t b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200386 int i;
387
388 /* Key load */
389 for (i=0; i<64; i++)
390 {
391 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
392
393 _a5_2_clock(r, 1);
394
395 r[0] ^= b;
396 r[1] ^= b;
397 r[2] ^= b;
398 r[3] ^= b;
399 }
400
401 /* Frame count load */
402 fn_count = osmo_a5_fn_count(fn);
403
404 for (i=0; i<22; i++)
405 {
406 b = (fn_count >> i) & 1;
407
408 _a5_2_clock(r, 1);
409
410 r[0] ^= b;
411 r[1] ^= b;
412 r[2] ^= b;
413 r[3] ^= b;
414 }
415
416 r[0] |= 1 << 15;
417 r[1] |= 1 << 16;
418 r[2] |= 1 << 18;
419 r[3] |= 1 << 10;
420
421 /* Mix */
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100422 for (i=0; i<99; i++)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200423 {
424 _a5_2_clock(r, 0);
425 }
426
Sylvain Munautf1d33442011-04-23 15:34:11 +0200427 /* Output */
428 for (i=0; i<114; i++) {
429 _a5_2_clock(r, 0);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200430 if (dl)
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100431 dl[i] = _a5_2_get_output(r);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200432 }
433
434 for (i=0; i<114; i++) {
435 _a5_2_clock(r, 0);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200436 if (ul)
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100437 ul[i] = _a5_2_get_output(r);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200438 }
439}
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100440
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200441/*! @} */