mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
chg: 'hf iclass decrypt' - now takes transport key as param. also search for key / dump. Also saves decrypted to bin/eml/json_decref
chg: 'hf iclass encrypt' - now takes transport key as param.
This commit is contained in:
parent
0d6a29197b
commit
f0d73dc3d1
3 changed files with 136 additions and 87 deletions
|
@ -790,75 +790,61 @@ static int CmdHFiClassELoad(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int readKeyfile(const char *filename, size_t len, uint8_t **buffer) {
|
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
|
||||||
|
|
||||||
char *path;
|
|
||||||
int res = searchFile(&path, PM3_USER_DIRECTORY, filename, ".bin");
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(INFO, "res: %d Curr path:: %s", res, path);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t datalen = 0;
|
|
||||||
res = loadFile(path, ".bin", (void*)*buffer, len, &datalen);
|
|
||||||
if ( res != PM3_SUCCESS )
|
|
||||||
return res;
|
|
||||||
|
|
||||||
if (datalen != len) {
|
|
||||||
PrintAndLogEx(ERR, "ERROR, Wrong filesize. Got %d bytes, expected %d", datalen, len);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFiClassDecrypt(const char *Cmd) {
|
static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
|
|
||||||
char opt = tolower(param_getchar(Cmd, 0));
|
bool errors = false;
|
||||||
if (strlen(Cmd) < 1 || opt == 'h') return usage_hf_iclass_decrypt();
|
bool have_key = false;
|
||||||
|
uint8_t cmdp = 0;
|
||||||
|
|
||||||
uint8_t key[16] = { 0 };
|
size_t keylen = 0;
|
||||||
uint8_t *keyptr = key;
|
uint8_t key[32] = {0};
|
||||||
if (readKeyfile("iclass_decryptionkey", sizeof(key), &keyptr) != PM3_SUCCESS)
|
uint8_t *keyptr = NULL;
|
||||||
return usage_hf_iclass_decrypt();
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "decryption key loaded from file");
|
size_t decryptedlen = 0;
|
||||||
|
uint8_t *decrypted = NULL;
|
||||||
//Open the tagdump-file
|
|
||||||
FILE *f;
|
|
||||||
char filename[FILE_PATH_SIZE];
|
char filename[FILE_PATH_SIZE];
|
||||||
if (opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) {
|
|
||||||
f = fopen(filename, "rb");
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
if (!f) {
|
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||||
PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename);
|
case 'h':
|
||||||
return PM3_EFILE;
|
return usage_hf_iclass_decrypt();
|
||||||
|
case 'f':
|
||||||
|
if ( param_getstr(Cmd, cmdp + 1, filename, sizeof(filename) ) == 0){
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( loadFile_safe(filename, "", (void**)&decrypted, &decryptedlen) != PM3_SUCCESS ) {
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
if (param_gethex(Cmd, cmdp + 1, key, 32)) {
|
||||||
|
PrintAndLogEx(ERR, "Transport key must include 32 HEX symbols");
|
||||||
|
errors = true;
|
||||||
|
}
|
||||||
|
have_key = true;
|
||||||
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return usage_hf_iclass_decrypt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
if (errors || cmdp < 1) return usage_hf_iclass_decrypt();
|
||||||
long fsize = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
|
|
||||||
if (fsize <= 0) {
|
if ( have_key == false ) {
|
||||||
PrintAndLogEx(ERR, "error, when getting filesize");
|
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void**)&keyptr, &keylen);
|
||||||
fclose(f);
|
if (res != PM3_SUCCESS)
|
||||||
return 2;
|
return PM3_EINVARG;
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *decrypted = calloc(fsize, sizeof(uint8_t));
|
memcpy(key, keyptr, sizeof(key));
|
||||||
if (!decrypted) {
|
|
||||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
|
||||||
fclose(f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t bytes_read = fread(decrypted, 1, fsize, f);
|
|
||||||
fclose(f);
|
|
||||||
if (bytes_read == 0) {
|
|
||||||
PrintAndLogEx(ERR, "file reading error");
|
|
||||||
free(decrypted);
|
|
||||||
return 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)decrypted;
|
picopass_hdr *hdr = (picopass_hdr *)decrypted;
|
||||||
|
@ -871,12 +857,6 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
uint8_t max_blk = 31;
|
uint8_t max_blk = 31;
|
||||||
getMemConfig(mem, chip, &max_blk, &app_areas, &kb);
|
getMemConfig(mem, chip, &max_blk, &app_areas, &kb);
|
||||||
|
|
||||||
//Use the first block (CSN) for filename
|
|
||||||
char outfilename[FILE_PATH_SIZE] = {0};
|
|
||||||
snprintf(outfilename, FILE_PATH_SIZE, "iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
|
|
||||||
hdr->csn[0], hdr->csn[1], hdr->csn[2], hdr->csn[3],
|
|
||||||
hdr->csn[4], hdr->csn[5], hdr->csn[6], hdr->csn[7]);
|
|
||||||
|
|
||||||
// tripledes
|
// tripledes
|
||||||
mbedtls_des3_context ctx;
|
mbedtls_des3_context ctx;
|
||||||
mbedtls_des3_set2key_dec(&ctx, key);
|
mbedtls_des3_set2key_dec(&ctx, key);
|
||||||
|
@ -894,12 +874,18 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveFile(outfilename, ".bin", decrypted, fsize);
|
//Use the first block (CSN) for filename
|
||||||
saveFileEML(outfilename, decrypted, fsize, 8);
|
char *fptr = calloc(42, sizeof(uint8_t));
|
||||||
saveFileJSON(outfilename, jsfIclass, decrypted, fsize);
|
strcat(fptr, "hf-iclass-");
|
||||||
|
FillFileNameByUID(fptr, hdr->csn, "-data-decrypted", sizeof(hdr->csn) );
|
||||||
|
|
||||||
printIclassDumpContents(decrypted, 1, (fsize / 8), fsize);
|
saveFile(fptr, ".bin", decrypted, decryptedlen);
|
||||||
|
saveFileEML(fptr, decrypted, decryptedlen, 8);
|
||||||
|
saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen);
|
||||||
|
|
||||||
|
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen);
|
||||||
free(decrypted);
|
free(decrypted);
|
||||||
|
free(fptr);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,7 +903,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||||
bool have_key = false;
|
bool have_key = false;
|
||||||
uint8_t blk_data[8] = {0};
|
uint8_t blk_data[8] = {0};
|
||||||
uint8_t key[16] = {0};
|
uint8_t key[16] = {0};
|
||||||
uint8_t *keyptr = key;
|
uint8_t *keyptr = NULL;
|
||||||
uint8_t cmdp = 0;
|
uint8_t cmdp = 0;
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
|
@ -925,17 +911,16 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||||
case 'h':
|
case 'h':
|
||||||
return usage_hf_iclass_encrypt();
|
return usage_hf_iclass_encrypt();
|
||||||
case 'd':
|
case 'd':
|
||||||
//get the bytes to encrypt
|
if (param_gethex(Cmd, cmdp + 1, blk_data, 16)) {
|
||||||
if (param_gethex(Cmd, cmdp + 1, blk_data, 16) != PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(ERR, "Block data must include 16 HEX symbols");
|
PrintAndLogEx(ERR, "Block data must include 16 HEX symbols");
|
||||||
errors = true;;
|
errors = true;
|
||||||
}
|
}
|
||||||
cmdp += 2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
if (param_gethex(Cmd, cmdp + 1, key, 32) != PM3_SUCCESS) {
|
if (param_gethex(Cmd, cmdp + 1, key, 32)) {
|
||||||
PrintAndLogEx(ERR, "Transport key must include 32 HEX symbols");
|
PrintAndLogEx(ERR, "Transport key must include 32 HEX symbols");
|
||||||
errors = true;;
|
errors = true;
|
||||||
}
|
}
|
||||||
have_key = true;
|
have_key = true;
|
||||||
cmdp += 2;
|
cmdp += 2;
|
||||||
|
@ -950,10 +935,12 @@ 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 ) {
|
if ( have_key == false ) {
|
||||||
if (readKeyfile("./iclass_decryptionkey", sizeof(key), &keyptr) != PM3_SUCCESS) {
|
size_t keylen = 0;
|
||||||
return usage_hf_iclass_encrypt();
|
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void**)&keyptr, &keylen);
|
||||||
}
|
if (res != PM3_SUCCESS)
|
||||||
PrintAndLogEx(SUCCESS, "Loaded transport key from decryption file");
|
return PM3_EINVARG;
|
||||||
|
|
||||||
|
memcpy(key, keyptr, sizeof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
iClassEncryptBlkData(blk_data, key);
|
iClassEncryptBlkData(blk_data, key);
|
||||||
|
@ -1283,6 +1270,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, "saving dump file - %d blocks read", gotBytes / 8);
|
PrintAndLogEx(SUCCESS, "saving dump file - %d blocks read", gotBytes / 8);
|
||||||
saveFile(filename, ".bin", tag_data, gotBytes);
|
saveFile(filename, ".bin", tag_data, gotBytes);
|
||||||
saveFileEML(filename, tag_data, gotBytes, 8);
|
saveFileEML(filename, tag_data, gotBytes, 8);
|
||||||
|
saveFileJSON(filename, jsfIclass, tag_data, gotBytes);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
#include "scandir.h"
|
#include "scandir.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PATH_MAX_LENGTH 100
|
#define PATH_MAX_LENGTH 200
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief checks if a file exists
|
* @brief checks if a file exists
|
||||||
|
@ -289,7 +289,7 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s
|
||||||
|
|
||||||
for (size_t i = 0; i < (datalen / 8); i++) {
|
for (size_t i = 0; i < (datalen / 8); i++) {
|
||||||
char path[PATH_MAX_LENGTH] = {0};
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
sprintf(path, "$blocks.%zu", i);
|
sprintf(path, "$.blocks.%zu", i);
|
||||||
JsonSaveBufAsHexCompact(root, path, data + (i * 8), 8);
|
JsonSaveBufAsHexCompact(root, path, data + (i * 8), 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -341,6 +341,7 @@ int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) {
|
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) {
|
||||||
|
|
||||||
if (data == NULL) return 1;
|
if (data == NULL) return 1;
|
||||||
|
@ -401,6 +402,54 @@ out:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) {
|
||||||
|
|
||||||
|
char *path;
|
||||||
|
int res = searchFile(&path, "", preferredName, suffix);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(INFO, "res: %d Curr path:: %s", res, path);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = PM3_SUCCESS;
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "rb");
|
||||||
|
if (!f) {
|
||||||
|
PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get filesize in order to malloc memory
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (fsize <= 0) {
|
||||||
|
PrintAndLogEx(FAILED, "error, when getting filesize");
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pdata = calloc(fsize, sizeof(uint8_t));
|
||||||
|
if (!pdata) {
|
||||||
|
PrintAndLogEx(FAILED, "error, cannot allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes_read = fread(*pdata, 1, fsize, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (bytes_read != fsize) {
|
||||||
|
PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*datalen = bytes_read;
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "loaded %d bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
|
int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
|
||||||
|
|
||||||
if (data == NULL) return 1;
|
if (data == NULL) return 1;
|
||||||
|
|
|
@ -120,7 +120,7 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s
|
||||||
*/
|
*/
|
||||||
int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr);
|
int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr);
|
||||||
|
|
||||||
/** STUB
|
/**
|
||||||
* @brief Utility function to load data from a binary file. This method takes a preferred name.
|
* @brief Utility function to load data from a binary file. This method takes a preferred name.
|
||||||
* E.g. dumpdata-15.bin
|
* E.g. dumpdata-15.bin
|
||||||
*
|
*
|
||||||
|
@ -129,10 +129,22 @@ int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr);
|
||||||
* @param data The data array to store the loaded bytes from file
|
* @param data The data array to store the loaded bytes from file
|
||||||
* @param maxdatalen the number of bytes that your data array has
|
* @param maxdatalen the number of bytes that your data array has
|
||||||
* @param datalen the number of bytes loaded from file
|
* @param datalen the number of bytes loaded from file
|
||||||
* @return 0 for ok, 1 for failz
|
* @return PM3_SUCCESS for ok, PM3_E* for failz
|
||||||
*/
|
*/
|
||||||
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen);
|
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to load data from a binary file. This method takes a preferred name.
|
||||||
|
* E.g. dumpdata-15.bin, tries to search for it, and allocated memory.
|
||||||
|
*
|
||||||
|
* @param preferredName
|
||||||
|
* @param suffix the file suffix. Including the ".".
|
||||||
|
* @param data The data array to store the loaded bytes from file
|
||||||
|
* @param datalen the number of bytes loaded from file
|
||||||
|
* @return PM3_SUCCESS for ok, PM3_E* for failz
|
||||||
|
*/
|
||||||
|
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen);
|
||||||
/**
|
/**
|
||||||
* @brief Utility function to load data from a textfile (EML). This method takes a preferred name.
|
* @brief Utility function to load data from a textfile (EML). This method takes a preferred name.
|
||||||
* E.g. dumpdata-15.txt
|
* E.g. dumpdata-15.txt
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue