From 40227edd7efb7c6caed2bb13ed21e72a1aaf428f Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 23 Jul 2021 20:50:23 +0300 Subject: [PATCH] refactoring and create value file command sketch --- client/src/cmdhfmfdes.c | 638 +++++++++++++++++++++++----------------- 1 file changed, 375 insertions(+), 263 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 1eafed7fe..655ebfbf2 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1980,39 +1980,6 @@ static int handler_desfire_clear_record_file(uint8_t file_no) { return res; } -static int handler_desfire_create_value_file(mfdes_value_file_t *value) { - if (value->fileno > 0x1F) return PM3_EINVARG; - - sAPDU apdu = {0x90, MFDES_CREATE_VALUE_FILE, 0x00, 0x00, sizeof(mfdes_value_file_t), (uint8_t *)value}; // 0xCc - - uint16_t sw = 0; - uint32_t recvlen = 0; - int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create value -> %s"), DesfireGetErrorString(res, &sw)); - DropFieldDesfire(); - return res; - } - return res; -} - -/*static int handler_desfire_create_std_file(mfdes_file_t *file) { - if (file->fileno > 0x1F) - return PM3_EINVARG; - - sAPDU apdu = {0x90, MFDES_CREATE_STD_DATA_FILE, 0x00, 0x00, sizeof(mfdes_file_t), (uint8_t *)file}; // 0xCD - - uint16_t sw = 0; - uint32_t recvlen = 0; - int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't create file -> %s"), DesfireGetErrorString(res, &sw)); - DropFieldDesfire(); - return res; - } - return res; -}*/ - static int handler_desfire_create_linearrecordfile(mfdes_linear_t *file) { if (file->fileno > 0x1F) return PM3_EINVARG; @@ -2875,152 +2842,6 @@ static int CmdHF14ADesCreateRecordFile(const char *Cmd) { return res; } -static int CmdHF14ADesCreateValueFile(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes createvaluefile", - "Create Value File\n" - "Make sure to select aid or authenticate aid before running this command.", - "hf mfdes createvaluefile -n 03 -c 0 -r EEEE -l 00000000 -u 00002000 --val 00000001 -m 02 -a 123456\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_int0("n", "fileno", "", "File Number (0 - 31)"), - arg_int0("c", "com", "", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"), - arg_strx0("r", "rights", "", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"), - arg_strx0("l", "lower", "", "Lower limit (4 hex bytes, big endian)"), - arg_strx0("u", "upper", "", "Upper limit (4 hex bytes, big endian)"), - arg_strx0(NULL, "val", "", "Value (4 hex bytes, big endian)"), - arg_int0("m", NULL, "", "Limited Credit enabled (Bit 0 = Limited Credit, 1 = FreeValue)"), - arg_strx0("a", "aid", "", "App ID to select as hex bytes (3 bytes,big endian,optional)"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, false); - int fno = arg_get_int_def(ctx, 1, 0); - uint8_t comset = arg_get_int(ctx, 2); - - int arlength = 0; - uint8_t ar[2] = {0}; - CLIGetHexWithReturn(ctx, 3, ar, &arlength); - - int lllen = 0; - uint8_t lowerlimit[4] = {0}; - CLIGetHexWithReturn(ctx, 4, lowerlimit, &lllen); - - int ullen = 0; - uint8_t upperlimit[4] = {0}; - CLIGetHexWithReturn(ctx, 5, upperlimit, &ullen); - - int vllen = 0; - uint8_t value[4] = {0}; - CLIGetHexWithReturn(ctx, 6, value, &vllen); - - uint8_t limited = arg_get_int_def(ctx, 7, 0); - - int aidlength = 3; - uint8_t aid[3] = {0}; - CLIGetHexWithReturn(ctx, 8, aid, &aidlength); - swap24(aid); - CLIParserFree(ctx); - - swap32(lowerlimit); - swap32(upperlimit); - swap32(value); - - if (fno > 0x1F) { - PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno); - return PM3_EINVARG; - } - - if (comset != 0 && comset != 1 && comset != 3) { - PrintAndLogEx(ERR, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt"); - return PM3_EINVARG; - } - - if (arlength != 2) { - PrintAndLogEx(ERR, "Access rights must have 2 hex bytes length"); - return PM3_EINVARG; - } - - if (lllen != 4) { - PrintAndLogEx(ERR, "Lower limit must have 4 hex bytes length"); - return PM3_EINVARG; - } - - if (ullen != 4) { - PrintAndLogEx(ERR, "Upper limit must have 4 hex bytes length"); - return PM3_EINVARG; - } - - if (vllen != 4) { - PrintAndLogEx(ERR, "Value must have 4 hex bytes length"); - return PM3_EINVARG; - } - - mfdes_value_file_t ft = { - .fileno = fno, - .comset = comset, - .limitedcreditenabled = limited, - }; - - memcpy(ft.access_rights, ar, 2); - memcpy(ft.lowerlimit, lowerlimit, 4); - memcpy(ft.upperlimit, upperlimit, 4); - memcpy(ft.value, value, 4); - - if (aidlength != 3 && aidlength != 0) { - PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian).")); - return PM3_ESOFT; - } else if (aidlength == 0) { - if (memcmp(&tag->selected_application, aid, 3) == 0) { - PrintAndLogEx(ERR, _RED_(" You need to select an aid first.")); - return PM3_ESOFT; - } - memcpy(aid, (uint8_t *)&tag->selected_application, 3); - } - - if (handler_desfire_select_application(aid) != PM3_SUCCESS) { - PrintAndLogEx(ERR, _RED_(" Error on selecting aid.")); - return PM3_ESOFT; - } - - int res = handler_desfire_create_value_file(&ft); - if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Successfully created value file."); - } else { - PrintAndLogEx(ERR, "Couldn't create value file. Error %d", res); - } - DropFieldDesfire(); - return res; -} -/* -static int CmdHF14ADesFormatPICC(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes formatpicc", - "Formats MIFARE DESFire PICC to factory state\n" - "Make sure to authenticate picc before running this command.", - "hf mfdes formatpicc" - ); - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - sAPDU apdu = {0x90, MFDES_FORMAT_PICC, 0x00, 0x00, 0, NULL}; // 0xDF - uint16_t sw = 0; - uint32_t recvlen = 0; - int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_(" Can't format picc -> %s"), DesfireGetErrorString(res, &sw)); - } else { - PrintAndLogEx(INFO, "Card successfully reset"); - } - DropFieldDesfire(); - return res; -}*/ - static int CmdHF14ADesInfo(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes info", @@ -6198,11 +6019,116 @@ static int CmdHF14ADesChFileSettings(const char *Cmd) { return PM3_SUCCESS; } +static int DesfireCreateFileParameters( + CLIParserContext *ctx, + + uint8_t pfileid, uint8_t pisofileid, + uint8_t amodeid, + uint8_t frightsid, + uint8_t r_modeid, uint8_t w_modeid, uint8_t rw_modeid, uint8_t ch_modeid, + + uint8_t *data, + size_t *datalen + ) { + *datalen = 0; + int res = 0; + + uint32_t fileid = 1; + if (pfileid) { + res = arg_get_u32_hexstr_def_nlen(ctx, pfileid, 1, &fileid, 1, true); + if (res == 2) { + PrintAndLogEx(ERR, "File ID must have 1 byte length"); + return PM3_EINVARG; + } + } + + uint32_t isofileid = 0; + if (pisofileid) { + res = arg_get_u32_hexstr_def_nlen(ctx, pisofileid, 0, &isofileid, 2, true); + if (res == 2) { + PrintAndLogEx(ERR, "ISO file ID must have 2 bytes length"); + return PM3_EINVARG; + } + } + + data[0] = fileid; + *datalen = 1; + + if (isofileid > 0) { + data[1] = (isofileid >> 8) & 0xff; + data[2] = isofileid & 0xff; + *datalen += 2; + } + + uint8_t *settings = &data[*datalen]; + + // file access mode + int cmode = DCMNone; + if (amodeid) { + if (CLIGetOptionList(arg_get_str(ctx, amodeid), DesfireCommunicationModeOpts, &cmode)) { + return PM3_ESOFT; + } + + if (cmode == DCMPlain) + settings[0] = 0x00; + if (cmode == DCMMACed) + settings[0] = 0x01; + if (cmode == DCMEncrypted) + settings[0] = 0x03; + (*datalen)++; + } + + // file rights + uint32_t frights = 0xeeee; + bool userawfrights = false; + if (frightsid) { + res = arg_get_u32_hexstr_def_nlen(ctx, frightsid, 0xeeee, &frights, 2, true); + userawfrights = (res == 1); + if (res == 2) { + PrintAndLogEx(ERR, "File rights must have 2 bytes length"); + return PM3_EINVARG; + } + } + settings[1] = frights & 0xff; + settings[2] = (frights >> 8) & 0xff; + + if (userawfrights == false) { + int r_mode = 0x0e; + if (r_modeid) { + if (CLIGetOptionList(arg_get_str(ctx, r_modeid), DesfireFileAccessModeOpts, &r_mode)) + return PM3_ESOFT; + } + + int w_mode = 0x0e; + if (w_modeid) { + if (CLIGetOptionList(arg_get_str(ctx, w_modeid), DesfireFileAccessModeOpts, &w_mode)) + return PM3_ESOFT; + } + + int rw_mode = 0x0e; + if (rw_modeid) { + if (CLIGetOptionList(arg_get_str(ctx, rw_modeid), DesfireFileAccessModeOpts, &rw_mode)) + return PM3_ESOFT; + } + + int ch_mode = 0x0e; + if (ch_modeid) { + if (CLIGetOptionList(arg_get_str(ctx, ch_modeid), DesfireFileAccessModeOpts, &ch_mode)) + return PM3_ESOFT; + } + + DesfireEncodeFileAcessMode(&settings[1], r_mode, w_mode, rw_mode, ch_mode) ; + } + *datalen += 2; + + return PM3_SUCCESS; +} + static int CmdHF14ADesCreateFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes createfile", "Create Standard/Backup file in the application. Application master key needs to be provided or flag --no-auth set (depend on application settings).", - "--rawtype/--rawdata have priority over the other settings. and with these parameters you can create any file\n" + "--rawtype/--rawdata have priority over the other settings. and with these parameters you can create any file. file id comes from parameters, all the rest data must be in the --rawdata parameter\n" "--rawrights have priority over the separate rights settings.\n" "Key/mode/etc of the authentication depends on application settings\n" "hf mfdes createfile --aid 123456 --fid 01 --rawtype 01 --rawdata 000100EEEE000100 -> create file via sending rawdata to the card. Can be used to create any type of file. Authentication with defaults from `default` command\n" @@ -6243,6 +6169,7 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { bool verbose = arg_get_lit(ctx, 2); bool noauth = arg_get_lit(ctx, 22); bool backup = arg_get_lit(ctx, 24); + uint8_t filetype = (backup) ? 0x01 : 0x00; // backup / standard data file DesfireContext dctx; int securechann = defaultSecureChannel; @@ -6258,32 +6185,14 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { CLIParserFree(ctx); return PM3_EINVARG; } - - uint32_t fileid = 1; - res = arg_get_u32_hexstr_def_nlen(ctx, 12, 1, &fileid, 1, true); - if (res == 2) { - PrintAndLogEx(ERR, "File ID must have 1 byte length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - uint32_t isofileid = 0; - res = arg_get_u32_hexstr_def_nlen(ctx, 13, 0, &isofileid, 2, true); - if (res == 2) { - PrintAndLogEx(ERR, "ISO file ID must have 2 bytes length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - - uint8_t filetype = (backup) ? 0x01 : 0x00; // backup / standard data file uint8_t data[250] = {0}; - data[0] = fileid; - size_t datalen = 1; + size_t datalen = 0; - if (isofileid > 0) { - data[1] = (isofileid >> 8) & 0xff; - data[2] = isofileid & 0xff; - datalen += 2; + res = DesfireCreateFileParameters(ctx, 12, 13, 16, 17, 18, 19, 20, 21, data, &datalen); + if (res) { + CLIParserFree(ctx); + return res; } uint32_t rawftype = 0x00; @@ -6306,69 +6215,13 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { if (useraw && sdatalen > 0) { filetype = rawftype; - memcpy(&data[datalen], sdata, sdatalen); + memcpy(&data[1], sdata, sdatalen); datalen += sdatalen; } else { useraw = false; } if (useraw == false) { - uint8_t *settings = &data[datalen]; - - // file access mode - int cmode = DCMNone; - if (CLIGetOptionList(arg_get_str(ctx, 16), DesfireCommunicationModeOpts, &cmode)) { - CLIParserFree(ctx); - return PM3_ESOFT; - } - - if (cmode == DCMPlain) - settings[0] = 0x00; - if (cmode == DCMMACed) - settings[0] = 0x01; - if (cmode == DCMEncrypted) - settings[0] = 0x03; - datalen++; - - // file rights - uint32_t frights = 0; - res = arg_get_u32_hexstr_def_nlen(ctx, 17, 0xeeee, &frights, 2, true); - bool userawfrights = (res == 1); - if (res == 2) { - PrintAndLogEx(ERR, "File rights must have 2 bytes length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - settings[1] = frights & 0xff; - settings[2] = (frights >> 8) & 0xff; - - if (userawfrights == false) { - int r_mode = 0x0e; - if (CLIGetOptionList(arg_get_str(ctx, 18), DesfireFileAccessModeOpts, &r_mode)) { - CLIParserFree(ctx); - return PM3_ESOFT; - } - int w_mode = 0x0e; - if (CLIGetOptionList(arg_get_str(ctx, 19), DesfireFileAccessModeOpts, &w_mode)) { - CLIParserFree(ctx); - return PM3_ESOFT; - } - int rw_mode = 0x0e; - if (CLIGetOptionList(arg_get_str(ctx, 20), DesfireFileAccessModeOpts, &rw_mode)) { - CLIParserFree(ctx); - return PM3_ESOFT; - } - int ch_mode = 0x0e; - if (CLIGetOptionList(arg_get_str(ctx, 21), DesfireFileAccessModeOpts, &ch_mode)) { - CLIParserFree(ctx); - return PM3_ESOFT; - } - - DesfireEncodeFileAcessMode(&settings[1], r_mode, w_mode, rw_mode, ch_mode) ; - } - datalen += 2; - - // file size uint32_t filesize = 0; res = arg_get_u32_hexstr_def_nlen(ctx, 23, 0, &filesize, 3, true); if (res == 2) { @@ -6408,7 +6261,9 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { } if (verbose) - PrintAndLogEx(INFO, "App: %06x. File num: 0x%02x type: 0x%02x data[%d]: %s", appid, fileid, filetype, datalen, sprint_hex(data, datalen)); + PrintAndLogEx(INFO, "App: %06x. File num: 0x%02x type: 0x%02x data[%d]: %s", appid, data[0], filetype, datalen, sprint_hex(data, datalen)); + DesfirePrintCreateFileSettings(filetype, data, datalen); + res = DesfireCreateFile(&dctx, filetype, data, datalen, useraw == false); // check length only if we nont use raw mode if (res != PM3_SUCCESS) { @@ -6417,12 +6272,269 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "File %02x in the app %06x created " _GREEN_("successfully"), fileid, appid); + PrintAndLogEx(SUCCESS, "File %02x in the app %06x created " _GREEN_("successfully"), data[0], appid); DropField(); return PM3_SUCCESS; } +static int CmdHF14ADesCreateValueFile(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes createvaluefile", + "Create Standard/Backup file in the application. Application master key needs to be provided or flag --no-auth set (depend on application settings).", + "--rawrights have priority over the separate rights settings.\n" + "Key/mode/etc of the authentication depends on application settings\n" + "hf mfdes createvaluefile --aid 123456 --fid 01 --rawtype 01 --rawdata 000100EEEE000100 -> create file via sending rawdata to the card. Can be used to create any type of file. Authentication with defaults from `default` command\n" + "hf mfdes createvaluefile --aid 123456 --fid 01 --amode plain --rrights free --wrights free --rwrights free --chrights key0 -> create file app=123456, file=01 and mentioned rights with defaults from `default` command\n" + "hf mfdes createvaluefile -n 0 -t des -k 0000000000000000 -f none --aid 123456 --fid 01 --rawtype 00 --rawdata 00EEEE000100 -> execute with default factory setup"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyno", "", "Key number"), + arg_str0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), + arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_str0("m", "cmode", "", "Communicaton mode: plain/mac/encrypt"), + arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), + arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2"), + arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), + arg_str0(NULL, "fid", "", "File ID (1 hex byte)"), + arg_str0(NULL, "isofid", "", "ISO File ID (2 hex bytes)"), + arg_str0(NULL, "amode", "", "File access mode: plain/mac/encrypt"), + arg_str0(NULL, "rawrights", "", "Access rights for file (HEX 2 byte) R/W/RW/Chg, 0x0 - 0xD Key, 0xE Free, 0xF Denied"), + arg_str0(NULL, "rrights", "", "Read file access mode: the specified key, free, deny"), + arg_str0(NULL, "wrights", "", "Write file access mode: the specified key, free, deny"), + arg_str0(NULL, "rwrights","", "Read/Write file access mode: the specified key, free, deny"), + arg_str0(NULL, "chrights","", "Change file settings access mode: the specified key, free, deny"), + arg_lit0(NULL, "no-auth", "execute without authentication"), + arg_str0(NULL, "lower", "", "Lower limit (4 hex bytes, big endian)"), + arg_str0(NULL, "upper", "", "Upper limit (4 hex bytes, big endian)"), + arg_str0(NULL, "value", "", "Value (4 hex bytes, big endian)"), + arg_int0(NULL, "lcredit", "", "Limited Credit enabled (Bit 0 = Limited Credit, 1 = FreeValue)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + bool noauth = arg_get_lit(ctx, 22); + + uint8_t filetype = 0x02; // value file + + DesfireContext dctx; + int securechann = defaultSecureChannel; + uint32_t appid = 0x000000; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + if (res) { + CLIParserFree(ctx); + return res; + } + + if (appid == 0x000000) { + PrintAndLogEx(ERR, "Can't create files at card level."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + if (appid == 0x000000) { + PrintAndLogEx(ERR, "Can't create files at card level."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint8_t data[250] = {0}; + size_t datalen = 0; + + res = DesfireCreateFileParameters(ctx, 12, 13, 16, 17, 18, 19, 20, 21, data, &datalen); + if (res) { + CLIParserFree(ctx); + return res; + } + + uint32_t filesize = 0; + res = arg_get_u32_hexstr_def_nlen(ctx, 23, 0, &filesize, 3, true); + if (res == 2) { + PrintAndLogEx(ERR, "File size must have 3 bytes length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + if (filesize == 0) { + PrintAndLogEx(ERR, "File size must be greater than 0"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + data[datalen] = (filesize >> 16) & 0xff; + data[datalen + 1] = (filesize >> 8) & 0xff; + data[datalen + 2] = filesize & 0xff; + datalen += 3; + + + SetAPDULogging(APDULogging); + CLIParserFree(ctx); + + if (noauth) { + res = DesfireSelectAIDHex(&dctx, appid, false, 0); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Desfire select " _RED_("error") "."); + DropField(); + return res; + } + } else { + res = DesfireSelectAndAuthenticate(&dctx, securechann, appid, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + } + + if (verbose) + PrintAndLogEx(INFO, "App: %06x. File num: 0x%02x type: 0x%02x data[%d]: %s", appid, data[0], filetype, datalen, sprint_hex(data, datalen)); + + + + + + + + + + + + + + + + + DropField(); + return PM3_SUCCESS; + + + + +/* CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes createvaluefile", + "Create Value File\n" + "Make sure to select aid or authenticate aid before running this command.", + "hf mfdes createvaluefile -n 03 -c 0 -r EEEE -l 00000000 -u 00002000 --val 00000001 -m 02 -a 123456\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_int0("n", "fileno", "", "File Number (0 - 31)"), + arg_int0("c", "com", "", "Communication setting (0 = Plain, 1 = Plain + MAC, 3 = Enciphered)"), + arg_strx0("r", "rights", "", "Access rights (2 hex bytes -> RW/Chg/R/W, 0x0 - 0xD Key, 0xE Free, 0xF Denied)"), + arg_strx0("l", "lower", "", "Lower limit (4 hex bytes, big endian)"), + arg_strx0("u", "upper", "", "Upper limit (4 hex bytes, big endian)"), + arg_strx0(NULL, "val", "", "Value (4 hex bytes, big endian)"), + arg_int0("m", NULL, "", "Limited Credit enabled (Bit 0 = Limited Credit, 1 = FreeValue)"), + arg_strx0("a", "aid", "", "App ID to select as hex bytes (3 bytes,big endian,optional)"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, false); + int fno = arg_get_int_def(ctx, 1, 0); + uint8_t comset = arg_get_int(ctx, 2); + + int arlength = 0; + uint8_t ar[2] = {0}; + CLIGetHexWithReturn(ctx, 3, ar, &arlength); + + int lllen = 0; + uint8_t lowerlimit[4] = {0}; + CLIGetHexWithReturn(ctx, 4, lowerlimit, &lllen); + + int ullen = 0; + uint8_t upperlimit[4] = {0}; + CLIGetHexWithReturn(ctx, 5, upperlimit, &ullen); + + int vllen = 0; + uint8_t value[4] = {0}; + CLIGetHexWithReturn(ctx, 6, value, &vllen); + + uint8_t limited = arg_get_int_def(ctx, 7, 0); + + int aidlength = 3; + uint8_t aid[3] = {0}; + CLIGetHexWithReturn(ctx, 8, aid, &aidlength); + swap24(aid); + CLIParserFree(ctx); + + swap32(lowerlimit); + swap32(upperlimit); + swap32(value); + + if (fno > 0x1F) { + PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno); + return PM3_EINVARG; + } + + if (comset != 0 && comset != 1 && comset != 3) { + PrintAndLogEx(ERR, "Communication setting must be either 0=Plain, 1=Plain+MAC or 3=Encrypt"); + return PM3_EINVARG; + } + + if (arlength != 2) { + PrintAndLogEx(ERR, "Access rights must have 2 hex bytes length"); + return PM3_EINVARG; + } + + if (lllen != 4) { + PrintAndLogEx(ERR, "Lower limit must have 4 hex bytes length"); + return PM3_EINVARG; + } + + if (ullen != 4) { + PrintAndLogEx(ERR, "Upper limit must have 4 hex bytes length"); + return PM3_EINVARG; + } + + if (vllen != 4) { + PrintAndLogEx(ERR, "Value must have 4 hex bytes length"); + return PM3_EINVARG; + } + + mfdes_value_file_t ft = { + .fileno = fno, + .comset = comset, + .limitedcreditenabled = limited, + }; + + memcpy(ft.access_rights, ar, 2); + memcpy(ft.lowerlimit, lowerlimit, 4); + memcpy(ft.upperlimit, upperlimit, 4); + memcpy(ft.value, value, 4); + + if (aidlength != 3 && aidlength != 0) { + PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian).")); + return PM3_ESOFT; + } else if (aidlength == 0) { + if (memcmp(&tag->selected_application, aid, 3) == 0) { + PrintAndLogEx(ERR, _RED_(" You need to select an aid first.")); + return PM3_ESOFT; + } + memcpy(aid, (uint8_t *)&tag->selected_application, 3); + } + + if (handler_desfire_select_application(aid) != PM3_SUCCESS) { + PrintAndLogEx(ERR, _RED_(" Error on selecting aid.")); + return PM3_ESOFT; + } + + int res = handler_desfire_create_value_file(&ft); + if (res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Successfully created value file."); + } else { + PrintAndLogEx(ERR, "Couldn't create value file. Error %d", res); + } + DropFieldDesfire(); + return res;*/ +} + static int CmdHF14ADesDeleteFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes deletefile", @@ -6544,7 +6656,7 @@ static command_t CommandTable[] = { {"changevalue", CmdHF14ADesChangeValue, IfPm3Iso14443a, "Write value of a value file (credit/debit/clear)"}, {"clearfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"}, {"createfile", CmdHF14ADesCreateFile, IfPm3Iso14443a, "[new]Create Standard/Backup File"}, - {"createvaluefile", CmdHF14ADesCreateValueFile, IfPm3Iso14443a, "Create Value File"}, + {"createvaluefile", CmdHF14ADesCreateValueFile, IfPm3Iso14443a, "[new]Create Value File"}, {"createrecordfile", CmdHF14ADesCreateRecordFile, IfPm3Iso14443a, "Create Linear/Cyclic Record File"}, {"deletefile", CmdHF14ADesDeleteFile, IfPm3Iso14443a, "[new]Delete File"}, {"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"},