Cytat:
/* An implementation of the GSM A3/A8 algorithm. (Specifically, COMP128.)
*
* Copyright 1998, Marc Briceno, Ian Goldberg, and David Wagner.
* All rights reserved.
*
* For expository purposes only. Coded in C merely because C is a much
* more precise, concise form of expression for these purposes. See Judge
* Patel if you have any problems with this...
* Of course, it's only authentication, so it should be exportable for the
* usual boring reasons.
*
*
* This software is free for commercial and non-commercial use as long as
* the following conditions are aheared to.
* Copyright remains the authors' and as such any Copyright notices in
* the code are not to be removed.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The license and distribution terms for any publicly available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution license
* [including the GNU Public License.]
*/
typedef unsigned char Byte;
#include <stdio.h>
/* #define TEST */
/*
* rand[0..15]: the challenge from the base station
* key[0..15]: the SIM's A3/A8 long-term key Ki
* simoutput[0..11]: what you'd get back if you fed rand and key to a real
* SIM.
*
* The GSM spec states that simoutput[0..3] is SRES,
* and simoutput[4..11] is Kc (the A5 session key).
* (See GSM 11.11, Section 8.16. See also the leaked document
* referenced below.)
* Note that Kc is bits 74..127 of the COMP128 output, followed by 10
* zeros.
* In other words, A5 is keyed with only 54 bits of entropy. This
* represents a deliberate weakening of the key used for voice privacy
* by a factor of over 1000.
*
* Verified with a Pacific Bell Schlumberger SIM. Your mileage may vary.
*
* Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>,
* and David Wagner <daw@cs.berkeley.edu>
*/
void A3/A8(/* in */ Byte rand[16], /* in */ Byte key[16],
/* out */ Byte simoutput[12]);
/* The compression tables. */
static const Byte table_0[512] = {
102,177,186,162, 2,156,112, 75, 55, 25, 8, 12,251,193,246,188,
109,213,151, 53, 42, 79,191,115,233,242,164,223,209,148,108,161,
252, 37,244, 47, 64,211, 6,237,185,160,139,113, 76,138, 59, 70,
67, 26, 13,157, 63,179,221, 30,214, 36,166, 69,152,124,207,116,
247,194, 41, 84, 71, 1, 49, 14, 95, 35,169, 21, 96, 78,215,225,
182,243, 28, 92,201,118, 4, 74,248,128, 17, 11,146,132,245, 48,
149, 90,120, 39, 87,230,106,232,175, 19,126,190,202,141,137,176,
250, 27,101, 40,219,227, 58, 20, 51,178, 98,216,140, 22, 32,121,
61,103,203, 72, 29,110, 85,212,180,204,150,183, 15, 66,172,196,
56,197,158, 0,100, 45,153, 7,144,222,163,167, 60,135,210,231,
174,165, 38,249,224, 34,220,229,217,208,241, 68,206,189,125,255,
239, 54,168, 89,123,122, 73,145,117,234,143, 99,129,200,192, 82,
104,170,136,235, 93, 81,205,173,236, 94,105, 52, 46,228,198, 5,
57,254, 97,155,142,133,199,171,187, 50, 65,181,127,107,147,226,
184,218,131, 33, 77, 86, 31, 44, 88, 62,238, 18, 24, 43,154, 23,
80,159,134,111, 9,114, 3, 91, 16,130, 83, 10,195,240,253,119,
177,102,162,186,156, 2, 75,112, 25, 55, 12, 8,193,251,188,246,
213,109, 53,151, 79, 42,115,191,242,233,223,164,148,209,161,108,
37,252, 47,244,211, 64,237, 6,160,185,113,139,138, 76, 70, 59,
26, 67,157, 13,179, 63, 30,221, 36,214, 69,166,124,152,116,207,
194,247, 84, 41, 1, 71, 14, 49, 35, 95, 21,169, 78, 96,225,215,
243,182, 92, 28,118,201, 74, 4,128,248, 11, 17,132,146, 48,245,
90,149, 39,120,230, 87,232,106, 19,175,190,126,141,202,176,137,
27,250, 40,101,227,219, 20, 58,178, 51,216, 98, 22,140,121, 32,
103, 61, 72,203,110, 29,212, 85,204,180,183,150, 66, 15,196,172,
197, 56, 0,158, 45,100, 7,153,222,144,167,163,135, 60,231,210,
165,174,249, 38, 34,224,229,220,208,217, 68,241,189,206,255,125,
54,239, 89,168,122,123,145, 73,234,117, 99,143,200,129, 82,192,
170,104,235,136, 81, 93,173,205, 94,236, 52,105,228, 46, 5,198,
254, 57,155, 97,133,142,171,199, 50,187,181, 65,107,127,226,147,
218,184, 33,131, 86, 77, 44, 31, 62, 88, 18,238, 43, 24, 23,154,
159, 80,111,134,114, 9, 91, 3,130, 16, 10, 83,240,195,119,253
}, table_1[256] = {
19, 11, 80,114, 43, 1, 69, 94, 39, 18,127,117, 97, 3, 85, 43,
27,124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5,
35,107,103, 68, 21, 86, 36, 91, 85,126, 32, 50,109, 94,120, 6,
53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55,110,125,105, 20,
90, 80, 76, 96, 23, 60, 89, 64,121, 56, 14, 74,101, 8, 19, 78,
76, 66,104, 46,111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51,
57, 65,119,116, 22,109, 7, 86, 59, 93, 62,110, 78, 99, 77, 67,
12,113, 87, 98,102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75,
95, 63, 28, 49,123,120, 20,112, 44, 30, 15, 98,106, 2,103, 29,
82,107, 42,124, 24, 30, 41, 16,108,100,117, 40, 73, 40, 7,114,
82,115, 36,112, 12,102,100, 84, 92, 48, 72, 97, 9, 54, 55, 74,
113,123, 17, 26, 53, 58, 4, 9, 69,122, 21,118, 42, 60, 27, 73,
118,125, 34, 15, 65,115, 84, 64, 62, 81, 70, 1, 24,111,121, 83,
104, 81, 49,127, 48,105, 31, 10, 6, 91, 87, 37, 16, 54,116,126,
31, 38, 13, 0, 72,106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52,
101, 17, 44,108, 71, 52, 66, 57, 33, 51, 25, 90, 2,119,122, 35
}, table_2[128] = {
52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43,
37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18,
55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59,
62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56,
48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61,
29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0,
20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27,
31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7
}, table_3[64] = {
1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31,
28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9,
20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10,
17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19
}, table_4[32] = {
15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8,
10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12
}, *table[5] = { table_0, table_1, table_2, table_3, table_4 };
/*
* This code derived from a leaked document from the GSM standards.
* Some missing pieces were filled in by reverse-engineering a working SIM.
* We have verified that this is the correct COMP128 algorithm.
*
* The first page of the document identifies it as
* _Technical Information: GSM System Security Study_.
* 10-1617-01, 10th June 1988.
* The bottom of the title page is marked
* Racal Research Ltd.
* Worton Drive, Worton Grange Industrial Estate,
* Reading, Berks. RG2 0SB, England.
* Telephone: Reading (0734) 868601 Telex: 847152
* The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy!
*
* Note: There are three typos in the spec (discovered by
* reverse-engineering).
* First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read
* "z = (2 * x[m] + x[n]) mod 2^(9-j)".
* Second, the "k" loop in the "Form bits from bytes" section is severely
* botched: the k index should run only from 0 to 3, and clearly the range
* on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8,
* to be consistent with the subsequent section).
* Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as
* claimed in the document. (And the document doesn't specify how Kc is
* derived, but that was also easily discovered with reverse engineering.)
* All of these typos have been corrected in the following code.
*/
void A3A8(/* in */ Byte rand[16], /* in */ Byte key[16],
/* out */ Byte simoutput[12])
{
Byte x[32], bit[128];
int i, j, k, l, m, n, y, z, next_bit;
/* ( Load RAND into last 16 bytes of input ) */
for (i=16; i<32; i++)
x[i] = rand[i-16];
/* ( Loop eight times ) */
for (i=1; i<9; i++) {
/* ( Load key into first 16 bytes of input ) */
for (j=0; j<16; j++)
x[j] = key[j];
/* ( Perform substitutions ) */
for (j=0; j<5; j++)
for (k=0; k<(1<<j); k++)
for (l=0; l<(1<<(4-j)); l++) {
m = l + k*(1<<(5-j));
n = m + (1<<(4-j));
y = (x[m]+2*x[n]) % (1<<(9-j));
z = (2*x[m]+x[n]) % (1<<(9-j));
x[m] = table[j][y];
x[n] = table[j][z];
}
/* ( Form bits from bytes ) */
for (j=0; j<32; j++)
for (k=0; k<4; k++)
bit[4*j+k] = (x[j]>>(3-k)) & 1;
/* ( Permutation but not on the last loop ) */
if (i < 8 )
for (j=0; j<16; j++) {
x[j+16] = 0;
for (k=0; k<8; k++) {
next_bit = ((8*j + k)*17) % 128;
x[j+16] |= bit[next_bit] << (7-k);
}
}
}
/*
* ( At this stage the vector x[] consists of 32 nibbles.
* The first 8 of these are taken as the output SRES. )
*/
/* The remainder of the code is not given explicitly in the
* standard, but was derived by reverse-engineering.
*/
for (i=0; i<4; i++)
simoutput[i] = (x[2*i]<<4) | x[2*i+1];
for (i=0; i<6; i++)
simoutput[4+i] = (x[2*i+18]<<6) | (x[2*i+18+1]<<2)
| (x[2*i+18+2]>>2);
simoutput[4+6] = (x[2*6+18]<<6) | (x[2*6+18+1]<<2);
simoutput[4+7] = 0;
}
#ifdef TEST
int hextoint(char x)
{
x = toupper(x);
if (x >= 'A' && x <= 'F')
return x-'A'+10;
else if (x >= '0' && x <= '9')
return x-'0';
fprintf(stderr, "bad input.\n");
exit(1);
}
int main(int argc, char **argv)
{
Byte rand[16], key [16], simoutput[12];
int i;
if (argc != 3 || strlen(argv[1]) != 34 || strlen(argv[2]) != 34
|| strncmp(argv[1], "0x", 2) != 0
|| strncmp(argv[2], "0x", 2) != 0) {
fprintf(stderr, "Usage: %s 0x<key> 0x<rand>\n", argv[0]);
exit(1);
}
for (i=0; i<16; i++)
key[i] = (hextoint(argv[1][2*i+2])<<4)
| hextoint(argv[1][2*i+3]);
for (i=0; i<16; i++)
rand[i] = (hextoint(argv[2][2*i+2])<<4)
| hextoint(argv[2][2*i+3]);
A3A8(key, rand, simoutput);
printf("simoutput: ");
for (i=0; i<12; i++)
printf("%02X", simoutput[i]);
printf("\n");
return 0;
}
#endif
A teraz algorytm A5
The GSM encryption algorithm, A5, is not much good. Its effective key length
is at most five bytes; and anyone with the time and energy to look for faster
attacks can find source code for it at the bottom of this post.
The politics of all this is bizarre. Readers may recall that there was a fuss
last year about whether GSM phones could be exported to the Middle East; the
official line then was that A5 was too good for the likes of Saddam Hussein.
However, a couple of weeks ago, they switched from saying that A5 was too
strong to disclose, to saying that it was too weak to disclose! The
government line now pleads that discussing it might harm export sales.
Maybe all the fuss was just a ploy to get Saddam to buy A5 chips on the black
market; but Occam's razor suggests that we are really seeing the results of
the usual blundering, infighting and incompetence of bloated government
departments.
Indeed, my spies inform me that there was a terrific row between the NATO
signals agencies in the mid 1980's over whether GSM encryption should be
strong or not. The Germans said it should be, as they shared a long border
with the Evil Empire; but the other countries didn't feel this way. and the
algorithm as now fielded is a French design.
A5 is a stream cipher, and the keystream is the xor of three clock controlled
registers. The clock control of each register is that register's own middle
bit, xor'ed with a threshold function of the middle bits of all three
registers (ie if two or more of the middle bits are 1, then invert each of
these bits; otherwise just use them as they are). The register lengths are
19, 22 and 23, and all the feedback polynomials are sparse.
Readers will note that there is a trivial 2^40 attack (guess the contents of
registers 1 and 2, work out register 3 from the keystream, and then step on
to check whether the guess was right). 2^40 trial encryptions could take
weeks on a workstation, but the low gate count of the algorithm means that
a Xilinx chip can easily be programmed to do keysearch, and an A5 " niespodzianka "
might have a few dozen of these running at maybe 2 keys per microsecond each.
Of course, if all you want to do is break the Royal Family's keys for sale to
News International, then software would do fine.
It is thus clear that A5 should be free of all export controls, just like
CDMF and the 40-bit versions of RC2 and RC4.
Indeed, there seems to be an even faster attack. As the clock control is
stop-go rather than 1-2, one would expect some kind of correlation attack to
be possible, and on June 3rd, Dr Simon Shepherd of Bradford University was
due to present an attack on A5 to an IEE colloquium in London. However, his
talk was spiked at the last minute by GCHQ, and all we know about his attack
is:
(a) that sparse matrix techniques are used to reconstruct the initial state
(this was published as a `trailer' in the April 93 `Mobile Europe');
(b) that he used some of the tricks from my paper `Solving a class of stream
ciphers' (Cryptologia XIV no 3 [July 90] pp 285 - 288) and from the
follow-up paper `Divide and conquer attacks on certain classes of stream
ciphers' by Ed Dawson and Andy Clark (Cryptologia XVIII no 1 [Jan 94]
pp 25 - 40) (he mentioned this to me on the phone).
I believe that we have to stand up for academic freedom, and I hope that
placing A5 in the public domain will lead to the embargo on Simon's paper
being lifted.
Ross Anderson
APPENDIX - AN IMPLEMENTATION OF A5
The documentation we have, which arrived anonymously in two brown envelopes,
is incomplete; we do not know the feedback taps of registers 2 and 3, but we
do know from the chip's gate count that they have at most 6 feedback taps
between them.
The following implementation of A5 is due to Mike Roe <mrr@cl.cam.ac.uk>, and
all comments and queries should be sent to him.
/*
* In writing this program, I've had to guess a few pices of information:
*
* 1. Which bits of the key are loaded into which bits of the shift register
* 2. Which order the frame sequence number is shifted into the SR (MSB
* first or LSB first)
* 3. The position of the feedback taps on R2 and R3 (R1 is known).
* 4. The position of the clock control taps. These are on the `middle' one,
* I've assumed to be 9 on R1, 11 on R2, 11 on R3.
*/
/*
* Look at the `middle' stage of each of the 3 shift registers.
* Either 0, 1, 2 or 3 of these 3 taps will be set high.
* If 0 or 1 or one of them are high, return true. This will cause each of
* the middle taps to be inverted before being used as a clock control. In all
* cases either 2 or 3 of the clock enable lines will be active. Thus, at least
* two shift registers change on every clock-tick and the system never becomes
* stuck.
*/
static int threshold(r1, r2, r3)
unsigned int r1;
unsigned int r2;
unsigned int r3;
{
int total;
total = (((r1 >> 9) & 0x1) == 1) +
(((r2 >> 11) & 0x1) == 1) +
(((r3 >> 11) & 0x1) == 1);
if (total > 1)
return (0);
else
return (1);
}
unsigned long clock_r1(ctl, r1)
int ctl;
unsigned long r1;
{
unsigned long feedback;
/*
* Primitive polynomial x**19 + x**5 + x**2 + x + 1
*/
ctl ^= ((r1 >> 9) & 0x1);
if (ctl)
{
feedback = (r1 >> 18 ) ^ (r1 >> 17) ^ (r1 >> 16) ^ (r1 >> 13);
r1 = (r1 << 1) & 0x7ffff;
if (feedback & 0x01)
r1 ^= 0x01;
}
return (r1);
}
unsigned long clock_r2(ctl, r2)
int ctl;
unsigned long r2;
{
unsigned long feedback;
/*
* Primitive polynomial x**22 + x**9 + x**5 + x + 1
*/
ctl ^= ((r2 >> 11) & 0x1);
if (ctl)
{
feedback = (r2 >> 21) ^ (r2 >> 20) ^ (r2 >> 16) ^ (r2 >> 12);
r2 = (r2 << 1) & 0x3fffff;
if (feedback & 0x01)
r2 ^= 0x01;
}
return (r2);
}
unsigned long clock_r3(ctl, r3)
int ctl;
unsigned long r3;
{
unsigned long feedback;
/*
* Primitive polynomial x**23 + x**5 + x**4 + x + 1
*/
ctl ^= ((r3 >> 11) & 0x1);
if (ctl)
{
feedback = (r3 >> 22) ^ (r3 >> 21) ^ (r3 >> 18 ) ^ (r3 >> 17);
r3 = (r3 << 1) & 0x7fffff;
if (feedback & 0x01)
r3 ^= 0x01;
}
return (r3);
}
int keystream(key, frame, alice, bob)
unsigned char *key; /* 64 bit session key */
unsigned long frame; /* 22 bit frame sequence number */
unsigned char *alice; /* 114 bit Alice to Bob key stream */
unsigned char *bob; /* 114 bit Bob to Alice key stream */
{
unsigned long r1; /* 19 bit shift register */
unsigned long r2; /* 22 bit shift register */
unsigned long r3; /* 23 bit shift register */
int i; /* counter for loops */
int clock_ctl; /* xored with clock enable on each shift register */
unsigned char *ptr; /* current position in keystream */
unsigned char byte; /* byte of keystream being assembled */
unsigned int bits; /* number of bits of keystream in byte */
unsigned int bit; /* bit output from keystream generator */
/* Initialise shift registers from session key */
r1 = (key[0] | (key[1] << 8 ) | (key[2] << 16) ) & 0x7ffff;
r2 = ((key[2] >> 3) | (key[3] << 5) | (key[4] << 13) | (key[5] << 21)) & 0x3fffff;
r3 = ((key[5] >> 1) | (key[6] << 7) | (key[7] << 15) ) & 0x7fffff;
/* Merge frame sequence number into shift register state, by xor'ing it
* into the feedback path
*/
for (i=0;i<22;i++)
{
clock_ctl = threshold(r1, r2, r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
if (frame & 1)
{
r1 ^= 1;
r2 ^= 1;
r3 ^= 1;
}
frame = frame >> 1;
}
/* Run shift registers for 100 clock ticks to allow frame number to
* be diffused into all the bits of the shift registers
*/
for (i=0;i<100;i++)
{
clock_ctl = threshold(r1, r2, r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
}
/* Produce 114 bits of Alice->Bob key stream */
ptr = alice;
bits = 0;
byte = 0;
for (i=0;i<114;i++)
{
clock_ctl = threshold(r1, r2, r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
bit = ((r1 >> 18 ) ^ (r2 >> 21) ^ (r3 >> 22)) & 0x01;
byte = (byte << 1) | bit;
bits++;
if (bits == 8 )
{
*ptr = byte;
ptr++;
bits = 0;
byte = 0;
}
}
if (bits)
*ptr = byte;
/* Run shift registers for another 100 bits to hide relationship between
* Alice->Bob key stream and Bob->Alice key stream.
*/
for (i=0;i<100;i++)
{
clock_ctl = threshold(r1, r2, r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
}
/* Produce 114 bits of Bob->Alice key stream */
ptr = bob;
bits = 0;
byte = 0;
for (i=0;i<114;i++)
{
clock_ctl = threshold(r1, r2, r2);
r1 = clock_r1(clock_ctl, r1);
r2 = clock_r2(clock_ctl, r2);
r3 = clock_r3(clock_ctl, r3);
bit = ((r1 >> 18 ) ^ (r2 >> 21) ^ (r3 >> 22)) & 0x01;
byte = (byte << 1) | bit;
bits++;
if (bits == 8 )
{
*ptr = byte;
ptr++;
bits = 0;
byte = 0;
}
}
if (bits)
*ptr = byte;
return (0);
}