blob: e330c759ca800165b99c8800907886250ea94bc2 [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 Munautf1d33442011-04-23 15:34:11 +020037#include <string.h>
38
39#include <osmocom/gsm/a5.h>
40
Sylvain Munaut2735ac42011-11-17 21:01:46 +010041/*! \brief Main method to generate a A5/x cipher stream
42 * \param[in] n Which A5/x method to use
43 * \param[in] key 8 byte array for the key (as received from the SIM)
44 * \param[in] fn Frame number
45 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
46 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
47 *
48 * Currently A5/[0-2] are supported.
49 * Either (or both) of dl/ul can be NULL if not needed.
50 */
Sylvain Munautf1d33442011-04-23 15:34:11 +020051void
Sylvain Munaut3e387cb2011-11-17 19:45:42 +010052osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +020053{
54 switch (n)
55 {
56 case 0:
57 if (dl)
58 memset(dl, 0x00, 114);
59 if (ul)
60 memset(ul, 0x00, 114);
61 break;
62
63 case 1:
64 osmo_a5_1(key, fn, dl, ul);
65 break;
66
67 case 2:
68 osmo_a5_2(key, fn, dl, ul);
69 break;
70
71 default:
72 /* a5/[3..7] not supported here/yet */
73 break;
74 }
75}
76
77
78/* ------------------------------------------------------------------------ */
79/* A5/1&2 common stuff */
80/* ------------------------------------------------------------------------ */
81
82#define A5_R1_LEN 19
83#define A5_R2_LEN 22
84#define A5_R3_LEN 23
85#define A5_R4_LEN 17 /* A5/2 only */
86
87#define A5_R1_MASK ((1<<A5_R1_LEN)-1)
88#define A5_R2_MASK ((1<<A5_R2_LEN)-1)
89#define A5_R3_MASK ((1<<A5_R3_LEN)-1)
90#define A5_R4_MASK ((1<<A5_R4_LEN)-1)
91
92#define A5_R1_TAPS 0x072000 /* x^19 + x^5 + x^2 + x + 1 */
93#define A5_R2_TAPS 0x300000 /* x^22 + x + 1 */
94#define A5_R3_TAPS 0x700080 /* x^23 + x^15 + x^2 + x + 1 */
95#define A5_R4_TAPS 0x010800 /* x^17 + x^5 + 1 */
96
Sylvain Munaut2735ac42011-11-17 21:01:46 +010097/*! \brief Computes parity of a 32-bit word
98 * \param[in] x 32 bit word
99 * \return Parity bit (xor of all bits) as 0 or 1
100 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200101static inline uint32_t
102_a5_12_parity(uint32_t x)
103{
104 x ^= x >> 16;
105 x ^= x >> 8;
106 x ^= x >> 4;
Sylvain Munautad4a6a82011-11-20 08:46:56 +0100107 x &= 0xf;
108 return (0x6996 >> x) & 1;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200109}
110
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100111/*! \brief Compute majority bit from 3 taps
112 * \param[in] v1 LFSR state ANDed with tap-bit
113 * \param[in] v2 LFSR state ANDed with tap-bit
114 * \param[in] v3 LFSR state ANDed with tap-bit
115 * \return The majority bit (0 or 1)
116 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200117static inline uint32_t
118_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
119{
120 return (!!v1 + !!v2 + !!v3) >= 2;
121}
122
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100123/*! \brief Compute the next LFSR state
124 * \param[in] r Current state
125 * \param[in] mask LFSR mask
126 * \param[in] taps LFSR taps
127 * \return Next state
128 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200129static inline uint32_t
130_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
131{
132 return ((r << 1) & mask) | _a5_12_parity(r & taps);
133}
134
135
136/* ------------------------------------------------------------------------ */
137/* A5/1 */
138/* ------------------------------------------------------------------------ */
139
140#define A51_R1_CLKBIT 0x000100
141#define A51_R2_CLKBIT 0x000400
142#define A51_R3_CLKBIT 0x000400
143
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100144/*! \brief GSM A5/1 Clocking function
145 * \param[in] r Register state
146 * \param[in] force Non-zero value disable conditional clocking
147 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200148static inline void
149_a5_1_clock(uint32_t r[], int force)
150{
151 int cb[3], maj;
152
153 cb[0] = !!(r[0] & A51_R1_CLKBIT);
154 cb[1] = !!(r[1] & A51_R2_CLKBIT);
155 cb[2] = !!(r[2] & A51_R3_CLKBIT);
156
157 maj = _a5_12_majority(cb[0], cb[1], cb[2]);
158
159 if (force || (maj == cb[0]))
160 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
161
162 if (force || (maj == cb[1]))
163 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
164
165 if (force || (maj == cb[2]))
166 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
167}
168
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100169/*! \brief GSM A5/1 Output function
170 * \param[in] r Register state
171 * \return The A5/1 output function bit
172 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200173static inline uint8_t
174_a5_1_get_output(uint32_t r[])
175{
176 return (r[0] >> (A5_R1_LEN-1)) ^
177 (r[1] >> (A5_R2_LEN-1)) ^
178 (r[2] >> (A5_R3_LEN-1));
179}
180
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100181/*! \brief Generate a GSM A5/1 cipher stream
182 * \param[in] key 8 byte array for the key (as received from the SIM)
183 * \param[in] fn Frame number
184 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
185 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
186 *
187 * Either (or both) of dl/ul can be NULL if not needed.
188 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200189void
Sylvain Munaut3e387cb2011-11-17 19:45:42 +0100190osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200191{
192 uint32_t r[3] = {0, 0, 0};
193 uint32_t fn_count;
194 uint32_t b;
195 int i;
196
197 /* Key load */
198 for (i=0; i<64; i++)
199 {
200 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
201
202 _a5_1_clock(r, 1);
203
204 r[0] ^= b;
205 r[1] ^= b;
206 r[2] ^= b;
207 }
208
209 /* Frame count load */
210 fn_count = osmo_a5_fn_count(fn);
211
212 for (i=0; i<22; i++)
213 {
214 b = (fn_count >> i) & 1;
215
216 _a5_1_clock(r, 1);
217
218 r[0] ^= b;
219 r[1] ^= b;
220 r[2] ^= b;
221 }
222
223 /* Mix */
224 for (i=0; i<100; i++)
225 {
226 _a5_1_clock(r, 0);
227 }
228
229 /* Output */
230 for (i=0; i<114; i++) {
231 _a5_1_clock(r, 0);
232 if (dl)
233 dl[i] = _a5_1_get_output(r);
234 }
235
236 for (i=0; i<114; i++) {
237 _a5_1_clock(r, 0);
238 if (ul)
239 ul[i] = _a5_1_get_output(r);
240 }
241}
242
243
244/* ------------------------------------------------------------------------ */
245/* A5/2 */
246/* ------------------------------------------------------------------------ */
247
248#define A52_R4_CLKBIT0 0x000400
249#define A52_R4_CLKBIT1 0x000008
250#define A52_R4_CLKBIT2 0x000080
251
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100252/*! \brief GSM A5/2 Clocking function
253 * \param[in] r Register state
254 * \param[in] force Non-zero value disable conditional clocking
255 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200256static inline void
257_a5_2_clock(uint32_t r[], int force)
258{
259 int cb[3], maj;
260
261 cb[0] = !!(r[3] & A52_R4_CLKBIT0);
262 cb[1] = !!(r[3] & A52_R4_CLKBIT1);
263 cb[2] = !!(r[3] & A52_R4_CLKBIT2);
264
265 maj = (cb[0] + cb[1] + cb[2]) >= 2;
266
267 if (force || (maj == cb[0]))
268 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
269
270 if (force || (maj == cb[1]))
271 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
272
273 if (force || (maj == cb[2]))
274 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
275
276 r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
277}
278
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100279/*! \brief GSM A5/2 Output function
280 * \param[in] r Register state
281 * \return The A5/2 output function bit
282 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200283static inline uint8_t
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100284_a5_2_get_output(uint32_t r[])
Sylvain Munautf1d33442011-04-23 15:34:11 +0200285{
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100286 uint8_t b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200287
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100288 b = (r[0] >> (A5_R1_LEN-1)) ^
289 (r[1] >> (A5_R2_LEN-1)) ^
290 (r[2] >> (A5_R3_LEN-1)) ^
291 _a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^
292 _a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^
293 _a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200294
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100295 return b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200296}
297
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100298/*! \brief Generate a GSM A5/1 cipher stream
299 * \param[in] key 8 byte array for the key (as received from the SIM)
300 * \param[in] fn Frame number
301 * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
302 * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
303 *
304 * Either (or both) of dl/ul can be NULL if not needed.
305 */
Sylvain Munautf1d33442011-04-23 15:34:11 +0200306void
Sylvain Munaut3e387cb2011-11-17 19:45:42 +0100307osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200308{
309 uint32_t r[4] = {0, 0, 0, 0};
310 uint32_t fn_count;
311 uint32_t b;
Sylvain Munautf1d33442011-04-23 15:34:11 +0200312 int i;
313
314 /* Key load */
315 for (i=0; i<64; i++)
316 {
317 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
318
319 _a5_2_clock(r, 1);
320
321 r[0] ^= b;
322 r[1] ^= b;
323 r[2] ^= b;
324 r[3] ^= b;
325 }
326
327 /* Frame count load */
328 fn_count = osmo_a5_fn_count(fn);
329
330 for (i=0; i<22; i++)
331 {
332 b = (fn_count >> i) & 1;
333
334 _a5_2_clock(r, 1);
335
336 r[0] ^= b;
337 r[1] ^= b;
338 r[2] ^= b;
339 r[3] ^= b;
340 }
341
342 r[0] |= 1 << 15;
343 r[1] |= 1 << 16;
344 r[2] |= 1 << 18;
345 r[3] |= 1 << 10;
346
347 /* Mix */
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100348 for (i=0; i<99; i++)
Sylvain Munautf1d33442011-04-23 15:34:11 +0200349 {
350 _a5_2_clock(r, 0);
351 }
352
Sylvain Munautf1d33442011-04-23 15:34:11 +0200353 /* Output */
354 for (i=0; i<114; i++) {
355 _a5_2_clock(r, 0);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200356 if (dl)
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100357 dl[i] = _a5_2_get_output(r);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200358 }
359
360 for (i=0; i<114; i++) {
361 _a5_2_clock(r, 0);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200362 if (ul)
Sylvain Munaut7f975d22011-11-17 20:36:50 +0100363 ul[i] = _a5_2_get_output(r);
Sylvain Munautf1d33442011-04-23 15:34:11 +0200364 }
365}
Sylvain Munaut2735ac42011-11-17 21:01:46 +0100366
367/*! }@ */