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) {
|
||||
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);
|
||||
}
|
||||
int CIPURSESelectMFDefaultFile(uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
|
||||
|
@ -351,27 +352,176 @@ void CIPURSEPrintFileDescriptor(uint8_t 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) {
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Key Attributes") "---------------------");
|
||||
PrintAndLogEx(INFO, "Additional info... 0x%02x", attr[0]);
|
||||
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]);
|
||||
CIPURSEPrintKeySecurityAttributes(attr[3]);
|
||||
PrintAndLogEx(INFO, "KVV............... 0x%02x%02x%02x", attr[4], attr[5], attr[6]);
|
||||
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) {
|
||||
PrintAndLogEx(FAILED, "Attributes length too short");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("File Attributes") "---------------------");
|
||||
if (attr[0] == 0x38) {
|
||||
if (attr[0] == 0x38 || attr[0] == 0x3F) {
|
||||
PrintAndLogEx(INFO, "Type... MF, ADF");
|
||||
|
||||
if (attr[1] == 0x00) {
|
||||
if (attr[0] == 0x3F)
|
||||
PrintAndLogEx(INFO, "Type... PxSE");
|
||||
else
|
||||
PrintAndLogEx(INFO, "Type... MF");
|
||||
} else {
|
||||
if ((attr[1] & 0xe0) == 0x00)
|
||||
|
@ -404,64 +554,59 @@ void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) {
|
|||
uint8_t keynum = attr[6];
|
||||
PrintAndLogEx(INFO, "Keys assigned... %d", keynum);
|
||||
|
||||
if (len >= 9) {
|
||||
PrintAndLogEx(INFO, "SMR entries... %02x%02x", attr[7], attr[8]);
|
||||
int idx = 7;
|
||||
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) {
|
||||
PrintAndLogEx(INFO, "ART... %s", sprint_hex(&attr[9], keynum + 1));
|
||||
if (len >= idx + 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;
|
||||
if (len >= idx + keynum * reclen) {
|
||||
for (int i = 0; i < keynum; i++) {
|
||||
PrintAndLogEx(INFO, "Key %d Attributes... %s", i, sprint_hex(&attr[11 + keynum + 1 + i * 7], 7));
|
||||
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]);
|
||||
}
|
||||
}
|
||||
// MF
|
||||
if (attr[1] == 0x00) {
|
||||
PrintAndLogEx(INFO, "Total memory size... %d", (attr[len - 6] << 16) + (attr[len - 1] << 5) + attr[len - 4]);
|
||||
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 only
|
||||
if (attr[1] == 0x00 && attr[0] != 0x3F) {
|
||||
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]);
|
||||
|
||||
} else {
|
||||
int ptr = 11 + keynum + 1 + keynum * 7;
|
||||
if (len > ptr) {
|
||||
PrintAndLogEx(INFO, "TLV file control... %s", sprint_hex(&attr[ptr], len - ptr));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Type... EF");
|
||||
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]);
|
||||
CIPURSEPrintEFFileAttr(attr, len);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
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);
|
||||
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 CIPURSEPrintFileDescriptor(uint8_t desc);
|
||||
void CIPURSEPrintDGIArray(uint8_t *dgi, size_t dgilen);
|
||||
void CIPURSEPrintDGI(uint8_t *dgi, size_t dgilen);
|
||||
|
||||
#endif /* __CIPURSECORE_H__ */
|
||||
|
|
|
@ -531,9 +531,10 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
|||
static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
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 -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[] = {
|
||||
arg_param_begin,
|
||||
|
@ -541,6 +542,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
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_int0("o", "offset", "<dec>", "offset for reading data from file"),
|
||||
arg_lit0(NULL, "noauth", "read file without authentication"),
|
||||
|
@ -559,17 +561,20 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||
|
||||
uint8_t aid[16] = {0};
|
||||
size_t aidLen = 0;
|
||||
bool useAID = false;
|
||||
uint16_t fileId = defaultFileId;
|
||||
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) {
|
||||
CLIParserFree(ctx);
|
||||
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);
|
||||
|
||||
|
@ -579,15 +584,17 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
uint16_t sw = 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) {
|
||||
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();
|
||||
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));
|
||||
}
|
||||
|
||||
if (noAuth == false) {
|
||||
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
|
||||
|
@ -605,7 +612,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
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);
|
||||
PrintAndLogEx(ERR, "File select ( " _RED_("error") " ). Card returns 0x%04x", sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -633,9 +640,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
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",
|
||||
"hf cipurse write --fid 2ff7 -> 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");
|
||||
"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 -d aabb -> Authenticate with keyID 1, write file with id 2ff7\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[] = {
|
||||
arg_param_begin,
|
||||
|
@ -643,12 +652,14 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
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_int0("o", "offset", "<dec>", "offset for reading data from file"),
|
||||
arg_lit0(NULL, "noauth", "read file without authentication"),
|
||||
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("d", "data", "<hex>", "hex data to write to new file"),
|
||||
arg_lit0(NULL, "commit", "need commit after write"),
|
||||
arg_param_end
|
||||
};
|
||||
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 aid[16] = {0};
|
||||
size_t aidLen = 0;
|
||||
bool useAID = false;
|
||||
uint16_t fileId = defaultFileId;
|
||||
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) {
|
||||
CLIParserFree(ctx);
|
||||
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};
|
||||
int hdatalen = sizeof(hdata);
|
||||
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
||||
CLIGetHexWithReturn(ctx, 11, hdata, &hdatalen);
|
||||
if (hdatalen == 0) {
|
||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
bool needCommit = arg_get_lit(ctx, 12);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
|
||||
size_t len = 0;
|
||||
uint16_t sw = 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) {
|
||||
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();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -742,6 +759,16 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
|
||||
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();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -750,7 +777,10 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
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",
|
||||
"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");
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -759,12 +789,13 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
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, "chfid", "<hex 2 bytes>", "child file ID (EF under application/master file)"),
|
||||
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, "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
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -772,41 +803,55 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
bool APDULogging = arg_get_lit(ctx, 1);
|
||||
bool verbose = arg_get_lit(ctx, 2);
|
||||
uint8_t keyId = arg_get_int_def(ctx, 3, defaultKeyId);
|
||||
bool selmfd = arg_get_lit(ctx, 5);
|
||||
|
||||
CipurseChannelSecurityLevel sreq = CPSMACed;
|
||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||
uint8_t key[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||
|
||||
uint8_t aid[16] = {0};
|
||||
size_t aidLen = 0;
|
||||
bool useAID = false;
|
||||
uint16_t fileId = defaultFileId;
|
||||
bool useFID = false;
|
||||
int res = CLIParseCommandParameters(ctx, 4, 0, 5, 7, 8, key, NULL, NULL, NULL, &fileId, &useFID, &sreq, &sresp);
|
||||
if (res || useFID == false) {
|
||||
uint16_t childFileId = defaultFileId;
|
||||
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);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
bool noAuth = arg_get_lit(ctx, 6);
|
||||
bool seladf = arg_get_lit(ctx, 9);
|
||||
bool selmf = arg_get_lit(ctx, 10);
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
bool noAuth = arg_get_lit(ctx, 9);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
SetAPDULogging(APDULogging);
|
||||
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 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) {
|
||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x", sw);
|
||||
PrintAndLogEx(WARNING, "useaid=%d res=%d sw=%x", useAID, res, sw);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
|
||||
, fileId
|
||||
if (selmfd)
|
||||
PrintAndLogEx(INFO, "File " _CYAN_("Master File"));
|
||||
else if (useFID)
|
||||
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)
|
||||
);
|
||||
|
@ -825,23 +870,6 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
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);
|
||||
if (res != 0 || sw != 0x9000) {
|
||||
if (verbose == false)
|
||||
|
@ -851,13 +879,13 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (len == 0) {
|
||||
PrintAndLogEx(WARNING, "File id " _YELLOW_("%x") " attributes is empty", fileId);
|
||||
PrintAndLogEx(WARNING, "File attributes is empty");
|
||||
DropField();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -1014,17 +1042,8 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
SetAPDULogging(APDULogging);
|
||||
|
||||
if (verbose && hdatalen > 3) {
|
||||
if (hdata[0] == 0x92 && hdata[1] == 0x00)
|
||||
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");
|
||||
}
|
||||
if (verbose && hdatalen > 3)
|
||||
CIPURSEPrintDGIArray(hdata, hdatalen);
|
||||
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
|
@ -1280,6 +1299,7 @@ static int CmdHFCipurseDefault(const char *Cmd) {
|
|||
memcpy(defaultKey, ckey, CIPURSE_AES_KEY_LENGTH);
|
||||
uint8_t aid[CIPURSE_MAX_AID_LENGTH] = CIPURSE_DEFAULT_AID;
|
||||
memcpy(defaultAID, aid, CIPURSE_MAX_AID_LENGTH);
|
||||
defaultAIDLength = 5;
|
||||
}
|
||||
|
||||
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```
|
||||
|
||||
|
||||
### 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
|
||||
^[Top](#top)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue