ID TECH
Contatto
Tutti gli articoli tecnici

Post tecnico

Come decriptare i dati delle carte di credito, parte II

I clienti chiedono spesso: Come posso decifrare i dati provenienti dal mio lettore di carte di credito ID TECH?

La risposta: è necessario conoscere l'algoritmo utilizzato per cifrare i dati e la chiave impiegata. A quel punto è possibile decifrare i dati tramite tale chiave.

Oggi quasi tutti i dati delle carte di credito vengono cifrati con una chiave monouso, ottenuta tramite uno speciale schema di gestione delle chiavi denominato DUKPT (acronimo di Derived Unique Key Per Transaction). È importante comprendere che nel sistema DUKPT ogni transazione dispone di una propria chiave. Tale chiave non può essere riutilizzata per altre transazioni; di conseguenza, gli attacchi di tipo replay sono impossibili.

La domanda è: come si può derivare una chiave DUKPT in grado di sbloccare una determinata transazione? La risposta è: in linea generale, è necessario disporre del Key Serial Number (KSN) della transazione, oltre a un valore speciale denominato IPEK, ovvero la chiave iniziale iniettata nel lettore di carte di credito. L'IPEK, a sua volta, è derivata da una chiave segreta (che non viene mai iniettata in un lettore di carte) chiamata BDK (Base Derivation Key). A differenza della BDK, l'IPEK è univoca per ogni dispositivo fisico. (Da una singola BDK possono essere generate numerose IPEK univoche.) Se non si conosce l'IPEK del proprio dispositivo (e non vi è motivo di conoscerla, poiché non viene mai annotata), è possibile derivarla da un KSN e da una Base Derivation Key, utilizzando la tecnica descritta nella Parte I di questo articolo.

La derivazione di una chiave di sessione (talvolta denominata chiave di lavoro, o semplicemente "data key") si articola in un processo che si suddivide in 3 fasi. Le fasi sono:

1. Utilizzare la BDK e il KSN per derivare l'IPEK. (Consultare Parte I di questo articolo per i dettagli su come eseguire questa operazione.)

2. Utilizzare l'algoritmo di derivazione delle chiavi ANSI X9.24 (DUKPT) per ricavare una chiave base, o "chiave derivata" iniziale, dal KSN e dall'IPEK.

3. Convertire la chiave derivata del Passaggio 2 nella variante desiderata: Data Key, PIN Key o MAC Key. (Si noti che, sebbene la maggior parte dei lettori di carte di credito sia configurata per utilizzare la variante Data come chiave di sessione per la transazione, alcuni sono in realtà configurati per utilizzare la variante PIN.)

Vediamo ora in cosa consiste l'ottenimento della "chiave derivata" (passaggio 2), che rappresenta di gran lunga la parte più laboriosa dell'intero processo in tre fasi. Una volta ottenuta la chiave derivata, spiegheremo come trasformarla in una variante Data, PIN o MAC, operazione relativamente semplice.

Di seguito faremo ampio uso di pseudocodice, ma sappiate che il codice sorgente completo e funzionante (in JavaScript) per tutti i passaggi descritti è disponibile nel nostro popolare Strumento di Cifratura/Decifratura. (Provatelo subito, se non l'avete ancora fatto. È una pagina web autonoma che funziona su qualsiasi browser moderno.)

Derivazione di una chiave

Per ricavare la chiave base da cui creare una variante Data, PIN o MAC, è necessario disporre di un KSN di transazione e di un IPEK. Una volta ottenuti (si rimanda nuovamente a Parte I di questa serie), procedere come segue:

1. Estrarre gli 8 byte inferiori (più a destra) del KSN a 10 byte. I due byte superiori vanno scartati.

2. Creare una variabile BaseKSN per contenere una versione mascherata del KSN a 8 byte. Ottenere la versione mascherata applicando l'operazione AND tra il KSN a 8 byte del Passaggio 1 e il valore esadecimale 0xFFFFFFFFFFE00000.

3. Estrarre i bit del contatore dal KSN originale a 10 byte (non mascherato!) applicando l'operazione AND tra i tre byte inferiori e il valore 0x1FFFFF. (Si ricorda che i 21 bit inferiori di un KSN costituiscono il contatore di transazione.) Questo valore verrà memorizzato in una variabile denominata (come altro?) counter.

4. Copia il tuo IPEK di 16 byte in una variabile chiamata curKey.

5. Ora è necessario impostare un ciclo. Ad ogni iterazione del ciclo, esamineremo i bit del contatore (partendo dal bit più significativo, ovvero il 21° bit; alla seconda iterazione verificheremo il 20° bit; poi il 19° bit; e così via). Ogni volta che troviamo un bit attivo, lo applicheremo tramite OR al BaseKSN, quindi chiameremo generateKey() per aggiornare curKey. Il BaseKSN accumula bit ad ogni iterazione del ciclo e il valore curKey si aggiorna ad ogni bit del contatore attivo rilevato.

Cosa fa generateKey() ? Ottima domanda! Se il tuo linguaggio di programmazione supporta la matematica con BigInteger, il codice apparirà più o meno così:

Bene. Come si può vedere, la chiave a 16 byte viene mascherata e quindi utilizzata per cifrare il valore ksn di 8 byte, ottenendo la metà sinistra (gli 8 byte a sinistra) di una nuova chiave. La metà destra della nuova chiave è un cifrario creato dallo stesso ksn, ma utilizzando una chiave non mascherata.

Infine, è necessario sapere cosa fa encryptRegister() si presenta così. Eccola:

Si noti che il Cipher Block Chaining è di fatto privo di significato in questo contesto, poiché stiamo cifrando un valore di 8 byte (un singolo blocco di dati). Non c'è nulla da "concatenare". È incluso nel codice semplicemente perché la routine di cifratura richiede un parametro che indichi se abilitare o meno il chaining.

Si noti inoltre che utilizziamo una chiave di 8 byte per eseguire la cifratura. TDES si comporta come single-DES quando la chiave è lunga soltanto 8 byte. Ciò avviene perché una chiave di 8 byte produrrebbe, in triple DES, un ciclo di cifratura/decifratura/cifratura equivalente a una singola cifratura.

In termini semplici, la routine utilizza gli 8 byte superiori di una chiave a 16 byte per cifrare un valore speciale ottenuto applicando l'operazione XOR tra gli 8 byte inferiori della chiave e il ksn (anch'esso di 8 byte). Il risultato è un hash unidirezionale del ksn.

Mettendo tutto insieme, il ciclo del Passaggio 5 descritto sopra produce un valore curKey che costituisce la chiave base da cui è possibile derivare le varianti Data, PIN o MAC. (Il ciclo del Passaggio 5 è, o dovrebbe essere, parte di una funzione che restituisce curKey, ovvero la chiave base.)

È giunto il momento di esaminare più in dettaglio le tre opzioni di "variante di chiave".

Creazione delle varianti di chiave Data, PIN e MAC

ANSI X9.24 consente a una chiave DUKPT di assumere una delle tre forme finali, denominate varianti: MAC, PIN e Data. Rimandiamo qualsiasi discussione sull'utilizzo di questi tipi di chiave per concentrarci sulle modalità con cui vengono create.

Il punto di partenza per qualsiasi variante è una chiave base DUKPT (la chiave derivata che abbiamo chiamato curKey nel Passaggio 5 descritto in precedenza). Per ottenere la variante MAC, è sufficiente applicare l'operazione XOR tra la chiave base (la "chiave derivata") e una costante speciale:

La variante PIN viene creata in modo analogo, ma utilizzando una costante diversa:

La variante Data richiede ancora un'altra costante:

Per le varianti MAC e PIN, l'operazione XOR costituisce il passaggio finale nella creazione della chiave di sessione corrispondente. Per la variante Data, è prassi comune eseguire un ulteriore passaggio, che prevede un hash unidirezionale (per escludere qualsiasi possibilità che qualcuno possa risalire da una chiave Data a una chiave MAC). In pseudocodice:

In sintesi: per prima cosa, si ottiene una versione a 24 byte della chiave derivata utilizzando il metodo di espansione EDE3. (Questo consiste semplicemente nel copiare i primi 8 byte di una chiave a 16 byte in coda alla chiave stessa, creando una chiave a 24 byte in cui il primo e l'ultimo blocco di 8 byte sono identici.) Si utilizza quindi tale chiave per cifrare in TDES i primi 8 byte della chiave derivata a 16 byte, ottenendo così un cifrario di 8 byte, che costituisce la metà sinistra della chiave dati finale. Per ottenere la metà destra, si usa la stessa chiave a 24 byte per cifrare gli 8 byte inferiori della chiave derivata. Combinando i due cifrari da 8 byte (parte sinistra e parte destra), l'operazione è completata.

Valori di riferimento noti

Se si desidera eseguire questa procedura in proprio, può essere utile verificare i risultati confrontandoli con valori di riferimento noti. Si parta quindi da un BDK a 16 byte pari a 0123456789ABCDEFFEDCBA9876543210 (esadecimale), che è il valore di chiave di test comunemente utilizzato. Si utilizzi come valore KSN di test 629949012C0000000003. Questi due valori dovrebbero consentire di derivare un IPEK pari a D2943CCF80F42E88E23C12D1162FD547. (Fare riferimento a Parte I di questo articolo per informazioni su come derivare l'IPEK.)

Partendo dall'IPEK sopra indicato, derivando una "chiave derivata" (o chiave base DUKPT) si dovrebbero ottenere i seguenti valori:

Al primo passaggio attraverso il ramo "if" del ciclo sul contatore KSN, il valore di BaseKSN sarà 49012C0000000002 e curKey diventerà B58CDA5C7A1E9FF5E7335B988626D01A dopo generateKey().

Al secondo passaggio attraverso l'"if" del ciclo del contatore, saranno stati elaborati entrambi i bit "ON" del contatore; di conseguenza, il BaseKSN sarà 49012C0000000003 e il curKey risultante sarà 841AB7B94ED086EBC2B8A8385DA7DFCA. (Si ricordi che i bit del contatore vengono inseriti nel BaseKSN tramite OR, a partire dal bit più significativo. Se il contatore termina con 0x0F, il BaseKSN passerà da 49012C0000000008 a 49012C000000000C, poi a 49012C000000000E e infine a 49012C000000000F man mano che i bit vengono applicati in successione tramite OR.)

La "chiave derivata" sarà quindi 841AB7B94ED086EBC2B8A8385DA7DFCA.

Dopo aver applicato lo XOR con la costante data-variant, la chiave derivata diventerà 841AB7B94E2F86EBC2B8A8385D58DFCA.

Dopo aver cifrato le metà superiore e inferiore di quest'ultimo valore, utilizzando una chiave di espansione EDE3 pari a 841AB7B94E2F86EBC2B8A8385D58DFCA841AB7B94E2F86EB, si otterrà una chiave dati finale di F739AEF595D3877F731782D28BB6AC4F. In altre parole: usando la chiave EDE3 a 24 byte per cifrare 841AB7B94E2F86EB, si otterrà il testo cifrato F739AEF595D3877F; usando la stessa chiave per cifrare C2B8A8385D58DFCA, si otterrà il testo cifrato 731782D28BB6AC4F. Concatenando i due testi cifrati, il processo è completato. Si dispone ora di una chiave a 16 byte con cui è possibile decifrare i dati della transazione il cui KSN era 629949012C0000000003.

Codice di esempio: lo strumento Encrypt/Decrypt di ID TECH

Per consultare il codice sorgente completo di tutte le routine di derivazione della chiave DUKPT descritte in questa sede, si consiglia di scaricare (ed esaminare il codice sorgente del) nostro strumento basato su HTML e JavaScript Strumento di Cifratura/Decifratura, che consente di calcolare gli IPEK, derivare tutte e 3 le varianti di chiave DUKPT, cifrare o decifrare dati mediante TDES o AES, e molto altro ancora. È possibile utilizzare l'eccellente set di strumenti della console per sviluppatori di Chrome per eseguire il codice dello strumento passo dopo passo in tempo reale, ispezionare i valori delle variabili man mano che cambiano, impostare breakpoint e altro ancora. Si tratta di un ausilio didattico di straordinaria efficacia, disponibile gratuitamente. Scarica lo strumento Strumento di Cifratura/Decifratura, provalo e condividilo con i tuoi colleghi. Per quanto ne sappiamo, è l'unica implementazione DUKPT in puro JavaScript disponibile sul Web.