Algoritmo A5
Possibile implementazione
L'algoritmo di seguito riportato rappresenta una possibile implementazione del vero algoritmo A5 utilizzato nelle reti GSM. NON é comunque garantita la sua autenticità e nemmeno il suo corretto funzionamento. E' stato riportato qui per completezza di informazione e semplice curiosità.
A cura di: M. Bresco, G. Pradal, E. Tomasco
Coordinamento: Prof. Alfredo De Santis
Sistemi di elaborazione dell'informazione (Sicurezza su Reti)
Università di Salerno - Anno Acc.1999-2000Descrizione dell'algoritmo in PDL
(carica la chiave segreta Kc) FOR ogni bit della chiave segreta from 1 to 64 carica il bit nella corrispondente posizione nell'LFSR END FOR (Carica il numero di frame) FOR ogni bit del numero di frame from 1 to 22 shift_bits = f() FOR ogni registro i, from 1 to 3 Esegui lo XOR del bit della chiave pubblica nell'LSB IF il bit i dello shift_bits is set THEN Shift END IF END FOR END FOR (produce entrambi gli stream di cifratura e decifratura) FOR i from 1 to 2 (esegui shift adizionali) FOR j from 1 to 100 shift_bits = f() FOR ogni registro k from 1 to 3 IF il bit k dello shift_bits is set THEN Shift END IF END FOR (output stram di 114 bits) FOR j from 1 to 114 shift_bits = f() FOR ogni registro k from 1 to 3 IF bit k of shift_bits is set THEN Shift END IF END FOR Output = XOR degli MSB di tutti e tre i registri END FOR END FOR Shift function f BEGIN FUNCTION f FOR ogni registro i from 1 to 3 Poni middle[i] = il bit 'medio' del registro i END FOR IF almeno due 'bit medi' sono 1 THEN bit-complement code END IF RETURN code END FUNCTIONImplementazione in linguaggio 'C' dell'algoritmo A5
/* * The following implementation of A5 is due to Mike Roe. * * Reading this program, note that: * * 1. Which bit 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, * it has been 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); }