mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-24 15:15:39 -07:00
Merge pull request #1579 from merlokk/cip_rdwr
Cipurse read and write commands update
This commit is contained in:
commit
3e7d32fee5
4 changed files with 343 additions and 118 deletions
|
@ -189,6 +189,7 @@ int CIPURSESelectFile(uint16_t fileid, uint8_t *result, size_t max_result_len, s
|
||||||
}
|
}
|
||||||
|
|
||||||
int CIPURSESelectMFDefaultFileEx(bool activate_field, bool leave_field_on, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
int CIPURSESelectMFDefaultFileEx(bool activate_field, bool leave_field_on, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
||||||
|
CipurseCClearContext(&cipurseContext);
|
||||||
return CIPURSEExchangeEx(activate_field, leave_field_on, (sAPDU_t) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, true, 0, result, max_result_len, result_len, sw);
|
return CIPURSEExchangeEx(activate_field, leave_field_on, (sAPDU_t) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, true, 0, result, max_result_len, result_len, sw);
|
||||||
}
|
}
|
||||||
int CIPURSESelectMFDefaultFile(uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
int CIPURSESelectMFDefaultFile(uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
||||||
|
@ -351,28 +352,177 @@ void CIPURSEPrintFileDescriptor(uint8_t desc) {
|
||||||
PrintAndLogEx(INFO, "Unknown file 0x%02x", desc);
|
PrintAndLogEx(INFO, "Unknown file 0x%02x", desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintDGIArray(uint8_t *dgi, size_t dgilen) {
|
||||||
|
if (dgilen < 3) {
|
||||||
|
PrintAndLogEx(WARNING, "DGI too small. Length: %zu", dgilen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *dgiptr = dgi;
|
||||||
|
size_t reslen = 0;
|
||||||
|
while (dgilen > reslen + 2) {
|
||||||
|
uint8_t len = dgiptr[2];
|
||||||
|
CIPURSEPrintDGI(dgiptr, len + 3);
|
||||||
|
|
||||||
|
dgiptr += len + 3;
|
||||||
|
reslen += len + 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen) {
|
||||||
|
if (dgilen < 3) {
|
||||||
|
PrintAndLogEx(WARNING, "DGI too small. Length: %zu", dgilen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t len = dgi[2];
|
||||||
|
if (len + 3 != dgilen) {
|
||||||
|
PrintAndLogEx(ERR, "DGI size does not match with record size. Length of record: %zu, DGI size: %d", dgilen, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check DGI
|
||||||
|
if (dgi[0] == 0x92 && dgi[1] == 0x00) {
|
||||||
|
PrintAndLogEx(INFO, "DGI 9200 - ADF file attributes");
|
||||||
|
CIPURSEPrintFileAttrEx(&dgi[3], len, true);
|
||||||
|
|
||||||
|
} else if (dgi[0] == 0x92 && dgi[1] == 0x01) {
|
||||||
|
PrintAndLogEx(INFO, "DGI 9201 - EF file attributes");
|
||||||
|
CIPURSEPrintFileAttrEx(&dgi[3], len, true);
|
||||||
|
|
||||||
|
} else if (dgi[0] == 0xa0 && dgi[1] == 0x0f) {
|
||||||
|
PrintAndLogEx(INFO, "DGI a00f - All key values");
|
||||||
|
|
||||||
|
if (len % 20 != 0) {
|
||||||
|
PrintAndLogEx(ERR, "Key values size must be array of 20-bite record. ADF size: %d", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < len / 20; i++) {
|
||||||
|
PrintAndLogEx(INFO, "Key[%d]............ %s", i + 1, sprint_hex_inrow(&dgi[3 + i * 20 + 0], 16));
|
||||||
|
PrintAndLogEx(INFO, " Additional info.. 0x%02x", dgi[3 + i * 20 + 16]);
|
||||||
|
uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
|
||||||
|
CipurseCGetKVV(&dgi[3 + i * 20 + 0], kvv);
|
||||||
|
bool kvvvalid = (memcmp(kvv, &dgi[3 + i * 20 + 17], 3) == 0);
|
||||||
|
PrintAndLogEx(INFO, " KVV.............. %s (%s)", sprint_hex_inrow(&dgi[3 + i * 20 + 17], 3), (kvvvalid) ? _GREEN_("valid") : _RED_("invalid"));
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, "Unknown DGI %02x%02x", dgi[0], dgi[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CIPURSEPrintKeySecurityAttributes(uint8_t attr) {
|
||||||
|
PrintAndLogEx(INFO, " Update right: %s", (attr & 0x01) ? "self" : "any");
|
||||||
|
PrintAndLogEx(INFO, " Change key and rights: %s", (attr & 0x02) ? "ok" : "frozen");
|
||||||
|
PrintAndLogEx(INFO, " Use as key encryption key: %s", (attr & 0x04) ? "blocked" : "ok");
|
||||||
|
PrintAndLogEx(INFO, " Key validity: %s", (attr & 0x80) ? "invalid" : "valid");
|
||||||
|
}
|
||||||
|
|
||||||
static void CIPURSEPrintKeyAttrib(uint8_t *attr) {
|
static void CIPURSEPrintKeyAttrib(uint8_t *attr) {
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Key Attributes") "---------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Key Attributes") "---------------------");
|
||||||
PrintAndLogEx(INFO, "Additional info... 0x%02x", attr[0]);
|
PrintAndLogEx(INFO, "Additional info... 0x%02x", attr[0]);
|
||||||
PrintAndLogEx(INFO, "Key length........ %d", attr[1]);
|
PrintAndLogEx(INFO, "Key length........ %d", attr[1]);
|
||||||
PrintAndLogEx(INFO, "Algorithm ID...... 0x%02x", attr[2]);
|
PrintAndLogEx(INFO, "Algorithm ID...... 0x%02x (%s)", attr[2], (attr[2] == 0x09) ? "AES" : "unknown");
|
||||||
PrintAndLogEx(INFO, "Security attr..... 0x%02x", attr[3]);
|
PrintAndLogEx(INFO, "Security attr..... 0x%02x", attr[3]);
|
||||||
|
CIPURSEPrintKeySecurityAttributes(attr[3]);
|
||||||
PrintAndLogEx(INFO, "KVV............... 0x%02x%02x%02x", attr[4], attr[5], attr[6]);
|
PrintAndLogEx(INFO, "KVV............... 0x%02x%02x%02x", attr[4], attr[5], attr[6]);
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) {
|
static void CIPURSEPrintKeyAttribDGI(uint8_t *attr) {
|
||||||
|
PrintAndLogEx(INFO, "--- " _CYAN_("DGI Key Attributes") "---------------------");
|
||||||
|
PrintAndLogEx(INFO, "Security attr..... 0x%02x", attr[0]);
|
||||||
|
CIPURSEPrintKeySecurityAttributes(attr[0]);
|
||||||
|
PrintAndLogEx(INFO, "Key length........ %d", attr[1]);
|
||||||
|
PrintAndLogEx(INFO, "Algorithm ID...... 0x%02x (%s)", attr[2], (attr[2] == 0x09) ? "AES" : "unknown");
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *CIPURSEGetSMR(uint8_t smr) {
|
||||||
|
switch (smr) {
|
||||||
|
case 0x00: return "plain";
|
||||||
|
case 0x01: return "mac";
|
||||||
|
case 0x02: return "enc";
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintSMR(uint8_t *smrrec) {
|
||||||
|
PrintAndLogEx(INFO, "1. %s/%s", CIPURSEGetSMR((smrrec[0] >> 6) & 0x03), CIPURSEGetSMR((smrrec[0] >> 4) & 0x03));
|
||||||
|
PrintAndLogEx(INFO, "2. %s/%s", CIPURSEGetSMR((smrrec[0] >> 2) & 0x03), CIPURSEGetSMR((smrrec[0] >> 0) & 0x03));
|
||||||
|
PrintAndLogEx(INFO, "3. %s/%s", CIPURSEGetSMR((smrrec[1] >> 6) & 0x03), CIPURSEGetSMR((smrrec[1] >> 4) & 0x03));
|
||||||
|
PrintAndLogEx(INFO, "4. %s/%s", CIPURSEGetSMR((smrrec[1] >> 2) & 0x03), CIPURSEGetSMR((smrrec[1] >> 0) & 0x03));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintART(uint8_t *artrec, size_t artlen) {
|
||||||
|
if (artlen < 1 || artlen > 9)
|
||||||
|
return;
|
||||||
|
for (int i = 0; i < artlen; i++) {
|
||||||
|
if (i == 0)
|
||||||
|
PrintAndLogEx(INFO, "always: " NOLF);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "key %d : " NOLF, i);
|
||||||
|
|
||||||
|
for (int n = 7; n >= 0; n--)
|
||||||
|
if ((artrec[i] >> n) & 0x01)
|
||||||
|
PrintAndLogEx(NORMAL, "%d " NOLF, n + 1);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(NORMAL, " " NOLF);
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintEFFileAttr(uint8_t *attr, size_t len) {
|
||||||
|
CIPURSEPrintFileDescriptor(attr[0]);
|
||||||
|
|
||||||
|
if (attr[1] == 0)
|
||||||
|
PrintAndLogEx(INFO, "SFI.... not assigned");
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "SFI.... 0x%02x", attr[1]);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "File ID... 0x%02x%02x", attr[2], attr[3]);
|
||||||
|
|
||||||
|
if (attr[0] == 0x01 || attr[0] == 0x11)
|
||||||
|
PrintAndLogEx(INFO, "File size... %d", (attr[4] << 8) + attr[5]);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "Record num " _YELLOW_("%d") " record size " _YELLOW_("%d"), attr[4], attr[5]);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Keys assigned... %d", attr[6]);
|
||||||
|
|
||||||
|
if (len >= 9) {
|
||||||
|
PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]);
|
||||||
|
CIPURSEPrintSMR(&attr[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 10) {
|
||||||
|
PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], len - 9));
|
||||||
|
CIPURSEPrintART(&attr[9], len - 9);
|
||||||
|
|
||||||
|
if (attr[6] + 1 != len - 9) {
|
||||||
|
PrintAndLogEx(WARNING, "ART length is wrong");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintFileAttrEx(uint8_t *attr, size_t len, bool isDGI) {
|
||||||
if (len < 7) {
|
if (len < 7) {
|
||||||
PrintAndLogEx(FAILED, "Attributes length too short");
|
PrintAndLogEx(FAILED, "Attributes length too short");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("File Attributes") "---------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("File Attributes") "---------------------");
|
||||||
if (attr[0] == 0x38) {
|
if (attr[0] == 0x38 || attr[0] == 0x3F) {
|
||||||
PrintAndLogEx(INFO, "Type... MF, ADF");
|
PrintAndLogEx(INFO, "Type... MF, ADF");
|
||||||
|
|
||||||
if (attr[1] == 0x00) {
|
if (attr[1] == 0x00) {
|
||||||
PrintAndLogEx(INFO, "Type... MF");
|
if (attr[0] == 0x3F)
|
||||||
|
PrintAndLogEx(INFO, "Type... PxSE");
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "Type... MF");
|
||||||
} else {
|
} else {
|
||||||
if ((attr[1] & 0xe0) == 0x00)
|
if ((attr[1] & 0xe0) == 0x00)
|
||||||
PrintAndLogEx(INFO, "Type... Unknown");
|
PrintAndLogEx(INFO, "Type... Unknown");
|
||||||
|
@ -404,64 +554,59 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) {
|
||||||
uint8_t keynum = attr[6];
|
uint8_t keynum = attr[6];
|
||||||
PrintAndLogEx(INFO, "Keys assigned... %d", keynum);
|
PrintAndLogEx(INFO, "Keys assigned... %d", keynum);
|
||||||
|
|
||||||
if (len >= 9) {
|
int idx = 7;
|
||||||
PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]);
|
if ( keynum > 0) {
|
||||||
}
|
if (len >= idx + 2) {
|
||||||
|
PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[idx], attr[idx + 1]);
|
||||||
|
CIPURSEPrintSMR(&attr[idx]);
|
||||||
|
}
|
||||||
|
idx += 2;
|
||||||
|
|
||||||
if (len >= 10 + keynum + 1) {
|
if (len >= idx + keynum + 1) {
|
||||||
PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], keynum + 1));
|
PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[idx], keynum + 1));
|
||||||
}
|
CIPURSEPrintART(&attr[idx], keynum + 1);
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
idx += keynum + 1;
|
||||||
|
|
||||||
if (len >= 11 + keynum + 1 + keynum * 7) {
|
size_t reclen = (isDGI) ? 3 : 7;
|
||||||
for (int i = 0; i < keynum; i++) {
|
if (len >= idx + keynum * reclen) {
|
||||||
PrintAndLogEx(INFO, "Key %d Attributes... %s", i, sprint_hex(&attr[11 + keynum + 1 + i * 7], 7));
|
for (int i = 0; i < keynum; i++) {
|
||||||
CIPURSEPrintKeyAttrib(&attr[11 + keynum + 1 + i * 7]);
|
PrintAndLogEx(INFO, "Key %d Attributes... %s", i + 1, sprint_hex(&attr[idx + i * reclen], reclen));
|
||||||
|
if (isDGI)
|
||||||
|
CIPURSEPrintKeyAttribDGI(&attr[idx + i * reclen]);
|
||||||
|
else
|
||||||
|
CIPURSEPrintKeyAttrib(&attr[idx + i * reclen]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx += keynum * reclen;
|
||||||
|
}
|
||||||
|
// FCP
|
||||||
|
if (len >= idx + 1) {
|
||||||
|
int xlen = len - idx;
|
||||||
|
// for MF only
|
||||||
|
if (attr[1] == 0x00 && attr[0] != 0x3F)
|
||||||
|
xlen = xlen - 6;
|
||||||
|
if (xlen > 0 && xlen < 200) {
|
||||||
|
PrintAndLogEx(INFO, "TLV file control parameters... [%d] %s", xlen, sprint_hex(&attr[idx], xlen));
|
||||||
|
TLVPrintFromBuffer(&attr[idx], xlen);
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// MF
|
// MF only
|
||||||
if (attr[1] == 0x00) {
|
if (attr[1] == 0x00 && attr[0] != 0x3F) {
|
||||||
PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 1] << 5) + attr[len - 4]);
|
PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 5] << 8) + attr[len - 4]);
|
||||||
PrintAndLogEx(INFO, "Free memory size.... %d", (attr[len - 3] << 16) + (attr[len - 2] << 8) + attr[len - 1]);
|
PrintAndLogEx(INFO, "Free memory size.... %d", (attr[len - 3] << 16) + (attr[len - 2] << 8) + attr[len - 1]);
|
||||||
|
|
||||||
} else {
|
|
||||||
int ptr = 11 + keynum + 1 + keynum * 7;
|
|
||||||
if (len > ptr) {
|
|
||||||
PrintAndLogEx(INFO, "TLV file control... %s", sprint_hex(&attr[ptr], len - ptr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "Type... EF");
|
PrintAndLogEx(INFO, "Type... EF");
|
||||||
CIPURSEPrintFileDescriptor(attr[0]);
|
CIPURSEPrintEFFileAttr(attr, len);
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
if (attr[1] == 0)
|
|
||||||
PrintAndLogEx(INFO, "SFI.... not assigned");
|
|
||||||
else
|
|
||||||
PrintAndLogEx(INFO, "SFI.... 0x%02x", attr[1]);
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "File ID... 0x%02x%02x", attr[2], attr[3]);
|
|
||||||
|
|
||||||
if (attr[0] == 0x01 || attr[0] == 0x11)
|
|
||||||
PrintAndLogEx(INFO, "File size... %d", (attr[4] << 8) + attr[5]);
|
|
||||||
else
|
|
||||||
PrintAndLogEx(INFO, "Record num " _YELLOW_("%d") " record size " _YELLOW_("%d"), attr[4], attr[5]);
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Keys assigned... %d", attr[6]);
|
|
||||||
|
|
||||||
if (len >= 9) {
|
|
||||||
PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len >= 10) {
|
|
||||||
PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], len - 9));
|
|
||||||
|
|
||||||
if (attr[6] + 1 != len - 9) {
|
|
||||||
PrintAndLogEx(WARNING, "ART length is wrong");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) {
|
||||||
|
return CIPURSEPrintFileAttrEx(attr, len, false);
|
||||||
|
}
|
||||||
|
|
|
@ -60,7 +60,14 @@ int CIPURSECancelTransaction(uint16_t *sw);
|
||||||
bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose);
|
bool CIPURSEChannelAuthenticate(uint8_t keyindex, uint8_t *key, bool verbose);
|
||||||
void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp);
|
void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp);
|
||||||
|
|
||||||
|
const char *CIPURSEGetSMR(uint8_t smr);
|
||||||
|
void CIPURSEPrintSMR(uint8_t *smrrec);
|
||||||
|
void CIPURSEPrintART(uint8_t *artrec, size_t artlen);
|
||||||
|
void CIPURSEPrintEFFileAttr(uint8_t *attr, size_t len);
|
||||||
|
void CIPURSEPrintFileAttrEx(uint8_t *attr, size_t len, bool isDGI);
|
||||||
void CIPURSEPrintFileAttr(uint8_t *attr, size_t len);
|
void CIPURSEPrintFileAttr(uint8_t *attr, size_t len);
|
||||||
void CIPURSEPrintFileDescriptor(uint8_t desc);
|
void CIPURSEPrintFileDescriptor(uint8_t desc);
|
||||||
|
void CIPURSEPrintDGIArray(uint8_t *dgi, size_t dgilen);
|
||||||
|
void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen);
|
||||||
|
|
||||||
#endif /* __CIPURSECORE_H__ */
|
#endif /* __CIPURSECORE_H__ */
|
||||||
|
|
|
@ -531,9 +531,10 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
||||||
static int CmdHFCipurseReadFile(const char *Cmd) {
|
static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf cipurse read",
|
CLIParserInit(&ctx, "hf cipurse read",
|
||||||
"Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
|
"Read file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
|
||||||
"hf cipurse read --fid 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n"
|
"hf cipurse read --fid 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n"
|
||||||
"hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n");
|
"hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n"
|
||||||
|
"hf cipurse read --aid 4144204631 --fid 0102 -> read file with id 0102 from application 4144204631\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
|
@ -541,6 +542,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
arg_lit0("v", "verbose", "show technical data"),
|
arg_lit0("v", "verbose", "show technical data"),
|
||||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||||
arg_str0("k", "key", "<hex>", "Auth key"),
|
arg_str0("k", "key", "<hex>", "Auth key"),
|
||||||
|
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
|
||||||
arg_str0(NULL, "fid", "<hex>", "file ID"),
|
arg_str0(NULL, "fid", "<hex>", "file ID"),
|
||||||
arg_int0("o", "offset", "<dec>", "offset for reading data from file"),
|
arg_int0("o", "offset", "<dec>", "offset for reading data from file"),
|
||||||
arg_lit0(NULL, "noauth", "read file without authentication"),
|
arg_lit0(NULL, "noauth", "read file without authentication"),
|
||||||
|
@ -559,17 +561,20 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||||
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||||
|
|
||||||
|
uint8_t aid[16] = {0};
|
||||||
|
size_t aidLen = 0;
|
||||||
|
bool useAID = false;
|
||||||
uint16_t fileId = defaultFileId;
|
uint16_t fileId = defaultFileId;
|
||||||
bool useFID = false;
|
bool useFID = false;
|
||||||
int res = CLIParseCommandParameters(ctx, 4, 0, 5, 8, 9, key, NULL, NULL, NULL, &fileId, &useFID, &sreq, &sresp);
|
int res = CLIParseCommandParameters(ctx, 4, 5, 6, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
|
||||||
if (res || useFID == false) {
|
if (res || useFID == false) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t offset = arg_get_int_def(ctx, 6, 0);
|
size_t offset = arg_get_int_def(ctx, 7, 0);
|
||||||
|
|
||||||
bool noAuth = arg_get_lit(ctx, 7);
|
bool noAuth = arg_get_lit(ctx, 8);
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
|
@ -579,15 +584,17 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
|
PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s") " ( " _GREEN_("ok") " )", sprint_hex_inrow(aid, aidLen));
|
||||||
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s"), fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s"), fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
||||||
|
}
|
||||||
|
|
||||||
if (noAuth == false) {
|
if (noAuth == false) {
|
||||||
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
|
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
|
||||||
|
@ -605,7 +612,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
@ -633,9 +640,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
static int CmdHFCipurseWriteFile(const char *Cmd) {
|
static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf cipurse write",
|
CLIParserInit(&ctx, "hf cipurse write",
|
||||||
"Write file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
|
"Write file in the application by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
|
||||||
"hf cipurse write --fid 2ff7 -> Authenticate with keyID 1, write file with id 2ff7\n"
|
"hf cipurse write --fid 2ff7 -d aabb -> Authenticate with keyID 1, write file with id 2ff7\n"
|
||||||
"hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and write file\n");
|
"hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -d aabb -> Authenticate keyID 2 and write file\n"
|
||||||
|
"hf cipurse write --aid 4144204631 --fid 0102 -d aabb -> write file with id 0102 in the 4144204631 application\n"
|
||||||
|
"hf cipurse write --fid 0102 -d aabb --commit -> write file with id 0102 and perform commit after write\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
|
@ -643,12 +652,14 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
arg_lit0("v", "verbose", "show technical data"),
|
arg_lit0("v", "verbose", "show technical data"),
|
||||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||||
arg_str0("k", "key", "<hex>", "Auth key"),
|
arg_str0("k", "key", "<hex>", "Auth key"),
|
||||||
|
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
|
||||||
arg_str0(NULL, "fid", "<hex>", "file ID"),
|
arg_str0(NULL, "fid", "<hex>", "file ID"),
|
||||||
arg_int0("o", "offset", "<dec>", "offset for reading data from file"),
|
arg_int0("o", "offset", "<dec>", "offset for reading data from file"),
|
||||||
arg_lit0(NULL, "noauth", "read file without authentication"),
|
arg_lit0(NULL, "noauth", "read file without authentication"),
|
||||||
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
|
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
|
||||||
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
|
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
|
||||||
arg_str0("d", "data", "<hex>", "hex data to write to new file"),
|
arg_str0("d", "data", "<hex>", "hex data to write to new file"),
|
||||||
|
arg_lit0(NULL, "commit", "need commit after write"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -662,43 +673,49 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
|
|
||||||
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||||
|
|
||||||
|
uint8_t aid[16] = {0};
|
||||||
|
size_t aidLen = 0;
|
||||||
|
bool useAID = false;
|
||||||
uint16_t fileId = defaultFileId;
|
uint16_t fileId = defaultFileId;
|
||||||
bool useFID = false;
|
bool useFID = false;
|
||||||
int res = CLIParseCommandParameters(ctx, 4, 0, 5, 8, 9, key, NULL, NULL, NULL, &fileId, &useFID, &sreq, &sresp);
|
int res = CLIParseCommandParameters(ctx, 4, 5, 6, 9, 10, key, aid, &aidLen, &useAID, &fileId, &useFID, &sreq, &sresp);
|
||||||
if (res || useFID == false) {
|
if (res || useFID == false) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t offset = arg_get_int_def(ctx, 6, 0);
|
size_t offset = arg_get_int_def(ctx, 7, 0);
|
||||||
|
|
||||||
bool noAuth = arg_get_lit(ctx, 7);
|
bool noAuth = arg_get_lit(ctx, 8);
|
||||||
|
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 11, hdata, &hdatalen);
|
||||||
if (hdatalen == 0) {
|
if (hdatalen == 0) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0");
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
bool needCommit = arg_get_lit(ctx, 12);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectAID(true, true, aid, aidLen, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
|
PrintAndLogEx(ERR, "Cipurse select application " _CYAN_("%s") " ( " _RED_("error") " ). Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s") " ( " _GREEN_("ok") " )", sprint_hex_inrow(aid, aidLen));
|
||||||
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
|
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
|
||||||
, fileId
|
, fileId
|
||||||
, offset
|
, offset
|
||||||
|
@ -742,6 +759,16 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " successfully written", fileId);
|
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " successfully written", fileId);
|
||||||
|
|
||||||
|
if (needCommit) {
|
||||||
|
sw = 0;
|
||||||
|
res = CIPURSECommitTransaction(&sw);
|
||||||
|
if (res != 0 || sw != 0x9000)
|
||||||
|
PrintAndLogEx(WARNING, "Commit " _YELLOW_("ERROR") ". Card returns 0x%04x", sw);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(INFO, "Commit ( " _GREEN_("ok") " )");
|
||||||
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -750,7 +777,10 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf cipurse aread",
|
CLIParserInit(&ctx, "hf cipurse aread",
|
||||||
"Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
|
"Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
|
||||||
"hf cipurse aread --fid 2ff7 -> Authenticate with keyID 1, read file attributes with id 2ff7\n"
|
"hf cipurse aread --fid 2ff7 -> Select MF, Authenticate with keyID 1, read file attributes with id 2ff7\n"
|
||||||
|
"hf cipurse aread --mfd -> read file attributes for master file (MF)\n"
|
||||||
|
"hf cipurse aread --chfid 0102 -> read file 0102 attributes in the default application\n"
|
||||||
|
"hf cipurse aread --aid 4144204632 --chfid 0102 -> read file 0102 attributes in the 4144204632 application\n"
|
||||||
"hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n");
|
"hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
|
@ -759,12 +789,13 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
arg_lit0("v", "verbose", "show technical data"),
|
arg_lit0("v", "verbose", "show technical data"),
|
||||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||||
arg_str0("k", "key", "<hex>", "Auth key"),
|
arg_str0("k", "key", "<hex>", "Auth key"),
|
||||||
|
arg_lit0(NULL, "mfd", "show info about master file"),
|
||||||
|
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "select application ID (AID)"),
|
||||||
arg_str0(NULL, "fid", "<hex>", "file ID"),
|
arg_str0(NULL, "fid", "<hex>", "file ID"),
|
||||||
|
arg_str0(NULL, "chfid", "<hex 2 bytes>", "child file ID (EF under application/master file)"),
|
||||||
arg_lit0(NULL, "noauth", "read file attributes without authentication"),
|
arg_lit0(NULL, "noauth", "read file attributes without authentication"),
|
||||||
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
|
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
|
||||||
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
|
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
|
||||||
arg_lit0(NULL, "sel-adf", "show info about ADF itself"),
|
|
||||||
arg_lit0(NULL, "sel-mf", "show info about master file"),
|
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -772,44 +803,58 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
|
uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
|
||||||
|
bool selmfd = arg_get_lit(ctx, 5);
|
||||||
|
|
||||||
CipurseChannelSecurityLevel sreq = CPSMACed;
|
CipurseChannelSecurityLevel sreq = CPSMACed;
|
||||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||||
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||||
|
|
||||||
|
uint8_t aid[16] = {0};
|
||||||
|
size_t aidLen = 0;
|
||||||
|
bool useAID = false;
|
||||||
uint16_t fileId = defaultFileId;
|
uint16_t fileId = defaultFileId;
|
||||||
bool useFID = false;
|
bool useFID = false;
|
||||||
int res = CLIParseCommandParameters(ctx, 4, 0, 5, 7, 8, key, NULL, NULL, NULL, &fileId, &useFID, &sreq, &sresp);
|
uint16_t childFileId = defaultFileId;
|
||||||
if (res || useFID == false) {
|
bool useChildFID = false;
|
||||||
|
int res = CLIParseCommandParametersEx(ctx, 4, 6, 7, 8, 10, 11, key, aid, &aidLen, &useAID, &fileId, &useFID, &childFileId, &useChildFID, &sreq, &sresp);
|
||||||
|
if (res) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool noAuth = arg_get_lit(ctx, 6);
|
bool noAuth = arg_get_lit(ctx, 9);
|
||||||
bool seladf = arg_get_lit(ctx, 9);
|
|
||||||
bool selmf = arg_get_lit(ctx, 10);
|
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = SelectCommandEx(selmfd, useAID, aid, aidLen, useFID, fileId, useChildFID, childFileId, verbose, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
|
PrintAndLogEx(WARNING, "useaid=%d res=%d sw=%x", useAID, res, sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
|
if (selmfd)
|
||||||
, fileId
|
PrintAndLogEx(INFO, "File " _CYAN_("Master File"));
|
||||||
, keyId
|
else if (useFID)
|
||||||
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
|
PrintAndLogEx(INFO, "File id " _CYAN_("%04x"), fileId);
|
||||||
);
|
else
|
||||||
|
PrintAndLogEx(INFO, "Application ID " _CYAN_("%s"), sprint_hex_inrow(aid, aidLen));
|
||||||
|
|
||||||
|
if (useChildFID)
|
||||||
|
PrintAndLogEx(INFO, "Child file id " _CYAN_("%04x"), childFileId);
|
||||||
|
|
||||||
|
if (!noAuth)
|
||||||
|
PrintAndLogEx(INFO, "Key id " _YELLOW_("%d") " key " _YELLOW_("%s")
|
||||||
|
, keyId
|
||||||
|
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noAuth == false) {
|
if (noAuth == false) {
|
||||||
|
@ -825,23 +870,6 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seladf == false) {
|
|
||||||
if (selmf)
|
|
||||||
res = CIPURSESelectMFDefaultFile(buf, sizeof(buf), &len, &sw);
|
|
||||||
else
|
|
||||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
|
||||||
|
|
||||||
if (res != 0 || sw != 0x9000) {
|
|
||||||
if (verbose == false)
|
|
||||||
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x", sw);
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
PrintAndLogEx(INFO, "Select file 0x%x ( " _GREEN_("ok") " )", fileId);
|
|
||||||
|
|
||||||
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
|
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -851,13 +879,13 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
PrintAndLogEx(WARNING, "File id " _YELLOW_("%x") " attributes is empty", fileId);
|
PrintAndLogEx(WARNING, "File attributes is empty");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " attributes[%zu]: %s", fileId, len, sprint_hex(buf, len));
|
PrintAndLogEx(INFO, "Attributes raw data [%zu]: %s", len, sprint_hex(buf, len));
|
||||||
|
|
||||||
CIPURSEPrintFileAttr(buf, len);
|
CIPURSEPrintFileAttr(buf, len);
|
||||||
|
|
||||||
|
@ -1014,17 +1042,8 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
if (verbose && hdatalen > 3) {
|
if (verbose && hdatalen > 3)
|
||||||
if (hdata[0] == 0x92 && hdata[1] == 0x00)
|
CIPURSEPrintDGIArray(hdata, hdatalen);
|
||||||
PrintAndLogEx(INFO, "DGI 9200 - ADF file attributes");
|
|
||||||
if (hdata[0] == 0x92 && hdata[1] == 0x01) {
|
|
||||||
PrintAndLogEx(INFO, "DGI 9201 - EF file attributes");
|
|
||||||
PrintAndLogEx(INFO, "File type:");
|
|
||||||
CIPURSEPrintFileDescriptor(hdata[3]);
|
|
||||||
}
|
|
||||||
if (hdata[0] == 0xa0 && hdata[1] == 0x0f)
|
|
||||||
PrintAndLogEx(INFO, "DGI a00f - All key values");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -1280,6 +1299,7 @@ static int CmdHFCipurseDefault(const char *Cmd) {
|
||||||
memcpy(defaultKey, ckey, CIPURSE_AES_KEY_LENGTH);
|
memcpy(defaultKey, ckey, CIPURSE_AES_KEY_LENGTH);
|
||||||
uint8_t aid[CIPURSE_MAX_AID_LENGTH] = CIPURSE_DEFAULT_AID;
|
uint8_t aid[CIPURSE_MAX_AID_LENGTH] = CIPURSE_DEFAULT_AID;
|
||||||
memcpy(defaultAID, aid, CIPURSE_MAX_AID_LENGTH);
|
memcpy(defaultAID, aid, CIPURSE_MAX_AID_LENGTH);
|
||||||
|
defaultAIDLength = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultKeyId = arg_get_int_def(ctx, 2, defaultKeyId);
|
defaultKeyId = arg_get_int_def(ctx, 2, defaultKeyId);
|
||||||
|
|
|
@ -120,6 +120,59 @@ select it with display output in raw and tlv views options
|
||||||
```hf cipurse delete --aid 4144204631 --chfid 0102```
|
```hf cipurse delete --aid 4144204631 --chfid 0102```
|
||||||
|
|
||||||
|
|
||||||
|
### How read file
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
with default key and aid
|
||||||
|
```hf cipurse read --fid 0102```
|
||||||
|
|
||||||
|
with default key and specified aid
|
||||||
|
```hf cipurse read --aid a0000005070100```
|
||||||
|
|
||||||
|
with default key and aid without authentication
|
||||||
|
```hf cipurse read --fid 0102 --no-auth```
|
||||||
|
|
||||||
|
|
||||||
|
### How write file
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
with default key and aid
|
||||||
|
```hf cipurse read --fid 0102 -d abbbccdd```
|
||||||
|
|
||||||
|
with default key and specified aid
|
||||||
|
```hf cipurse read --aid a0000005070100 -d abbbccdd```
|
||||||
|
|
||||||
|
with default key and aid without authentication
|
||||||
|
```hf cipurse read --fid 0102 -d abbbccdd --no-auth```
|
||||||
|
|
||||||
|
with default key and aid, perform commit (works for files with transactions mechanism switched on)
|
||||||
|
```hf cipurse read --fid 0102 -d abbbccdd --commit```
|
||||||
|
|
||||||
|
|
||||||
|
### How read file attributes
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
read master file attributes
|
||||||
|
```hf cipurse aread --mfd```
|
||||||
|
|
||||||
|
read EF.ID_INFO root file attributes
|
||||||
|
```hf cipurse aread --fid 2ff7```
|
||||||
|
|
||||||
|
read PxSE application attributes
|
||||||
|
```hf cipurse aread --aid a0000005070100```
|
||||||
|
|
||||||
|
read application attributes
|
||||||
|
```hf cipurse aread --aid 4144204632```
|
||||||
|
|
||||||
|
read file (EF) attributes
|
||||||
|
|
||||||
|
```hf cipurse aread --aid 4144204632 --chfid 0102```
|
||||||
|
|
||||||
|
or with default application
|
||||||
|
|
||||||
|
```hf cipurse aread --aid 4144204632 --chfid 0102```
|
||||||
|
|
||||||
|
|
||||||
### How to personalize card
|
### How to personalize card
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue