Cifrare con A5/1 nei sistemi GSM

Il GSM è lo standard utilizzato per la trasmissione su mobile e A5/1 è uno dei sistemi per cifrarne le informazioni. In questo articolo vedremo alcune caratteristiche e la realizzazione di un algoritmo di questo tipo.

Ogni frame, in ambito GSM, è composto di 114 bit (per ogni direzione) e uno degli algoritmi maggiormente utilizzati per cifrarne le informazioni è senz’altro A5: un algoritmo a 64 bit inserito nell’hardware del terminale e nella BS. Di questo algoritmo esistono diverse realizzazioni per differenti piattaforme. Gli algoritmi A5/1 e A5/2 sono classificati come stream cipher e proteggono la comunicazione fra telefono e stazione radio-base mentre la comunicazione fra stazione radio-base e resto della rete non è protetta. L’ A5/1 è un algoritmo che garantisce un maggior livello di protezione, ed è quello usato prevalentemente in Europa, mentre l’A5/2, usato in molti altri paesi, permette un minor livello di protezione. Comunque entrambi i sistemi di crittografia si sono rivelati vulnerabili, tanto che sono stati previsti meccanismi automatici di cambio dell’algoritmo in caso di necessità (al seguente link un approfondimento). Esiste anche la versione A5/3 basato su Kasumi e successive. Un approccio alternativo a quello dei cifrari a blocchi è quello degli stream cipher. A differenza dei cifrari a blocchi nei quali la stessa chiave viene riutilizzata per la cifratura di ogni blocco, l’idea di base degli stream cipher consiste nel generare una sequenza, a partire da k, detta keystream. Lo stream cipher è inizializzato ogni volta che un frame viene inviato con la chiave di sessione Kc  e con il numero di frame da cifrare. La stessa Kc  viene utilizzata per tutta la sessione, durante la quale il numero del frame di 22 bit cambia. In questo modo viene generata un’ unica keystream per ciascun frame. La figura 1 mostra la fase di inizializzazione. A5/1 è composto da 3 LFSR (registri di traslazione a retroazione lineare) di lunghezze differenti chiamati R1, R2 e R3. Il blocco R1 è  costituito da 19 bits, R2 22 bits e R3 23 bits.

Figura 1: fase di inizializzazione.

Figura 1: fase di inizializzazione.

Ognuno ha un suo specifico polinomio:

R1: x19 + x5 + x2 + x + 1,
R2: x22 + x + 1
R3: x23 + x15 + x2 + x + 1.

Il flusso di dati tra la MS e la BTS viene suddiviso in frame di 228 bit, 114 bit per cifrare e 114 bit per decifrare. Un nuovo frame viene inviato ogni 4,6 ms ed è identificato da un numero sequenziale Fn di 22 bit. Lo XOR dei bit meno significativi dei tre registri rappresenta un bit della keystream. La sequenza delle operazioni previste prevede che ciascun registro viene shiftato se il suo bit centrale concorda con il valore di maggioranza dei bit centrali dei tre registri. Con la funzione keysetup, listato 1, vediamo come i tre registri sono inizializzati. Di norma le operazioni di inizializzazione sono comprensive delle seguenti fasi: i tre registri sono posti ad un valore pari ad una combinazione non lineare della chiave di sessione Ked il numero di frame, si caricano i 64 bit  della chiave in modo sequenziale. Durante il caricamento  dei bit della chiave, la regola di shift, spostamento laterale, dei registri che contengono i bit di maggioranza è disabilitata. Dopo il caricamento  dei bit della chiave ciascuno dei 22 bit del Fn sono posti in XOR, operazione logica, con i tre valori di feedback dei registri (clock enabled). Durante il caricamento  di ciascun bit del numero di frame, vengono shiftati i registri  il cui bit centrale concorda con il bit di maggioranza. In seguito primi 100 bit di keystream vengono scartati (allo scopo di distribuire  i bit del numero di frame in modo casuale nei tre LFSR) e i 114 bit successivi del keystream sono sottoposti all’operazione di XOR per cifrare il plaintext,  sono poi scartati altri 100 bit di keystream (per nasconderne le eventuali relazioni). Infine, i 114 bit successivi di keystream vengono XORati per decifrare  il ciphertext. Ad ogni passo, viene prodotto un bit della keystream. La cifratura effettiva avviene mettendo in XOR 114 bit della keystream e 114 bit del messaggio in chiaro. Al termine l’algoritmo è reinizializzato con la stessa chiave Kc e il numero del frame successivo (Fn+1). La figura 2 mostra il processo di generazione del flusso.

Figura 2: processo finale.

Figura 2: processo finale.

 

/* Do the A5/1 key setup. This routine accepts a 64-bit key and
* a 22-bit frame number. */
void keysetup(byte key[8], word frame) {
    int i;
    bit keybit, framebit;
    /* Zero out the shift registers. */
    R1 = R2 = R3 = 0;
    /* Load the key into the shift registers,
     * LSB of first byte of key array first,
     * clocking each register once for every
     * key bit loaded. (The usual clock
     * control rule is temporarily disabled.) */
   for (i=0; i<64; i++) {
          clockallthree(); /* always clock */
          keybit = (key[i/8] >> (i&7)) & 1; /* The i-th bit of the key */
          R1 ^= keybit; R2 ^= keybit; R3 ^= keybit;
    }
    /* Load the frame number into the shift
     * registers, LSB first,
     * clocking each register once for every
     * key bit loaded. (The usual clock
     * control rule is still disabled.) */
    for (i=0; i<22; i++) {
           clockallthree(); /* always clock */
           framebit = (frame >> i) & 1; /* The i-th bit of the frame #*/
           R1 ^= framebit; R2 ^= framebit; R3 ^= framebit;
    }
   /* Run the shift registers for 100 clocks
    * to mix the keying material and frame number
    * together with output generation disabled,
    * so that there is sufficient avalanche.
    * We re-enable the majority-based clock control
    * rule from now on. */
   for (i=0; i<100; i++) {
          clock();
    }
    /* Now the key is properly set up. */
}
/* Generate output. We generate 228 bits of
* keystream output. The first 114 bits is for
* the A->B frame; the next 114 bits is for the
* B->A frame. You allocate a 15-byte buffer
* for each direction, and this function fills
* it in. */
void run(byte AtoBkeystream[], byte BtoAkeystream[]) {
      int i;
      /* Zero out the output buffers. */
      for (i=0; i<=113/8; i++)
             AtoBkeystream[i] = BtoAkeystream[i] = 0;

      /* Generate 114 bits of keystream for the
       * A->B direction. Store it, MSB first. */
      for (i=0; i<114; i++) {
              clock();
              AtoBkeystream[i/8] |= getbit() << (7-(i&7));
     }

     /* Generate 114 bits of keystream for the
      * B->A direction. Store it, MSB first. */
     for (i=0; i<114; i++) {
            clock();
            BtoAkeystream[i/8] |= getbit() << (7-(i&7));
      }
}
Listato 1

Una risposta

Scrivi un commento

ESPertino è la nuova scheda per IoT compatibile ARDUINO.
Scopri come averla GRATIS!