diff --git a/CHANGELOG.md b/CHANGELOG.md index f32ea1497..66fa27ac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Port 'hf mfdes' Authentification to CommandNG structure, fix auth session key (@bkerler) - Updates `hf mfdes` functions, improved logging and added new commands (@bkerler) - Updated 'legic.lua' and 'legic_clone.lua' script - works with current command set (@Pizza_4u) - Rewrote `hf mfdes` functions and added apdu debugging (@bkerler) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5bec32364..b44dbc5c5 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1271,7 +1271,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_DESFIRE_AUTH1: { - MifareDES_Auth1(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + MifareDES_Auth1(packet->data.asBytes); break; } case CMD_HF_DESFIRE_AUTH2: { @@ -1287,7 +1287,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_DESFIRE_COMMAND: { - MifareSendCommand(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + MifareSendCommand(packet->data.asBytes); break; } case CMD_HF_MIFARE_NACK_DETECT: { diff --git a/armsrc/des.c b/armsrc/des.c index ccd32be7d..af10423f3 100644 --- a/armsrc/des.c +++ b/armsrc/des.c @@ -388,30 +388,6 @@ void tdes_dec(void *out, void *in, const uint8_t *key) { des_dec(out, out, (uint8_t *)key + 0); } -void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { - - if (length % 8) return; - - uint8_t i; - uint8_t *tin = (uint8_t *) in; - uint8_t *tout = (uint8_t *) out; - - while (length > 0) { - for (i = 0; i < 8; i++) - tout[i] = (unsigned char)(tin[i] ^ iv[i]); - - des_enc(tout, tin, (uint8_t *)key + 0); - des_dec(tout, tout, (uint8_t *)key + 8); - des_enc(tout, tout, (uint8_t *)key + 0); - - memcpy(iv, tout, 8); - - tin += 8; - tout += 8; - length -= 8; - } -} - void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { if (length % 8) return; @@ -439,6 +415,82 @@ void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, un } } +void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { + + if (length % 8) return; + + uint8_t i; + uint8_t *tin = (uint8_t *) in; + uint8_t *tout = (uint8_t *) out; + + while (length > 0) { + for (i = 0; i < 8; i++) + tout[i] = (unsigned char)(tin[i] ^ iv[i]); + + des_enc(tout, tin, (uint8_t *)key + 0); + des_dec(tout, tout, (uint8_t *)key + 8); + des_enc(tout, tout, (uint8_t *)key + 0); + + memcpy(iv, tout, 8); + + tin += 8; + tout += 8; + length -= 8; + } +} + +void tdes_3key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { + + if (length % 8) return; + + uint8_t i; + uint8_t *tin = (uint8_t *) in; + uint8_t *tout = (uint8_t *) out; + + while (length > 0) { + for (i = 0; i < 8; i++) + tout[i] = (unsigned char)(tin[i] ^ iv[i]); + + des_enc(tout, tin, (uint8_t *)key + 0); + des_dec(tout, tout, (uint8_t *)key + 8); + des_enc(tout, tout, (uint8_t *)key + 16); + + memcpy(iv, tout, 8); + + tin += 8; + tout += 8; + length -= 8; + } +} + +void tdes_3key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { + + if (length % 8) return; + + uint8_t i; + unsigned char temp[8]; + uint8_t *tin = (uint8_t *) in; + uint8_t *tout = (uint8_t *) out; + + while (length > 0) { + memcpy(temp, tin, 8); + + des_dec(tout, tin, (uint8_t *)key + 0); + des_enc(tout, tout, (uint8_t *)key + 8); + des_dec(tout, tout, (uint8_t *)key + 16); + + for (i = 0; i < 8; i++) + tout[i] = (unsigned char)(tout[i] ^ iv[i]); + + memcpy(iv, temp, 8); + + tin += 8; + tout += 8; + length -= 8; + } +} + + /******************************************************************************/ diff --git a/armsrc/des.h b/armsrc/des.h index 8cf41b8ae..1a0549606 100644 --- a/armsrc/des.h +++ b/armsrc/des.h @@ -104,6 +104,8 @@ void tdes_dec(void *out, void *in, const uint8_t *key); void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]); void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]); +void tdes_3key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]); +void tdes_3key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]); // Copied from des.h in desfire imp. typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */ diff --git a/armsrc/desfire.h b/armsrc/desfire.h index e753106e7..507bda424 100644 --- a/armsrc/desfire.h +++ b/armsrc/desfire.h @@ -61,7 +61,8 @@ enum DESFIRE_CRYPTOALGO { T_DES = 0x00, T_3DES = 0x01, T_3K3DES = 0x02, - T_AES = 0x03 + T_AES = 0x03, + T_2K3DES = 0x04 }; diff --git a/armsrc/desfire_key.c b/armsrc/desfire_key.c index 272f18562..60219260a 100644 --- a/armsrc/desfire_key.c +++ b/armsrc/desfire_key.c @@ -19,6 +19,7 @@ #include "desfire_key.h" #include "string.h" +#include "dbprint.h" static inline void update_key_schedules(desfirekey_t key); @@ -74,6 +75,14 @@ void Desfire_3k3des_key_new(const uint8_t value[24], desfirekey_t key) { Desfire_3k3des_key_new_with_version(data, key); } +void Desfire_2k3des_key_new_with_version(const uint8_t value[16], desfirekey_t key) { + if (key != NULL) { + key->type = T_2K3DES; + memcpy(key->data, value, 16); + update_key_schedules(key); + } +} + void Desfire_3k3des_key_new_with_version(const uint8_t value[24], desfirekey_t key) { if (key != NULL) { key->type = T_3K3DES; @@ -136,6 +145,13 @@ void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfire memcpy(buffer + 12, rndb + 4, 4); Desfire_3des_key_new_with_version(buffer, key); break; + case T_2K3DES: + memcpy(buffer, rnda, 4); + memcpy(buffer + 4, rndb, 4); + memcpy(buffer + 8, rnda + 4, 4); + memcpy(buffer + 12, rndb + 4, 4); + Desfire_2k3des_key_new_with_version(buffer, key); + break; case T_3K3DES: memcpy(buffer, rnda, 4); memcpy(buffer + 4, rndb, 4); diff --git a/armsrc/desfire_key.h b/armsrc/desfire_key.h index 603fd5663..286d47178 100644 --- a/armsrc/desfire_key.h +++ b/armsrc/desfire_key.h @@ -9,6 +9,7 @@ void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key); void Desfire_3des_key_new_with_version(const uint8_t value[16], desfirekey_t key); void Desfire_3k3des_key_new(const uint8_t value[24], desfirekey_t key); void Desfire_3k3des_key_new_with_version(const uint8_t value[24], desfirekey_t key); +void Desfire_2k3des_key_new_with_version(const uint8_t value[16], desfirekey_t key); void Desfire_aes_key_new(const uint8_t value[16], desfirekey_t key); void Desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version, desfirekey_t key); uint8_t Desfire_key_get_version(desfirekey_t key); diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index aa70e5ccb..10a7a3204 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -52,29 +52,38 @@ bool InitDesfireCard() { return true; } -void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) { +typedef struct { + uint8_t len; + uint8_t data[RECEIVE_SIZE]; +} cmdres_t; + +void MifareSendCommand(uint8_t *datain) { + struct p { + uint8_t flags; + uint8_t datalen; + uint8_t datain[FRAME_PAYLOAD_SIZE]; + } PACKED; + struct p *payload = (struct p *) datain; - uint8_t flags = arg0; - size_t datalen = arg1; uint8_t resp[RECEIVE_SIZE]; memset(resp, 0, sizeof(resp)); if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf(" flags : %02X", flags); - Dbprintf(" len : %02X", datalen); - print_result(" RX : ", datain, datalen); + Dbprintf(" flags : %02X", payload->flags); + Dbprintf(" len : %02X", payload->datalen); + print_result(" RX : ", payload->datain, payload->datalen); } - if (flags & CLEARTRACE) + if (payload->flags & CLEARTRACE) clear_trace(); - if (flags & INIT) { + if (payload->flags & INIT) { if (!InitDesfireCard()) { return; } } - int len = DesfireAPDU(datain, datalen, resp); + int len = DesfireAPDU(payload->datain, payload->datalen, resp); if (DBGLEVEL >= DBG_EXTENDED) print_result("RESP <--: ", resp, len); @@ -83,10 +92,18 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) { return; } - if (flags & DISCONNECT) + if (payload->flags & DISCONNECT) OnSuccess(); - reply_mix(CMD_ACK, 1, len, 0, resp, len); + //reply_mix(CMD_ACK, 1, len, 0, resp, len); + LED_B_ON(); + + + cmdres_t rpayload; + rpayload.len = len; + memcpy(rpayload.data, resp, rpayload.len); + reply_ng(CMD_HF_DESFIRE_COMMAND, PM3_SUCCESS, (uint8_t *)&rpayload, sizeof(rpayload)); + LED_B_OFF(); } void MifareDesfireGetInformation() { @@ -117,7 +134,7 @@ void MifareDesfireGetInformation() { clear_trace(); set_tracing(true); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - + // reset the pcb_blocknum, pcb_blocknum = 0; @@ -188,504 +205,417 @@ void MifareDesfireGetInformation() { OnSuccess(); } -void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // mode = arg0 - // algo = arg1 - // keyno = arg2 +typedef struct { + uint8_t sessionkeylen; + uint8_t sessionkey[24]; +} authres_t; + +void MifareDES_Auth1(uint8_t *datain) { int len = 0; - //uint8_t PICC_MASTER_KEY8[8] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47}; - uint8_t PICC_MASTER_KEY16[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; - //uint8_t null_key_data16[16] = {0x00}; - //uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; - //uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; - - uint8_t resp[256] = {0x00}; - - size_t datalen = datain[0]; - - uint8_t cmd[40] = {0x00}; - uint8_t encRndB[16] = {0x00}; - uint8_t decRndB[16] = {0x00}; - uint8_t both[32] = {0x00}; - - //InitDesfireCard(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); + struct p { + uint8_t mode; + uint8_t algo; + uint8_t keyno; + uint8_t keylen; + uint8_t key[24]; + } PACKED; + struct p *payload = (struct p *) datain; // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) // 4 different crypto arg1 DES, 3DES, 3K3DES, AES // 3 different communication modes, PLAIN,MAC,CRYPTO - // des, key 0, - switch (arg0) { - case 1: { - uint8_t keybytes[16]; - uint8_t RndA[8] = {0x00}; - uint8_t RndB[8] = {0x00}; + mbedtls_aes_context ctx; - if (arg1 == 2) { - if (datain[1] == 0xff) { - memcpy(keybytes, PICC_MASTER_KEY16, 16); - } else { - memcpy(keybytes, datain + 1, datalen); - } - } else { - if (arg1 == 1) { - if (datain[1] == 0xff) { - uint8_t null_key_data8[8] = {0x00}; - memcpy(keybytes, null_key_data8, 8); - } else { - memcpy(keybytes, datain + 1, datalen); - } - } - } + uint8_t keybytes[24]; + uint8_t resp[256] = {0x00}; + uint8_t cmd[40] = {0x00}; - struct desfire_key defaultkey = {0}; - desfirekey_t key = &defaultkey; + // Crypt constants + uint8_t IV[16] = {0x00}; + uint8_t RndA[16] = {0x00}; + uint8_t RndB[16] = {0x00}; + uint8_t encRndB[16] = {0x00}; + uint8_t rotRndB[16] = {0x00}; //RndB' + uint8_t both[32] = {0x00}; // ek/dk_keyNo(RndA+RndB') - if (arg1 == 2) - Desfire_3des_key_new_with_version(keybytes, key); - else if (arg1 == 1) - Desfire_des_key_new(keybytes, key); + // Generate Random Value + uint32_t value = prng_successor(GetTickCount(), 32); + num_to_bytes(value, 4, &RndA[0]); + value = prng_successor(GetTickCount(), 32); + num_to_bytes(value, 4, &RndA[4]); + value = prng_successor(GetTickCount(), 32); + num_to_bytes(value, 4, &RndA[8]); + value = prng_successor(GetTickCount(), 32); + num_to_bytes(value, 4, &RndA[12]); - cmd[0] = 0x90; - cmd[1] = AUTHENTICATE; - cmd[2] = 0x0; - cmd[3] = 0x0; - cmd[4] = 0x1; - cmd[5] = arg2; //keynumber - cmd[6] = 0x0; - len = DesfireAPDU(cmd, 7, resp); + // Default Keys + uint8_t PICC_MASTER_KEY8[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t PICC_MASTER_KEY16[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t PICC_MASTER_KEY24[24] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + //uint8_t null_key_data16[16] = {0x00}; + //uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; + //uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; - if (!len) { - if (DBGLEVEL >= DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } - if (resp[2] == (uint8_t)0xaf) { - DbpString("Authentication failed. Invalid key number."); - OnError(3); - return; - } + //InitDesfireCard(); - memcpy(encRndB, resp + 1, 8); - if (arg1 == 2) - tdes_dec(&decRndB, &encRndB, key->data); - else if (arg1 == 1) - des_dec(&decRndB, &encRndB, key->data); + // Part 1 + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); - memcpy(RndB, decRndB, 8); - rol(decRndB, 8); - - // This should be random - uint8_t decRndA[8] = {0x00}; - uint32_t value = prng_successor(GetTickCount(), 32); - num_to_bytes(value, 4, &decRndA[0]); - value = prng_successor(GetTickCount(), 32); - num_to_bytes(value, 4, &decRndA[4]); - - memcpy(RndA, decRndA, 8); - uint8_t encRndA[8] = {0x00}; - - if (arg1 == 2) - tdes_dec(&encRndA, &decRndA, key->data); - else if (arg1 == 1) - des_dec(&encRndA, &decRndA, key->data); - - memcpy(both, encRndA, 8); - - for (int x = 0; x < 8; x++) { - decRndB[x] = decRndB[x] ^ encRndA[x]; - - } - - if (arg1 == 2) - tdes_dec(&encRndB, &decRndB, key->data); - else if (arg1 == 1) - des_dec(&encRndB, &decRndB, key->data); - - memcpy(both + 8, encRndB, 8); - - cmd[0] = 0x90; - cmd[1] = ADDITIONAL_FRAME; - cmd[2] = 0x00; - cmd[3] = 0x00; - cmd[4] = 0x10; - memcpy(cmd + 5, both, 16); - cmd[16 + 5] = 0x0; - len = DesfireAPDU(cmd, 5 + 16 + 1, resp); - if (!len) { - if (DBGLEVEL >= DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } - - if (resp[len - 3] == 0x00) { - - struct desfire_key sessionKey = {0}; - desfirekey_t skey = &sessionKey; - Desfire_session_key_new(RndA, RndB, key, skey); - //print_result("SESSION : ", skey->data, 8); - - memcpy(encRndA, resp + 1, 8); - - if (arg1 == 2) - tdes_dec(&encRndA, &encRndA, key->data); - else if (arg1 == 1) - des_dec(&encRndA, &encRndA, key->data); - - rol(decRndA, 8); - for (int x = 0; x < 8; x++) { - if (decRndA[x] != encRndA[x]) { - DbpString("Authentication failed. Cannot verify PICC."); - OnError(4); - return; - } - } - - //Change the selected key to a new value. - - /* - // Current key is a 3DES key, change it to a DES key - if (arg1 == 2) { - cmd[0] = 0x90; - cmd[1] = CHANGE_KEY; - cmd[2] = arg2; - - uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; - - uint8_t first, second; - uint8_t buff1[8] = {0x00}; - uint8_t buff2[8] = {0x00}; - uint8_t buff3[8] = {0x00}; - - memcpy(buff1,newKey, 8); - memcpy(buff2,newKey + 8, 8); - - compute_crc(CRC_14443_A, newKey, 16, &first, &second); - memcpy(buff3, &first, 1); - memcpy(buff3 + 1, &second, 1); - - tdes_dec(&buff1, &buff1, skey->data); - memcpy(cmd+2,buff1,8); - - for (int x = 0; x < 8; x++) { - buff2[x] = buff2[x] ^ buff1[x]; - } - tdes_dec(&buff2, &buff2, skey->data); - memcpy(cmd+10,buff2,8); - - for (int x = 0; x < 8; x++) { - buff3[x] = buff3[x] ^ buff2[x]; - } - tdes_dec(&buff3, &buff3, skey->data); - memcpy(cmd+19,buff3,8); - - // The command always times out on the first attempt, this will retry until a response - // is recieved. - len = 0; - while(!len) { - len = DesfireAPDU(cmd,27,resp); - } - - } else { - // Current key is a DES key, change it to a 3DES key - if (arg1 == 1) { - cmd[0] = 0x90; - cmd[1] = CHANGE_KEY; - cmd[2] = arg2; - - uint8_t newKey[16] = {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; - - uint8_t first, second; - uint8_t buff1[8] = {0x00}; - uint8_t buff2[8] = {0x00}; - uint8_t buff3[8] = {0x00}; - - memcpy(buff1,newKey, 8); - memcpy(buff2,newKey + 8, 8); - - compute_crc(CRC_14443_A, newKey, 16, &first, &second); - memcpy(buff3, &first, 1); - memcpy(buff3 + 1, &second, 1); - - des_dec(&buff1, &buff1, skey->data); - memcpy(cmd+3,buff1,8); - - for (int x = 0; x < 8; x++) { - buff2[x] = buff2[x] ^ buff1[x]; - } - des_dec(&buff2, &buff2, skey->data); - memcpy(cmd+11,buff2,8); - - for (int x = 0; x < 8; x++) { - buff3[x] = buff3[x] ^ buff2[x]; - } - des_dec(&buff3, &buff3, skey->data); - memcpy(cmd+19,buff3,8); - - // The command always times out on the first attempt, this will retry until a response - // is recieved. - len = 0; - while(!len) { - len = DesfireAPDU(cmd,27,resp); - } - } - } - */ - - //OnSuccess(); - if (arg1 == 2) - reply_old(CMD_ACK, 1, 0, 0, skey->data, 16); - else if (arg1 == 1) - reply_old(CMD_ACK, 1, 0, 0, skey->data, 8); - } else { - DbpString("Authentication failed."); - OnError(6); - return; - } + if (payload->key == NULL) { + if (payload->algo == MFDES_AUTH_DES) { + memcpy(keybytes, PICC_MASTER_KEY8, 8); + } else if (payload->algo == MFDES_ALGO_AES || payload->algo == MFDES_ALGO_3DES || payload->algo == MFDES_ALGO_2K3DES) { + memcpy(keybytes, PICC_MASTER_KEY16, 16); + } else if (payload->algo == MFDES_ALGO_3DES) { + memcpy(keybytes, PICC_MASTER_KEY24, 24); } - break; - case 2: { - //SendDesfireCommand(AUTHENTICATE_ISO, &arg2, resp); - uint8_t keybytes[16]; - uint8_t RndA[8] = {0x00}; - uint8_t RndB[8] = {0x00}; + } else { + memcpy(keybytes, payload->key, payload->keylen); + } - if (arg1 == 2) { - if (datain[1] == 0xff) { - memcpy(keybytes, PICC_MASTER_KEY16, 16); - } else { - memcpy(keybytes, datain + 1, datalen); - } - } else { - if (arg1 == 1) { - if (datain[1] == 0xff) { - uint8_t null_key_data8[8] = {0x00}; - memcpy(keybytes, null_key_data8, 8); - } else { - memcpy(keybytes, datain + 1, datalen); - } - } - } + struct desfire_key defaultkey = {0}; + desfirekey_t key = &defaultkey; - struct desfire_key defaultkey = {0}; - desfirekey_t key = &defaultkey; + if (payload->algo == MFDES_ALGO_AES) { + mbedtls_aes_init(&ctx); + Desfire_aes_key_new(keybytes, key); + } else if (payload->algo == MFDES_ALGO_3DES) { + Desfire_3des_key_new_with_version(keybytes, key); + } else if (payload->algo == MFDES_ALGO_DES) { + Desfire_des_key_new(keybytes, key); + } else if (payload->algo == MFDES_ALGO_2K3DES) { + Desfire_2k3des_key_new_with_version(keybytes, key); + } else if (payload->algo == MFDES_ALGO_3K3DES) { + Desfire_3k3des_key_new_with_version(keybytes, key); + } - if (arg1 == 2) - Desfire_3des_key_new_with_version(keybytes, key); - else if (arg1 == 1) - Desfire_des_key_new(keybytes, key); + uint8_t subcommand = AUTHENTICATE; - cmd[0] = AUTHENTICATE; - cmd[1] = arg2; //keynumber - len = DesfireAPDU(cmd, 2, resp); + if (payload->mode == MFDES_AUTH_AES) + subcommand = AUTHENTICATE_AES; + else if (payload->mode == MFDES_AUTH_ISO) + subcommand = AUTHENTICATE_ISO; - if (!len) { - if (DBGLEVEL >= DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } + if (payload->mode != MFDES_AUTH_PICC) { + // Let's send our auth command + cmd[0] = 0x90; + cmd[1] = subcommand; + cmd[2] = 0x0; + cmd[3] = 0x0; + cmd[4] = 0x1; + cmd[5] = payload->keyno; + cmd[6] = 0x0; + len = DesfireAPDU(cmd, 7, resp); + } else { + cmd[0] = AUTHENTICATE; + cmd[1] = payload->keyno; + len = DesfireAPDU(cmd, 2, resp); + } - if (resp[2] == (uint8_t)0xaf) { - DbpString("Authentication failed. Invalid key number."); - OnError(3); - return; - } - - memcpy(encRndB, resp + 2, 8); - if (arg1 == 2) - tdes_dec(&decRndB, &encRndB, key->data); - else if (arg1 == 1) - des_dec(&decRndB, &encRndB, key->data); - - memcpy(RndB, decRndB, 8); - rol(decRndB, 8); - - // This should be random - uint8_t decRndA[8] = {0x00}; - uint32_t value = prng_successor(GetTickCount(), 32); - num_to_bytes(value, 4, &decRndA[0]); - value = prng_successor(GetTickCount(), 32); - num_to_bytes(value, 4, &decRndA[4]); - - memcpy(RndA, decRndA, 8); - uint8_t encRndA[8] = {0x00}; - - if (arg1 == 2) - tdes_dec(&encRndA, &decRndA, key->data); - else if (arg1 == 1) - des_dec(&encRndA, &decRndA, key->data); - - memcpy(both, encRndA, 8); - - for (int x = 0; x < 8; x++) { - decRndB[x] = decRndB[x] ^ encRndA[x]; - - } - - if (arg1 == 2) - tdes_dec(&encRndB, &decRndB, key->data); - else if (arg1 == 1) - des_dec(&encRndB, &decRndB, key->data); - - memcpy(both + 8, encRndB, 8); - - cmd[0] = ADDITIONAL_FRAME; - memcpy(cmd + 1, both, 16); - len = DesfireAPDU(cmd, 1 + 16, resp); - if (!len) { - if (DBGLEVEL >= DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } - - if (resp[1] == 0x00) { - struct desfire_key sessionKey = {0}; - desfirekey_t skey = &sessionKey; - Desfire_session_key_new(RndA, RndB, key, skey); - //print_result("SESSION : ", skey->data, 8); - - memcpy(encRndA, resp + 2, 8); - - if (arg1 == 2) - tdes_dec(&encRndA, &encRndA, key->data); - else if (arg1 == 1) - des_dec(&encRndA, &encRndA, key->data); - - rol(decRndA, 8); - for (int x = 0; x < 8; x++) { - if (decRndA[x] != encRndA[x]) { - DbpString("Authentication failed. Cannot verify PICC."); - OnError(4); - return; - } - } - - //OnSuccess(); - if (arg1 == 2) - reply_old(CMD_ACK, 1, 0, 0, skey->data, 16); - else if (arg1 == 1) - reply_old(CMD_ACK, 1, 0, 0, skey->data, 8); - } else { - DbpString("Authentication failed."); - OnError(6); - return; - } + if (!len) { + if (DBGLEVEL >= DBG_ERROR) { + DbpString("Authentication failed. Card timeout."); } - break; - case 3: { - //defaultkey - uint8_t keybytes[16] = {0x00}; - if (datain[1] == 0xff) { - memcpy(keybytes, PICC_MASTER_KEY16, 16); - } else { - memcpy(keybytes, datain + 1, datalen); + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 3); + return; + } + + if (resp[2] == (uint8_t)0xaf) { + DbpString("Authentication failed. Invalid key number."); + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 3); + return; + } + + int expectedlen = 1 + 8 + 2 + 2; + if (payload->algo == MFDES_ALGO_AES || payload->algo == MFDES_ALGO_3K3DES) { + expectedlen = 1 + 16 + 2 + 2; + } + + if (len != expectedlen) { + if (DBGLEVEL >= DBG_ERROR) { + DbpString("Authentication failed. Length of answer doesn't match algo."); + print_result("Res-Buffer: ", resp, len); + } + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 3); + return; + } + + // Part 2 + if (payload->mode != MFDES_AUTH_PICC) { + memcpy(encRndB, resp + 1, payload->keylen); + } else { + memcpy(encRndB, resp + 2, payload->keylen); + } + + // Part 3 + if (payload->algo == MFDES_ALGO_AES) { + if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { + if (DBGLEVEL >= DBG_EXTENDED) { + DbpString("mbedtls_aes_setkey_dec failed"); } + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 7); + return; + } + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, 16, IV, encRndB, RndB); + } else if (payload->algo == MFDES_ALGO_3DES) + tdes_dec(RndB, encRndB, key->data); + else if (payload->algo == MFDES_ALGO_DES) + des_dec(RndB, encRndB, key->data); + else if (payload->algo == MFDES_ALGO_2K3DES) + tdes_2key_dec(RndB, encRndB, 8, key->data, IV); + else if (payload->algo == MFDES_ALGO_3K3DES) + tdes_3key_dec(RndB, encRndB, 16, key->data, IV); - struct desfire_key defaultkey = {0x00}; - desfirekey_t key = &defaultkey; - Desfire_aes_key_new(keybytes, key); + // - Rotate RndB by 8 bits + memcpy(rotRndB, RndB, payload->keylen); + rol(rotRndB, payload->keylen); - mbedtls_aes_context ctx; - uint8_t IV[16] = {0x00}; - mbedtls_aes_init(&ctx); + uint8_t encRndA[16] = {0x00}; - cmd[0] = 0x90; - cmd[1] = AUTHENTICATE_AES; - cmd[2] = 0x0; - cmd[3] = 0x0; - cmd[4] = 0x1; - cmd[5] = arg2; //keynumber - cmd[6] = 0x0; - len = DesfireAPDU(cmd, 7, resp); - if (!len) { - if (DBGLEVEL >= DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } + // - Encrypt our response + if (payload->mode == MFDES_AUTH_DES || payload->mode == MFDES_AUTH_ISO || payload->mode == MFDES_AUTH_PICC) { + if (payload->algo == MFDES_ALGO_3DES) { + tdes_dec(encRndA, RndA, key->data); + memcpy(both, encRndA, 8); + } else if (payload->algo == MFDES_ALGO_DES) { + des_dec(encRndA, RndA, key->data); + memcpy(both, encRndA, 8); + } else if (payload->algo == MFDES_ALGO_2K3DES) { + tdes_2key_dec(encRndA, RndA, 8, key->data, IV); + memcpy(both, encRndA, 8); + } else if (payload->algo == MFDES_ALGO_3K3DES) { + tdes_3key_dec(encRndA, RndA, 16, key->data, IV); + memcpy(both, encRndA, 16); + } - memcpy(encRndB, resp + 1, 16); - // dekryptera tagnonce. - if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { - if (DBGLEVEL >= DBG_EXTENDED) { - DbpString("mbedtls_aes_setkey_dec failed"); - } - OnError(7); - return; - } - mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, 16, IV, encRndB, decRndB); - rol(decRndB, 16); - uint8_t nonce[16] = {0x00}; - uint32_t val = prng_successor(GetTickCount(), 32); - num_to_bytes(val, 4, &nonce[0]); - val = prng_successor(GetTickCount(), 32); - num_to_bytes(val, 4, &nonce[4]); - val = prng_successor(GetTickCount(), 32); - num_to_bytes(val, 4, &nonce[8]); - val = prng_successor(GetTickCount(), 32); - num_to_bytes(val, 4, &nonce[12]); - memcpy(both, nonce, 16); - memcpy(both + 16, decRndB, 16); - uint8_t encBoth[32] = {0x00}; + for (int x = 0; x < 8; x++) { + rotRndB[x] = rotRndB[x] ^ encRndA[x]; + } + + if (payload->algo == MFDES_ALGO_3DES) { + tdes_dec(encRndB, rotRndB, key->data); + memcpy(both + 8, encRndB, 8); + } else if (payload->algo == MFDES_ALGO_DES) { + des_dec(encRndB, rotRndB, key->data); + memcpy(both + 8, encRndB, 8); + } else if (payload->algo == MFDES_ALGO_2K3DES) { + tdes_2key_dec(encRndB, rotRndB, 8, key->data, IV); + memcpy(both + 8, encRndB, 8); + } else if (payload->algo == MFDES_ALGO_3K3DES) { + tdes_3key_dec(encRndB, rotRndB, 16, key->data, IV); + memcpy(both + 16, encRndB, 16); + } + + } else if (payload->mode == MFDES_AUTH_AES) { + uint8_t tmp[32] = {0x00}; + memcpy(tmp, RndA, 16); + memcpy(tmp + 16, rotRndB, 16); + if (payload->algo == MFDES_ALGO_AES) { if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) { if (DBGLEVEL >= DBG_EXTENDED) { DbpString("mbedtls_aes_setkey_enc failed"); } - OnError(7); + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 7); return; } - mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, both, encBoth); - - cmd[0] = 0x90; - cmd[1] = ADDITIONAL_FRAME; - cmd[2] = 0x00; - cmd[3] = 0x00; - cmd[4] = 0x20; - memcpy(cmd + 5, encBoth, 32); - cmd[32 + 5] = 0x0; - - len = DesfireAPDU(cmd, 5 + 32 + 1, resp); - if (!len) { - if (DBGLEVEL >= DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } - - if ((resp[1 + 16] == 0x91) && (resp[1 + 16 + 1] == 0x00)) { - // Create AES Session key - struct desfire_key sessionKey = {0}; - desfirekey_t skey = &sessionKey; - Desfire_session_key_new(nonce, decRndB, key, skey); - print_result("SESSION : ", skey->data, 16); - } else { - DbpString("Authentication failed."); - OnError(7); - return; - } - - break; + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, tmp, both); } } + int bothlen = 16; + if (payload->algo == MFDES_ALGO_AES || payload->algo == MFDES_ALGO_3K3DES) { + bothlen = 32; + } + if (payload->mode != MFDES_AUTH_PICC) { + cmd[0] = 0x90; + cmd[1] = ADDITIONAL_FRAME; + cmd[2] = 0x00; + cmd[3] = 0x00; + cmd[4] = bothlen; + memcpy(cmd + 5, both, bothlen); + cmd[bothlen + 5] = 0x0; + len = DesfireAPDU(cmd, 5 + bothlen + 1, resp); + } else { + cmd[0] = ADDITIONAL_FRAME; + memcpy(cmd + 1, both, 16); + len = DesfireAPDU(cmd, 1 + 16, resp); + } + + if (!len) { + if (DBGLEVEL >= DBG_ERROR) { + DbpString("Authentication failed. Card timeout."); + } + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 3); + return; + } + + if (payload->mode != MFDES_AUTH_PICC) { + if ((resp[len - 4] != 0x91) || (resp[len - 3] != 0x00)) { + DbpString("Authentication failed."); + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 6); + return; + } + } else { + if (resp[1] != 0x00) { + DbpString("Authentication failed."); + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 6); + return; + } + } + + // Part 4 + struct desfire_key sessionKey = {0}; + desfirekey_t skey = &sessionKey; + Desfire_session_key_new(RndA, RndB, key, skey); + if (DBGLEVEL >= DBG_EXTENDED) + print_result("SESSIONKEY : ", sessionKey.data, payload->keylen); + + if (payload->mode != MFDES_AUTH_PICC) { + memcpy(encRndA, resp + 1, payload->keylen); + } else { + memcpy(encRndA, resp + 2, payload->keylen); + } + + if (payload->mode == MFDES_AUTH_DES || payload->mode == MFDES_AUTH_PICC) { + if (payload->algo == MFDES_ALGO_3DES) + tdes_dec(encRndA, encRndA, key->data); + else if (payload->algo == MFDES_ALGO_DES) + des_dec(encRndA, encRndA, key->data); + else if (payload->algo == MFDES_ALGO_2K3DES) + tdes_2key_dec(encRndA, encRndA, 8, key->data, IV); + else if (payload->algo == MFDES_ALGO_3K3DES) + tdes_3key_dec(encRndA, encRndA, 16, key->data, IV); + } else if (payload->mode == MFDES_AUTH_AES) { + if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { + if (DBGLEVEL >= DBG_EXTENDED) { + DbpString("mbedtls_aes_setkey_dec failed"); + } + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 7); + return; + } + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, 16, IV, encRndA, encRndA); + } + + rol(RndA, payload->keylen); + if (DBGLEVEL >= DBG_EXTENDED) { + print_result("RndA : ", RndA, payload->keylen); + print_result("RndB: ", RndB, payload->keylen); + print_result("encRndA : ", encRndA, payload->keylen); + } + for (int x = 0; x < payload->keylen; x++) { + if (RndA[x] != encRndA[x]) { + DbpString("Authentication failed. Cannot verify Session Key."); + OnErrorNG(CMD_HF_DESFIRE_AUTH1, 4); + return; + } + } + //Change the selected key to a new value. + + /* + // Current key is a 3DES key, change it to a DES key + if (payload->algo == 2) { + cmd[0] = 0x90; + cmd[1] = CHANGE_KEY; + cmd[2] = payload->keyno; + + uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; + + uint8_t first, second; + uint8_t buff1[8] = {0x00}; + uint8_t buff2[8] = {0x00}; + uint8_t buff3[8] = {0x00}; + + memcpy(buff1,newKey, 8); + memcpy(buff2,newKey + 8, 8); + + compute_crc(CRC_14443_A, newKey, 16, &first, &second); + memcpy(buff3, &first, 1); + memcpy(buff3 + 1, &second, 1); + + tdes_dec(&buff1, &buff1, skey->data); + memcpy(cmd+2,buff1,8); + + for (int x = 0; x < 8; x++) { + buff2[x] = buff2[x] ^ buff1[x]; + } + tdes_dec(&buff2, &buff2, skey->data); + memcpy(cmd+10,buff2,8); + + for (int x = 0; x < 8; x++) { + buff3[x] = buff3[x] ^ buff2[x]; + } + tdes_dec(&buff3, &buff3, skey->data); + memcpy(cmd+19,buff3,8); + + // The command always times out on the first attempt, this will retry until a response + // is recieved. + len = 0; + while(!len) { + len = DesfireAPDU(cmd,27,resp); + } + + } else { + // Current key is a DES key, change it to a 3DES key + if (payload->algo == 1) { + cmd[0] = 0x90; + cmd[1] = CHANGE_KEY; + cmd[2] = payload->keyno; + + uint8_t newKey[16] = {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + + uint8_t first, second; + uint8_t buff1[8] = {0x00}; + uint8_t buff2[8] = {0x00}; + uint8_t buff3[8] = {0x00}; + + memcpy(buff1,newKey, 8); + memcpy(buff2,newKey + 8, 8); + + compute_crc(CRC_14443_A, newKey, 16, &first, &second); + memcpy(buff3, &first, 1); + memcpy(buff3 + 1, &second, 1); + + des_dec(&buff1, &buff1, skey->data); + memcpy(cmd+3,buff1,8); + + for (int x = 0; x < 8; x++) { + buff2[x] = buff2[x] ^ buff1[x]; + } + des_dec(&buff2, &buff2, skey->data); + memcpy(cmd+11,buff2,8); + + for (int x = 0; x < 8; x++) { + buff3[x] = buff3[x] ^ buff2[x]; + } + des_dec(&buff3, &buff3, skey->data); + memcpy(cmd+19,buff3,8); + + // The command always times out on the first attempt, this will retry until a response + // is recieved. + len = 0; + while(!len) { + len = DesfireAPDU(cmd,27,resp); + } + } + } + */ + + //OnSuccess(); - reply_mix(CMD_ACK, 1, len, 0, resp, len); + //reply_old(CMD_ACK, 1, 0, 0, skey->data, payload->keylen); + //reply_mix(CMD_ACK, 1, len, 0, resp, len); + + LED_B_ON(); + authres_t rpayload; + rpayload.sessionkeylen = payload->keylen; + memcpy(rpayload.sessionkey, sessionKey.data, rpayload.sessionkeylen); + reply_ng(CMD_HF_DESFIRE_AUTH1, PM3_SUCCESS, (uint8_t *)&rpayload, sizeof(rpayload)); + LED_B_OFF(); } // 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO) @@ -770,3 +700,8 @@ void OnError(uint8_t reason) { reply_mix(CMD_ACK, 0, reason, 0, 0, 0); OnSuccess(); } + +void OnErrorNG(uint16_t cmd, uint8_t reason) { + reply_ng(cmd, reason, NULL, 0); + OnSuccess(); +} diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h index 8daed69aa..1e19ec49f 100644 --- a/armsrc/mifaredesfire.h +++ b/armsrc/mifaredesfire.h @@ -14,13 +14,14 @@ #include "common.h" bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain); +void MifareSendCommand(uint8_t *datain); void MifareDesfireGetInformation(); -void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareDES_Auth1(uint8_t *datain); void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t *datain); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout); void OnSuccess(); void OnError(uint8_t reason); +void OnErrorNG(uint16_t cmd, uint8_t reason); #endif diff --git a/client/Makefile b/client/Makefile index 87cf03a19..e46e51eb2 100644 --- a/client/Makefile +++ b/client/Makefile @@ -253,7 +253,7 @@ CMDSRCS = crapto1/crapto1.c \ wiegand_formats.c \ wiegand_formatutils.c \ cardhelper.c \ - settings.c + preferences.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 0afc03cde..357d82e65 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -34,6 +34,19 @@ uint8_t key_ones_data[16] = { 0x01 }; uint8_t key_defa_data[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; +typedef struct { + uint8_t mode; + uint8_t algo; + uint8_t keyno; + uint8_t keylen; + uint8_t key[24]; +} mfdes_authinput_t; + +typedef struct mfdes_auth_res { + uint8_t sessionkeylen; + uint8_t sessionkey[24]; +} mfdes_auth_res_t; + #define status(x) ( ((uint16_t)(0x91<<8)) + x ) typedef enum { @@ -78,13 +91,13 @@ static char *getCardSizeStr(uint8_t fsize) { static char *getProtocolStr(uint8_t id, bool hw) { - static char buf[50] = {0x00}; + static char buf[50] = {0x00}; char *retStr = buf; if (id == 0x04) { sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); } else if (id == 0x05) { - if (hw) + if (hw) sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") ")", id); else sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id); @@ -222,7 +235,7 @@ static char *getstatus(uint16_t *sw) { return "Application count is limited to 28, not addition CreateApplication possible"; case MFDES_E_DUPLICATE: - return "Duplicate entry: File/Application does already exist"; + return "Duplicate entry: File/Application/ISO Text does already exist"; case MFDES_E_EEPROM: return "Eeprom error due to loss of power, internal backup/rollback mechanism activated"; @@ -294,13 +307,13 @@ static char *GetErrorString(int res, uint16_t *sw) { static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize, bool readalldata) { if (apdu == NULL) { - PrintAndLogEx(DEBUG, "APDU=NULL"); + PrintAndLogEx(DEBUG, "APDU=NULL"); return PM3_EINVARG; } - if (dest == NULL) { + /*if (dest == NULL) { PrintAndLogEx(DEBUG, "DEST=NULL"); return PM3_EINVARG; - } + }*/ if (sw == NULL) { PrintAndLogEx(DEBUG, "SW=NULL"); return PM3_EINVARG; @@ -348,7 +361,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw)); return res; } - + if (dest != NULL) { if (splitbysize) { memcpy(&dest[i * splitbysize], data, resplen); @@ -362,7 +375,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l if (*sw != status(MFDES_ADDITIONAL_FRAME)) break; } - *recv_len = (splitbysize) ? i : pos; + *recv_len = (splitbysize) ? i : pos; return PM3_SUCCESS; } @@ -378,7 +391,7 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { // return DESFIRE_EV3; if (major == 0x30 && minor == 0x00) return DESFIRE_LIGHT; - if (major == 0x11 && minor == 0x00 ) + if (major == 0x11 && minor == 0x00) return PLUS_EV1; return UNKNOWN; @@ -428,12 +441,12 @@ static int get_desfire_freemem(uint32_t *free_mem) { int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true); - if (res != PM3_SUCCESS ) + if (res != PM3_SUCCESS) return res; - + if (sw != status(MFDES_S_OPERATION_OK)) return PM3_ESOFT; - + *free_mem = le24toh(fmem); return res; } @@ -573,7 +586,7 @@ static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) { uint8_t data[2] = {0}; int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true); - if (res != PM3_SUCCESS ) + if (res != PM3_SUCCESS) return res; if (sw != status(MFDES_S_OPERATION_OK)) return PM3_ESOFT; @@ -598,8 +611,8 @@ static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { int recv_len = 0; uint16_t sw = 0; int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS ) + + if (res != PM3_SUCCESS) return res; if (sw != status(MFDES_S_OPERATION_OK)) @@ -611,8 +624,8 @@ static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { // --- GET APPIDS static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) { if (dest == NULL) { - PrintAndLogEx(DEBUG, "DEST=NULL"); - return PM3_EINVARG; + PrintAndLogEx(DEBUG, "DEST=NULL"); + return PM3_EINVARG; } if (app_ids_len == NULL) { PrintAndLogEx(DEBUG, "APP_IDS_LEN=NULL"); @@ -623,8 +636,8 @@ static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) { int recv_len = 0; uint16_t sw = 0; int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS ) + + if (res != PM3_SUCCESS) return res; if (sw != status(MFDES_S_OPERATION_OK)) @@ -661,9 +674,9 @@ static int get_desfire_select_application(uint8_t *aid) { sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a int recv_len = 0; uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, sizeof(dfname_t), true); + int res = send_desfire_cmd(&apdu, true, NONE, &recv_len, &sw, sizeof(dfname_t), true); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't select AID 0x%X -> %s"), (aid[0] << 16) + (aid[1] << 8) + aid[2], GetErrorString(res, &sw)); + PrintAndLogEx(WARNING, _RED_(" Can't select AID 0x%X -> %s"), (aid[2] << 16) + (aid[1] << 8) + aid[0], GetErrorString(res, &sw)); DropField(); return res; } @@ -854,26 +867,37 @@ int getKeySettings(uint8_t *aid) { return PM3_SUCCESS; } +static void swap24(uint8_t *data) { + if (data == NULL) return; + uint8_t tmp = data[0]; + data[0] = data[2]; + data[2] = tmp; +}; + +static void swap16(uint8_t *data) { + if (data == NULL) return; + uint8_t tmp = data[0]; + data[0] = data[1]; + data[1] = tmp; +}; + static int CmdHF14ADesCreateApp(const char *Cmd) { - clearCommandBuffer(); - CLIParserInit("hf mfdes createaid", "Create Application ID", - "Usage:\n\t-m Auth type (1=normal, 2=iso, 3=aes)\n\t-t Crypt algo (1=DES, 2=3DES, 3=3K3DES, 4=aes)\n\t-a aid (3 bytes)\n\t-n keyno\n\t-k key (8-24 bytes)\n\n" - "Example:\n\thf mfdes createaid -a 123456 -f 1122 -k 0F -l 2E -n AppName\n" + "Usage:\n\thf mfdes createaid -a 123456 -f 1122 -k 0F -l 2E -n AppName\n" ); void *argtable[] = { arg_param_begin, - arg_strx0("aA", "aid", "", "App ID to create"), - arg_strx0("fF", "fid", "", "File ID"), + arg_strx0("aA", "aid", "", "App ID to create as hex bytes ("), + arg_strx0("fF", "fid", "", "File ID to create"), arg_strx0("kK", "keysetting1", "", "Key Setting 1 (Application Master Key Settings)"), arg_strx0("lL", "keysetting2", "", "Key Setting 2"), arg_str0("nN", "name", "", "App ISO-4 Name"), arg_param_end }; - CLIExecWithReturn(Cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, false); /* KeySetting 1 (AMK Setting): 0: Allow change master key 1: Free Directory list access without master key @@ -913,7 +937,9 @@ static int CmdHF14ADesCreateApp(const char *Cmd) { int keylen2 = 1; int namelen = 16; CLIGetHexWithReturn(1, aid, &aidlength); + swap24(aid); CLIGetHexWithReturn(2, fid, &fidlength); + swap16(fid); CLIGetHexWithReturn(3, &keysetting1, &keylen1); CLIGetHexWithReturn(4, &keysetting2, &keylen2); CLIGetStrWithReturn(5, name, &namelen); @@ -971,8 +997,6 @@ static int CmdHF14ADesCreateApp(const char *Cmd) { } static int CmdHF14ADesDeleteApp(const char *Cmd) { - clearCommandBuffer(); - CLIParserInit("hf mfdes deleteaid", "Delete Application ID", "Usage:\n\t-a aid (3 bytes)\n\n" @@ -984,7 +1008,7 @@ static int CmdHF14ADesDeleteApp(const char *Cmd) { arg_strx0("aA", "aid", "", "App ID to delete"), arg_param_end }; - CLIExecWithReturn(Cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, false); int aidlength = 3; uint8_t aid[3] = {0}; CLIGetHexWithReturn(1, aid, &aidlength); @@ -1008,7 +1032,6 @@ static int CmdHF14ADesDeleteApp(const char *Cmd) { static int CmdHF14ADesFormatPICC(const char *Cmd) { - (void) Cmd; // Cmd is not used so far CLIParserInit("hf mfdes formatpicc", "Formats MIFARE DESFire PICC to factory state", "Usage:\n\t-k PICC key (8 bytes)\n\n" @@ -1020,7 +1043,7 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) { arg_str0("kK", "key", "", "Key for checking (HEX 16 bytes)"), arg_param_end }; - CLIExecWithReturn(Cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, false); uint8_t key[8] = {0}; int keylen = 8; @@ -1029,36 +1052,51 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) { if ((keylen < 8) || (keylen > 8)) { PrintAndLogEx(ERR, "Specified key must have 8 bytes length."); - //SetAPDULogging(false); return PM3_EINVARG; } - clearCommandBuffer(); DropField(); uint8_t aid[3] = {0}; int res = get_desfire_select_application(aid); if (res != PM3_SUCCESS) return res; - uint8_t data[25] = {keylen}; // max length: 1 + 24 (3k3DES) - memcpy(data + 1, key, keylen); - SendCommandOLD(CMD_HF_DESFIRE_AUTH1, 2, 1, 0, data, keylen + 1); + + mfdes_authinput_t payload; + payload.keylen = keylen; + memcpy(payload.key, key, keylen); + payload.mode = MFDES_AUTH_PICC; + payload.algo = MFDES_ALGO_DES; + payload.keyno = 0; + SendCommandNG(CMD_HF_DESFIRE_AUTH1, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { + if (!WaitForResponseTimeout(CMD_HF_DESFIRE_AUTH1, &resp, 3000)) { PrintAndLogEx(WARNING, "Client command execute timeout"); DropField(); return PM3_ETIMEOUT; } - uint8_t isOK = resp.oldarg[0] & 0xff; + uint8_t isOK = (resp.status == PM3_SUCCESS); if (isOK) { - uint8_t rdata[] = {0xFC}; // 0xFC - SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(rdata), 0, rdata, sizeof(rdata)); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { + struct { + uint8_t flags; + uint8_t datalen; + uint8_t datain[FRAME_PAYLOAD_SIZE]; + } PACKED payload; + payload.datain[0] = 0xFC; + payload.flags = NONE; + payload.datalen = 1; + SendCommandNG(CMD_HF_DESFIRE_COMMAND, (uint8_t *)&payload, sizeof(payload)); + if (!WaitForResponseTimeout(CMD_HF_DESFIRE_COMMAND, &resp, 3000)) { PrintAndLogEx(WARNING, "Client reset command execute timeout"); DropField(); return PM3_ETIMEOUT; } - if (resp.oldarg[0] & 0xFF) { + if (resp.status == PM3_SUCCESS) { + /*struct r { + uint8_t len; + uint8_t data[RECEIVE_SIZE]; + } PACKED; + struct r *rpayload = (struct r *)&resp.data.asBytes;*/ PrintAndLogEx(INFO, "Card successfully reset"); return PM3_SUCCESS; } @@ -1072,7 +1110,7 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) { static int CmdHF14ADesInfo(const char *Cmd) { (void)Cmd; // Cmd is not used so far - + DropField(); SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0); PacketResponseNG resp; @@ -1107,7 +1145,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { } return PM3_ESOFT; } - + nxp_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]); if (cardtype == PLUS_EV1) { PrintAndLogEx(INFO, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`")); @@ -1165,7 +1203,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { size_t signature_len = 0; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS) { desfire_print_signature(package->uid, signature, signature_len, cardtype); } else { @@ -1278,7 +1316,7 @@ static void DecodeAccessRights(uint16_t accrights) { char *rwa = DecodeAccessValue(read_write_access); if (rwa == NULL) return; - + char *wa = DecodeAccessValue(write_access); if (wa == NULL) return; @@ -1314,13 +1352,22 @@ static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) { DecodeAccessRights(accrights); PrintAndLogEx(INFO, " Lower limit: %d - Upper limit: %d - limited credit value: %d - limited credit enabled: %d", lowerlimit, upperlimit, limitcredvalue, limited_credit_enabled); return PM3_SUCCESS; + } else if (src_len == 1 + 1 + 2 + 3 + 3 + 3 + maclen) { + int recordsize = (src[7] << 16) + (src[6] << 8) + src[5]; + int maxrecords = (src[10] << 16) + (src[9] << 8) + src[8]; + int currentrecord = (src[13] << 16) + (src[12] << 8) + src[11]; + DecodeFileType(filetype); + DecodeComSet(comset); + DecodeAccessRights(accrights); + PrintAndLogEx(INFO, " Record size: %d - MaxNumberRecords: %d - Current Number Records: %d", recordsize, maxrecords, currentrecord); + return PM3_SUCCESS; } return PM3_ESOFT; } static int CmdHF14ADesEnumApplications(const char *Cmd) { (void)Cmd; // Cmd is not used so far - + DropField(); // uint8_t isOK = 0x00; uint8_t aid[3] = {0}; uint8_t app_ids[78] = {0}; @@ -1366,10 +1413,10 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings")); } - PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X %02X %02X"), aid[0], aid[1], aid[2]); + PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]); for (int m = 0; m < dfname_count; m++) { if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) { - PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X %02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[0], dfnames[m].fid[1], dfnames[m].name); + PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name); } } @@ -1387,7 +1434,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { uint8_t filesettings[20] = {0}; int fileset_len = 0; - int res = get_desfire_filesettings(j, filesettings, &fileset_len); + int res = get_desfire_filesettings(file_ids[j], filesettings, &fileset_len); int maclen = 0; // To be implemented if (res == PM3_SUCCESS) { if (DecodeFileSettings(filesettings, fileset_len, maclen) != PM3_SUCCESS) { @@ -1431,32 +1478,30 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { static int CmdHF14ADesAuth(const char *Cmd) { int res = 0; DropField(); - clearCommandBuffer(); // NR DESC KEYLENGHT // ------------------------ // 1 = DES 8 // 2 = 3DES 16 // 3 = 3K 3DES 24 // 4 = AES 16 - //SetAPDULogging(true); uint8_t keylength = 8; CLIParserInit("hf mfdes auth", "Authenticates Mifare DESFire using Key", - "Usage:\n\t-m Auth type (1=normal, 2=iso, 3=aes)\n\t-t Crypt algo (1=DES, 2=3DES, 3=3K3DES, 4=aes)\n\t-a aid (3 bytes)\n\t-n keyno\n\t-k key (8-24 bytes)\n\n" - "Example:\n\thf mfdes auth -m 3 -t 4 -a 018380 -n 0 -k 404142434445464748494a4b4c4d4e4f\n" + "Usage:\n\t-m Auth type (1=normal, 2=iso, 3=aes)\n\t-t Crypt algo (1=DES, 2=3DES, 3=2K3DES, 4=3K3DES, 5=AES)\n\t-a aid (3 bytes)\n\t-n keyno\n\t-k key (8-24 bytes)\n\n" + "Example:\n\thf mfdes auth -m 3 -t 5 -a 838001 -n 0 -k 00000000000000000000000000000000\n" ); void *argtable[] = { arg_param_begin, - arg_int0("mM", "type", "Auth type (1=normal, 2=iso, 3=aes)", NULL), - arg_int0("tT", "algo", "Crypt algo (1=DES, 2=3DES, 3=3K3DES, 4=aes)", NULL), - arg_strx0("aA", "aid", "", "AID used for authentification"), + arg_int0("mM", "type", "Auth type (1=normal, 2=iso, 3=aes, 4=picc)", NULL), + arg_int0("tT", "algo", "Crypt algo (1=DES, 2=3DES, 3=2K3DES, 4=3K3DES, 5=AES)", NULL), + arg_strx0("aA", "aid", "", "AID used for authentification (HEX 3 bytes)"), arg_int0("nN", "keyno", "Key number used for authentification", NULL), arg_str0("kK", "key", "", "Key for checking (HEX 16 bytes)"), arg_param_end }; - CLIExecWithReturn(Cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, false); uint8_t cmdAuthMode = arg_get_int_def(1, 0); uint8_t cmdAuthAlgo = arg_get_int_def(2, 0); @@ -1464,7 +1509,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { int aidlength = 3; uint8_t aid[3] = {0}; CLIGetHexWithReturn(3, aid, &aidlength); - + swap24(aid); uint8_t cmdKeyNo = arg_get_int_def(4, 0); uint8_t key[24] = {0}; @@ -1473,61 +1518,65 @@ static int CmdHF14ADesAuth(const char *Cmd) { CLIParserFree(); if ((keylen < 8) || (keylen > 24)) { - PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); - //SetAPDULogging(false); + PrintAndLogEx(ERR, "Specified key must have %d bytes length.", keylen); return PM3_EINVARG; } // AID if (aidlength != 3) { PrintAndLogEx(WARNING, "aid must include %d HEX symbols", 3); - //SetAPDULogging(false); return PM3_EINVARG; } switch (cmdAuthMode) { - case 1: - if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) { - PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - //SetAPDULogging(false); + case MFDES_AUTH_DES: + if (cmdAuthAlgo != MFDES_ALGO_DES && cmdAuthAlgo != MFDES_ALGO_3DES) { + PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth des mode"); return PM3_EINVARG; } break; - case 2: - if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) { - PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - //SetAPDULogging(false); + case MFDES_AUTH_ISO: + if (cmdAuthAlgo != MFDES_ALGO_2K3DES && cmdAuthAlgo != MFDES_ALGO_3K3DES) { + PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth iso mode"); return PM3_EINVARG; } break; - case 3: - if (cmdAuthAlgo != 4) { - PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - //SetAPDULogging(false); + case MFDES_AUTH_AES: + if (cmdAuthAlgo != MFDES_ALGO_AES) { + PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth aes mode"); + return PM3_EINVARG; + } + break; + case MFDES_AUTH_PICC: + if (cmdAuthAlgo != MFDES_AUTH_DES) { + PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth picc mode"); return PM3_EINVARG; } break; default: PrintAndLogEx(WARNING, "Wrong Auth mode (%d) -> (1=normal, 2=iso, 3=aes)", cmdAuthMode); - //SetAPDULogging(false); return PM3_EINVARG; } switch (cmdAuthAlgo) { - case 2: + case MFDES_ALGO_2K3DES: + keylength = 16; + PrintAndLogEx(NORMAL, "2 key 3DES selected"); + break; + case MFDES_ALGO_3DES: keylength = 16; PrintAndLogEx(NORMAL, "3DES selected"); break; - case 3: + case MFDES_ALGO_3K3DES: keylength = 24; PrintAndLogEx(NORMAL, "3 key 3DES selected"); break; - case 4: + case MFDES_ALGO_AES: keylength = 16; PrintAndLogEx(NORMAL, "AES selected"); break; default: - cmdAuthAlgo = 1; + cmdAuthAlgo = MFDES_ALGO_DES; keylength = 8; PrintAndLogEx(NORMAL, "DES selected"); break; @@ -1550,28 +1599,30 @@ static int CmdHF14ADesAuth(const char *Cmd) { if (res != PM3_SUCCESS) return res; } - // algo, keylength, - uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES) - memcpy(data + 1, key, keylength); - SendCommandOLD(CMD_HF_DESFIRE_AUTH1, cmdAuthMode, cmdAuthAlgo, cmdKeyNo, data, keylength + 1); + mfdes_authinput_t payload; + payload.keylen = keylength; + memcpy(payload.key, key, keylength); + payload.mode = cmdAuthMode; + payload.algo = cmdAuthAlgo; + payload.keyno = cmdKeyNo; + SendCommandNG(CMD_HF_DESFIRE_AUTH1, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { + if (!WaitForResponseTimeout(CMD_HF_DESFIRE_AUTH1, &resp, 3000)) { PrintAndLogEx(WARNING, "Client command execute timeout"); DropField(); return PM3_ETIMEOUT; } - uint8_t isOK = resp.oldarg[0] & 0xff; + uint8_t isOK = (resp.status == PM3_SUCCESS); if (isOK) { - uint8_t *session_key = resp.data.asBytes; - + struct mfdes_auth_res *rpayload = (struct mfdes_auth_res *)&resp.data.asBytes; PrintAndLogEx(SUCCESS, " Key : " _GREEN_("%s"), sprint_hex(key, keylength)); - PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(session_key, keylength)); + PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(rpayload->sessionkey, keylength)); PrintAndLogEx(INFO, "-------------------------------------------------------------"); - //PrintAndLogEx(NORMAL, " Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); } else { - PrintAndLogEx(WARNING, _RED_("Client command failed.")); + PrintAndLogEx(WARNING, _RED_("Auth command failed, reason: %d."), resp.status); } PrintAndLogEx(INFO, "-------------------------------------------------------------"); return PM3_SUCCESS; @@ -1593,6 +1644,18 @@ static command_t CommandTable[] = { {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, // {"rdbl", CmdHF14ADesRb, IfPm3Iso14443a, "Read MIFARE DesFire block"}, // {"wrbl", CmdHF14ADesWb, IfPm3Iso14443a, "write MIFARE DesFire block"}, + /* + ISO/IEC 7816 Cmds + 'A4' Select + 'B0' Read Binary + 'D6' Update Binary + 'B2' Read Records + 'E2' Append Records + '84' Get Challenge + '88' Internal Authenticate + '82' External Authenticate + + */ {NULL, NULL, NULL, NULL} }; @@ -1603,7 +1666,6 @@ static int CmdHelp(const char *Cmd) { } int CmdHFMFDes(const char *Cmd) { - // flush clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } diff --git a/client/cmdmain.c b/client/cmdmain.c index 8d4b1c8b7..906a354f6 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -37,6 +37,7 @@ #include "ui.h" #include "util_posix.h" #include "commonutil.h" // ARRAYLEN +#include "preferences.h" static int CmdHelp(const char *Cmd); @@ -241,6 +242,11 @@ static int CmdRev(const char *Cmd) { return PM3_SUCCESS; } +static int CmdPref(const char *Cmd) { + CmdPreferences(Cmd); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help. Use ' help' for details of a particular command."}, {"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"}, @@ -259,6 +265,7 @@ static command_t CommandTable[] = { {"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"}, {"", CmdHelp, AlwaysAvailable, ""}, {"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"}, + {"pref", CmdPref, AlwaysAvailable, "Edit preferences"}, {"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"}, {"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"}, {"quit", CmdQuit, AlwaysAvailable, ""}, diff --git a/client/fileutils.c b/client/fileutils.c index 05a7e8949..1eb82e57c 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -38,7 +38,7 @@ // this define is needed for scandir/alphasort to work #define _GNU_SOURCE #include "fileutils.h" -#include "settings.h" +#include "preferences.h" #include #include @@ -427,7 +427,7 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s } break; case jsfSettings: - settings_save_callback (root); + preferences_save_callback (root); break; default: break; @@ -868,7 +868,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ *datalen = sptr; } if (!strcmp(ctype,"settings")) { - settings_load_callback (root); + preferences_load_callback (root); } PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), fileName); out: diff --git a/client/preferences.c b/client/preferences.c new file mode 100644 index 000000000..21c38fb2e --- /dev/null +++ b/client/preferences.c @@ -0,0 +1,564 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + ****************************************************************************/ + +//----------------------------------------------------------------------------- +// Preferences Functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Notes +// To add a new setting +// Add the new setting to the session_arg_t; in ui.h +// Add the default value for the setting in the settings_load page below +// Update the preferences_load_callback to load your setting into the stucture +// Update the preferences_save_callback to enusre your setting gets saved when needed. +// use the preference as needed : session. +// Can use (session.preferences_loaded) to check if json settings file was used +//----------------------------------------------------------------------------- + +#include "preferences.h" +#include "comms.h" +#include "emv/emvjson.h" +#include +#include "cmdparser.h" +#include + +static int CmdHelp(const char *Cmd); + +// Load all settings into memory (struct) +int preferences_load (void) { + + // Set all defaults + session.client_debug_level = OFF; + session.window_plot_xpos = 10; + session.window_plot_ypos = 30; + session.window_plot_hsize = 400; + session.window_plot_wsize = 800; + session.window_overlay_xpos = session.window_plot_xpos; + session.window_overlay_ypos = 60+session.window_plot_ypos + session.window_plot_hsize; + session.window_overlay_hsize = 200; + session.window_overlay_wsize = session.window_plot_wsize; + session.emoji_mode = ALIAS; + session.show_hints = false; + session.supports_colors = false; + + // loadFileJson wants these, so pass in place holder values, though not used + // in settings load; + uint8_t dummyData = 0x00; + size_t dummyDL = 0x00; + + if (loadFileJSON(preferencesFilename, &dummyData, sizeof(dummyData), &dummyDL) == PM3_SUCCESS) { + session.preferences_loaded = true; + } + // Note, if session.settings_loaded == false then the settings_save + // will be called in main () to save settings as set in defaults and main() checks. + + return PM3_SUCCESS; +} + +// Save all settings from memory (struct) to file +int preferences_save (void) { + // Note sure if backup has value ? + char backupFilename[500]; + + snprintf (backupFilename,sizeof(backupFilename),"%s.bak",preferencesFilename); + + if (fileExists (backupFilename)) { + if (remove (backupFilename) != 0) { + PrintAndLogEx (FAILED, "Error - could not delete old settings backup file \"%s\"",backupFilename); + return PM3_ESOFT; + } + } + + if (fileExists (preferencesFilename)) { + if (rename (preferencesFilename,backupFilename) != 0) { + PrintAndLogEx (FAILED, "Error - could not backup settings file \"%s\" to \"%s\"",preferencesFilename,backupFilename); + return PM3_ESOFT; + } + } + + uint8_t dummyData = 0x00; + size_t dummyDL = 0x00; + + if (saveFileJSON(preferencesFilename, jsfSettings, &dummyData, dummyDL) != PM3_SUCCESS) + PrintAndLogEx (ERR, "Error saving preferences to \"%s\"",preferencesFilename); + + return PM3_SUCCESS; +} + +void preferences_save_callback (json_t *root) { + + JsonSaveStr (root,"FileType","settings"); + + // Log level, convert to text + switch (session.client_debug_level) { + case OFF: JsonSaveStr (root,"client.debug.level","off"); break; + case SIMPLE: JsonSaveStr (root,"client.debug.level","simple"); break; + case FULL: JsonSaveStr (root,"client.debug.level","full"); break; + default: + JsonSaveStr (root,"logging.level","NORMAL"); + } + + // Plot window + JsonSaveInt (root,"window.plot.xpos",session.window_plot_xpos); + JsonSaveInt (root,"window.plot.ypos",session.window_plot_ypos); + JsonSaveInt (root,"window.plot.hsize",session.window_plot_hsize); + JsonSaveInt (root,"window.plot.wsize",session.window_plot_wsize); + + // Overlay/Slider window + JsonSaveInt (root,"window.overlay.xpos",session.window_overlay_xpos); + JsonSaveInt (root,"window.overlay.ypos",session.window_overlay_ypos); + JsonSaveInt (root,"window.overlay.hsize",session.window_overlay_hsize); + JsonSaveInt (root,"window.overlay.wsize",session.window_overlay_wsize); + + // Emoji + switch (session.emoji_mode) { + case ALIAS: JsonSaveStr (root,"show.emoji","alias"); break; + case EMOJI: JsonSaveStr (root,"show.emoji","emoji"); break; + case ALTTEXT: JsonSaveStr (root,"show.emoji","alttext"); break; + case ERASE: JsonSaveStr (root,"show.emoji","erase"); break; + default: + JsonSaveStr (root,"show.emoji","ALIAS"); + } + + JsonSaveBoolean (root,"show.hints",session.show_hints); + + JsonSaveBoolean (root,"os.supports.colors",session.supports_colors); +} + +void preferences_load_callback (json_t *root) { + json_error_t up_error = {0}; + bool b1; + int i1; + const char *s1; + char tempStr [500]; // to use str_lower() since json unpack uses const char * + + // Logging Level + if (json_unpack_ex(root,&up_error, 0, "{s:s}","client.debug.level",&s1) == 0) { + strncpy (tempStr,s1,sizeof(tempStr)-1); + str_lower (tempStr); + if (strncmp (tempStr,"off",3) == 0) session.client_debug_level = OFF; + if (strncmp (tempStr,"simple",6) == 0) session.client_debug_level = SIMPLE; + if (strncmp (tempStr,"full",4) == 0) session.client_debug_level = FULL; + } + + // window plot + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.xpos",&i1) == 0) + session.window_plot_xpos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.ypos",&i1) == 0) + session.window_plot_ypos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.hsize",&i1) == 0) + session.window_plot_hsize = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.wsize",&i1) == 0) + session.window_plot_wsize = i1; + + // overlay/slider plot + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.xpos",&i1) == 0) + session.window_overlay_xpos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.ypos",&i1) == 0) + session.window_overlay_ypos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.hsize",&i1) == 0) + session.window_overlay_hsize = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.wsize",&i1) == 0) + session.window_overlay_wsize = i1; + + // show options + if (json_unpack_ex(root,&up_error, 0, "{s:s}","show.emoji",&s1) == 0) { + strncpy (tempStr,s1,sizeof(tempStr)-1); + str_lower (tempStr); + if (strncmp (tempStr,"alias",5) == 0) session.emoji_mode = ALIAS; + if (strncmp (tempStr,"emoji",5) == 0) session.emoji_mode = EMOJI; + if (strncmp (tempStr,"alttext",7) == 0) session.emoji_mode = ALTTEXT; + if (strncmp (tempStr,"erase",5) == 0) session.emoji_mode = ERASE; + } + + if (json_unpack_ex(root,&up_error, 0, "{s:b}","show.hints",&b1) == 0) + session.show_hints = b1; + + if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.supports.colors",&b1) == 0) + session.supports_colors = b1; + +} + +// Help Functions +static int usage_pref_set() { + PrintAndLogEx(NORMAL, "Usage: pref set [(h)elp] [(e)moji ...] [(c)olor ...] [(hi)nts ...] [debug ...]"); + PrintAndLogEx(NORMAL, " [(p)lot ...] [(o)verlay ...]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " help - This help"); + PrintAndLogEx(NORMAL, " emoji <(ali)as | (em)oji | (alt)text | (er)ase> - Set the level of emoji support"); + PrintAndLogEx(NORMAL, " alias : show alias"); + PrintAndLogEx(NORMAL, " emoji : show emoji"); + PrintAndLogEx(NORMAL, " alttext : show alternative text"); + PrintAndLogEx(NORMAL, " erase : dont show any emoji"); + + PrintAndLogEx(NORMAL, " color <(o)ff|(a)nsi> - Color support level"); + PrintAndLogEx(NORMAL, " off : dont use color"); + PrintAndLogEx(NORMAL, " ansi : use ansi color (linux, mac, windows terminal)"); + + PrintAndLogEx(NORMAL, " hints <(of)f | on> - Show hints on/off"); + + PrintAndLogEx(NORMAL, " debug <(o)ff | (s)imple | (f)ull> - Client debug level"); + PrintAndLogEx(NORMAL, " off : no debug output"); + PrintAndLogEx(NORMAL, " simple : information level debug"); + PrintAndLogEx(NORMAL, " full : full debug information"); + + PrintAndLogEx(NORMAL, " plot [x ] [y ] [h ] [w ] - Position the plot window"); + PrintAndLogEx(NORMAL, " overlay [x ] [y ] [h ] [w ] - Position the overlay/slider window"); + + return PM3_SUCCESS; +} + +static int usage_pref_show() { + PrintAndLogEx(NORMAL, "Usage: pref show [help] [emoji|color]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " help - This help"); + PrintAndLogEx(NORMAL, " emoji - show current settings for emoji"); + PrintAndLogEx(NORMAL, " color - show current settings for color"); + + return PM3_SUCCESS; +} + +// Preference Processing Functions +typedef enum preferenceId {prefNONE,prefHELP,prefEMOJI,prefCOLOR,prefPLOT,prefOVERLAY,prefHINTS,prefCLIENTDEBUG} preferenceId_t; + +// Enumerate text to ID +preferenceId_t prefGetID (char* cmdOpt) +{ + str_lower (cmdOpt); + + if (strncmp (cmdOpt,"hi",2) == 0) return prefHINTS; + if (strncmp (cmdOpt,"h",1) == 0) return prefHELP; + if (strncmp (cmdOpt,"e",1) == 0) return prefEMOJI; + if (strncmp (cmdOpt,"c",1) == 0) return prefCOLOR; + if (strncmp (cmdOpt,"p",1) == 0) return prefPLOT; + if (strncmp (cmdOpt,"o",1) == 0) return prefOVERLAY; + if (strncmp (cmdOpt,"d",1) == 0) return prefCLIENTDEBUG; + + return NONE; +} + +void showEmojiState (void) { + switch (session.emoji_mode) { + case ALIAS: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("show alias")); + break; + case EMOJI: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("show emoji")); + break; + case ALTTEXT: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("show alt text")); + break; + case ERASE: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("dont show emoji")); + break; + default: + PrintAndLogEx(NORMAL, " emoji.................. "_RED_("unknown")); + } +} + +void showColorState (void) { +/* + switch (session.supports_colors) { + case false: PrintAndLogEx(NORMAL, "Color : "_GREEN_("off")); + break; + case true: PrintAndLogEx(NORMAL, "Color : "_GREEN_("ansi")); + break; + default: + PrintAndLogEx(NORMAL, "Color support set to : "_RED_("unknown")); + } +*/ + // this will change to 1 of a set from bool + if (session.supports_colors) + PrintAndLogEx(NORMAL, " color.................. "_GREEN_("ansi")); + else + PrintAndLogEx(NORMAL, " color.................. "_GREEN_("off")); +} + +void showClientDebugState (void) { + switch (session.client_debug_level) { + case OFF: PrintAndLogEx (NORMAL," client debug........... "_GREEN_("off")); + break; + case SIMPLE: PrintAndLogEx (NORMAL," client debug........... "_GREEN_("simple")); + break; + case FULL: PrintAndLogEx (NORMAL," client debug........... "_GREEN_("full")); + break; + default: + PrintAndLogEx(NORMAL, " client debug........... "_RED_("unknown")); + } +} + +void showPlotPosState (void){ + PrintAndLogEx (NORMAL," Plot window............ X "_GREEN_("%4d")" Y "_GREEN_("%4d")" H "_GREEN_("%4d")" W "_GREEN_("%4d"), + session.window_plot_xpos,session.window_plot_ypos,session.window_plot_hsize,session.window_plot_wsize); +} + +void showOverlayPosState (void){ + PrintAndLogEx (NORMAL," Slider/Overlay window.. X "_GREEN_("%4d")" Y "_GREEN_("%4d")" H "_GREEN_("%4d")" W "_GREEN_("%4d"), + session.window_overlay_xpos,session.window_overlay_ypos,session.window_overlay_hsize,session.window_overlay_wsize); +} + +void showHintsState (void){ + if (session.show_hints) + PrintAndLogEx (NORMAL," Hints.................. "_GREEN_("on")); + else + PrintAndLogEx (NORMAL," Hints.................. "_GREEN_("off")); +} + +static int CmdPrefShow (const char *Cmd) { + uint8_t cmdp = 0; + preferenceId_t CmdPref; + bool errors = false; + char strOpt[50]; + + PrintAndLogEx(NORMAL,""); + PrintAndLogEx(NORMAL,_BLUE_("Preferences")); + + if (!session. preferences_loaded) { + PrintAndLogEx (ERR,"Preferneces not loaded"); + return PM3_ESOFT; + } + + if (param_getchar(Cmd, cmdp) == 0x00) { // No options - Show all + showEmojiState (); + showColorState (); + showPlotPosState (); + showOverlayPosState (); + showClientDebugState(); + showHintsState (); + } + else { + + while ((param_getchar(Cmd, cmdp) != 0x00) && !errors) { + + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + CmdPref = prefGetID(strOpt); + } + else + CmdPref = prefNONE; + + switch (CmdPref) { + case prefHELP: + return usage_pref_show(); + case prefEMOJI: + showEmojiState (); + break; + case prefCOLOR: // color + showColorState (); + break; + case prefPLOT: + showPlotPosState (); + break; + case prefOVERLAY: + showOverlayPosState (); + break; + case prefCLIENTDEBUG: + showClientDebugState(); + break; + case prefHINTS: + showHintsState(); + break; + case prefNONE: + PrintAndLogEx (ERR,"Invalid option supplied"); + errors = true; + break; + // errors + } + cmdp ++; + } + } + PrintAndLogEx(NORMAL,""); + return PM3_SUCCESS; +} + +static int CmdPrefSet (const char *Cmd) +{ + uint8_t cmdp = 0; + preferenceId_t CmdPref; + bool errors = false; + // char charOpt; + char strOpt[50]; + int x,y,h,w; + + if (param_getchar(Cmd, cmdp) == 0x00) + return usage_pref_set(); + + while ((param_getchar(Cmd, cmdp) != 0x00) && !errors) { + + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + CmdPref = prefGetID(strOpt); + } + else + CmdPref = prefNONE; + + switch (CmdPref) { + case prefHELP: + return usage_pref_set(); + case prefEMOJI: + showEmojiState (); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp (strOpt,"ali",3) == 0) { session.emoji_mode = ALIAS; showEmojiState (); break; } + if (strncmp (strOpt,"em",2) == 0) { session.emoji_mode = EMOJI; showEmojiState (); break; } + if (strncmp (strOpt,"alt",3) == 0) { session.emoji_mode = ALTTEXT; showEmojiState (); break; } + if (strncmp (strOpt,"er",2) == 0) { session.emoji_mode = ERASE; showEmojiState (); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid emoji option"); + errors = true; + } + else + errors = true; + break; + case prefCOLOR: // color + showColorState (); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp(strOpt,"a",1) == 0) { session.supports_colors = true; showColorState (); break; } + if (strncmp(strOpt,"o",1) == 0) { session.supports_colors = false; showColorState (); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid color option"); + errors = true; + } + else + errors = true; + break; + case prefPLOT: + showPlotPosState (); + cmdp++; + x = y = h = w = -99999; // Some invalid value + for (int i = 0; i < 4; i++) { // upto 4 values X, Y, H, WARNING + if (param_getchar(Cmd, cmdp) != 0){ + switch (tolower(param_getchar(Cmd, cmdp++))) { + case 'x': x = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'y': y = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'h': h = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'w': w = param_get32ex(Cmd,cmdp++,-99999,10); break; + default: + errors = true; + } + } + } + if (x != -99999) session.window_plot_xpos = x; + if (y != -99999) session.window_plot_ypos = y; + if (h != -99999) session.window_plot_hsize = h; + if (w != -99999) session.window_plot_wsize = w; + // Need to work out how to change live.... + // calling data plot seems to work + + showPlotPosState (); + break; + case prefOVERLAY: + showOverlayPosState (); + cmdp++; + x = y = h = w = -99999; // Some invalid value + for (int i = 0; i < 4; i++) { // upto 4 values X, Y, H, WARNING + if (param_getchar(Cmd, cmdp) != 0){ + switch (tolower(param_getchar(Cmd, cmdp++))) { + case 'x': x = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'y': y = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'h': h = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'w': w = param_get32ex(Cmd,cmdp++,-99999,10); break; + default: + errors = true; + } + } + } + if (x != -99999) session.window_overlay_xpos = x; + if (y != -99999) session.window_overlay_ypos = y; + if (h != -99999) session.window_overlay_hsize = h; + if (w != -99999) session.window_overlay_wsize = w; + showOverlayPosState (); + // Need to work out how to change live.... + break; + case prefCLIENTDEBUG: + showClientDebugState(); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp(strOpt,"o",1) == 0) { session.client_debug_level = OFF; g_debugMode = OFF; showClientDebugState(); break; } + if (strncmp(strOpt,"s",1) == 0) { session.client_debug_level = SIMPLE; g_debugMode = SIMPLE; showClientDebugState(); break; } + if (strncmp(strOpt,"f",1) == 0) { session.client_debug_level = FULL; g_debugMode = FULL; showClientDebugState(); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid client debug option"); + errors = true; + } + else + errors = true; + break; + case prefHINTS: + showHintsState (); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp(strOpt,"on",2) == 0) { session.show_hints = true; showHintsState (); break; } + if (strncmp(strOpt,"of",2) == 0) { session.show_hints = false; showHintsState (); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid hint option"); + errors = true; + } + else + errors = true; + break; + case prefNONE: + PrintAndLogEx (ERR,"Invalid option supplied"); + errors = true; + break; + } + cmdp ++; + } + preferences_save(); + return PM3_SUCCESS; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"set", CmdPrefSet, AlwaysAvailable, "Set a preference"}, + {"show", CmdPrefShow, AlwaysAvailable, "Show (a preference)"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + + return PM3_SUCCESS; +} + +int CmdPreferences (const char *Cmd) +{ + clearCommandBuffer(); + + return CmdsParse(CommandTable, Cmd); +} \ No newline at end of file diff --git a/client/settings.h b/client/preferences.h similarity index 67% rename from client/settings.h rename to client/preferences.h index c404a82e2..7dce07fc6 100644 --- a/client/settings.h +++ b/client/preferences.h @@ -8,17 +8,18 @@ //----------------------------------------------------------------------------- // Settings Functions //----------------------------------------------------------------------------- -#ifndef SETTINGS_H_ -#define SETTINGS_H_ +#ifndef PREFERENCES_H_ +#define PREFERENCES_H_ #include "fileutils.h" -#define settingsFilename "settings.json" +#define preferencesFilename "preferences.json" -int settings_load (void); -int settings_save (void); +int CmdPreferences (const char *Cmd); +int preferences_load (void); +int preferences_save (void); -void settings_save_callback (json_t *root); -void settings_load_callback (json_t *root); +void preferences_save_callback (json_t *root); +void preferences_load_callback (json_t *root); #endif diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index dd5fd3f24..cbe4ade8d 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -170,7 +170,7 @@ void ProxWidget::vchange_dthr_down(int v) { ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) { this->master = master; // Set the initail postion and size from settings - if (session.settings_loaded) + if (session.preferences_loaded) setGeometry (session.window_plot_xpos,session.window_plot_ypos,session.window_plot_wsize,session.window_plot_hsize); else resize(800, 400); @@ -210,9 +210,13 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) { // shows plot window on the screen. show(); - // Move controller widget below plot - controlWidget->move(x(), y() + frameSize().height()); - controlWidget->resize(size().width(), 200); + if (session.preferences_loaded) + controlWidget->setGeometry (session.window_overlay_xpos,session.window_overlay_ypos,session.window_overlay_wsize,session.window_overlay_hsize); + else { + // Move controller widget below plot + controlWidget->move(x(), y() + frameSize().height()); + controlWidget->resize(size().width(), 200); + } // Olverlays / slider window title QString ct = QString("[*]Slider [ %1 ]").arg((char *)gui_serial_port_name); diff --git a/client/proxmark3.c b/client/proxmark3.c index 4d36c490b..bfc7b6212 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -27,13 +27,58 @@ #include "comms.h" #include "fileutils.h" #include "flash.h" -#include "settings.h" +#include "preferences.h" -// Used to enable/disable use of settings json file -// #define USE_SETTING_FILE +// Used to enable/disable use of preferences json file +// #define USE_PREFERENCE_FILE +#ifdef _WIN32 + +static void utf8_showBanner (void) { + + char sq[] = { 0xE2,0x96,0x88,0x00 }; // square block + char tr[] = { 0xE2,0x95,0x97,0x00 }; // top rigth corner + char tl[] = { 0xE2,0x95,0x94,0x00 }; // top left corner + char br[] = { 0xE2,0x95,0x9D,0x00 }; // bottom right corner + char bl[] = { 0xE2,0x95,0x9A,0x00 }; // bottom left corner + char hl[] = { 0xE2,0x95,0x90,0x00 }; // horiz line + char vl[] = { 0xE2,0x95,0x91,0x00 }; // vert line + char msg1 [60]; + char msg2 [60]; + char msg3 [60]; + + strcpy (msg1," :snowflake: iceman@icesql.net :coffee:"); + strcpy (msg2," https://github.com/rfidresearchgroup/proxmark3/"); + strcpy (msg3,"pre-release v4.0"); + + g_printAndLog = PRINTANDLOG_PRINT; + + PrintAndLogEx(NORMAL, "\n"); + + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s %s%s%s%s %s%s%s%s %s%s%s%s%s "),sq,sq,sq,sq,sq,sq,tr,sq,sq,sq,tr,sq,sq,sq,tr,sq,sq,sq,sq,tr); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s %s%s%s%s%s %s%s%s%s"),sq,sq,tl,hl,hl,sq,sq,tr,sq,sq,sq,sq,tr,sq,sq,sq,sq,vl,hl,hl,sq,vl); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s %s%s%s%s%s%s"),sq,sq,sq,sq,sq,sq,tl,br,sq,sq,tl,sq,sq,sq,sq,tl,sq,sq,vl,sq,sq,sq,sq,tl,br); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s %s%s%s%s%s%s%s%s%s%s%s %s%s%s%s")"%s",sq,sq,tr,hl,hl,hl,br,sq,sq,vl,bl,sq,sq,tl,br,sq,sq,vl,hl,hl,sq,vl,msg1); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s %s%s%s %s%s%s %s%s%s %s%s%s%s%s%s")"%s",sq,sq,vl,sq,sq,vl,bl,hl,br,sq,sq,vl,sq,sq,sq,sq,tl,br,msg2); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s %s%s%s %s%s%s %s%s%s%s%s ")"%s",bl,hl,br,bl,hl,br,bl,hl,br,bl,hl,hl,hl,br,msg3); + + PrintAndLogEx(NORMAL, ""); + fflush(stdout); + g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; +} + +#endif static void showBanner(void) { + +#ifdef _WIN32 + // If on windows and using UTF-8 then we need utf-8 ascii art for banner. + if (GetConsoleCP() == 65001) { + utf8_showBanner (); + return; + } +#endif + g_printAndLog = PRINTANDLOG_PRINT; PrintAndLogEx(NORMAL, "\n"); @@ -60,6 +105,7 @@ static void showBanner(void) { g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; } + static int check_comm(void) { // If communications thread goes down. Device disconnected then this should hook up PM3 again. if (IsCommunicationThreadDead() && session.pm3_present) { @@ -493,7 +539,7 @@ finish2: return ret; } -#ifndef USE_SETTING_FILE +#ifndef USE_PREFERENCE_FILE // Check if windows AnsiColor Support is enabled in the registery // [HKEY_CURRENT_USER\Console] @@ -591,11 +637,14 @@ int main(int argc, char *argv[]) { set_my_executable_path(); set_my_user_directory(); -#ifdef USE_SETTING_FILE +#ifdef USE_PREFERENCE_FILE // Load Settings and assign // This will allow the command line to override the settings.json values - settings_load (); - + preferences_load (); + // Change height/width (Rows,Cols) - Testing + // printf ("\e[8;50;100t"); + // printf ("\e[3;50;50t"); // x,y + //printf ("Path : %s \n",my_user_directory); // quick patch for debug level g_debugMode = session.client_debug_level; // settings_save (); @@ -780,7 +829,7 @@ int main(int argc, char *argv[]) { return 1; } -#ifndef USE_SETTING_FILE +#ifndef USE_PREFERENCE_FILE // comment next 2 lines to use session values set from settings_load session.supports_colors = DetectWindowsAnsiSupport(); session.emoji_mode = ALTTEXT; @@ -854,12 +903,12 @@ int main(int argc, char *argv[]) { if (!script_cmds_file && !script_cmd && session.stdinOnTTY && session.stdoutOnTTY && !flash_mode) showBanner(); -#ifdef USE_SETTING_FILE +#ifdef USE_PREFERENCE_FILE // Save settings if not load from settings json file. // Doing this here will ensure other checks and updates are saved to over rule default // e.g. Linux color use check - if (!session.settings_loaded) - settings_save (); + if (!session.preferences_loaded) + preferences_save (); #endif #ifdef HAVE_GUI diff --git a/client/settings.c b/client/settings.c deleted file mode 100644 index c3cb02ad6..000000000 --- a/client/settings.c +++ /dev/null @@ -1,191 +0,0 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, or, at your option, any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - ****************************************************************************/ - -//----------------------------------------------------------------------------- -// Settings Functions -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Notes -// To add a new setting -// Add the new setting to the session_arg_t; in ui.h -// Add the default value for the setting in the settings_load page below -// Update the settings_load_callback to load your setting into the stucture -// Update the settings_save_callback to enusre your setting gets saved when needed. -// use the setting as needed : session. -// Can use (session.settings_loaded) to check if json settings file was used -//----------------------------------------------------------------------------- - -#include "settings.h" -#include "comms.h" -#include "emv/emvjson.h" -#include - -// Load all settings into memory (struct) -int settings_load (void) { - - // Set all defaults - session.client_debug_level = OFF; - session.window_plot_xpos = 10; - session.window_plot_ypos = 30; - session.window_plot_hsize = 400; - session.window_plot_wsize = 800; - session.emoji_mode = ALIAS; - session.show_hints = false; - session.supports_colors = false; - - // loadFileJson wants these, so pass in place holder values, though not used - // in settings load; - uint8_t dummyData = 0x00; - size_t dummyDL = 0x00; - - if (loadFileJSON(settingsFilename, &dummyData, sizeof(dummyData), &dummyDL) == PM3_SUCCESS) { - session.settings_loaded = true; - } - // Note, if session.settings_loaded == false then the settings_save - // will be called in main () to save settings as set in defaults and main() checks. - - return PM3_SUCCESS; -} - -// Save all settings from memory (struct) to file -int settings_save (void) { - // Note sure if backup has value ? - char backupFilename[500]; - - snprintf (backupFilename,sizeof(backupFilename),"%s.bak",settingsFilename); - - if (fileExists (backupFilename)) { - if (remove (backupFilename) != 0) { - PrintAndLogEx (FAILED, "Error - could not delete old settings backup file \"%s\"",backupFilename); - return PM3_ESOFT; - } - } - - if (fileExists (settingsFilename)) { - if (rename (settingsFilename,backupFilename) != 0) { - PrintAndLogEx (FAILED, "Error - could not backup settings file \"%s\" to \"%s\"",settingsFilename,backupFilename); - return PM3_ESOFT; - } - } - - uint8_t dummyData = 0x00; - size_t dummyDL = 0x00; - - if (saveFileJSON(settingsFilename, jsfSettings, &dummyData, dummyDL) == PM3_SUCCESS) - PrintAndLogEx (NORMAL, "settings have been saved to \"%s\"",settingsFilename); - - return PM3_SUCCESS; -} - -void settings_save_callback (json_t *root) { - - JsonSaveStr (root,"FileType","settings"); - - // Log level, convert to text - switch (session.client_debug_level) { - case OFF: JsonSaveStr (root,"client.debug.level","off"); break; - case SIMPLE: JsonSaveStr (root,"client.debug.level","simple"); break; - case FULL: JsonSaveStr (root,"client.debug.level","full"); break; - default: - JsonSaveStr (root,"logging.level","NORMAL"); - } - - // Plot window - JsonSaveInt (root,"window.plot.xpos",session.window_plot_xpos); - JsonSaveInt (root,"window.plot.ypos",session.window_plot_ypos); - JsonSaveInt (root,"window.plot.hsize",session.window_plot_hsize); - JsonSaveInt (root,"window.plot.wsize",session.window_plot_wsize); - - // Emoji - switch (session.emoji_mode) { - case ALIAS: JsonSaveStr (root,"show.emoji","alias"); break; - case EMOJI: JsonSaveStr (root,"show.emoji","emoji"); break; - case ALTTEXT: JsonSaveStr (root,"show.emoji","alttext"); break; - case ERASE: JsonSaveStr (root,"show.emoji","erase"); break; - default: - JsonSaveStr (root,"show.emoji","ALIAS"); - } - - JsonSaveBoolean (root,"show.hints",session.show_hints); - - JsonSaveBoolean (root,"os.supports.colors",session.supports_colors); -} - -void settings_load_callback (json_t *root) { - json_error_t up_error = {0}; - bool b1; - int i1; - const char *s1; - char tempStr [500]; // to use str_lower() since json unpack uses const char * - - // Logging Level - if (json_unpack_ex(root,&up_error, 0, "{s:s}","client.debug.level",&s1) == 0) { - strncpy (tempStr,s1,sizeof(tempStr)-1); - str_lower (tempStr); - if (strncmp (tempStr,"off",3) == 0) session.client_debug_level = OFF; - if (strncmp (tempStr,"simple",6) == 0) session.client_debug_level = SIMPLE; - if (strncmp (tempStr,"full",4) == 0) session.client_debug_level = FULL; - } - - // window plot - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.xpos",&i1) == 0) - session.window_plot_xpos = i1; - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.ypos",&i1) == 0) - session.window_plot_ypos = i1; - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.hsize",&i1) == 0) - session.window_plot_hsize = i1; - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.wsize",&i1) == 0) - session.window_plot_wsize = i1; - - // show options - if (json_unpack_ex(root,&up_error, 0, "{s:s}","show.emoji",&s1) == 0) { - strncpy (tempStr,s1,sizeof(tempStr)-1); - str_lower (tempStr); - if (strncmp (tempStr,"alias",5) == 0) session.emoji_mode = ALIAS; - if (strncmp (tempStr,"emoji",5) == 0) session.emoji_mode = EMOJI; - if (strncmp (tempStr,"alttext",7) == 0) session.emoji_mode = ALTTEXT; - if (strncmp (tempStr,"erase",5) == 0) session.emoji_mode = ERASE; - } - - if (json_unpack_ex(root,&up_error, 0, "{s:b}","show.hints",&b1) == 0) - session.show_hints = b1; - - if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.supports.colors",&b1) == 0) - session.supports_colors = b1; - -} diff --git a/client/ui.h b/client/ui.h index 343b55c1f..3875c27c8 100644 --- a/client/ui.h +++ b/client/ui.h @@ -22,7 +22,7 @@ typedef enum emojiMode {ALIAS, EMOJI, ALTTEXT, ERASE} emojiMode_t; typedef enum clientdebugLevel {OFF,SIMPLE,FULL} clientdebugLevel_t; typedef struct { - bool settings_loaded; + bool preferences_loaded; bool stdinOnTTY; bool stdoutOnTTY; bool supports_colors; @@ -34,6 +34,10 @@ typedef struct { int window_plot_ypos; int window_plot_hsize; int window_plot_wsize; + int window_overlay_xpos; + int window_overlay_ypos; + int window_overlay_hsize; + int window_overlay_wsize; clientdebugLevel_t client_debug_level; } session_arg_t; diff --git a/include/mifare.h b/include/mifare.h index b8df9a2ec..5cca91cbc 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -80,6 +80,22 @@ typedef enum DESFIRE_COMMAND { BAR = 0x10, } desfire_command_t; +typedef enum { + MFDES_AUTH_DES = 1, + MFDES_AUTH_ISO = 2, + MFDES_AUTH_AES = 3, + MFDES_AUTH_PICC = 4 +} mifare_des_authmode_t; + +typedef enum { + MFDES_ALGO_DES = 1, + MFDES_ALGO_3DES = 2, + MFDES_ALGO_2K3DES = 3, + MFDES_ALGO_3K3DES = 4, + MFDES_ALGO_AES = 5 +} mifare_des_authalgo_t; + + //----------------------------------------------------------------------------- // ISO 14443B //-----------------------------------------------------------------------------