mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3 into cip_key
This commit is contained in:
commit
01761cc273
12 changed files with 1163 additions and 929 deletions
|
@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `hf_mf_uidbruteforce` - added support for S70, enhance UID length management (@cactuschibre)
|
||||
- Fixed build issues that may happen from building `mfd_aes_brute` (@linuxgemini)
|
||||
- Added silicon data parsing logic for NXP chips in `hf mfu info` (@linuxgemini)
|
||||
- Addes luascript `hf_mf_em_util.lua` - Script for emulator configuration (@nisgola)
|
||||
- Fixes `hf mf restore` - now takes bin/eml/json as dump files (@iceman1001)
|
||||
- Fixes `script run some_python_script` segfault on armhf architecture (@doegox)
|
||||
- Added `trace extract` - extract authentication parts from trace (@iceman1001)
|
||||
|
|
108
client/luascripts/hf_mf_em_util.lua
Normal file
108
client/luascripts/hf_mf_em_util.lua
Normal file
|
@ -0,0 +1,108 @@
|
|||
local getopt = require('getopt')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
--Copyright
|
||||
copyright = ''
|
||||
author = 'nisgola'
|
||||
version = 'v1'
|
||||
|
||||
-- Script description
|
||||
desc = [[
|
||||
This is a script that write Sector Trailers to the emulator memory.
|
||||
|
||||
By default, both keys A and B are set to 0xFFFFFFFFFFFF.
|
||||
The Access Bytes are set to 0xFF0780 and User Bytes to 0x00.
|
||||
]]
|
||||
example = [[
|
||||
-- Use default formatting
|
||||
1. script run hf_mf_em_util
|
||||
|
||||
-- Change keys A and B
|
||||
2. script run hf_mf_em_util -a 112233445566 -b AABBCCDDEEFF
|
||||
|
||||
-- Define access bits and User byte
|
||||
3. script run hf_mf_em_util -x 00f0ff -u 12
|
||||
]]
|
||||
-- Usage info
|
||||
usage = [[
|
||||
script run hf_mf_em_util [-h] [-4] [-a <hex>] [-b <hex>] [-x <hex>] [-u <hex>]
|
||||
]]
|
||||
-- Arguments
|
||||
arguments = [[
|
||||
-h this help
|
||||
-4 format as 4K card
|
||||
-a <hex> define key A
|
||||
-b <hex> define key B
|
||||
-x <hex> define Access Bytes
|
||||
-u <hex> define User Byte
|
||||
]]
|
||||
-- Help function
|
||||
local function help()
|
||||
print(copyright)
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ansicolors.cyan..'Usage'..ansicolors.reset)
|
||||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
-- Print error
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
return nil,err
|
||||
end
|
||||
|
||||
-- Memory formatting
|
||||
local function card_format(key_a,key_b,ab,user,s70)
|
||||
local blocks = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107,111,115,119,123,127,143,159,175,191,207,223,239,255}
|
||||
for k,v in ipairs(blocks) do
|
||||
local cmd = string.format("hf mf esetblk --blk %s -d %s%s%s%s",v,key_a,ab,user,key_b)
|
||||
core.console(cmd)
|
||||
print(cmd)
|
||||
core.clearCommandBuffer()
|
||||
if s70 == false and k > 15 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
-- Receive parameters
|
||||
for o, a in getopt.getopt(args, 'ha:b:x:u:4') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'a' then KeyA = a end
|
||||
if o == 'b' then KeyB = a end
|
||||
if o == 'x' then Accessbit = a end
|
||||
if o == 'u' then User = a end
|
||||
if o == '4' then kkkk = true end
|
||||
end
|
||||
|
||||
local KeyA = KeyA or 'FFFFFFFFFFFF'
|
||||
if #(KeyA) ~= 12 then
|
||||
return oops( string.format('Wrong length of the Key A, receveid %d, expected 12', #KeyA))
|
||||
end
|
||||
|
||||
local KeyB = KeyB or 'FFFFFFFFFFFF'
|
||||
if #(KeyB) ~= 12 then
|
||||
return oops( string.format('Wrong length of the Key B, received %d, expected 12', #KeyB))
|
||||
end
|
||||
|
||||
local Accessbit = Accessbit or 'FF0780'
|
||||
if #(Accessbit) ~= 6 then
|
||||
return oops( string.format('Wrong length of the Access bit, received %d, expected 6', #Accessbit))
|
||||
end
|
||||
|
||||
local User = User or '00'
|
||||
if #(User) ~= 2 then
|
||||
return oops( string.format('Wrong lenght for the user defined byte, received %d, expected 2', #User))
|
||||
end
|
||||
|
||||
local kkkk = kkkk or false
|
||||
|
||||
-- Call card_format function
|
||||
card_format(KeyA,KeyB,Accessbit,User,kkkk)
|
||||
end
|
||||
main (args)
|
|
@ -11,11 +11,11 @@ desc =[[
|
|||
This script bruteforces 4 or 7 byte UID Mifare classic card numbers.
|
||||
]]
|
||||
example =[[
|
||||
Bruteforce a 4 byte UID Mifare classic card number, starting at 11223344, ending at 11223346.
|
||||
Bruteforce a 4 bytes UID Mifare classic card number, starting at 11223344, ending at 11223346.
|
||||
|
||||
script run hf_mf_uidbruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc
|
||||
|
||||
Bruteforce a 7 byte UID Mifare Ultralight card number, starting at 11223344556677, ending at 11223344556679.
|
||||
Bruteforce a 7 bytes UID Mifare Ultralight card number, starting at 11223344556677, ending at 11223344556679.
|
||||
|
||||
script run hf_mf_uidbruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu
|
||||
]]
|
||||
|
@ -28,8 +28,9 @@ arguments = [[
|
|||
-e 0-0xFFFFFFFF end id
|
||||
-t 0-99999, pause timeout (ms) between cards
|
||||
(use the word 'pause' to wait for user input)
|
||||
-x mfc, mfu mifare type:
|
||||
-x mfc, mfc4, mfu mifare type:
|
||||
mfc for Mifare Classic (default)
|
||||
mfc4 for Mifare Classic 4K
|
||||
mfu for Mifare Ultralight EV1
|
||||
]]
|
||||
|
||||
|
@ -86,23 +87,32 @@ local function main(args)
|
|||
local start_id = 0
|
||||
local end_id = 0xFFFFFFFFFFFFFF
|
||||
local mftype = 'mfc'
|
||||
local uid_format = '%14x'
|
||||
|
||||
for o, a in getopt.getopt(args, 'e:s:t:x:h') do
|
||||
if o == 's' then start_id = a end
|
||||
if o == 'e' then end_id = a end
|
||||
if o == 't' then timeout = a end
|
||||
if o == 'x' then mftype = a end
|
||||
if o == 'h' then return print(usage) end
|
||||
if o == 'h' then return help() end
|
||||
end
|
||||
|
||||
-- template
|
||||
local command = ''
|
||||
|
||||
-- if the end_id is equals or inferior to 0xFFFFFFFF then use the 4 bytes UID format by default
|
||||
if string.len(end_id) <= 10 then
|
||||
uid_format = '%08x'
|
||||
end
|
||||
|
||||
if mftype == 'mfc' then
|
||||
command = 'hf 14a sim -t 1 -u %014x'
|
||||
command = 'hf 14a sim -t 1 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Classic card numbers')
|
||||
elseif mftype == 'mfc4' then
|
||||
command = 'hf 14a sim -t 8 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Classic 4K card numbers')
|
||||
elseif mftype == 'mfu' then
|
||||
command = 'hf 14a sim -t 2 -u %014x'
|
||||
command = 'hf 14a sim -t 2 -u ' .. uid_format
|
||||
msg('Bruteforcing Mifare Ultralight card numbers')
|
||||
else
|
||||
return print(usage)
|
||||
|
|
|
@ -200,25 +200,30 @@ static int CLIParseCommandParametersEx(CLIParserContext *ctx, size_t keyid, size
|
|||
uint8_t hdata[250] = {0};
|
||||
int hdatalen = sizeof(hdata);
|
||||
if (keyid) {
|
||||
if (CLIParamHexToBuf(arg_get_str(ctx, keyid), hdata, hdatalen, &hdatalen))
|
||||
if (CLIParamHexToBuf(arg_get_str(ctx, keyid), hdata, hdatalen, &hdatalen)) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (hdatalen && hdatalen != 16) {
|
||||
PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (hdatalen)
|
||||
memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
|
||||
else
|
||||
memcpy(key, defaultKey, sizeof(defaultKey));
|
||||
}
|
||||
|
||||
if (useaid)
|
||||
if (useaid) {
|
||||
*useaid = false;
|
||||
}
|
||||
|
||||
if (aidid && aid && aidlen) {
|
||||
hdatalen = sizeof(hdata);
|
||||
if (CLIParamHexToBuf(arg_get_str(ctx, aidid), hdata, hdatalen, &hdatalen))
|
||||
if (CLIParamHexToBuf(arg_get_str(ctx, aidid), hdata, hdatalen, &hdatalen)) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (hdatalen && (hdatalen < 1 || hdatalen > 16)) {
|
||||
PrintAndLogEx(ERR, _RED_("ERROR:") " application id length must be 1-16 bytes only");
|
||||
|
@ -229,16 +234,19 @@ static int CLIParseCommandParametersEx(CLIParserContext *ctx, size_t keyid, size
|
|||
if (hdatalen) {
|
||||
memcpy(aid, hdata, hdatalen);
|
||||
*aidlen = hdatalen;
|
||||
if (useaid)
|
||||
if (useaid) {
|
||||
*useaid = true;
|
||||
}
|
||||
} else {
|
||||
memcpy(aid, defaultAID, defaultAIDLength);
|
||||
*aidlen = defaultAIDLength;
|
||||
}
|
||||
}
|
||||
|
||||
if (usefid)
|
||||
if (usefid) {
|
||||
*usefid = false;
|
||||
}
|
||||
|
||||
if (fidid && fid) {
|
||||
hdatalen = sizeof(hdata);
|
||||
if (CLIParamHexToBuf(arg_get_str(ctx, fidid), hdata, hdatalen, &hdatalen))
|
||||
|
@ -337,56 +345,75 @@ static int SelectCommandEx(bool selectDefaultFile, bool useAID, uint8_t *aid, si
|
|||
int res = 0;
|
||||
if (verbose && selChildFile)
|
||||
PrintAndLogEx(INFO, "Select top level application/file");
|
||||
|
||||
if (useAID && aidLen > 0) {
|
||||
|
||||
res = CIPURSESelectAID(true, true, aid, aidLen, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select application " _GREEN_("%s ") _RED_("error") ". Card returns 0x%04x", sprint_hex_inrow(aid, aidLen), *sw);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Cipurse select application " _CYAN_("%s ") _GREEN_("OK"), sprint_hex_inrow(aid, aidLen));
|
||||
}
|
||||
|
||||
} else if (useFID) {
|
||||
|
||||
res = CIPURSESelectFileEx(true, true, fileId, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select file 0x%04x " _RED_("error") ". Card returns 0x%04x", fileId, *sw);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Cipurse select file " _CYAN_("0x%04x ") _GREEN_("OK"), fileId);
|
||||
}
|
||||
|
||||
} else if (selectDefaultFile) {
|
||||
|
||||
res = CIPURSESelectMFDefaultFileEx(true, true, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select default file " _RED_("error") ". Card returns 0x%04x", *sw);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Cipurse select default file " _GREEN_("OK"));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
res = CIPURSESelect(true, true, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Cipurse select default application " _RED_("error") ". Card returns 0x%04x", *sw);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Cipurse select default application " _GREEN_("OK"));
|
||||
}
|
||||
}
|
||||
|
||||
if (selChildFile) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Select child file");
|
||||
}
|
||||
|
||||
res = CIPURSESelectFileEx(false, true, childFileId, buf, bufSize, len, sw);
|
||||
if (res != 0 || *sw != 0x9000) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(ERR, "Select child file 0x%04x " _RED_("error") ". Card returns 0x%04x", childFileId, *sw);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Select child file " _CYAN_("0x%04x ") _GREEN_("OK"), childFileId);
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
|
@ -408,13 +435,13 @@ static int CmdHFCipurseSelect(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_lit0("t", "tlv", "TLV decode returned data"),
|
||||
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
|
||||
arg_str0(NULL, "fid", "<hex 2 bytes>", "top level file (or application) ID (FID)"),
|
||||
arg_lit0(NULL, "mfd", "select masterfile by empty id"),
|
||||
arg_str0(NULL, "chfid", "<hex 2 bytes>", "child file ID (EF under application/master file)"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Application ID (AID) 1..16 bytes"),
|
||||
arg_str0(NULL, "fid", "<hex>", "Top level file (or application) ID (FID) 2 bytes"),
|
||||
arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
|
||||
arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) 2 bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -474,12 +501,12 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
|
||||
arg_str0(NULL, "fid", "<hex 2 bytes>", "top file/application ID (FID)"),
|
||||
arg_lit0(NULL, "mfd", "select masterfile by empty id"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
|
||||
arg_str0(NULL, "fid", "<hex>", "Top file/application ID (FID) ( 2 bytes )"),
|
||||
arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
|
||||
arg_int0("n", NULL, "<dec>", "Key ID"),
|
||||
arg_str0("k", "key", "<hex>", "Auth key"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -545,21 +572,21 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf cipurse read",
|
||||
"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 --aid 4144204631 --fid 0102 -> read file with id 0102 from application 4144204631\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,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
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(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
|
||||
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|encode>", "Communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -660,18 +687,18 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
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_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
|
||||
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|encode>", "communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "communication PICC-reader security level (def: mac)"),
|
||||
arg_str0("d", "data", "<hex>", "Data to write to new file"),
|
||||
arg_lit0(NULL, "commit", "Commit after write"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -797,17 +824,17 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
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, "mfd", "Show info about master file"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Select application ID (AID) ( 1..16 bytes )"),
|
||||
arg_str0(NULL, "fid", "<hex>", "File ID"),
|
||||
arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) ( 2 bytes )"),
|
||||
arg_lit0(NULL, "noauth", "Read file attributes without authentication"),
|
||||
arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -909,26 +936,26 @@ static int CmdHFCipurseWriteFileAttr(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf cipurse awrite",
|
||||
"Write 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 awrite --fid 2ff7 -d 080000C1C1C1C1C1C1C1C1C1 -> write default file attributes with id 2ff7\n"
|
||||
"hf cipurse awrite --mfd -d 080000FFFFFFFFFFFFFFFFFF86023232 --commit -> write file attributes for master file (MF)\n"
|
||||
"hf cipurse awrite --fid 2ff7 -d 080000C1C1C1C1C1C1C1C1C1 -> write default file attributes with id 2ff7\n"
|
||||
"hf cipurse awrite --mfd -d 080000FFFFFFFFFFFFFFFFFF86023232 --commit -> write file attributes for master file (MF)\n"
|
||||
"hf cipurse awrite --chfid 0102 -d 020000ffffff -> write file 0102 attributes in the default application to full access\n"
|
||||
"hf cipurse awrite --chfid 0102 -d 02000040ffff -> write file 0102 attributes in the default application to full access with keys 1 and 2\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
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_str0("d", "data", "<hex>", "file attributes"),
|
||||
arg_lit0(NULL, "commit", "need commit after write"),
|
||||
arg_lit0(NULL, "mfd", "Show info about master file"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Select application ID (AID) ( 1..16 bytes )"),
|
||||
arg_str0(NULL, "fid", "<hex>", "File ID"),
|
||||
arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) ( 2 bytes )"),
|
||||
arg_lit0(NULL, "noauth", "Read file attributes without authentication"),
|
||||
arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
|
||||
arg_str0("d", "data", "<hex>", "File attributes"),
|
||||
arg_lit0(NULL, "commit", "Commit after write"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -1053,13 +1080,13 @@ static int CmdHFCipurseFormatAll(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_int0("n", NULL, "<dec>", "Key ID"),
|
||||
arg_str0("k", "key", "<hex>", "Auth key"),
|
||||
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, "no-auth", "execute without authentication"),
|
||||
arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
|
||||
arg_lit0(NULL, "no-auth", "Execute without authentication"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -1138,20 +1165,20 @@ static int CmdHFCipurseCreateDGI(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
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 2 bytes>", "file ID (FID)"),
|
||||
arg_lit0(NULL, "mfd", "select masterfile by empty id"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
|
||||
arg_str0(NULL, "fid", "<hex>", "file ID (FID) ( 2 bytes )"),
|
||||
arg_lit0(NULL, "mfd", "Select masterfile by empty id"),
|
||||
|
||||
arg_str0("d", "data", "<hex>", "data with DGI for create"),
|
||||
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, "no-auth", "execute without authentication"),
|
||||
arg_lit0(NULL, "commit", "need commit after create"),
|
||||
arg_str0("d", "data", "<hex>", "Data with DGI for create"),
|
||||
arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
|
||||
arg_lit0(NULL, "no-auth", "Execute without authentication"),
|
||||
arg_lit0(NULL, "commit", "Commit after create"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -1272,17 +1299,17 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_int0("n", NULL, "<dec>", "key ID"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_int0("n", NULL, "<dec>", "Key ID"),
|
||||
arg_str0("k", "key", "<hex>", "Auth key"),
|
||||
arg_str0(NULL, "fid", "<hex>", "file/application ID under MF for delete"),
|
||||
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID) for delete"),
|
||||
arg_str0(NULL, "chfid", "<hex 2 bytes>", "child file ID (EF under application/master file)"),
|
||||
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, "no-auth", "execute without authentication"),
|
||||
arg_lit0(NULL, "commit", "commit "),
|
||||
arg_str0(NULL, "fid", "<hex>", "File/application ID under MF for delete"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Application ID (AID) for delete ( 1..16 bytes )"),
|
||||
arg_str0(NULL, "chfid", "<hex>", "Child file ID (EF under application/master file) ( 2 bytes )"),
|
||||
arg_str0(NULL, "sreq", "<plain|mac|encode>", "Communication reader-PICC security level (def: mac)"),
|
||||
arg_str0(NULL, "sresp", "<plain|mac|encode>", "Communication PICC-reader security level (def: mac)"),
|
||||
arg_lit0(NULL, "no-auth", "Execute without authentication"),
|
||||
arg_lit0(NULL, "commit", "commit after delete"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -1582,11 +1609,11 @@ static int CmdHFCipurseDefault(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0(NULL, "clear", "resets to defaults"),
|
||||
arg_lit0(NULL, "clear", "Resets to defaults"),
|
||||
arg_int0("n", NULL, "<dec>", "Key ID"),
|
||||
arg_str0("k", "key", "<hex>", "Authentication key"),
|
||||
arg_str0(NULL, "aid", "<hex 1..16 bytes>", "application ID (AID)"),
|
||||
arg_str0(NULL, "fid", "<hex 2 bytes>", "File ID"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Application ID (AID) ( 1..16 bytes )"),
|
||||
arg_str0(NULL, "fid", "<hex>", "File ID ( 2 bytes )"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
|
|
@ -137,22 +137,22 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
"challenge parameter (32b) and application parameter (32b).\n"
|
||||
"The default config filename is `fido2_defparams.json`\n"
|
||||
"\n",
|
||||
"hf fido reg -> execute command with 2 parameters, filled 0x00\n"
|
||||
"hf fido reg --cp s0 --ap s1 -> execute command with plain parameters\n"
|
||||
"hf fido reg -> execute command with 2 parameters, filled 0x00\n"
|
||||
"hf fido reg --cp s0 --ap s1 -> execute command with plain parameters\n"
|
||||
"hf fido reg --cpx 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f --apx 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\n"
|
||||
"hf fido reg -f fido2-params -> execute command with custom config file\n"
|
||||
"hf fido reg -f fido2-params -> execute command with custom config file\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU requests and responses"),
|
||||
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
||||
arg_str0("f", "file", "<fn>", "JSON input file name for parameters"),
|
||||
arg_str0(NULL, "cp", "<ascii>", "challenge parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "ap", "<ascii>", "application parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "cpx", "<hex>", "challenge parameter (32 bytes hex)"),
|
||||
arg_str0(NULL, "apx", "<hex>", "application parameter (32 bytes hex)"),
|
||||
arg_lit0("a", "apdu", "Show APDU requests and responses"),
|
||||
arg_litn("v", "verbose", 0, 2, "Verbose mode. vv - show full certificates data"),
|
||||
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
||||
arg_str0("f", "file", "<fn>", "JSON input file name for parameters"),
|
||||
arg_str0(NULL, "cp", "<str>", "Challenge parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "ap", "<str>", "Application parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "cpx", "<hex>", "Challenge parameter (32 bytes hex)"),
|
||||
arg_str0(NULL, "apx", "<hex>", "Application parameter (32 bytes hex)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||
|
@ -409,18 +409,18 @@ static int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_lit0("a", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_rem("default mode:", "dont-enforce-user-presence-and-sign"),
|
||||
arg_lit0("u", "user", "mode: enforce-user-presence-and-sign"),
|
||||
arg_lit0("c", "check", "mode: check-only"),
|
||||
arg_str0("f", "file", "<fn>", "JSON input file name for parameters"),
|
||||
arg_str0("k", "key", "<hex>", "public key to verify signature"),
|
||||
arg_str0(NULL, "kh", "<hex>", "key handle (var 0..255b)"),
|
||||
arg_str0(NULL, "cp", "<ascii>", "challenge parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "ap", "<ascii>", "application parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "cpx", "<hex>", "challenge parameter (32 bytes hex)"),
|
||||
arg_str0(NULL, "apx", "<hex>", "application parameter (32 bytes hex)"),
|
||||
arg_str0("f", "file", "<fn>", "JSON file name for parameters"),
|
||||
arg_str0("k", "key", "<hex>", "Public key to verify signature"),
|
||||
arg_str0(NULL, "kh", "<hex>", "Key handle (var 0..255b)"),
|
||||
arg_str0(NULL, "cp", "<str>", "Challenge parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "ap", "<str>", "Application parameter (1..16 chars)"),
|
||||
arg_str0(NULL, "cpx", "<hex>", "Challenge parameter (32 bytes hex)"),
|
||||
arg_str0(NULL, "apx", "<hex>", "Application parameter (32 bytes hex)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||
|
@ -671,11 +671,11 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
||||
arg_lit0("c", "cbor", "show CBOR decoded data"),
|
||||
arg_str0("f", "file", "<fn>", "parameter JSON file name"),
|
||||
arg_lit0("a", "apdu", "Show APDU reqests and responses"),
|
||||
arg_litn("v", "verbose", 0, 2, "Verbose mode. vv - show full certificates data"),
|
||||
arg_lit0("t", "tlv", "Show DER certificate contents in TLV representation"),
|
||||
arg_lit0("c", "cbor", "Show CBOR decoded data"),
|
||||
arg_str0("f", "file", "<fn>", "Parameter JSON file name"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||
|
@ -790,11 +790,11 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||
arg_litn("v", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||
arg_lit0("c", "cbor", "show CBOR decoded data"),
|
||||
arg_lit0("l", "list", "add CredentialId from json to allowList"),
|
||||
arg_str0("f", "file", "<fn>", "parameter JSON file name"),
|
||||
arg_lit0("a", "apdu", "Show APDU reqests and responses"),
|
||||
arg_litn("v", "verbose", 0, 2, "Verbose mode. vv - show full certificates data"),
|
||||
arg_lit0("c", "cbor", "Show CBOR decoded data"),
|
||||
arg_lit0("l", "list", "Add CredentialId from json to allowList"),
|
||||
arg_str0("f", "file", "<fn>", "Parameter JSON file name"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||
|
|
|
@ -3008,7 +3008,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
|
|||
arg_param_begin,
|
||||
arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
|
||||
arg_int0(NULL, "blk", "<dec>", "Input block number"),
|
||||
arg_lit0("a", NULL, "Target Key A, if found also check Key B for duplicate"),
|
||||
arg_lit0("a", NULL, "Target Key A"),
|
||||
arg_lit0("b", NULL, "Target Key B"),
|
||||
arg_lit0("*", "all", "Target both key A & B (default)"),
|
||||
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
|
||||
|
@ -3017,7 +3017,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
|
|||
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
||||
arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
|
||||
arg_lit0(NULL, "dump", "Dump found keys to binary file"),
|
||||
arg_str0("f", "file", "<fn>", "filename of dictionary"),
|
||||
arg_str0("f", "file", "<fn>", "Filename of dictionary"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -461,9 +461,9 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show internal data."),
|
||||
arg_str1(NULL, "ki", "<hex>", " key number, 2 hex bytes"),
|
||||
arg_str0(NULL, "key", "<hex>", " key, 16 hex bytes"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_str1(NULL, "ki", "<hex>", " Key number, 2 hex bytes"),
|
||||
arg_str0(NULL, "key", "<hex>", " Key, 16 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -527,8 +527,8 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_litn("v", "verbose", 0, 2, "show internal data."),
|
||||
arg_str0("k", "key", "<hex>", "key, 16 hex bytes"),
|
||||
arg_litn("v", "verbose", 0, 2, "Verbose mode"),
|
||||
arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -602,7 +602,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show internal data."),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
// arg_int0(NULL, "sl", "<dec>", "SL mode"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -649,9 +649,9 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show internal data."),
|
||||
arg_str1(NULL, "ki", "<hex>", "key number, 2 hex bytes"),
|
||||
arg_str1(NULL, "key", "<hex>", "key, 16 hex bytes"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_str1(NULL, "ki", "<hex>", "Key number, 2 hex bytes"),
|
||||
arg_str1(NULL, "key", "<hex>", "Key, 16 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -683,11 +683,11 @@ static int CmdHFMFPRdbl(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show internal data"),
|
||||
arg_int0("n", "count", "<dec>", "blocks count (by default 1)"),
|
||||
arg_lit0("b", "keyb", "use key B (by default keyA)"),
|
||||
arg_lit0("p", "plain", "plain communication mode between reader and card"),
|
||||
arg_int1(NULL, "blk", "<dec>", "block number (0..255)"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_int0("n", "count", "<dec>", "Blocks count (def: 1)"),
|
||||
arg_lit0("b", "keyb", "Use key B (def: keyA)"),
|
||||
arg_lit0("p", "plain", "Plain communication mode between reader and card"),
|
||||
arg_int1(NULL, "blk", "<0..255>", "Block number"),
|
||||
arg_str0(NULL, "key", "<hex>", "Key, 16 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -790,17 +790,17 @@ static int CmdHFMFPRdbl(const char *Cmd) {
|
|||
static int CmdHFMFPRdsc(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp rdsc",
|
||||
"Reads one sector from Mifare Plus card",
|
||||
"Reads one sector from MIFARE Plus card",
|
||||
"hf mfp rdsc -s 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n"
|
||||
"hf mfp rdsc -s 1 -v -> executes authentication and shows sector 1 data with default key");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show internal data."),
|
||||
arg_lit0("b", "keyb", "use key B (by default keyA)."),
|
||||
arg_lit0("p", "plain", "plain communication mode between reader and card."),
|
||||
arg_int1("s", "sn", "<dec>", "sector number (0..255)"),
|
||||
arg_str0("k", "key", "<hex>", "key, 16 hex bytes"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_lit0("b", "keyb", "Use key B (def: keyA)"),
|
||||
arg_lit0("p", "plain", "Plain communication mode between reader and card"),
|
||||
arg_int1("s", "sn", "<0..255>", "Sector number"),
|
||||
arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -893,11 +893,11 @@ static int CmdHFMFPWrbl(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show internal data."),
|
||||
arg_lit0("b", "keyb", "use key B (by default keyA)."),
|
||||
arg_int1(NULL, "blk", "<dec>", "block number (0..255)"),
|
||||
arg_str1("d", "data", "<hex>", "data, 16 hex bytes"),
|
||||
arg_str0("k", "key", "<hex>", "key, 16 hex bytes"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_lit0("b", "keyb", "Use key B (def: keyA)"),
|
||||
arg_int1(NULL, "blk", "<0..255>", "Block number"),
|
||||
arg_str1("d", "data", "<hex>", "Data, 16 hex bytes"),
|
||||
arg_str0("k", "key", "<hex>", "Key, 16 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -1097,7 +1097,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp chk",
|
||||
"Checks keys with Mifare Plus card.",
|
||||
"Checks keys on MIFARE Plus card",
|
||||
"hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
|
||||
"hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n"
|
||||
"hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
|
||||
|
@ -1106,17 +1106,17 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("a", "keya", "check only key A (by default check all keys)."),
|
||||
arg_lit0("b", "keyb", "check only key B (by default check all keys)."),
|
||||
arg_int0("s", "startsec", "Start sector Num (0..255)", NULL),
|
||||
arg_int0("e", "endsec", "End sector Num (0..255)", NULL),
|
||||
arg_str0("k", "key", "<Key>", "Key for checking (HEX 16 bytes)"),
|
||||
arg_str0("d", "dict", "<file>", "file with keys dictionary"),
|
||||
arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
|
||||
arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
|
||||
arg_str0(NULL, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||
arg_str0("j", "json", "<file>", "json file to save keys"),
|
||||
arg_lit0("v", "verbose", "verbose mode."),
|
||||
arg_lit0("a", "keya", "Check only key A (def: check all keys)"),
|
||||
arg_lit0("b", "keyb", "Check only key B (def: check all keys)"),
|
||||
arg_int0("s", "startsec", "<0..255>", "Start sector number"),
|
||||
arg_int0("e", "endsec", "<0..255>", "End sector number"),
|
||||
arg_str0("k", "key", "<hex>", "Key for checking (HEX 16 bytes)"),
|
||||
arg_str0("d", "dict", "<fn>", "Dictionary file with keys"),
|
||||
arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
|
||||
arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
|
||||
arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||
arg_str0("j", "json", "<fn>", "Json filename to save keys"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -1339,12 +1339,12 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "show technical data"),
|
||||
arg_str0(NULL, "aid", "<aid>", "print all sectors with aid"),
|
||||
arg_str0("k", "key", "<key>", "key for printing sectors"),
|
||||
arg_lit0("b", "keyb", "use key B for access printing sectors (by default: key A)"),
|
||||
arg_lit0(NULL, "be", "(optional, BigEndian)"),
|
||||
arg_lit0(NULL, "dch", "decode Card Holder information"),
|
||||
arg_lit0("v", "verbose", "Show technical data"),
|
||||
arg_str0(NULL, "aid", "<hex>", "Print all sectors with aid"),
|
||||
arg_str0("k", "key", "<hex>", "Key for printing sectors"),
|
||||
arg_lit0("b", "keyb", "Use key B for access printing sectors (def: key A)"),
|
||||
arg_lit0(NULL, "be", "(optional: BigEndian)"),
|
||||
arg_lit0(NULL, "dch", "Decode Card Holder information"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
|
|
@ -123,6 +123,39 @@ static char *getProductTypeStr(uint8_t id) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
static int ul_print_nxp_silicon_info(uint8_t *card_uid) {
|
||||
|
||||
if (card_uid[0] != 0x04) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t uid[7];
|
||||
memcpy(&uid, card_uid, 7);
|
||||
|
||||
uint16_t waferCoordX = ((uid[6] & 3) << 8) | uid[1];
|
||||
uint16_t waferCoordY = ((uid[6] & 12) << 6) | uid[2];
|
||||
uint32_t waferCounter = (
|
||||
(uid[4] << 5) |
|
||||
((uid[6] & 0xF0) << 17) |
|
||||
(uid[5] << 13) |
|
||||
(uid[3] >> 3)
|
||||
);
|
||||
uint8_t testSite = uid[3] & 7;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Silicon Information"));
|
||||
PrintAndLogEx(INFO, " Wafer Counter: %" PRId32 " ( 0x%02" PRIX32 " )", waferCounter, waferCounter);
|
||||
PrintAndLogEx(INFO, " Wafer Coordinates: x %" PRId16 ", y %" PRId16 " (0x%02" PRIX16 ", 0x%02" PRIX16 ")"
|
||||
, waferCoordX
|
||||
, waferCoordY
|
||||
, waferCoordX
|
||||
, waferCoordY
|
||||
);
|
||||
PrintAndLogEx(INFO, " Test Site: %u", testSite);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The 7 MSBits (=n) code the storage size itself based on 2^n,
|
||||
the LSBit is set to '0' if the size is exactly 2^n
|
||||
|
@ -456,16 +489,16 @@ static int ul_print_default(uint8_t *data, uint8_t *real_uid) {
|
|||
// CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2
|
||||
int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
|
||||
if (data[3] == crc0)
|
||||
PrintAndLogEx(SUCCESS, " BCC0: %02X (" _GREEN_("ok") ")", data[3]);
|
||||
PrintAndLogEx(SUCCESS, " BCC0: %02X ( " _GREEN_("ok") " )", data[3]);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, " BCC0: %02X, crc should be %02X", data[3], crc0);
|
||||
|
||||
int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
|
||||
if (data[8] == crc1)
|
||||
PrintAndLogEx(SUCCESS, " BCC1: %02X (" _GREEN_("ok") ")", data[8]);
|
||||
PrintAndLogEx(SUCCESS, " BCC1: %02X ( " _GREEN_("ok") " )", data[8]);
|
||||
else
|
||||
PrintAndLogEx(NORMAL, " BCC1: %02X, crc should be %02X", data[8], crc1);
|
||||
PrintAndLogEx(SUCCESS, " Internal: %02X (%s)", data[9], (data[9] == 0x48) ? _GREEN_("default") : _RED_("not default"));
|
||||
PrintAndLogEx(SUCCESS, " Internal: %02X ( %s )", data[9], (data[9] == 0x48) ? _GREEN_("default") : _RED_("not default"));
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Blocks 0-2: %s", sprint_hex(data + 0, 12));
|
||||
}
|
||||
|
@ -579,10 +612,10 @@ static int ndef_print_CC(uint8_t *data) {
|
|||
PrintAndLogEx(SUCCESS, " Additional feature information");
|
||||
PrintAndLogEx(SUCCESS, " %02X", data[3]);
|
||||
PrintAndLogEx(SUCCESS, " 00000000");
|
||||
PrintAndLogEx(SUCCESS, " xxx - %02X: RFU (%s)", msb3, (msb3 == 0) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx(SUCCESS, " xxx - %02X: RFU ( %s )", msb3, (msb3 == 0) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx(SUCCESS, " x - %02X: %s special frame", sf, (sf) ? "support" : "don\'t support");
|
||||
PrintAndLogEx(SUCCESS, " x - %02X: %s lock block", lb, (lb) ? "support" : "don\'t support");
|
||||
PrintAndLogEx(SUCCESS, " xx - %02X: RFU (%s)", mlrule, (mlrule == 0) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx(SUCCESS, " xx - %02X: RFU ( %s )", mlrule, (mlrule == 0) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx(SUCCESS, " x - %02X: IC %s multiple block reads", mbread, (mbread) ? "support" : "don\'t support");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1644,6 +1677,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
// print silicon info
|
||||
ul_print_nxp_silicon_info(card.uid);
|
||||
|
||||
// Get Version
|
||||
uint8_t version[10] = {0x00};
|
||||
status = ulev1_getVersion(version, sizeof(version));
|
||||
|
|
|
@ -97,6 +97,27 @@ static uint8_t extract_epurse[8] = {0};
|
|||
|
||||
#define SKIP_TO_NEXT(a) (TRACELOG_HDR_LEN + (a)->data_len + TRACELOG_PARITY_LEN((a)))
|
||||
|
||||
static uint16_t extractChall_ev2(uint16_t tracepos, uint8_t *trace, uint8_t cmdpos, uint8_t long_jmp) {
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
if (next_hdr->data_len != 21) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
PrintAndLogEx(INFO, "1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 16));
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[cmdpos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + cmdpos + long_jmp, 32));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
return tracepos;
|
||||
}
|
||||
|
||||
static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t *trace) {
|
||||
|
||||
// sanity check
|
||||
|
@ -270,6 +291,10 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
|||
return tracepos;
|
||||
}
|
||||
|
||||
if (hdr->isResponse) {
|
||||
return tracepos;
|
||||
}
|
||||
|
||||
// PCB [CID] [NAD] [INF] CRC CRC
|
||||
uint8_t pos = calc_pos(frame);
|
||||
uint8_t long_jmp = (data_len > 6) ? 4 : 1;
|
||||
|
@ -279,93 +304,103 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
|||
switch (frame[pos]) {
|
||||
|
||||
case MFDES_AUTHENTICATE: {
|
||||
|
||||
// Assume wrapped or unwrapped
|
||||
PrintAndLogEx(INFO, "AUTH NATIVE (keyNo %d)", frame[pos + long_jmp]);
|
||||
|
||||
if (hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
if (next_hdr->data_len < 7) {
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "DES 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, 16));
|
||||
}
|
||||
return tracepos;
|
||||
if (next_record_is_response(tracepos, trace) == false) {
|
||||
break;
|
||||
}
|
||||
break; // AUTHENTICATE_NATIVE
|
||||
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
if (next_hdr->data_len < 7) {
|
||||
break;
|
||||
}
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
PrintAndLogEx(INFO, "DES 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, 16));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
return tracepos; // AUTHENTICATE_NATIVE
|
||||
}
|
||||
case MFDES_AUTHENTICATE_ISO: {
|
||||
|
||||
// Assume wrapped or unwrapped
|
||||
PrintAndLogEx(INFO, "AUTH ISO (keyNo %d)", frame[pos + long_jmp]);
|
||||
if (hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
if (next_hdr->data_len < 7) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t tdea = 8;
|
||||
if (next_hdr->data_len > 20) {
|
||||
tdea = 16;
|
||||
PrintAndLogEx(INFO, "3TDEA 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, tdea));
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "2TDEA 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, tdea));
|
||||
}
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, (tdea << 1)));
|
||||
}
|
||||
return tracepos;
|
||||
if (next_record_is_response(tracepos, trace) == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
break; // AUTHENTICATE_STANDARD
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
if (next_hdr->data_len < 7) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t tdea = 8;
|
||||
if (next_hdr->data_len > 20) {
|
||||
tdea = 16;
|
||||
PrintAndLogEx(INFO, "3TDEA 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, tdea));
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "2TDEA 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, tdea));
|
||||
}
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, (tdea << 1)));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
return tracepos; // AUTHENTICATE_STANDARD
|
||||
}
|
||||
case MFDES_AUTHENTICATE_AES: {
|
||||
// Assume wrapped or unwrapped
|
||||
PrintAndLogEx(INFO, "AUTH AES (keyNo %d)", frame[pos + long_jmp]);
|
||||
if (hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
if (next_hdr->data_len < 7) {
|
||||
break;
|
||||
}
|
||||
PrintAndLogEx(INFO, "AES 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, 16));
|
||||
}
|
||||
return tracepos;
|
||||
if (next_record_is_response(tracepos, trace)) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
if (next_hdr->data_len < 7) {
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "AES 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||
|
||||
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||
|
||||
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, 16));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
return tracepos;
|
||||
}
|
||||
case MFDES_AUTHENTICATE_EV2F: {
|
||||
if (hdr->isResponse == false) {
|
||||
PrintAndLogEx(INFO, "AUTH EV2 First");
|
||||
}
|
||||
break;
|
||||
PrintAndLogEx(INFO, "AUTH EV2 First");
|
||||
uint16_t tmp = extractChall_ev2(tracepos, trace, pos, long_jmp);
|
||||
if (tmp == 0)
|
||||
break;
|
||||
else
|
||||
return tmp;
|
||||
|
||||
}
|
||||
case MFDES_AUTHENTICATE_EV2NF: {
|
||||
if (hdr->isResponse == false) {
|
||||
PrintAndLogEx(INFO, "AUTH EV2 Non First");
|
||||
}
|
||||
break;
|
||||
PrintAndLogEx(INFO, "AUTH EV2 Non First");
|
||||
uint16_t tmp = extractChall_ev2(tracepos, trace, pos, long_jmp);
|
||||
if (tmp == 0)
|
||||
break;
|
||||
else
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,11 +87,11 @@ static int CmdEMVSelect(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "keep field for next command"),
|
||||
arg_lit0("aA", "apdu", "show APDU requests and responses"),
|
||||
arg_lit0("sS", "select", "Activate field and select card"),
|
||||
arg_lit0("kK", "keep", "Keep field for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU requests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_str1(NULL, NULL, "<hex>", "Applet AID"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -138,11 +138,11 @@ static int CmdEMVSearch(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("sS", "select", "Activate field and select card"),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -192,13 +192,13 @@ static int CmdEMVPPSE(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("1", "pse", "pse (1PAY.SYS.DDF01) mode"),
|
||||
arg_lit0("2", "ppse", "ppse (2PAY.SYS.DDF01) mode (default mode)"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("sS", "select", "Activate field and select card"),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("1", "pse", "PSE (1PAY.SYS.DDF01) mode"),
|
||||
arg_lit0("2", "ppse", "PPSE (2PAY.SYS.DDF01) mode (def)"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -252,12 +252,12 @@ static int CmdEMVGPO(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("pP", "params", "load parameters from `emv_defparams.json` file for PDOLdata making from PDOL and parameters"),
|
||||
arg_lit0("mM", "make", "make PDOLdata from PDOL (tag 9F38) and parameters (by default uses default parameters)"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("pP", "params", "Load parameters from `emv_defparams.json` file for PDOLdata making from PDOL and parameters"),
|
||||
arg_lit0("mM", "make", "Make PDOLdata from PDOL (tag 9F38) and parameters (def: uses default parameters)"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_strx0(NULL, NULL, "<hex>", "PDOLdata/PDOL"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -361,10 +361,10 @@ static int CmdEMVReadRecord(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_strx1(NULL, NULL, "<hex>", "<SFI 1 byte><SFIrecord 1 byte"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -421,14 +421,14 @@ static int CmdEMVAC(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("cC", "cda", "executes CDA transaction. Needs to get SDAD in results."),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("cC", "cda", "Executes CDA transaction. Needs to get SDAD in results."),
|
||||
arg_str0("dD", "decision", "<aac|tc|arqc>", "Terminal decision. aac - declined, tc - approved, arqc - online authorisation requested"),
|
||||
arg_lit0("pP", "params", "load parameters from `emv_defparams.json` file for CDOLdata making from CDOL and parameters"),
|
||||
arg_lit0("mM", "make", "make CDOLdata from CDOL (tag 8C and 8D) and parameters (by default uses default parameters)"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("pP", "params", "Load parameters from `emv_defparams.json` file for CDOLdata making from CDOL and parameters"),
|
||||
arg_lit0("mM", "make", "Make CDOLdata from CDOL (tag 8C and 8D) and parameters (def: use default parameters)"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_strx1(NULL, NULL, "<hex>", "CDOLdata/CDOL"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -543,9 +543,9 @@ static int CmdEMVGenerateChallenge(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -595,12 +595,12 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("pP", "params", "load parameters from `emv_defparams.json` file for DDOLdata making from DDOL and parameters"),
|
||||
arg_lit0("mM", "make", "make DDOLdata from DDOL (tag 9F49) and parameters (by default uses default parameters)"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("kK", "keep", "Keep field ON for next command"),
|
||||
arg_lit0("pP", "params", "Load parameters from `emv_defparams.json` file for DDOLdata making from DDOL and parameters"),
|
||||
arg_lit0("mM", "make", "Make DDOLdata from DDOL (tag 9F49) and parameters (def: use default parameters)"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_strx1(NULL, NULL, "<hex>", "DDOLdata/DDOL"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -822,17 +822,17 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card."),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses."),
|
||||
arg_lit0("tT", "tlv", "TLV decode results."),
|
||||
arg_lit0("jJ", "jload", "Load transaction parameters from `emv_defparams.json` file."),
|
||||
arg_lit0("fF", "forceaid", "Force search AID. Search AID instead of execute PPSE."),
|
||||
arg_lit0("sS", "select", "Activate field and select card"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("jJ", "jload", "Load transaction parameters from `emv_defparams.json` file"),
|
||||
arg_lit0("fF", "forceaid", "Force search AID. Search AID instead of execute PPSE"),
|
||||
arg_rem("By default:", "Transaction type - MSD"),
|
||||
arg_lit0("vV", "qvsdc", "Transaction type - qVSDC or M/Chip."),
|
||||
arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."),
|
||||
arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standard behavior."),
|
||||
arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("vV", "qvsdc", "Transaction type - qVSDC or M/Chip"),
|
||||
arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)"),
|
||||
arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standard behavior"),
|
||||
arg_lit0("gG", "acgpo", "VISA. generate AC from GPO"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -1448,17 +1448,17 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses."),
|
||||
arg_lit0("tT", "tlv", "TLV decode results."),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("tT", "tlv", "TLV decode results"),
|
||||
arg_lit0("eE", "extract", "Extract TLV elements and fill Application Data"),
|
||||
arg_lit0("jJ", "jload", "Load transaction parameters from `emv_defparams.json` file."),
|
||||
arg_lit0("jJ", "jload", "Load transaction parameters from `emv_defparams.json` file"),
|
||||
arg_rem("By default:", "Transaction type - MSD"),
|
||||
arg_lit0("vV", "qvsdc", "Transaction type - qVSDC or M/Chip."),
|
||||
arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."),
|
||||
arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standard behavior."),
|
||||
arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."),
|
||||
arg_lit0("vV", "qvsdc", "Transaction type - qVSDC or M/Chip"),
|
||||
arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)"),
|
||||
arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standard behavior"),
|
||||
arg_lit0("gG", "acgpo", "VISA. generate AC from GPO"),
|
||||
arg_lit0("mM", "merge", "Merge output file with card's data. (warning: the file may be corrupted!)"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_str1(NULL, NULL, "<fn>", "JSON output filename"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -1839,8 +1839,8 @@ static int CmdEMVTest(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("i", "ignore", "ignore timing tests for VM"),
|
||||
arg_lit0("l", "long", "run long tests too"),
|
||||
arg_lit0("i", "ignore", "Ignore timing tests for VM"),
|
||||
arg_lit0("l", "long", "Run long tests too"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -1871,9 +1871,9 @@ static int CmdEMVRoca(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("tT", "selftest", "self test"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default"),
|
||||
arg_lit0("tT", "selftest", "Self test"),
|
||||
arg_lit0("aA", "apdu", "Show APDU reqests and responses"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. (def: Contactless interface)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -2124,17 +2124,17 @@ out:
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"exec", CmdEMVExec, IfPm3Iso14443, "Executes EMV contactless transaction."},
|
||||
{"pse", CmdEMVPPSE, IfPm3Iso14443, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
|
||||
{"search", CmdEMVSearch, IfPm3Iso14443, "Try to select all applets from applets list and print installed applets."},
|
||||
{"select", CmdEMVSelect, IfPm3Iso14443, "Select applet."},
|
||||
{"gpo", CmdEMVGPO, IfPm3Iso14443, "Execute GetProcessingOptions."},
|
||||
{"readrec", CmdEMVReadRecord, IfPm3Iso14443, "Read files from card."},
|
||||
{"genac", CmdEMVAC, IfPm3Iso14443, "Generate ApplicationCryptogram."},
|
||||
{"challenge", CmdEMVGenerateChallenge, IfPm3Iso14443, "Generate challenge."},
|
||||
{"intauth", CmdEMVInternalAuthenticate, IfPm3Iso14443, "Internal authentication."},
|
||||
{"scan", CmdEMVScan, IfPm3Iso14443, "Scan EMV card and save it contents to json file for emulator."},
|
||||
{"test", CmdEMVTest, AlwaysAvailable, "Crypto logic test."},
|
||||
{"exec", CmdEMVExec, IfPm3Iso14443, "Executes EMV contactless transaction"},
|
||||
{"pse", CmdEMVPPSE, IfPm3Iso14443, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory"},
|
||||
{"search", CmdEMVSearch, IfPm3Iso14443, "Try to select all applets from applets list and print installed applets"},
|
||||
{"select", CmdEMVSelect, IfPm3Iso14443, "Select applet"},
|
||||
{"gpo", CmdEMVGPO, IfPm3Iso14443, "Execute GetProcessingOptions"},
|
||||
{"readrec", CmdEMVReadRecord, IfPm3Iso14443, "Read files from card"},
|
||||
{"genac", CmdEMVAC, IfPm3Iso14443, "Generate ApplicationCryptogram"},
|
||||
{"challenge", CmdEMVGenerateChallenge, IfPm3Iso14443, "Generate challenge"},
|
||||
{"intauth", CmdEMVInternalAuthenticate, IfPm3Iso14443, "Internal authentication"},
|
||||
{"scan", CmdEMVScan, IfPm3Iso14443, "Scan EMV card and save it contents to json file for emulator"},
|
||||
{"test", CmdEMVTest, AlwaysAvailable, "Crypto logic test"},
|
||||
/*
|
||||
{"getrng", CmdEMVGetrng, IfPm3Iso14443, "get random number from terminal"},
|
||||
{"eload", CmdEmvELoad, IfPm3Iso14443, "load EMV tag into device"},
|
||||
|
@ -2142,7 +2142,7 @@ static command_t CommandTable[] = {
|
|||
{"sim", CmdEmvSim, IfPm3Iso14443, "simulate EMV tag"},
|
||||
{"clone", CmdEmvClone, IfPm3Iso14443, "clone an EMV tag"},
|
||||
*/
|
||||
{"list", CmdEMVList, AlwaysAvailable, "List ISO7816 history"},
|
||||
{"list", CmdEMVList, AlwaysAvailable, "List ISO7816 history"},
|
||||
{"roca", CmdEMVRoca, IfPm3Iso14443, "Extract public keys and run ROCA test"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
|
|
@ -2252,10 +2252,11 @@ static const DesfireCreateFileCommands_t DesfireFileCommands[] = {
|
|||
};
|
||||
|
||||
const DesfireCreateFileCommands_t *GetDesfireFileCmdRec(uint8_t type) {
|
||||
for (int i = 0; i < ARRAYLEN(DesfireFileCommands); i++)
|
||||
if (DesfireFileCommands[i].id == type)
|
||||
for (int i = 0; i < ARRAYLEN(DesfireFileCommands); i++) {
|
||||
if (DesfireFileCommands[i].id == type) {
|
||||
return &DesfireFileCommands[i];
|
||||
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2303,6 +2304,7 @@ const char *GetDesfireAccessRightStr(uint8_t right) {
|
|||
sprintf(int_access_str, "key 0x%02x", right);
|
||||
return int_access_str;
|
||||
}
|
||||
|
||||
if (right == 0x0e)
|
||||
return DesfireFreeStr;
|
||||
|
||||
|
@ -2332,8 +2334,9 @@ const char *AccessRightShortStr[] = {
|
|||
};
|
||||
|
||||
const char *GetDesfireAccessRightShortStr(uint8_t right) {
|
||||
if (right > 0x0f)
|
||||
if (right > 0x0F) {
|
||||
return DesfireNAStr;
|
||||
}
|
||||
|
||||
return AccessRightShortStr[right];
|
||||
}
|
||||
|
@ -2346,23 +2349,20 @@ void DesfireEncodeFileAcessMode(uint8_t *mode, uint8_t r, uint8_t w, uint8_t rw,
|
|||
void DesfireDecodeFileAcessMode(const uint8_t *mode, uint8_t *r, uint8_t *w, uint8_t *rw, uint8_t *ch) {
|
||||
// read
|
||||
if (r)
|
||||
*r = (mode[1] >> 4) & 0x0f; // hi 2b
|
||||
*r = (mode[1] >> 4) & 0x0F; // hi 2b
|
||||
// write
|
||||
if (w)
|
||||
*w = mode[1] & 0x0f;
|
||||
*w = mode[1] & 0x0F;
|
||||
// read/write
|
||||
if (rw)
|
||||
*rw = (mode[0] >> 4) & 0x0f; // low 2b
|
||||
*rw = (mode[0] >> 4) & 0x0F; // low 2b
|
||||
// change
|
||||
if (ch)
|
||||
*ch = mode[0] & 0x0f;
|
||||
*ch = mode[0] & 0x0F;
|
||||
}
|
||||
|
||||
void DesfirePrintAccessRight(uint8_t *data) {
|
||||
uint8_t r = 0;
|
||||
uint8_t w = 0;
|
||||
uint8_t rw = 0;
|
||||
uint8_t ch = 0;
|
||||
uint8_t r = 0, w = 0, rw = 0, ch = 0;
|
||||
DesfireDecodeFileAcessMode(data, &r, &w, &rw, &ch);
|
||||
PrintAndLogEx(SUCCESS, "read : %s", GetDesfireAccessRightStr(r));
|
||||
PrintAndLogEx(SUCCESS, "write : %s", GetDesfireAccessRightStr(w));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue