4 * Full reimplementation of A5/1,2 (split and threadsafe)
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.
10 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
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.
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.
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.
31 #include <osmocom/gsm/a5.h>
34 osmo_a5(int n, uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
40 memset(dl, 0x00, 114);
42 memset(ul, 0x00, 114);
46 osmo_a5_1(key, fn, dl, ul);
50 osmo_a5_2(key, fn, dl, ul);
54 /* a5/[3..7] not supported here/yet */
60 /* ------------------------------------------------------------------------ */
61 /* A5/1&2 common stuff */
62 /* ------------------------------------------------------------------------ */
67 #define A5_R4_LEN 17 /* A5/2 only */
69 #define A5_R1_MASK ((1<<A5_R1_LEN)-1)
70 #define A5_R2_MASK ((1<<A5_R2_LEN)-1)
71 #define A5_R3_MASK ((1<<A5_R3_LEN)-1)
72 #define A5_R4_MASK ((1<<A5_R4_LEN)-1)
74 #define A5_R1_TAPS 0x072000 /* x^19 + x^5 + x^2 + x + 1 */
75 #define A5_R2_TAPS 0x300000 /* x^22 + x + 1 */
76 #define A5_R3_TAPS 0x700080 /* x^23 + x^15 + x^2 + x + 1 */
77 #define A5_R4_TAPS 0x010800 /* x^17 + x^5 + 1 */
79 static inline uint32_t
80 _a5_12_parity(uint32_t x)
90 static inline uint32_t
91 _a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
93 return (!!v1 + !!v2 + !!v3) >= 2;
96 static inline uint32_t
97 _a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
99 return ((r << 1) & mask) | _a5_12_parity(r & taps);
103 /* ------------------------------------------------------------------------ */
105 /* ------------------------------------------------------------------------ */
107 #define A51_R1_CLKBIT 0x000100
108 #define A51_R2_CLKBIT 0x000400
109 #define A51_R3_CLKBIT 0x000400
112 _a5_1_clock(uint32_t r[], int force)
116 cb[0] = !!(r[0] & A51_R1_CLKBIT);
117 cb[1] = !!(r[1] & A51_R2_CLKBIT);
118 cb[2] = !!(r[2] & A51_R3_CLKBIT);
120 maj = _a5_12_majority(cb[0], cb[1], cb[2]);
122 if (force || (maj == cb[0]))
123 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
125 if (force || (maj == cb[1]))
126 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
128 if (force || (maj == cb[2]))
129 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
132 static inline uint8_t
133 _a5_1_get_output(uint32_t r[])
135 return (r[0] >> (A5_R1_LEN-1)) ^
136 (r[1] >> (A5_R2_LEN-1)) ^
137 (r[2] >> (A5_R3_LEN-1));
141 osmo_a5_1(uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
143 uint32_t r[3] = {0, 0, 0};
151 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
160 /* Frame count load */
161 fn_count = osmo_a5_fn_count(fn);
165 b = (fn_count >> i) & 1;
175 for (i=0; i<100; i++)
181 for (i=0; i<114; i++) {
184 dl[i] = _a5_1_get_output(r);
187 for (i=0; i<114; i++) {
190 ul[i] = _a5_1_get_output(r);
195 /* ------------------------------------------------------------------------ */
197 /* ------------------------------------------------------------------------ */
199 #define A52_R4_CLKBIT0 0x000400
200 #define A52_R4_CLKBIT1 0x000008
201 #define A52_R4_CLKBIT2 0x000080
204 _a5_2_clock(uint32_t r[], int force)
208 cb[0] = !!(r[3] & A52_R4_CLKBIT0);
209 cb[1] = !!(r[3] & A52_R4_CLKBIT1);
210 cb[2] = !!(r[3] & A52_R4_CLKBIT2);
212 maj = (cb[0] + cb[1] + cb[2]) >= 2;
214 if (force || (maj == cb[0]))
215 r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
217 if (force || (maj == cb[1]))
218 r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
220 if (force || (maj == cb[2]))
221 r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
223 r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
226 static inline uint8_t
227 _a5_2_get_output(uint32_t r[], uint8_t *db)
231 tb = (r[0] >> (A5_R1_LEN-1)) ^
232 (r[1] >> (A5_R2_LEN-1)) ^
233 (r[2] >> (A5_R3_LEN-1));
238 _a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^
239 _a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^
240 _a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000)
247 osmo_a5_2(uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
249 uint32_t r[4] = {0, 0, 0, 0};
258 b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
268 /* Frame count load */
269 fn_count = osmo_a5_fn_count(fn);
273 b = (fn_count >> i) & 1;
289 for (i=0; i<100; i++)
294 _a5_2_get_output(r, &db);
298 for (i=0; i<114; i++) {
300 o = _a5_2_get_output(r, &db);
305 for (i=0; i<114; i++) {
307 o = _a5_2_get_output(r, &db);