Newsgroup: it.tlc.cellulari
Titolo: Implementazione algoritmo A5 (codifica gsm)

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 ,
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> 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;iBob key stream */
  ptr = alice;
  bits = 0;
  byte = 0;
  for (i=0;i> 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;iAlice key stream */
  ptr = bob;
  bits = 0;
  byte = 0;
  for (i=0;i> 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);
}

Io ho l'A3A8, se ti serve
Francesco