mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 18:48:13 -07:00
add: cryptohelper support
This commit is contained in:
parent
cac25e1c63
commit
2886a99350
7 changed files with 231 additions and 108 deletions
|
@ -130,7 +130,7 @@ CORESRCS = uart_posix.c \
|
|||
util_posix.c \
|
||||
scandir.c \
|
||||
crc16.c \
|
||||
comms.c
|
||||
comms.c
|
||||
|
||||
CMDSRCS = crapto1/crapto1.c \
|
||||
crapto1/crypto1.c \
|
||||
|
@ -250,7 +250,8 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
bucketsort.c \
|
||||
flash.c \
|
||||
wiegand_formats.c \
|
||||
wiegand_formatutils.c
|
||||
wiegand_formatutils.c \
|
||||
cardhelper.c
|
||||
|
||||
cpu_arch = $(shell uname -m)
|
||||
ifneq ($(findstring 86, $(cpu_arch)), )
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
|
||||
// Copyright (C) 2011 Gerhard de Koning Gans
|
||||
// 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,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
|
@ -12,14 +12,11 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdhficlass.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdtrace.h"
|
||||
#include "util_posix.h"
|
||||
|
||||
#include "comms.h"
|
||||
#include "mbedtls/des.h"
|
||||
#include "loclass/cipherutils.h"
|
||||
|
@ -28,12 +25,14 @@
|
|||
#include "loclass/elite_crack.h"
|
||||
#include "fileutils.h"
|
||||
#include "protocols.h"
|
||||
#include "cardhelper.h"
|
||||
#include "wiegand_formats.h"
|
||||
#include "wiegand_formatutils.h"
|
||||
|
||||
#define NUM_CSNS 9
|
||||
#define ICLASS_KEYS_MAX 8
|
||||
#define ICLASS_AUTH_RETRY 10
|
||||
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -290,16 +289,6 @@ static int usage_hf_iclass_permutekey(void) {
|
|||
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
|
||||
typedef struct {
|
||||
uint8_t app_limit; //[8]
|
||||
|
@ -311,7 +300,6 @@ typedef struct {
|
|||
uint8_t fuses; //[15]
|
||||
} picopass_conf_block;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t csn[8];
|
||||
picopass_conf_block conf;
|
||||
|
@ -321,6 +309,13 @@ typedef struct {
|
|||
uint8_t app_issuer_area[8];
|
||||
} picopass_hdr;
|
||||
|
||||
typedef enum {
|
||||
None = 0,
|
||||
DES,
|
||||
RFU,
|
||||
TRIPLEDES
|
||||
} BLOCK79ENCRYPTION;
|
||||
|
||||
static uint8_t isset(uint8_t val, uint8_t mask) {
|
||||
return (val & mask);
|
||||
}
|
||||
|
@ -429,18 +424,18 @@ static void mem_app_config(const picopass_hdr *hdr) {
|
|||
PrintAndLogEx(NORMAL, " Credit - Kc");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_picopass_info(const picopass_hdr *hdr) {
|
||||
fuse_config(hdr);
|
||||
mem_app_config(hdr);
|
||||
}
|
||||
|
||||
static void printIclassDumpInfo(uint8_t *iclass_dump) {
|
||||
print_picopass_info((picopass_hdr *) iclass_dump);
|
||||
}
|
||||
|
||||
|
||||
static int CmdHFiClassList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list iclass' instead");
|
||||
CmdTraceList("iclass");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -475,24 +470,9 @@ static int CmdHFiClassSim(const char *Cmd) {
|
|||
return usage_hf_iclass_sim();
|
||||
}
|
||||
|
||||
/*
|
||||
// pre-defined 8 CSN by Holiman
|
||||
uint8_t csns[8*NUM_CSNS] = {
|
||||
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)
|
||||
*/
|
||||
// remember to change the define NUM_CSNS to match.
|
||||
|
||||
// pre-defined 9 CSN by iceman
|
||||
uint8_t csns[8 * NUM_CSNS] = {
|
||||
0x01, 0x0A, 0x0F, 0xFF, 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
|
||||
//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:
|
||||
*
|
||||
|
@ -801,8 +760,6 @@ static int CmdHFiClassELoad(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
|
||||
|
||||
static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||
|
||||
bool errors = false;
|
||||
|
@ -812,6 +769,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
uint8_t cmdp = 0;
|
||||
|
||||
uint8_t enc_data[8] = {0};
|
||||
uint8_t dec_data[8] = {0};
|
||||
|
||||
size_t keylen = 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 (have_key == false) {
|
||||
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
|
||||
if (res != PM3_SUCCESS)
|
||||
return PM3_EINVARG;
|
||||
bool use_sc = IsCryptoHelperPresent();
|
||||
|
||||
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));
|
||||
free(keyptr);
|
||||
}
|
||||
|
@ -878,10 +839,13 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_set2key_dec(&ctx, key);
|
||||
|
||||
uint8_t dec_data[8] = {0};
|
||||
|
||||
if (have_data) {
|
||||
mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
|
||||
|
||||
if (use_sc) {
|
||||
Decrypt(enc_data, dec_data);
|
||||
} else {
|
||||
mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(dec_data, sizeof(dec_data)));
|
||||
}
|
||||
|
||||
|
@ -897,6 +861,8 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
getMemConfig(mem, chip, &max_blk, &app_areas, &kb);
|
||||
|
||||
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) {
|
||||
|
||||
|
@ -904,8 +870,17 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
memcpy(enc_data, decrypted + idx, 8);
|
||||
|
||||
// block 7 or higher, and not empty 0xFF
|
||||
if (blocknum > 6 && memcmp(enc_data, empty, 8) != 0) {
|
||||
mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx);
|
||||
// look inside block 6 to determine if aa1 is encrypted.
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -920,16 +895,43 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
|
||||
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen);
|
||||
|
||||
uint32_t top = 0, mid, bot;
|
||||
mid = bytes_to_num(decrypted + (8*7), 4);
|
||||
bot = bytes_to_num(decrypted + (8*7) + 4, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(INFO, "block 7 - Wiegand decode");
|
||||
wiegand_message_t packed = initialize_message_object(top, mid, bot);
|
||||
HIDTryUnpack(&packed, true);
|
||||
PrintAndLogEx(INFO, "-----------------------------------------------------------------");
|
||||
|
||||
// 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;
|
||||
mid = bytes_to_num(decrypted + (8*7), 4);
|
||||
bot = bytes_to_num(decrypted + (8*7) + 4, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "Block 7 binary");
|
||||
|
||||
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);
|
||||
HIDTryUnpack(&packed, true);
|
||||
PrintAndLogEx(INFO, "-----------------------------------------------------------------");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "No credential found.");
|
||||
}
|
||||
|
||||
free(decrypted);
|
||||
free(fptr);
|
||||
}
|
||||
|
@ -984,7 +986,9 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
|||
|
||||
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;
|
||||
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
|
||||
if (res != PM3_SUCCESS)
|
||||
|
@ -994,8 +998,11 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
|||
free(keyptr);
|
||||
}
|
||||
|
||||
iClassEncryptBlkData(blk_data, key);
|
||||
|
||||
if (use_sc) {
|
||||
Encrypt(blk_data, blk_data);
|
||||
} else {
|
||||
iClassEncryptBlkData(blk_data, key);
|
||||
}
|
||||
printvar("encrypted block", blk_data, 8);
|
||||
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)));
|
||||
|
||||
if (blockno == 6) {
|
||||
if (IsCryptoHelperPresent()) {
|
||||
DecodeBlock6(result->blockdata);
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -216,23 +216,23 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
bool protocol_T15_present = false;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if (T0 & 0x80) {
|
||||
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;
|
||||
if ((TD1 & 0x0f) == 0) {
|
||||
protocol_T0_present = true;
|
||||
|
@ -244,20 +244,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
T1len++;
|
||||
|
||||
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++;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
if (TD1 & 0x80) {
|
||||
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) {
|
||||
protocol_T0_present = true;
|
||||
}
|
||||
|
@ -271,20 +271,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
while (nextCycle) {
|
||||
nextCycle = false;
|
||||
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++;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
if (TDi & 0x80) {
|
||||
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++;
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
PrintAndLogEx(INFO, "\tHistorical bytes");
|
||||
|
@ -361,7 +361,9 @@ static int smart_responseEx(uint8_t *data, bool silent) {
|
|||
|
||||
if (needGetData) {
|
||||
int len = data[datalen - 1];
|
||||
|
||||
if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
|
||||
|
||||
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
|
||||
clearCommandBuffer();
|
||||
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, "-------------------------------------------------------------");
|
||||
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
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "ATR");
|
||||
PrintATR(card.atr, card.atr_len);
|
||||
|
||||
|
@ -756,14 +757,14 @@ static int CmdSmartInfo(const char *Cmd) {
|
|||
if (GetATRTA1(card.atr, card.atr_len) == 0x11)
|
||||
PrintAndLogEx(INFO, "Using default values...");
|
||||
|
||||
PrintAndLogEx(NORMAL, "\t- Di %d", Di);
|
||||
PrintAndLogEx(NORMAL, "\t- Fi %d", Fi);
|
||||
PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F);
|
||||
PrintAndLogEx(INFO, "\t- Di %d", Di);
|
||||
PrintAndLogEx(INFO, "\t- Fi %d", Fi);
|
||||
PrintAndLogEx(INFO, "\t- F %.1f MHz", F);
|
||||
|
||||
if (Di && Fi) {
|
||||
PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi / Di);
|
||||
PrintAndLogEx(NORMAL, "\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- Cycles/ETU %d", Fi / Di);
|
||||
PrintAndLogEx(INFO, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di));
|
||||
PrintAndLogEx(INFO, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "\t- Di or Fi is RFU.");
|
||||
};
|
||||
|
@ -1156,11 +1157,12 @@ int CmdSmartcard(const char *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;
|
||||
|
||||
if (activateCard)
|
||||
smart_select(false, NULL);
|
||||
smart_select(true, NULL);
|
||||
|
||||
PrintAndLogEx(DEBUG, "APDU SC");
|
||||
|
||||
|
@ -1168,10 +1170,11 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
|
|||
if (activateCard) {
|
||||
flags |= SC_SELECT | SC_CONNECT;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen);
|
||||
|
||||
int len = smart_responseEx(dataout, true);
|
||||
int len = smart_responseEx(dataout, silent);
|
||||
|
||||
if (len < 0) {
|
||||
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?
|
||||
SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data));
|
||||
|
||||
len = smart_responseEx(dataout, true);
|
||||
len = smart_responseEx(dataout, silent);
|
||||
}
|
||||
|
||||
*dataoutlen = len;
|
||||
|
@ -1204,6 +1207,7 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
|
|||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@
|
|||
int CmdSmartcard(const char *Cmd);
|
||||
|
||||
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
|
||||
|
|
|
@ -305,7 +305,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea
|
|||
break;
|
||||
case ECC_CONTACT:
|
||||
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
|
||||
res = 1;
|
||||
if (res) {
|
||||
|
|
83
common/cardhelper.c
Normal file
83
common/cardhelper.c
Normal 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
21
common/cardhelper.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue