add: cryptohelper support

This commit is contained in:
iceman1001 2020-02-27 16:35:17 +01:00
commit 2886a99350
7 changed files with 231 additions and 108 deletions

View file

@ -250,7 +250,8 @@ CMDSRCS = crapto1/crapto1.c \
bucketsort.c \ bucketsort.c \
flash.c \ flash.c \
wiegand_formats.c \ wiegand_formats.c \
wiegand_formatutils.c wiegand_formatutils.c \
cardhelper.c
cpu_arch = $(shell uname -m) cpu_arch = $(shell uname -m)
ifneq ($(findstring 86, $(cpu_arch)), ) ifneq ($(findstring 86, $(cpu_arch)), )

View file

@ -1,8 +1,8 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
// Copyright (C) 2011 Gerhard de Koning Gans // Copyright (C) 2011 Gerhard de Koning Gans
// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
// Copyright (C) 2020 Iceman
// //
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of // at your option, any later version. See the LICENSE.txt file for the text of
@ -12,14 +12,11 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdhficlass.h" #include "cmdhficlass.h"
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "cmdtrace.h" #include "cmdtrace.h"
#include "util_posix.h" #include "util_posix.h"
#include "comms.h" #include "comms.h"
#include "mbedtls/des.h" #include "mbedtls/des.h"
#include "loclass/cipherutils.h" #include "loclass/cipherutils.h"
@ -28,12 +25,14 @@
#include "loclass/elite_crack.h" #include "loclass/elite_crack.h"
#include "fileutils.h" #include "fileutils.h"
#include "protocols.h" #include "protocols.h"
#include "cardhelper.h"
#include "wiegand_formats.h" #include "wiegand_formats.h"
#include "wiegand_formatutils.h" #include "wiegand_formatutils.h"
#define NUM_CSNS 9 #define NUM_CSNS 9
#define ICLASS_KEYS_MAX 8 #define ICLASS_KEYS_MAX 8
#define ICLASS_AUTH_RETRY 10 #define ICLASS_AUTH_RETRY 10
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -290,16 +289,6 @@ static int usage_hf_iclass_permutekey(void) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
/*
static int xorbits_8(uint8_t val) {
uint8_t res = val ^ (val >> 1); //1st pass
res = res ^ (res >> 1); // 2nd pass
res = res ^ (res >> 2); // 3rd pass
res = res ^ (res >> 4); // 4th pass
return res & 1;
}
*/
// iclass / picopass chip config structures and shared routines // iclass / picopass chip config structures and shared routines
typedef struct { typedef struct {
uint8_t app_limit; //[8] uint8_t app_limit; //[8]
@ -311,7 +300,6 @@ typedef struct {
uint8_t fuses; //[15] uint8_t fuses; //[15]
} picopass_conf_block; } picopass_conf_block;
typedef struct { typedef struct {
uint8_t csn[8]; uint8_t csn[8];
picopass_conf_block conf; picopass_conf_block conf;
@ -321,6 +309,13 @@ typedef struct {
uint8_t app_issuer_area[8]; uint8_t app_issuer_area[8];
} picopass_hdr; } picopass_hdr;
typedef enum {
None = 0,
DES,
RFU,
TRIPLEDES
} BLOCK79ENCRYPTION;
static uint8_t isset(uint8_t val, uint8_t mask) { static uint8_t isset(uint8_t val, uint8_t mask) {
return (val & mask); return (val & mask);
} }
@ -429,18 +424,18 @@ static void mem_app_config(const picopass_hdr *hdr) {
PrintAndLogEx(NORMAL, " Credit - Kc"); PrintAndLogEx(NORMAL, " Credit - Kc");
} }
} }
static void print_picopass_info(const picopass_hdr *hdr) { static void print_picopass_info(const picopass_hdr *hdr) {
fuse_config(hdr); fuse_config(hdr);
mem_app_config(hdr); mem_app_config(hdr);
} }
static void printIclassDumpInfo(uint8_t *iclass_dump) { static void printIclassDumpInfo(uint8_t *iclass_dump) {
print_picopass_info((picopass_hdr *) iclass_dump); print_picopass_info((picopass_hdr *) iclass_dump);
} }
static int CmdHFiClassList(const char *Cmd) { static int CmdHFiClassList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list iclass' instead");
CmdTraceList("iclass"); CmdTraceList("iclass");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -475,24 +470,9 @@ static int CmdHFiClassSim(const char *Cmd) {
return usage_hf_iclass_sim(); return usage_hf_iclass_sim();
} }
/* // remember to change the define NUM_CSNS to match.
// pre-defined 8 CSN by Holiman
uint8_t csns[8*NUM_CSNS] = { // pre-defined 9 CSN by iceman
0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x13, 0x94, 0x7E, 0x76, 0xFF, 0x12, 0xE0,
0x2A, 0x99, 0xAC, 0x79, 0xEC, 0xFF, 0x12, 0xE0,
0x17, 0x12, 0x01, 0xFD, 0xF7, 0xFF, 0x12, 0xE0,
0xCD, 0x56, 0x01, 0x7C, 0x6F, 0xFF, 0x12, 0xE0,
0x4B, 0x5E, 0x0B, 0x72, 0xEF, 0xFF, 0x12, 0xE0,
0x00, 0x73, 0xD8, 0x75, 0x58, 0xFF, 0x12, 0xE0,
0x0C, 0x90, 0x32, 0xF3, 0x5D, 0xFF, 0x12, 0xE0
};
*/
/*
pre-defined 9 CSN by iceman
only one csn depend on several others.
six depends only on the first csn, (0,1, 0x45)
*/
uint8_t csns[8 * NUM_CSNS] = { uint8_t csns[8 * NUM_CSNS] = {
0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
@ -505,27 +485,6 @@ static int CmdHFiClassSim(const char *Cmd) {
0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
//0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
}; };
/*
// pre-defined 15 CSN by Carl55
// remember to change the define NUM_CSNS to match.
uint8_t csns[8*NUM_CSNS] = {
0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0
};
*/
/* DUMPFILE FORMAT: /* DUMPFILE FORMAT:
* *
@ -801,8 +760,6 @@ static int CmdHFiClassELoad(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
static int CmdHFiClassDecrypt(const char *Cmd) { static int CmdHFiClassDecrypt(const char *Cmd) {
bool errors = false; bool errors = false;
@ -812,6 +769,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
uint8_t enc_data[8] = {0}; uint8_t enc_data[8] = {0};
uint8_t dec_data[8] = {0};
size_t keylen = 0; size_t keylen = 0;
uint8_t key[32] = {0}; uint8_t key[32] = {0};
@ -865,11 +823,14 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
if (errors || cmdp < 1) return usage_hf_iclass_decrypt(); if (errors || cmdp < 1) return usage_hf_iclass_decrypt();
if (have_key == false) { bool use_sc = IsCryptoHelperPresent();
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
if (res != PM3_SUCCESS)
return PM3_EINVARG;
if (have_key == false && use_sc == false) {
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Couldn't find any decryption methods");
return PM3_EINVARG;
}
memcpy(key, keyptr, sizeof(key)); memcpy(key, keyptr, sizeof(key));
free(keyptr); free(keyptr);
} }
@ -878,10 +839,13 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
mbedtls_des3_context ctx; mbedtls_des3_context ctx;
mbedtls_des3_set2key_dec(&ctx, key); mbedtls_des3_set2key_dec(&ctx, key);
uint8_t dec_data[8] = {0};
if (have_data) { if (have_data) {
if (use_sc) {
Decrypt(enc_data, dec_data);
} else {
mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data); mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
}
PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(dec_data, sizeof(dec_data))); PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(dec_data, sizeof(dec_data)));
} }
@ -898,16 +862,27 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03);
for (uint16_t blocknum = 0; blocknum < applimit; ++blocknum) { for (uint16_t blocknum = 0; blocknum < applimit; ++blocknum) {
uint8_t idx = blocknum * 8; uint8_t idx = blocknum * 8;
memcpy(enc_data, decrypted + idx, 8); memcpy(enc_data, decrypted + idx, 8);
// block 7 or higher, and not empty 0xFF // block 7 or higher, and not empty 0xFF
// look inside block 6 to determine if aa1 is encrypted.
if (blocknum > 6 && memcmp(enc_data, empty, 8) != 0) { if (blocknum > 6 && memcmp(enc_data, empty, 8) != 0) {
if (aa1_encryption == RFU || aa1_encryption == None)
continue;
if (use_sc) {
Decrypt(enc_data, decrypted + idx);
} else {
mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx); mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx);
} }
} }
}
//Use the first block (CSN) for filename //Use the first block (CSN) for filename
char *fptr = calloc(42, sizeof(uint8_t)); char *fptr = calloc(42, sizeof(uint8_t));
@ -920,15 +895,42 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen);
// decode block 6
if (memcmp(decrypted + (8*6), empty, 8) != 0 ) {
if (use_sc) {
DecodeBlock6(decrypted + (8*6));
}
}
// decode block 7-8-9
if (memcmp(decrypted + (8*7), empty, 8) != 0 ) {
//todo: remove preamble/sentinal
uint32_t top = 0, mid, bot; uint32_t top = 0, mid, bot;
mid = bytes_to_num(decrypted + (8*7), 4); mid = bytes_to_num(decrypted + (8*7), 4);
bot = bytes_to_num(decrypted + (8*7) + 4, 4); bot = bytes_to_num(decrypted + (8*7) + 4, 4);
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "Block 7 binary");
PrintAndLogEx(INFO, "block 7 - Wiegand decode");
char hexstr[8+1] = {0};
hex_to_buffer((uint8_t *)hexstr, decrypted + (8*7), 8, sizeof(hexstr) - 1, 0, 0, true);
char binstr[8*8+1] = {0};
hextobinstring(binstr, hexstr);
uint8_t i=0;
while (i<strlen(binstr) && binstr[i++] == '0');
PrintAndLogEx(SUCCESS, "%s", binstr + i);
PrintAndLogEx(INFO, "Wiegand decode");
wiegand_message_t packed = initialize_message_object(top, mid, bot); wiegand_message_t packed = initialize_message_object(top, mid, bot);
HIDTryUnpack(&packed, true); HIDTryUnpack(&packed, true);
PrintAndLogEx(INFO, "-----------------------------------------------------------------"); PrintAndLogEx(INFO, "-----------------------------------------------------------------");
} else {
PrintAndLogEx(INFO, "No credential found.");
}
free(decrypted); free(decrypted);
free(fptr); free(fptr);
@ -984,7 +986,9 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
if (errors || cmdp < 1) return usage_hf_iclass_encrypt(); if (errors || cmdp < 1) return usage_hf_iclass_encrypt();
if (have_key == false) { bool use_sc = IsCryptoHelperPresent();
if (have_key == false && use_sc == false) {
size_t keylen = 0; size_t keylen = 0;
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
if (res != PM3_SUCCESS) if (res != PM3_SUCCESS)
@ -994,8 +998,11 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
free(keyptr); free(keyptr);
} }
if (use_sc) {
Encrypt(blk_data, blk_data);
} else {
iClassEncryptBlkData(blk_data, key); iClassEncryptBlkData(blk_data, key);
}
printvar("encrypted block", blk_data, 8); printvar("encrypted block", blk_data, 8);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1750,6 +1757,13 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
} }
PrintAndLogEx(SUCCESS, "block %02X: %s\n", blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); PrintAndLogEx(SUCCESS, "block %02X: %s\n", blockno, sprint_hex(result->blockdata, sizeof(result->blockdata)));
if (blockno == 6) {
if (IsCryptoHelperPresent()) {
DecodeBlock6(result->blockdata);
}
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -216,23 +216,23 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
bool protocol_T15_present = false; bool protocol_T15_present = false;
if (T0 & 0x10) { if (T0 & 0x10) {
PrintAndLogEx(NORMAL, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]); PrintAndLogEx(INFO, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
T1len++; T1len++;
} }
if (T0 & 0x20) { if (T0 & 0x20) {
PrintAndLogEx(NORMAL, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]); PrintAndLogEx(INFO, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
T1len++; T1len++;
} }
if (T0 & 0x40) { if (T0 & 0x40) {
PrintAndLogEx(NORMAL, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]); PrintAndLogEx(INFO, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
T1len++; T1len++;
} }
if (T0 & 0x80) { if (T0 & 0x80) {
uint8_t TD1 = atr[2 + T1len]; uint8_t TD1 = atr[2 + T1len];
PrintAndLogEx(NORMAL, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); PrintAndLogEx(INFO, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
protocol_T0_present = false; protocol_T0_present = false;
if ((TD1 & 0x0f) == 0) { if ((TD1 & 0x0f) == 0) {
protocol_T0_present = true; protocol_T0_present = true;
@ -244,20 +244,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
T1len++; T1len++;
if (TD1 & 0x10) { if (TD1 & 0x10) {
PrintAndLogEx(NORMAL, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]); PrintAndLogEx(INFO, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
TD1len++; TD1len++;
} }
if (TD1 & 0x20) { if (TD1 & 0x20) {
PrintAndLogEx(NORMAL, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]); PrintAndLogEx(INFO, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
TD1len++; TD1len++;
} }
if (TD1 & 0x40) { if (TD1 & 0x40) {
PrintAndLogEx(NORMAL, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]); PrintAndLogEx(INFO, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
TD1len++; TD1len++;
} }
if (TD1 & 0x80) { if (TD1 & 0x80) {
uint8_t TDi = atr[2 + T1len + TD1len]; uint8_t TDi = atr[2 + T1len + TD1len];
PrintAndLogEx(NORMAL, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); PrintAndLogEx(INFO, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
if ((TDi & 0x0f) == 0) { if ((TDi & 0x0f) == 0) {
protocol_T0_present = true; protocol_T0_present = true;
} }
@ -271,20 +271,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
while (nextCycle) { while (nextCycle) {
nextCycle = false; nextCycle = false;
if (TDi & 0x10) { if (TDi & 0x10) {
PrintAndLogEx(NORMAL, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); PrintAndLogEx(INFO, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
TDilen++; TDilen++;
} }
if (TDi & 0x20) { if (TDi & 0x20) {
PrintAndLogEx(NORMAL, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); PrintAndLogEx(INFO, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
TDilen++; TDilen++;
} }
if (TDi & 0x40) { if (TDi & 0x40) {
PrintAndLogEx(NORMAL, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); PrintAndLogEx(INFO, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
TDilen++; TDilen++;
} }
if (TDi & 0x80) { if (TDi & 0x80) {
TDi = atr[2 + T1len + TD1len + TDilen]; TDi = atr[2 + T1len + TD1len + TDilen];
PrintAndLogEx(NORMAL, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f); PrintAndLogEx(INFO, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
TDilen++; TDilen++;
nextCycle = true; nextCycle = true;
@ -314,7 +314,7 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K);
if (K > 0) if (K > 0)
PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); PrintAndLogEx(INFO, "Historical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
if (K > 1) { if (K > 1) {
PrintAndLogEx(INFO, "\tHistorical bytes"); PrintAndLogEx(INFO, "\tHistorical bytes");
@ -361,7 +361,9 @@ static int smart_responseEx(uint8_t *data, bool silent) {
if (needGetData) { if (needGetData) {
int len = data[datalen - 1]; int len = data[datalen - 1];
if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len}; uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus)); SendCommandOLD(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus));
@ -740,10 +742,9 @@ static int CmdSmartInfo(const char *Cmd) {
PrintAndLogEx(INFO, "--- Smartcard Information ---------"); PrintAndLogEx(INFO, "--- Smartcard Information ---------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
PrintAndLogEx(INFO, "\nhttp://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len)); PrintAndLogEx(INFO, "http://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len));
// print ATR // print ATR
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "ATR"); PrintAndLogEx(INFO, "ATR");
PrintATR(card.atr, card.atr_len); PrintATR(card.atr, card.atr_len);
@ -756,14 +757,14 @@ static int CmdSmartInfo(const char *Cmd) {
if (GetATRTA1(card.atr, card.atr_len) == 0x11) if (GetATRTA1(card.atr, card.atr_len) == 0x11)
PrintAndLogEx(INFO, "Using default values..."); PrintAndLogEx(INFO, "Using default values...");
PrintAndLogEx(NORMAL, "\t- Di %d", Di); PrintAndLogEx(INFO, "\t- Di %d", Di);
PrintAndLogEx(NORMAL, "\t- Fi %d", Fi); PrintAndLogEx(INFO, "\t- Fi %d", Fi);
PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F); PrintAndLogEx(INFO, "\t- F %.1f MHz", F);
if (Di && Fi) { if (Di && Fi) {
PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi / Di); PrintAndLogEx(INFO, "\t- Cycles/ETU %d", Fi / Di);
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di)); PrintAndLogEx(INFO, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di));
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F); PrintAndLogEx(INFO, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F);
} else { } else {
PrintAndLogEx(WARNING, "\t- Di or Fi is RFU."); PrintAndLogEx(WARNING, "\t- Di or Fi is RFU.");
}; };
@ -1156,11 +1157,12 @@ int CmdSmartcard(const char *Cmd) {
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
*dataoutlen = 0; *dataoutlen = 0;
if (activateCard) if (activateCard)
smart_select(false, NULL); smart_select(true, NULL);
PrintAndLogEx(DEBUG, "APDU SC"); PrintAndLogEx(DEBUG, "APDU SC");
@ -1168,10 +1170,11 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
if (activateCard) { if (activateCard) {
flags |= SC_SELECT | SC_CONNECT; flags |= SC_SELECT | SC_CONNECT;
} }
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen); SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen);
int len = smart_responseEx(dataout, true); int len = smart_responseEx(dataout, silent);
if (len < 0) { if (len < 0) {
return 1; return 1;
@ -1189,7 +1192,7 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
// something fishy: we have only 5 bytes but we put datainlen in arg1? // something fishy: we have only 5 bytes but we put datainlen in arg1?
SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data)); SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data));
len = smart_responseEx(dataout, true); len = smart_responseEx(dataout, silent);
} }
*dataoutlen = len; *dataoutlen = len;
@ -1204,6 +1207,7 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
SendCommandNG(CMD_SMART_ATR, NULL, 0); SendCommandNG(CMD_SMART_ATR, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return false; return false;
} }

View file

@ -17,6 +17,6 @@
int CmdSmartcard(const char *Cmd); int CmdSmartcard(const char *Cmd);
bool smart_select(bool silent, smart_card_atr_t *atr); bool smart_select(bool silent, smart_card_atr_t *atr);
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#endif #endif

View file

@ -305,7 +305,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea
break; break;
case ECC_CONTACT: case ECC_CONTACT:
if (IfPm3Smartcard()) if (IfPm3Smartcard())
res = ExchangeAPDUSC(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); res = ExchangeAPDUSC(true, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
else else
res = 1; res = 1;
if (res) { if (res) {

83
common/cardhelper.c Normal file
View file

@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// Iceman, February 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Support functions for smart card
//-----------------------------------------------------------------------------
#include "cardhelper.h"
#include <string.h>
#include <stdio.h>
#include "cmdparser.h"
#include "cmdsmartcard.h"
#include "ui.h"
#include "util.h"
#define CARD_INS_DECRYPT 0x01
#define CARD_INS_ENCRYPT 0x02
#define CARD_INS_DECODE 0x06
static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// look for CryptoHelper
bool IsCryptoHelperPresent(void) {
if (IfPm3Smartcard()) {
int resp_len = 0;
uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00};
uint8_t resp[20] = {0};
ExchangeAPDUSC(true, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len);
if (strstr("CryptoHelper", (char*)resp) == 0) {
PrintAndLogEx(INFO, "Found smart card helper");
return true;
} else {
return false;
}
} else {
return false;
}
}
static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
int resp_len = 0;
uint8_t dec[11] = {0};
cmd[1] = ins;
memcpy(cmd + 5, src, 8);
ExchangeAPDUSC(true, cmd, sizeof(cmd), false, true, dec, sizeof(dec), &resp_len);
if (resp_len == 10) {
memcpy(dest, dec, 8);
return true;
}
return false;
}
bool Decrypt(uint8_t *src, uint8_t *dest){
return executeCrypto(CARD_INS_DECRYPT, src, dest);
}
bool Encrypt(uint8_t *src, uint8_t *dest){
return executeCrypto(CARD_INS_ENCRYPT, src, dest);
}
void DecodeBlock6(uint8_t *src) {
int resp_len = 0;
uint8_t resp[254] = {0};
uint8_t c[] = {0x96, CARD_INS_DECODE, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(c + 6, src, 8);
// first part
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len);
PrintAndLogEx(SUCCESS, "%0.*s", resp_len - 11, resp + 9);
// second part
c[5] = 0x02;
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len);
PrintAndLogEx(SUCCESS, "%0.*s", resp_len - 11, resp + 9);
}

21
common/cardhelper.h Normal file
View file

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
// Iceman, February 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Utility functions used in many places, not specific to any piece of code.
//-----------------------------------------------------------------------------
#ifndef __CARDHELPER_H
#define __CARDHELPER_H
#include <ctype.h>
#include "common.h"
bool IsCryptoHelperPresent(void);
bool Encrypt(uint8_t *src, uint8_t *dest);
bool Decrypt(uint8_t *src, uint8_t *dest);
void DecodeBlock6(uint8_t *src);
#endif