Calcolo della chiave segreta dell'ufficio demissione

Come accennato, l'autenticazione della Postcard si basa su una tecnica di firma che usa una cifratura RSA: per questo i dati in chiaro della carta (che consta, tra gli altri, quelli del numero della carta ed il periodo di validità) all'emissione della carta sono firmati allemissione della carta con la chiave privata dell'emissore (PostFinance) ed il cifrario ricevuto archiviato in una zona ROM della carta.

Fondamenti matematici

Nella tecnica RSA la chiave privata può essere teoricamente calcolata dalla chiave pubblica; la sicurezza della tecnica si basa sull'impossibilità pratica di questo calcolo ed è direttamente dipendente dalla lunghezza della chiave usata così come dall'aver a disposizione la tecniche matematiche avanzate per la scomposizione a numeri primi di numeri molto grandi.

Nella tecnica RSA un paio di chiavi è costituito da tre parametri: il modulo m, l'esponente pubblico e e l'esponente privato d. La chiave pubblica è poi data attraverso { e, m }, mentre la chiave privata equivalente con { d, m }.

La codificazione e decodificazione di un testo chiaro k e testo crittato c accade secondo le seguenti equazioni:

codifica: c = k^d mod m

decodifica: k = c^e mod m

Tutti e tre i parametri del paio di chiavi sono collegati da rapporti matematici: il modulo m è il prodotto di due due grandi numeri primi p e q, cioè: m = p · q. Come variabile ausiliaria è usato il minimo comune multiplo di p-1 e q-1, cioè: r = MCM(p-1,q-1). Per gli esponenti e e d vale il rapporto e · d 1 mod r, così l'esponente pubblico liberamente scelto e deve essere un numero primo di r.

Scomposto il modulo m in ambedue i suoi fattori primi p e q, si può calcolare la chiave privata conoscendo l'esponente pubblico e (con l'uso delle suddette equazioni) e l'esponente privato d.

Individuazione del modulo m

Normalmente il modulo m può essere desunto dalla chiave pubblica; nel nostro caso la chiave pubblica non è stata resa pubblica. Per individuare il modulo del paio di chiavi sono possibili due modi per procedere :

  1. Estrazione della chiave pubblica da un terminale Postcard-EFT-POS:

    Se mai qualcuno entrasse in possesso di un terminale Postcard, potrebbe provare ad estrarre la chiave dall'hardware. Questo procedimento è comunque dispendioso in termini di tempo e necessita specifiche conoscenze sull'hardware utilizzato.

  2. alcolo del modulo dai dati della carta:

    Il modulo può essere però calcolato direttamente dai dati di due Postcards: questa tecnica è chiaramente più semplice visto che non è necessario nessun hardware specifico.

Analizziamo la tecnica 2, quella più semplice. Per risalire al modulo abbiamo bisogno dei dati di due Postcard da cui rispettivamente dobbiamo ricavare il valore per il testo in chiaro k ed il testo cifrato.

Per scoprire il valore del modulo, usiamo la seguente ponderazione, dove assumiamo come valore per l'esponente pubblico il valore di tre (analogamente alle carte di credito francesi).

Sono valide le seguenti equazioni:

k1 = c1³ mod m ∧ k2 = c2³ mod m
→ c1³ - k1 = n1 · m ∧ c2³ - k2 = n2 · m
→ m = MCD(c1³ - k1, c2³ - k2)

Usando due qualsiasi Postcard, può capitare di non conoscere i rispettivi prefissi delle carte. Per questo fissiamo solo kx (k' senza prefisso) per ogni carta. Il seguente programma calcola il modulo dai dati di due carte.

import java.math.BigInteger;

public class ComputeMod2 {

  public static void main (String[] argv) {
    
    String c1Str  = "0EC6DA0D247A69CD093B6D852118CA4346B44EEECE4A3394F872C1356A8070BFEBB54669F375A63F2";
    String kx1Str = "0050162300000234208157701030503";

    String c2Str  = "09BA94341F1DD339766F71DF4BA1CC807C565AA0FC3BE835570104F5A0DF636D4F4F4AC7BFA481257";
    String kx2Str = "0050162300000234208157706021002";

    BigInteger c13 = new BigInteger (c1Str, 16).pow(3);
    BigInteger c23 = new BigInteger (c2Str, 16).pow(3);
    
    for (int n1 = 0; n1 < 16; n1++) {
      String tmp = "00004" + hex.charAt(n1) + "000" + kx1Str;
      BigInteger k1 = new BigInteger (tmp + tmp, 16);
      BigInteger a = c13.add(k1.negate());
      for (int n2 = 0; n2 < 16; n2++) {
        tmp = "00004" + hex.charAt(n2) + "000" + kx2Str;
        BigInteger k2 = new BigInteger (tmp + tmp, 16);
        BigInteger b = c23.add(k2.negate());
        
        BigInteger m = a.gcd(b);
        if (m.bitLength() > 318) {
          System.out.println ("Modulus:  0x" + m.toString(16));
          System.out.println ("          " + m.toString());
          return;
        }
      }
    }
    System.out.println ("No modulus found?!");
  }
  
  private static String hex = "0123456789ABCDEF";
}

Effettuiamo questo calcolo per due Postcard, avremo così i seguenti valori per il modulo che cerchiamo:

m = 100000000000000000000D62C6F32CD0EBF84B9339E3997B46570D236179E4675433DAA5FF513A6CF

Fattorizzazione del modulo

Il modulo m trovato può essere ora scomposto nei suoi fattori primi p e q; per questo si può impiegare un programma come qsieve, che effettua contemporaneamente la fattorizzazione di più numeri. Dopo alcune ore di calcolo otteniamo il risultato desiderato:

p = 39D6E856F2DF3C90B6C973BF29DFB66E8E73DEA7
q = 46D111C85E2E5DD769207D4BAC02B0C039F9F6399

Calcolo dell'esponente privato

Per stabilire l'esponente privato possiamo usare l'equazione e · d 1 mod r dove la variabile ausiliaria r ha il valore:

r = 800000000000000000006B16379966875FC25C977BA8C96bC7D5DC1767667EFDAC9973F6E3803248

Con I valori calcolati per e ed r si ricava:

d = 2AAAAAAAAAAAAAAAAAAACE5CBD33222d1FEB74327E8D9879429C9EB277CCD4FF39887BFCF68010C3

Verifica dei risultati

Con il seguente piccolo programma in Java possiamo verificare se tutti i nostri risultati sono corretti; tutti i casi dovrebbero riportare come esito "true". Chi possiede una Postcard ed un lettore di chip per le carte, può leggere i dati della carta e cambiare i valori di c e k attraverso valori stabiliti da sé.

import java.math.BigInteger;

public class Test {

  public static void main (String[] argv) {
    
    BigInteger c = new BigInteger ("0EC6DA0D247A69CD093B6D852118CA4346B44EEECE4A3394F872C1356A8070BFEBB54669F375A63F2", 16);
    BigInteger k = new BigInteger ("04400000501623000002342081577010305030000440000050162300000234208157701030503", 16);
     
    BigInteger m = new BigInteger ("100000000000000000000D62C6F32CD0EBF84B9339E3997B46570D236179E4675433DAA5FF513A6CF", 16);
    BigInteger p = new BigInteger ("39D6E856F2DF3C90B6C973BF29DFB66E8E73DEA7", 16);
    BigInteger q = new BigInteger ("46D111C85E2E5DD769207D4BAC02B0C039F9F6399", 16);
    BigInteger d = new BigInteger ("2AAAAAAAAAAAAAAAAAAACE5CBD33222d1FEB74327E8D9879429C9EB277CCD4FF39887BFCF68010C3", 16);
    BigInteger e = BigInteger.valueOf (3);

    check ("p * q == m", p.multiply (q), m);
    check ("c^d mod m == k", c.modPow (e, m), k);
    check ("k^d mod m == c", k.modPow (d, m), c);
  }

  private static void check (String msg, BigInteger a, BigInteger b) {
    boolean ok = a.equals(b);
    if (ok)
      System.out.println (msg + ": SUCCESS");
    else {
      System.out.println (msg + ": FAILED!");
      System.out.println ("     " + a.toString(16));
      System.out.println ("  <> " + b.toString(16));
    }
  }
}

Nel prossimo capitolo vedrete cosa include il PIN della Postcard...