Merged two iclass-reader functions into one to remove duplicated code, update loclass library with hash2 algo

This commit is contained in:
Martin Holst Swende 2014-06-29 23:34:24 +02:00
parent d2d0af8ca6
commit aa41c6058a
6 changed files with 262 additions and 164 deletions

View file

@ -870,9 +870,6 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_READER_ICLASS_REPLAY:
ReaderIClass_Replay(c->arg[0], c->d.asBytes);
break;
case CMD_ICLASS_ISO14443A_GETPUBLIC:
IClass_iso14443A_GetPublic(c->arg[0]);
break;
#endif
case CMD_SIMULATE_TAG_HF_LISTEN:

View file

@ -1466,69 +1466,110 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer)
return Demod.len;
}
// Reader iClass Anticollission
void ReaderIClass(uint8_t arg0) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
void setupIclassReader()
{
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Reset trace buffer
// Reset trace buffer
iso14a_set_tracing(TRUE);
iso14a_clear_trace();
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
LED_A_ON();
}
for(;;) {
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
if (BUTTON_PRESS()) break;
// Reader iClass Anticollission
void ReaderIClass(uint8_t arg0) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
ReaderTransmitIClass(identify, 1);
if(ReaderReceiveIClass(resp) == 10) {
// Select card
memcpy(&select[1],resp,8);
ReaderTransmitIClass(select, sizeof(select));
uint8_t card_data[24]={0};
uint8_t last_csn[8]={0};
if(ReaderReceiveIClass(resp) == 10) {
Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
// Card selected, whats next... ;-)
}
}
WDT_HIT();
}
LED_A_OFF();
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
int read_status= 0;
bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
setupIclassReader();
size_t datasize = 0;
while(!BUTTON_PRESS())
{
WDT_HIT();
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
ReaderTransmitIClass(identify, 1);
if(ReaderReceiveIClass(resp) == 10) {
//Copy the Anti-collision CSN to our select-packet
memcpy(&select[1],resp,8);
//Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2],
// resp[3], resp[4], resp[5],
// resp[6], resp[7]);
//Select the card
ReaderTransmitIClass(select, sizeof(select));
if(ReaderReceiveIClass(resp) == 10) {
//Save CSN in response data
memcpy(card_data,resp,8);
datasize += 8;
//Flag that we got to at least stage 1, read CSN
read_status = 1;
// Card selected
//Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
//Save CC (e-purse) in response data
memcpy(card_data+8,resp,8);
datasize += 8;
//Got both
read_status = 2;
}
LED_B_ON();
//Send back to client, but don't bother if we already sent this
if(memcmp(last_csn, card_data, 8) != 0)
cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
//Save that we already sent this....
if(read_status == 2)
memcpy(last_csn, card_data, 8);
LED_B_OFF();
if(abort_after_read) break;
}
}
}
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
}
LED_A_OFF();
}
void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
@ -1675,89 +1716,6 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
LED_A_OFF();
}
//1. Create Method to Read sectors/blocks 0,1,2 and Send to client
void IClass_iso14443A_GetPublic(uint8_t arg0) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t card_data[24]={0};
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
int read_success= 0;
// Enable and clear the trace
iso14a_set_tracing(TRUE);
iso14a_clear_trace();
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
ReaderTransmitIClass(identify, 1);
if(ReaderReceiveIClass(resp) == 10) {
//Copy the Anti-collision CSN to our select-packet
memcpy(&select[1],resp,8);
Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
//Select the card
ReaderTransmitIClass(select, sizeof(select));
if(ReaderReceiveIClass(resp) == 10) {
Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
//Save CSN in response data
memcpy(card_data,resp,8);
//Flag that we got to at least stage 1, read CSN
read_success = 1;
// Card selected
Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
//Save CC (e-purse) in response data
memcpy(card_data+8,resp,8);
//Got both
read_success = 2;
}
}
}
}
WDT_HIT();
LED_A_OFF();
LED_B_ON();
//Send back to client
cmd_send(CMD_ACK,read_success,0,0,card_data,16);
LED_B_OFF();
}
//2. Create Read method (cut-down from above) based off responses from 1.
// Since we have the MAC could continue to use replay function.
//3. Create Write method

View file

@ -401,19 +401,30 @@ int CmdHFiClassSim(const char *Cmd)
int CmdHFiClassReader(const char *Cmd)
{
uint8_t readerType = 0;
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf iclass reader <reader type>");
PrintAndLog(" sample: hf iclass reader 0");
return 0;
}
readerType = param_get8(Cmd, 0);
PrintAndLog("--readertype:%02x", readerType);
UsbCommand c = {CMD_READER_ICLASS, {readerType}};
UsbCommand c = {CMD_READER_ICLASS, {0}};
SendCommand(&c);
UsbCommand resp;
while(!ukbhit()){
if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
PrintAndLog("isOk:%02x", isOK);
if(isOK > 0)
{
PrintAndLog("CSN: %s",sprint_hex(data,8));
}
if(isOK >= 1)
{
PrintAndLog("CC: %s",sprint_hex(data+8,8));
}else{
PrintAndLog("No CC obtained");
}
} else {
PrintAndLog("Command execute timeout");
}
}
return 0;
}
@ -464,7 +475,8 @@ int CmdHFiClassReader_Dump(const char *Cmd)
return 1;
}
UsbCommand c = {CMD_ICLASS_ISO14443A_GETPUBLIC, {0}};
UsbCommand c = {CMD_READER_ICLASS, {0}};
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE;
SendCommand(&c);
@ -479,11 +491,11 @@ int CmdHFiClassReader_Dump(const char *Cmd)
PrintAndLog("isOk:%02x", isOK);
if(isOK != 0)
if(isOK > 0)
{
PrintAndLog("CSN: %s",sprint_hex(CSN,8));
}
if(isOK == 0)
if(isOK >= 1)
{
//PrintAndLog("CC: %s",sprint_hex(CCNR,8));
diversifyKey(CSN,KEY, div_key);
@ -540,7 +552,7 @@ int CmdHFiClass_iso14443A_write(const char *Cmd)
return 1;
}
UsbCommand c = {CMD_ICLASS_ISO14443A_GETPUBLIC, {0}};
UsbCommand c = {CMD_ICLASS_ISO14443A_WRITE, {0}};
SendCommand(&c);
UsbCommand resp;

View file

@ -205,14 +205,14 @@ void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
output(k,initState,&input_32_zeroes,&out);
}
void doMAC(uint8_t *cc_nr_p, int length,uint8_t *div_key_p, uint8_t mac[4])
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4])
{
uint8_t *cc_nr;
uint8_t div_key[8];
cc_nr=(uint8_t*)malloc(length+1);
memcpy(cc_nr,cc_nr_p,length);
memcpy(div_key,div_key_p,8);
reverse_arraybytes(cc_nr,length);
BitstreamIn bitstream = {cc_nr,length * 8,0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
@ -220,10 +220,10 @@ void doMAC(uint8_t *cc_nr_p, int length,uint8_t *div_key_p, uint8_t mac[4])
MAC(div_key,bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac, dest, 4);
printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
memcpy(mac, dest, 4);
//printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
free(cc_nr);
return 1;
return;
}
int testMAC()
@ -237,7 +237,7 @@ int testMAC()
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
uint8_t calculated_mac[4] = {0};
doMAC(cc_nr, 12, div_key, calculated_mac);
doMAC(cc_nr, 12,div_key, calculated_mac);
if(memcmp(calculated_mac, correct_MAC,4) == 0)
{

View file

@ -122,7 +122,109 @@ void hash1(uint8_t csn[] , uint8_t k[])
for(i = 7; i >=0; i--)
k[i] = k[i] & 0x7F;
}
/**
Definition 14. Define the rotate key function rk : (F 82 ) 8 × N (F 82 ) 8 as
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
**/
void rk(uint8_t *key, uint8_t n, uint8_t *outp_key)
{
memcpy(outp_key, key, 8);
uint8_t j;
while(n-- > 0)
for(j=0; j < 8 ; j++)
outp_key[j] = rl(outp_key[j]);
return;
}
static des_context ctx_enc = {DES_ENCRYPT,{0}};
static des_context ctx_dec = {DES_DECRYPT,{0}};
void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
{
uint8_t key_std_format[8] = {0};
permutekey_rev(iclass_key, key_std_format);
des_setkey_dec( &ctx_dec, key_std_format);
des_crypt_ecb(&ctx_dec,input,output);
}
void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
{
uint8_t key_std_format[8] = {0};
permutekey_rev(iclass_key, key_std_format);
des_setkey_enc( &ctx_enc, key_std_format);
des_crypt_ecb(&ctx_enc,input,output);
}
/**
* @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select.
* @param key unpermuted custom key
* @param hash1 hash1
* @param key_sel output key_sel=h[hash1[i]]
*/
void hash2(uint8_t *key64, uint8_t *outp_keytable)
{
/**
*Expected:
* High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/
uint8_t key64_negated[8] = {0};
uint8_t z[8][8]={{0},{0}};
uint8_t temp_output[8]={0};
//calculate complement of key
int i;
for(i=0;i<8;i++)
key64_negated[i]= ~key64[i];
// Once again, key is on iclass-format
desencrypt_iclass(key64, key64_negated, z[0]);
prnlog("\nHigh security custom key (Kcus):");
printvar("z0 ", z[0],8);
uint8_t y[8][8]={{0},{0}};
// y[0]=DES_dec(z[0],~key)
// Once again, key is on iclass-format
desdecrypt_iclass(z[0], key64_negated, y[0]);
printvar("y0 ", y[0],8);
for(i=1; i<8; i++)
{
// z [i] = DES dec (rk(K cus , i), z [i1] )
rk(key64, i, temp_output);
//y [i] = DES enc (rk(K cus , i), y [i1] )
desdecrypt_iclass(temp_output,z[i-1], z[i]);
desencrypt_iclass(temp_output,y[i-1], y[i]);
}
if(outp_keytable != NULL)
{
for(i = 0 ; i < 8 ; i++)
{
memcpy(outp_keytable+i*16,y[i],8);
memcpy(outp_keytable+8+i*16,z[i],8);
}
}else
{
printarr_human_readable("hash2", outp_keytable,128);
}
}
/**
* @brief Reads data from the iclass-reader-attack dump file.
@ -254,7 +356,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[])
//Diversify
diversifyKey(item.csn, key_sel_p, div_key);
//Calc mac
doMAC(item.cc_nr, div_key,calculated_MAC);
doMAC(item.cc_nr,12, div_key,calculated_MAC);
if(memcmp(calculated_MAC, item.mac, 4) == 0)
{
@ -515,7 +617,35 @@ int _test_iclass_key_permutation()
int testElite()
{
prnlog("[+] Testing iClass Elite functinality...");
prnlog("[+] Testing key diversification ...");
prnlog("[+] Testing hash2");
uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39};
/**
*Expected:
* High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
*/
uint8_t keytable[128] = {0};
hash2(k_cus, keytable);
printarr_human_readable("Hash2", keytable, 128);
if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95)
{
prnlog("[+] Hash2 looks fine...");
}
prnlog("[+] Testing key diversification ...");
int errors = 0 ;
errors +=_test_iclass_key_permutation();

View file

@ -118,7 +118,6 @@ typedef struct {
#define CMD_SIMULATE_TAG_ICLASS 0x0393
#define CMD_READER_ICLASS 0x0394
#define CMD_READER_ICLASS_REPLAY 0x0395
#define CMD_ICLASS_ISO14443A_GETPUBLIC 0x0396
#define CMD_ICLASS_ISO14443A_WRITE 0x0397
// For measurements of the antenna tuning
@ -165,6 +164,8 @@ typedef struct {
#define FLAG_NR_AR_ATTACK 0x08
//Iclass reader flags
#define FLAG_ICLASS_READER_ONLY_ONCE 0x01
// CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions:
/* Whether a bootloader that understands the common_area is present */