Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
Guilhem7 2021-06-25 11:50:06 +02:00 committed by GitHub
commit 9b63675e05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1060 additions and 337 deletions

View file

@ -3,6 +3,14 @@ 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 `hw setmux` - improve user feedback for special case (@iceman1001)
- Changed 'filename' - unified file name param across client (@iceman1001)
- Fix `lf em 4x05 brute/chk` - fixed input params crash (@iceman1001)
- Fix `lf hitag reader --23` - now accepts 6bytes key (@iceman1001)
- Fix coverity scans findigs (@merlokk, @iceman1001)
- Fix `hf iclass config` - now fallback to default config card configuration (@iceman1001)
- Changed `nfc parser` - now also identify xvcard types (@iceman1001)
- Added `hf mf gview` - view contents of a magic Gen3 GTU (@iceman1001)
- Added Standalone mode for nexwatch ID credentials (@Guilhem7, @MaximeBosca)
- Fix `lf em 4x50/4x70 *` reverted a missunderstanding in byte order macros (@iceman1001)
- Added more keys (@equipter)

View file

@ -131,7 +131,7 @@ The [public roadmap](https://github.com/RfidResearchGroup/proxmark3/wiki/Public-
## Supported operative systems
This repo compiles nicely on
- WSL1 on Windows 10
- Proxspace v3.9 [release v3.9](https://github.com/Gator96100/ProxSpace/releases)
- Proxspace enviroment [release v3.9](https://github.com/Gator96100/ProxSpace/releases)
- Windows/MinGW environment
- Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian
- Android / Termux
@ -155,7 +155,7 @@ We don't maintain any precompiled binaries in this repo. There is community effo
## Official channels
Where do you find the community?
- [RFID Hacking community discord server](https://discord.gg/QfPvGFRQxH)
- [Proxmark3 IRC channel](http://webchat.freenode.net/?channels=#proxmark3)
- [Proxmark3 IRC channel](https://web.libera.chat/?channels=#proxmark3)
- [Proxmark3 sub reddit](https://www.reddit.com/r/proxmark3/)
- [Proxmark3 forum](http://www.proxmark.org/forum/index.php)

View file

@ -1568,6 +1568,14 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareGen3Freez();
break;
}
case CMD_HF_MIFARE_G3_RDBL: {
struct p {
uint8_t blockno;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareG3ReadBlk(payload->blockno);
break;
}
case CMD_HF_MIFARE_PERSONALIZE_UID: {
struct p {
uint8_t keytype;

View file

@ -1148,6 +1148,9 @@ void SniffHitag2(void) {
// Enable and reset counter
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
int frame_count = 0, response = 0, overflow = 0, lastbit = 1, tag_sof = 4;
bool rising_edge = false, reader_frame = false, bSkip = true;
uint8_t rx[HITAG_FRAME_LEN];
@ -1293,11 +1296,15 @@ void SniffHitag2(void) {
// Reset the timer to restart while-loop that receives frames
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
}
LEDsoff();
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false);

View file

@ -246,6 +246,9 @@ void lf_init(bool reader, bool simulate) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
// Prepare data trace
uint32_t bufsize = 10000;

View file

@ -2594,6 +2594,42 @@ OUT:
BigBuf_free();
}
void MifareG3ReadBlk(uint8_t blockno) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
int retval = PM3_SUCCESS;
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *uid = BigBuf_malloc(10);
if (iso14443a_select_card(uid, NULL, NULL, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
LED_B_ON();
uint32_t save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
uint8_t cmd[] = { 0xCF, 0x00, 0x00, 0x00, 0x00, 0xCE, blockno, 0x00, 0x00};
AddCrc14A(cmd, sizeof(cmd) - 2);
ReaderTransmit(cmd, sizeof(cmd), NULL);
int res = ReaderReceive(buf, par);
if (res != 18) {
retval = PM3_ESOFT;
}
iso14a_set_timeout(save_iso14a_timeout);
LED_B_OFF();
OUT:
reply_ng(CMD_HF_MIFARE_G3_RDBL, retval, buf, 18);
// turns off
OnSuccessMagic();
BigBuf_free();
}
void MifareSetMod(uint8_t *datain) {
uint8_t mod = datain[0];

View file

@ -49,6 +49,9 @@ void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID wi
void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
// MFC GEN3 GTU
void MifareG3ReadBlk(uint8_t blockno);
void MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);

View file

@ -14,13 +14,17 @@
#define ALLOC 16
size_t DemodPCF7931(uint8_t **outBlocks) {
// 2021 iceman, memor
uint8_t bits[256] = {0x00};
uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr();
int GraphTraceLen = BigBuf_max_traceLen();
if (GraphTraceLen > 18000)
if (GraphTraceLen > 18000) {
GraphTraceLen = 18000;
}
int i = 2, j, lastval, bitidx, half_switch;
int clock = 64;
@ -38,15 +42,17 @@ size_t DemodPCF7931(uint8_t **outBlocks) {
/* Find first local max/min */
if (dest[1] > dest[0]) {
while (i < GraphTraceLen) {
if (!(dest[i] > dest[i - 1]) && dest[i] > lmax)
if (!(dest[i] > dest[i - 1]) && dest[i] > lmax) {
break;
}
i++;
}
dir = 0;
} else {
while (i < GraphTraceLen) {
if (!(dest[i] < dest[i - 1]) && dest[i] < lmin)
if (!(dest[i] < dest[i - 1]) && dest[i] < lmin) {
break;
}
i++;
}
dir = 1;
@ -58,6 +64,7 @@ size_t DemodPCF7931(uint8_t **outBlocks) {
block_done = 0;
for (bitidx = 0; i < GraphTraceLen; i++) {
if ((dest[i - 1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i - 1] < dest[i] && dir == 0 && dest[i] < lmin)) {
lc = i - lastval;
lastval = i;
@ -66,8 +73,8 @@ size_t DemodPCF7931(uint8_t **outBlocks) {
// Tolerance is 1/8 of clock rate (arbitrary)
if (ABS(lc - clock / 4) < tolerance) {
// 16T0
if ((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
if ((i - pmc) == lc) { // 16T0 was previous one
// It's a PMC
i += (128 + 127 + 16 + 32 + 33 + 16) - 1;
lastval = i;
pmc = 0;
@ -77,8 +84,8 @@ size_t DemodPCF7931(uint8_t **outBlocks) {
}
} else if (ABS(lc - clock / 2) < tolerance) {
// 32TO
if ((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
if ((i - pmc) == lc) { // 16T0 was previous one
// It's a PMC !
i += (128 + 127 + 16 + 32 + 33) - 1;
lastval = i;
pmc = 0;
@ -95,8 +102,9 @@ size_t DemodPCF7931(uint8_t **outBlocks) {
// Error
if (++warnings > 10) {
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("Error: too many detection errors, aborting.");
if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf("Error: too many detection errors, aborting");
}
return 0;
}
@ -122,13 +130,19 @@ size_t DemodPCF7931(uint8_t **outBlocks) {
block_done = 0;
half_switch = 0;
}
if (i < GraphTraceLen)
if (i < GraphTraceLen) {
dir = (dest[i - 1] > dest[i]) ? 0 : 1;
}
}
if (bitidx == 255)
if (bitidx == 255) {
bitidx = 0;
warnings = 0;
if (num_blocks == 4) break;
}
if (num_blocks == 4) {
break;
}
}
memcpy(outBlocks, blocks, 16 * num_blocks);
return num_blocks;
@ -138,10 +152,11 @@ bool IsBlock0PCF7931(uint8_t *block) {
// assuming all RFU bits are set to 0
// if PAC is enabled password is set to 0
if (block[7] == 0x01) {
if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7)
&& !memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7)) {
if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) &&
!memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7)) {
return true;
}
} else if (block[7] == 0x00) {
if (!memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7)) {
return true;
@ -211,8 +226,9 @@ void ReadPCF7931(void) {
// exit if too many errors during reading
if (tries > 50 && (2 * errors > tries)) {
if (DBGLEVEL >= DBG_INFO)
if (DBGLEVEL >= DBG_INFO) {
Dbprintf("[!!] Error reading the tag, only partial content");
}
goto end;
}
@ -461,27 +477,32 @@ void SendCmdPCF7931(uint32_t *tab) {
//initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; // clock at 48/32 MHz
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
tempo = AT91C_BASE_TC0->TC_CV;
for (u = 0; tab[u] != 0; u += 3) {
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while (tempo != tab[u])
while (tempo != tab[u]) {
tempo = AT91C_BASE_TC0->TC_CV;
}
// stop modulating antenna
LOW(GPIO_SSC_DOUT);
while (tempo != tab[u + 1])
while (tempo != tab[u + 1]) {
tempo = AT91C_BASE_TC0->TC_CV;
}
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while (tempo != tab[u + 2])
while (tempo != tab[u + 2]) {
tempo = AT91C_BASE_TC0->TC_CV;
}
}
LED_A_OFF();

View file

@ -125,6 +125,8 @@ void StartCountUS(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV > 0);

View file

@ -213,6 +213,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/iso7816/iso7816core.c
${PM3_ROOT}/client/src/cipurse/cipursecrypto.c
${PM3_ROOT}/client/src/cipurse/cipursecore.c
${PM3_ROOT}/client/src/cipurse/cipursetest.c
${PM3_ROOT}/client/src/loclass/cipher.c
${PM3_ROOT}/client/src/loclass/cipherutils.c
${PM3_ROOT}/client/src/loclass/elite_crack.c

View file

@ -559,6 +559,7 @@ SRCS = aiddesfire.c \
fido/fidocore.c \
cipurse/cipursecore.c \
cipurse/cipursecrypto.c \
cipurse/cipursetest.c \
fileutils.c \
flash.c \
generator.c \

View file

@ -506,6 +506,11 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat
CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen);
//PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(buf, buflen));
if (buflen == 0) {
PrintAndLogEx(ERR, "APDU can't decode crypto stream");
break;
}
micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH;
memcpy(micdata, buf, buflen);
memcpy(&micdata[micdatalen], &buf[buflen - 2], 2);

View file

@ -0,0 +1,375 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2021 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// tests for crypto
//-----------------------------------------------------------------------------
#include "cipursetest.h"
#include <unistd.h>
#include <string.h> // memcpy memset
#include "fileutils.h"
#include "cipurse/cipursecrypto.h"
#include "cipurse/cipursecore.h"
uint8_t Key[] = CIPURSE_DEFAULT_KEY;
uint8_t KeyKvv[CIPURSE_KVV_LENGTH] = {0x5f, 0xd6, 0x7b, 0xcb};
uint8_t TestRandom[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22};
uint8_t TestData[16] = {0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t TestDataPadded[16] = {0x11, 0x22, 0x33, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static bool TestKVV(void) {
uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
CipurseCGetKVV(Key, kvv);
bool res = memcmp(KeyKvv, kvv, CIPURSE_KVV_LENGTH) == 0;
if (res)
PrintAndLogEx(INFO, "kvv.............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "kvv.............. " _RED_("fail"));
return res;
}
static bool TestISO9797M2(void) {
uint8_t data[32] = {0};
size_t ddatalen = 0;
AddISO9797M2Padding(data, &ddatalen, TestData, 4, 16);
bool res = (ddatalen == 16);
res = res && (memcmp(data, TestDataPadded, ddatalen) == 0);
res = res && (FindISO9797M2PaddingDataLen(data, ddatalen) == 4);
if (res)
PrintAndLogEx(INFO, "ISO9797M2........ " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "ISO9797M2........ " _RED_("fail"));
return res;
}
static bool TestSMI(void) {
CipurseContext ctx = {0};
CipurseCClearContext(&ctx);
bool res = (isCipurseCChannelSecuritySet(&ctx) == false);
CipurseCChannelSetSecurityLevels(&ctx, CPSPlain, CPSPlain);
res = res && (CipurseCGetSMI(&ctx, false) == 0x00);
res = res && (CipurseCGetSMI(&ctx, true) == 0x01);
CipurseCChannelSetSecurityLevels(&ctx, CPSPlain, CPSMACed);
res = res && (CipurseCGetSMI(&ctx, false) == 0x04);
res = res && (CipurseCGetSMI(&ctx, true) == 0x05);
CipurseCChannelSetSecurityLevels(&ctx, CPSMACed, CPSMACed);
res = res && (CipurseCGetSMI(&ctx, false) == 0x44);
res = res && (CipurseCGetSMI(&ctx, true) == 0x45);
CipurseCChannelSetSecurityLevels(&ctx, CPSMACed, CPSEncrypted);
res = res && (CipurseCGetSMI(&ctx, false) == 0x48);
res = res && (CipurseCGetSMI(&ctx, true) == 0x49);
CipurseCChannelSetSecurityLevels(&ctx, CPSEncrypted, CPSEncrypted);
res = res && (CipurseCGetSMI(&ctx, false) == 0x88);
res = res && (CipurseCGetSMI(&ctx, true) == 0x89);
if (res)
PrintAndLogEx(INFO, "SMI.............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "SMI.............. " _RED_("fail"));
return res;
}
static bool TestMIC(void) {
uint8_t mic[4] = {0};
CipurseCGenerateMIC(TestData, 4, mic);
uint8_t valid_mic4[4] = {0xD4, 0x71, 0xA7, 0x73};
bool res = (memcmp(mic, valid_mic4, 4) == 0);
res = res && (CipurseCCheckMIC(TestData, 4, mic));
CipurseCGenerateMIC(TestData, 6, mic);
uint8_t valid_mic6[4] = {0xAA, 0x90, 0xFC, 0x5A};
res = res && (memcmp(mic, valid_mic6, 4) == 0);
res = res && (CipurseCCheckMIC(TestData, 6, mic));
if (res)
PrintAndLogEx(INFO, "MIC.............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "MIC.............. " _RED_("fail"));
return res;
}
static bool TestAuth(void) {
CipurseContext ctx = {0};
CipurseCClearContext(&ctx);
bool res = (isCipurseCChannelSecuritySet(&ctx) == false);
CipurseCSetKey(&ctx, 1, Key);
res = res && (memcmp(ctx.key, Key, 16) == 0);
res = res && (ctx.keyId == 1);
CipurseCSetRandomFromPICC(&ctx, TestRandom);
res = res && (memcmp(ctx.RP, TestRandom, 16) == 0);
res = res && (memcmp(ctx.rP, &TestRandom[16], 6) == 0);
uint8_t hrandom[] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
CipurseCSetRandomHost(&ctx);
res = res && (memcmp(ctx.RT, hrandom, 16) == 0);
res = res && (memcmp(ctx.rT, &hrandom[16], 6) == 0);
uint8_t authparams[16 + 16 + 6] = {0};
CipurseCAuthenticateHost(&ctx, authparams);
uint8_t aparamstest[] = {0x12, 0xAA, 0x79, 0xA9, 0x03, 0xC5, 0xB4, 0x6A, 0x27, 0x1B, 0x13, 0xAE, 0x02, 0x50, 0x1C, 0x99, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
};
res = res && (memcmp(authparams, aparamstest, sizeof(authparams)) == 0);
uint8_t ct[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
res = res && CipurseCCheckCT(&ctx, ct);
CipurseCChannelSetSecurityLevels(&ctx, CPSMACed, CPSMACed);
res = res && (isCipurseCChannelSecuritySet(&ctx) == true);
uint8_t framekey[] = {0xCF, 0x6F, 0x3A, 0x47, 0xFC, 0xAC, 0x8D, 0x38, 0x25, 0x75, 0x8B, 0xFC, 0x8B, 0x61, 0x68, 0xF3};
res = res && (memcmp(ctx.frameKey, framekey, sizeof(framekey)) == 0);
if (res)
PrintAndLogEx(INFO, "Auth............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "Auth............. " _RED_("fail"));
return res;
}
static bool TestMAC(void) {
CipurseContext ctx = {0};
// authentication
CipurseCClearContext(&ctx);
CipurseCSetKey(&ctx, 1, Key);
CipurseCSetRandomFromPICC(&ctx, TestRandom);
uint8_t authparams[16 + 16 + 6] = {0};
CipurseCAuthenticateHost(&ctx, authparams);
uint8_t ct[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
bool res = CipurseCCheckCT(&ctx, ct);
CipurseCChannelSetSecurityLevels(&ctx, CPSMACed, CPSMACed);
res = res && (isCipurseCChannelSecuritySet(&ctx) == true);
// check MAC
uint8_t mac[8] = {0};
CipurseCGenerateMAC(&ctx, TestData, 4, mac);
uint8_t testmac1[8] = {0xAB, 0x5C, 0x86, 0x18, 0x7F, 0x73, 0xEC, 0x4E};
res = res && (memcmp(mac, testmac1, 8) == 0);
uint8_t framekey1[] = {0x7D, 0x6F, 0x31, 0x40, 0xC8, 0x47, 0xED, 0x3F, 0x0A, 0x21, 0xE6, 0xFB, 0xC7, 0xDB, 0x27, 0xB0};
res = res && (memcmp(ctx.frameKey, framekey1, sizeof(framekey1)) == 0);
CipurseCCalcMACPadded(&ctx, TestData, 4, mac);
uint8_t testmac2[8] = {0x9F, 0xE9, 0x54, 0xBF, 0xFC, 0xA0, 0x7D, 0x75};
res = res && (memcmp(mac, testmac2, 8) == 0);
uint8_t framekey2[] = {0x1E, 0xD4, 0xB6, 0x87, 0x85, 0x93, 0x5B, 0xAF, 0xA9, 0xF2, 0xF0, 0x8F, 0xA9, 0xF0, 0xA5, 0xFB};
res = res && (memcmp(ctx.frameKey, framekey2, sizeof(framekey2)) == 0);
CipurseCCalcMACPadded(&ctx, TestData, 4, mac);
uint8_t testmac3[8] = {0x15, 0x6F, 0x08, 0x5C, 0x0F, 0x80, 0xE7, 0x07};
res = res && (memcmp(mac, testmac3, 8) == 0);
uint8_t framekey3[] = {0x0C, 0x42, 0x93, 0x73, 0x88, 0x8F, 0x63, 0xB3, 0x10, 0x8E, 0xDF, 0xDB, 0xC1, 0x20, 0x63, 0x4C};
res = res && (memcmp(ctx.frameKey, framekey3, sizeof(framekey3)) == 0);
uint8_t testmac4[8] = {0x0E, 0xF0, 0x70, 0xA6, 0xA1, 0x15, 0x9A, 0xB6};
res = res && CipurseCCheckMACPadded(&ctx, TestData, 4, testmac4);
uint8_t framekey4[] = {0xA0, 0x65, 0x1A, 0x62, 0x56, 0x5D, 0xD7, 0xC9, 0x32, 0xAE, 0x1D, 0xE0, 0xCF, 0x8D, 0xC1, 0xB9};
res = res && (memcmp(ctx.frameKey, framekey4, sizeof(framekey4)) == 0);
if (res)
PrintAndLogEx(INFO, "channel MAC...... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "channel MAC...... " _RED_("fail"));
return res;
}
static bool TestEncDec(void) {
CipurseContext ctx = {0};
// authentication
CipurseCClearContext(&ctx);
CipurseCSetKey(&ctx, 1, Key);
CipurseCSetRandomFromPICC(&ctx, TestRandom);
uint8_t authparams[16 + 16 + 6] = {0};
CipurseCAuthenticateHost(&ctx, authparams);
uint8_t ct[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
bool res = CipurseCCheckCT(&ctx, ct);
CipurseCChannelSetSecurityLevels(&ctx, CPSMACed, CPSMACed);
res = res && (isCipurseCChannelSecuritySet(&ctx) == true);
// check Encode-Decode
uint8_t dstdata[32] = {0};
size_t dstdatalen = 0;
CipurseCEncryptDecrypt(&ctx, TestData, 16, dstdata, true);
uint8_t tested1[16] = {0x5F, 0x01, 0x18, 0x79, 0xE0, 0x57, 0xA7, 0xE5, 0x34, 0x39, 0x6E, 0x32, 0x62, 0xF2, 0x71, 0x27};
res = res && (memcmp(dstdata, tested1, 16) == 0);
uint8_t tested2[16] = {0xA6, 0x22, 0xB5, 0xCF, 0xE8, 0x6E, 0x67, 0xF4, 0xAA, 0x88, 0xB1, 0x19, 0x87, 0xCF, 0xC9, 0xD2};
CipurseCEncryptDecrypt(&ctx, tested2, 16, dstdata, false);
res = res && (memcmp(dstdata, TestData, 16) == 0);
CipurseCChannelEncrypt(&ctx, TestData, 16, dstdata, &dstdatalen);
uint8_t tested3[32] = {0x1E, 0x0C, 0xD1, 0xF5, 0x8E, 0x0B, 0xAE, 0xF0, 0x06, 0xC6, 0xED, 0x73, 0x3F, 0x8A, 0x87, 0xCF,
0x36, 0xCC, 0xF2, 0xF4, 0x7D, 0x33, 0x50, 0xF1, 0x8E, 0xFF, 0xD1, 0x7D, 0x42, 0x88, 0xD5, 0xEE
};
res = res && (dstdatalen == 32);
res = res && (memcmp(dstdata, tested3, 32) == 0);
uint8_t tested4[32] = {0xC0, 0x42, 0xDB, 0xD9, 0x53, 0xFF, 0x01, 0xE5, 0xCC, 0x49, 0x8C, 0x9C, 0xDA, 0x60, 0x73, 0xA7,
0xE1, 0xEB, 0x14, 0x69, 0xF6, 0x39, 0xF3, 0xE1, 0x07, 0x03, 0x32, 0xF4, 0x27, 0xF9, 0x48, 0x3D
};
CipurseCChannelDecrypt(&ctx, tested4, 32, dstdata, &dstdatalen);
res = res && (dstdatalen == 16);
res = res && (memcmp(dstdata, TestData, 16) == 0);
if (res)
PrintAndLogEx(INFO, "channel EncDec... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "channel EncDec... " _RED_("fail"));
return res;
}
//void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, uint8_t *dstdatabuf, bool includeLe, uint8_t Le);
//void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw);
static bool TestAPDU(void) {
CipurseContext ctx = {0};
// authentication
CipurseCClearContext(&ctx);
CipurseCSetKey(&ctx, 1, Key);
CipurseCSetRandomFromPICC(&ctx, TestRandom);
uint8_t authparams[16 + 16 + 6] = {0};
CipurseCAuthenticateHost(&ctx, authparams);
uint8_t ct[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
bool res = CipurseCCheckCT(&ctx, ct);
CipurseCChannelSetSecurityLevels(&ctx, CPSMACed, CPSMACed);
res = res && (isCipurseCChannelSecuritySet(&ctx) == true);
// check APDU formatting
sAPDU srcAPDU = {0};
sAPDU dstAPDU = {0};
uint8_t dstdata[256] = {0};
size_t dstdatalen = 0;
// MACED APDU
srcAPDU.CLA = 0x00;
srcAPDU.INS = 0x55;
srcAPDU.P1 = 0x11;
srcAPDU.P2 = 0x22;
srcAPDU.data = TestData;
srcAPDU.Lc = 5;
CipurseCAPDUReqEncode(&ctx, &srcAPDU, &dstAPDU, dstdata, true, 0x88);
uint8_t test1[] = {0x45, 0x11, 0x22, 0x33, 0x44, 0x00, 0x88, 0x79, 0x2B, 0xB7, 0xDD, 0xD1, 0x69, 0xA6, 0x66};
res = res && ((srcAPDU.CLA | 0x04) == dstAPDU.CLA);
res = res && (srcAPDU.INS == dstAPDU.INS);
res = res && (srcAPDU.P1 == dstAPDU.P1);
res = res && (srcAPDU.P2 == dstAPDU.P2);
res = res && (dstAPDU.Lc == sizeof(test1));
res = res && (memcmp(dstdata, test1, sizeof(test1)) == 0);
uint16_t sw = 0;
uint8_t test2[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x9D, 0x80, 0xE7, 0xE3, 0x34, 0xE9, 0x97, 0x82, 0xdd, 0xee};
CipurseCAPDURespDecode(&ctx, test2, sizeof(test2), dstdata, &dstdatalen, &sw);
res = res && (dstdatalen == 6);
res = res && (memcmp(test2, dstdata, dstdatalen) == 0);
res = res && (sw == 0xddee);
// Plain APDU
CipurseCChannelSetSecurityLevels(&ctx, CPSPlain, CPSPlain);
CipurseCAPDUReqEncode(&ctx, &srcAPDU, &dstAPDU, dstdata, true, 0x55);
uint8_t test3[] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x00, 0x55};
res = res && ((srcAPDU.CLA | 0x04) == dstAPDU.CLA);
res = res && (srcAPDU.INS == dstAPDU.INS);
res = res && (srcAPDU.P1 == dstAPDU.P1);
res = res && (srcAPDU.P2 == dstAPDU.P2);
res = res && (dstAPDU.Lc == sizeof(test3));
res = res && (memcmp(dstdata, test3, sizeof(test3)) == 0);
uint8_t test4[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xcc, 0xdd};
CipurseCAPDURespDecode(&ctx, test4, sizeof(test4), dstdata, &dstdatalen, &sw);
res = res && (dstdatalen == 6);
res = res && (memcmp(test4, dstdata, dstdatalen) == 0);
res = res && (sw == 0xccdd);
// Encrypted APDU
CipurseCChannelSetSecurityLevels(&ctx, CPSEncrypted, CPSEncrypted);
CipurseCAPDUReqEncode(&ctx, &srcAPDU, &dstAPDU, dstdata, true, 0x55);
uint8_t test5[] = {0x89, 0x7D, 0xED, 0x0D, 0x04, 0x8E, 0xE1, 0x99, 0x08, 0x70, 0x56, 0x7C, 0xEE, 0x67, 0xB3, 0x33, 0x6F, 0x00};
res = res && ((srcAPDU.CLA | 0x04) == dstAPDU.CLA);
res = res && (srcAPDU.INS == dstAPDU.INS);
res = res && (srcAPDU.P1 == dstAPDU.P1);
res = res && (srcAPDU.P2 == dstAPDU.P2);
res = res && (dstAPDU.Lc == sizeof(test5));
res = res && (memcmp(dstdata, test5, sizeof(test5)) == 0);
uint8_t test6[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x7E, 0x4B, 0xA0, 0xB7, 0xcc, 0xdd};
//CipurseCChannelEncrypt(&ctx, test6, sizeof(test6), dstdata, &dstdatalen);
//PrintAndLogEx(INFO, "dstdata[%d]: %s", dstdatalen, sprint_hex(dstdata, dstdatalen));
uint8_t test7[] = {0x07, 0xEF, 0x16, 0x91, 0xE7, 0x0F, 0xB5, 0x10, 0x63, 0xCE, 0x66, 0xDB, 0x3B, 0xC6, 0xD4, 0xE0, 0x90, 0x00};
CipurseCAPDURespDecode(&ctx, test7, sizeof(test7), dstdata, &dstdatalen, &sw);
res = res && (dstdatalen == 8);
res = res && (memcmp(test6, dstdata, dstdatalen) == 0);
res = res && (sw == 0xccdd);
if (res)
PrintAndLogEx(INFO, "apdu............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "apdu............. " _RED_("fail"));
return res;
}
bool CIPURSETest(bool verbose) {
bool res = true;
PrintAndLogEx(INFO, "------ " _CYAN_("CIPURSE Tests") " ------");
res = res && TestKVV();
res = res && TestISO9797M2();
res = res && TestSMI();
res = res && TestMIC();
res = res && TestAuth();
res = res && TestMAC();
res = res && TestEncDec();
res = res && TestAPDU();
PrintAndLogEx(INFO, "---------------------------");
if (res)
PrintAndLogEx(SUCCESS, " Tests [ %s ]", _GREEN_("ok"));
else
PrintAndLogEx(FAILED, " Tests [ %s ]", _RED_("fail"));
PrintAndLogEx(NORMAL, "");
return res;
}

View file

@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2021 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// tests for crypto
//-----------------------------------------------------------------------------
#ifndef __CIPURSETEST_H__
#define __CIPURSETEST_H__
#include <stdbool.h>
#include "common.h"
#include "cipurse/cipursecrypto.h"
bool CIPURSETest(bool verbose);
#endif /* __CIPURSETEST_H__ */

View file

@ -91,11 +91,13 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, " Searching for ISO14443-A tag...");
if (IfPm3Iso14443a()) {
if (infoHF14A(false, false, false) > 0) {
int sel_state = infoHF14A(false, false, false);
if (sel_state > 0) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO 14443-A tag") " found\n");
res = PM3_SUCCESS;
infoHF14A4Applications(verbose);
if (sel_state == 1)
infoHF14A4Applications(verbose);
}
}

View file

@ -1027,7 +1027,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
// 3 byte here - 1b framing header, 2b crc16
if (APDUInFramingEnable &&
((g_frame_len && (datainlen > g_frame_len - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) {
((g_frame_len && (datainlen > g_frame_len - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) {
int clen = 0;
@ -1807,6 +1807,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]);
card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes
if (card.ats_len > 3)
select_status = 1;
}
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
@ -2097,6 +2099,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if ((card.sak & 0x20) == 0x20) {
PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--");
}
if (select_status == 1)
select_status = 2;
}
int isMagic = 0;
@ -2169,7 +2173,7 @@ int infoHF14A4Applications(bool verbose) {
int res = Iso7816Select(CC_CONTACTLESS, ActivateField, true, (uint8_t *)hintAIDList[i].aid, hintAIDList[i].aid_length, result, sizeof(result), &resultlen, &sw);
ActivateField = false;
if (res)
continue;
break;
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
if (!found) {

View file

@ -25,6 +25,7 @@
#include "cmdhfcipurse.h"
#include "cipurse/cipursecore.h"
#include "cipurse/cipursecrypto.h"
#include "cipurse/cipursetest.h"
#include "ui.h"
#include "cmdhf14a.h"
#include "cmdtrace.h"
@ -150,10 +151,10 @@ static int CmdHFCipurseAuth(const char *Cmd) {
CipurseCGetKVV(key, kvv);
if (verbose) {
PrintAndLogEx(INFO, "Key id" _YELLOW_("%d") " key " _YELLOW_("%s") " KVV " _YELLOW_("%s")
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
, sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)
);
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
, sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)
);
}
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
@ -172,7 +173,9 @@ static int CmdHFCipurseAuth(const char *Cmd) {
static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, size_t sreqid, size_t srespid, uint8_t *key, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
uint8_t hdata[250] = {0};
int hdatalen = sizeof(hdata);
CLIGetHexWithReturn(ctx, keyid, hdata, &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;
@ -186,7 +189,9 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
char cdata[250] = {0};
int cdatalen = sizeof(cdata);
cdatalen--; // for trailer 0x00
CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &cdatalen);
if (CLIParamStrToBuf(arg_get_str(ctx, sreqid), (uint8_t *)cdata, cdatalen, &cdatalen))
return PM3_ESOFT;
if (cdatalen) {
str_lower(cdata);
if (strcmp(cdata, "plain") == 0)
@ -204,7 +209,9 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
cdatalen = sizeof(cdata);
memset(cdata, 0, cdatalen);
cdatalen--; // for trailer 0x00
CLIGetStrWithReturn(ctx, srespid, (uint8_t *)cdata, &cdatalen);
if (CLIParamStrToBuf(arg_get_str(ctx, srespid), (uint8_t *)cdata, cdatalen, &cdatalen))
return PM3_ESOFT;
if (cdatalen) {
str_lower(cdata);
if (strcmp(cdata, "plain") == 0)
@ -226,7 +233,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse read",
"Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse read -f 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n"
"hf cipurse read --fid 2ff7 -> Authenticate with keyID 1, read file with id 2ff7\n"
"hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n");
void *argtable[] = {
@ -235,7 +242,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
arg_lit0("v", "verbose", "show technical data"),
arg_int0("n", NULL, "<dec>", "key ID"),
arg_str0("k", "key", "<hex>", "Auth key"),
arg_str0(NULL, "fid", "<hex>", "file ID"),
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"),
@ -338,7 +345,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse write",
"Write file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse write -f 2ff7 -> Authenticate with keyID 1, write file with id 2ff7\n"
"hf cipurse write --fid 2ff7 -> Authenticate with keyID 1, write file with id 2ff7\n"
"hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and write file\n");
void *argtable[] = {
@ -347,7 +354,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
arg_lit0("v", "verbose", "show technical data"),
arg_int0("n", NULL, "<dec>", "key ID"),
arg_str0("k", "key", "<hex>", "Auth key"),
arg_str0(NULL, "fid", "<hex>", "file ID"),
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"),
@ -413,11 +420,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
if (verbose) {
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " offset " _YELLOW_("%zu") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
, fileId
, offset
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
);
, fileId
, offset
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
);
PrintAndLogEx(INFO, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen));
}
@ -463,7 +470,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse aread",
"Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse aread -f 2ff7 -> Authenticate with keyID 1, read file attributes with id 2ff7\n"
"hf cipurse aread --fid 2ff7 -> Authenticate with keyID 1, read file attributes with id 2ff7\n"
"hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n");
void *argtable[] = {
@ -529,10 +536,10 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
if (verbose) {
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
, fileId
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
);
, fileId
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
);
}
if (noAuth == false) {
@ -592,7 +599,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse delete",
"Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse delete -f 2ff7 -> Authenticate with keyID 1, delete file with id 2ff7\n"
"hf cipurse delete --fid 2ff7 -> Authenticate with keyID 1, delete file with id 2ff7\n"
"hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and delete file\n");
void *argtable[] = {
@ -651,10 +658,10 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
if (verbose) {
PrintAndLogEx(INFO, "File id " _YELLOW_("%x") " key id " _YELLOW_("%d") " key " _YELLOW_("%s")
, fileId
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
);
, fileId
, keyId
, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)
);
}
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
@ -682,7 +689,6 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
return PM3_SUCCESS;
}
bool CheckCardCipurse(void) {
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
@ -692,6 +698,11 @@ bool CheckCardCipurse(void) {
return (res == 0 && sw == 0x9000);
}
static int CmdHFCipurseTest(const char *Cmd) {
CIPURSETest(true);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help."},
{"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Get info about CIPURSE tag"},
@ -700,6 +711,7 @@ static command_t CommandTable[] = {
{"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file"},
{"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes"},
{"delete", CmdHFCipurseDeleteFile, IfPm3Iso14443a, "Delete file"},
{"test", CmdHFCipurseTest, AlwaysAvailable, "Tests"},
{NULL, NULL, 0, NULL}
};

View file

@ -260,7 +260,7 @@ static int CmdHFCryptoRFDump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<filename>", "filename to save dump to"),
arg_str0("f", "file", "<fn>", "filename to save dump to"),
arg_lit0(NULL, "64", "64byte / 512bit memory"),
arg_lit0(NULL, "512", "512byte / 4096bit memory"),
arg_param_end
@ -486,7 +486,7 @@ static int CmdHFCryptoRFESave(const char *Cmd) {
);
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<filename>", "filename of dumpfile"),
arg_str0("f", "file", "<fn>", "filename of dumpfile"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

View file

@ -37,6 +37,9 @@
#define ICLASS_AUTH_RETRY 10
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
static void print_picopass_info(const picopass_hdr_t *hdr);
void print_picopass_header(const picopass_hdr_t *hdr);
static picopass_hdr_t iclass_last_known_card;
static void iclass_set_last_known_card(picopass_hdr_t *card) {
memcpy(&iclass_last_known_card, card, sizeof(picopass_hdr_t));
@ -129,7 +132,7 @@ static void iclass_upload_emul(uint8_t *d, uint16_t n, uint16_t *bytes_sent) {
uint16_t bytes_remaining = n;
while (bytes_remaining > 0) {
uint32_t bytes_in_packet = MIN(PM3_CMD_DATA_SIZE, bytes_remaining);
uint32_t bytes_in_packet = MIN(PM3_CMD_DATA_SIZE - 4, bytes_remaining);
if (bytes_in_packet == bytes_remaining) {
// Disable fast mode on last packet
conn.block_after_ACK = false;
@ -244,8 +247,8 @@ static void print_config_cards(void) {
static void print_config_card(const iclass_config_card_item_t *o) {
if (check_config_card(o)) {
PrintAndLogEx(INFO, "description... %s", o->desc);
PrintAndLogEx(INFO, "data....... " _YELLOW_("%s"), sprint_hex_inrow(o->data, sizeof(o->data)));
PrintAndLogEx(INFO, "description... " _YELLOW_("%s"), o->desc);
PrintAndLogEx(INFO, "data.......... " _YELLOW_("%s"), sprint_hex_inrow(o->data, sizeof(o->data)));
}
}
@ -253,20 +256,37 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
if (check_config_card(o) == false) {
return PM3_EINVARG;
}
// generated config card header
picopass_hdr_t configcard;
memset(&configcard, 0xFF, sizeof(picopass_hdr_t));
memcpy(configcard.csn, "\x41\x87\x66\x00\xFB\xFF\x12\xE0", 8);
memcpy(&configcard.conf, "\xFF\xFF\xFF\xFF\xF9\xFF\xFF\xBC", 8);
memcpy(&configcard.epurse, "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
// defaulting to known AA1 key
HFiClassCalcDivKey(configcard.csn, iClass_Key_Table[0], configcard.key_d, false);
// reference
picopass_hdr_t *cc = &configcard;
// get header from card
//bool have = memcmp(iclass_last_known_card.csn, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
PrintAndLogEx(INFO, "trying to read a card..");
int res = read_iclass_csn(false, false);
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Put a card on antenna and try again...");
return res;
if (res == PM3_SUCCESS) {
cc = &iclass_last_known_card;
// calc diversified key for selected card
HFiClassCalcDivKey(cc->csn, iClass_Key_Table[0], cc->key_d, false);
} else {
PrintAndLogEx(INFO, "failed to read a card, will use default config card data");
}
// generate dump file
uint8_t app1_limit = iclass_last_known_card.conf.app_limit;
uint8_t app1_limit = cc->conf.app_limit;
uint8_t old_limit = app1_limit;
uint8_t tot_bytes = (app1_limit + 1) * 8;
uint16_t tot_bytes = (app1_limit + 1) * 8;
PrintAndLogEx(INFO, " APP1 limit: %u", app1_limit);
PrintAndLogEx(INFO, "total bytes: %u", tot_bytes);
// normal size
uint8_t *data = calloc(1, tot_bytes);
if (data == NULL) {
@ -274,12 +294,9 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
return PM3_EMALLOC;
}
memcpy(data, cc, sizeof(picopass_hdr_t));
// calc diversified key for selected card
HFiClassCalcDivKey(iclass_last_known_card.csn, iClass_Key_Table[0], iclass_last_known_card.key_d, false);
memset(data, 0x00, tot_bytes);
memcpy(data, (uint8_t *)&iclass_last_known_card, sizeof(picopass_hdr_t));
print_picopass_header(cc);
// Keyrolling configuration cards are special.
if (strstr(o->desc, "Keyroll") != NULL) {
@ -295,7 +312,7 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
PrintAndLogEx(WARNING, "Adapting applimit1 for KEY rolling..");
app1_limit = 0x16;
iclass_last_known_card.conf.app_limit = 0x16;
cc->conf.app_limit = 0x16;
tot_bytes = (app1_limit + 1) * 8;
uint8_t *p = realloc(data, tot_bytes);
@ -308,25 +325,22 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
memset(data, 0xFF, tot_bytes);
}
// need to encrypt
PrintAndLogEx(INFO, "Detecting cardhelper...");
if (IsCardHelperPresent(false) == false) {
PrintAndLogEx(FAILED, "failed to detect cardhelper");
free(data);
return PM3_ENODATA;
}
// KEYROLL need to encrypt
uint8_t ffs[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if (Encrypt(ffs, ffs) == false) {
PrintAndLogEx(WARNING, "failed to encrypt FF");
}
// local key copy
uint8_t lkey[8];
memcpy(lkey, key, sizeof(lkey));
uint8_t enckey1[8];
if (Encrypt(key, enckey1) == false) {
if (Encrypt(lkey, enckey1) == false) {
PrintAndLogEx(WARNING, "failed to encrypt key1");
}
memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t));
memcpy(data, cc, sizeof(picopass_hdr_t));
memcpy(data + (6 * 8), o->data, sizeof(o->data));
// encrypted keyroll key 0D
@ -338,7 +352,7 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
// encrypted partial keyroll key 14
uint8_t foo[8] = {0x15};
memcpy(foo + 1, key, 7);
memcpy(foo + 1, lkey, 7);
uint8_t enckey2[8];
if (Encrypt(foo, enckey2) == false) {
PrintAndLogEx(WARNING, "failed to encrypt partial 1");
@ -347,7 +361,7 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
// encrypted partial keyroll key 15
memset(foo, 0xFF, sizeof(foo));
foo[0] = key[7];
foo[0] = lkey[7];
if (Encrypt(foo, enckey2) == false) {
PrintAndLogEx(WARNING, "failed to encrypt partial 2");
}
@ -358,12 +372,11 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke
memcpy(data + (i * 8), ffs, sizeof(ffs));
}
// revert potential modified app1_limit
iclass_last_known_card.conf.app_limit = old_limit;
cc->conf.app_limit = old_limit;
} else {
memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t));
memcpy(data, cc, sizeof(picopass_hdr_t));
memcpy(data + (6 * 8), o->data, sizeof(o->data));
}
@ -532,13 +545,13 @@ static void mem_app_config(const picopass_hdr_t *hdr) {
}
}
static void print_picopass_info(const picopass_hdr_t *hdr) {
void print_picopass_info(const picopass_hdr_t *hdr) {
PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------");
fuse_config(hdr);
mem_app_config(hdr);
}
static void print_picopass_header(const picopass_hdr_t *hdr) {
void print_picopass_header(const picopass_hdr_t *hdr) {
PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------");
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
@ -3859,6 +3872,8 @@ int CmdHFiClass(const char *Cmd) {
// SR | 6,7,8,9, | AA1, Access control payload | 2
// | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) |
// SEOS | | |
// MFC SIO| | |
// DESFIRE| | |
//}
int info_iclass(void) {

View file

@ -762,7 +762,7 @@ static int CmdLegicDump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<filename>", "specify a filename for dump file"),
arg_str0("f", "file", "<fn>", "specify a filename for dump file"),
arg_lit0(NULL, "de", "deobfuscate dump data (xor with MCC)"),
arg_param_end
};
@ -1032,7 +1032,7 @@ static int CmdLegicESave(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<filename>", "Specify a filename to save"),
arg_str0("f", "file", "<fn>", "Specify a filename to save"),
arg_int0("t", "type", "<dec>", "Tag type"),
arg_lit0(NULL, "deobfuscate", "De-obfuscate dump data (xor with MCC)"),
arg_param_end

View file

@ -650,7 +650,7 @@ static int CmdHfLTODump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<filename>", "specify a filename for dumpfile"),
arg_str0("f", "file", "<fn>", "specify a filename for dumpfile"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

View file

@ -2885,7 +2885,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", "<filename>", "filename of dictionary"),
arg_str0("f", "file", "<fn>", "filename of dictionary"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -5031,7 +5031,7 @@ static int CmdHF14AMfice(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<filename>", "filename of nonce dump"),
arg_str0("f", "file", "<fn>", "filename of nonce dump"),
arg_u64_0(NULL, "limit", "<dec>", "nonces to be collected"),
arg_param_end
};
@ -6007,6 +6007,110 @@ static int CmdHF14AMfView(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14AGen3View(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gview",
"View `magic gen3 gtu` card memory",
"hf mf gview\n"
"hf mf gview --4k"
);
void *argtable[] = {
arg_param_begin,
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool m0 = arg_get_lit(ctx, 1);
bool m1 = arg_get_lit(ctx, 2);
bool m2 = arg_get_lit(ctx, 3);
bool m4 = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
// validations
if ((m0 + m1 + m2 + m4) > 1) {
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
return PM3_EINVARG;
} else if ((m0 + m1 + m2 + m4) == 0) {
m1 = true;
}
char s[6];
memset(s, 0, sizeof(s));
uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
if (m0) {
block_cnt = MIFARE_MINI_MAXBLOCK;
strncpy(s, "Mini", 5);
} else if (m1) {
block_cnt = MIFARE_1K_MAXBLOCK;
strncpy(s, "1K", 3);
} else if (m2) {
block_cnt = MIFARE_2K_MAXBLOCK;
strncpy(s, "2K", 3);
} else if (m4) {
block_cnt = MIFARE_4K_MAXBLOCK;
strncpy(s, "4K", 3);
} else {
PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "View magic gen3 GTU MIFARE Classic " _GREEN_("%s"), s);
PrintAndLogEx(INFO, "." NOLF);
// Select card to get UID/UIDLEN information
clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "iso14443a card select timeout");
return PM3_ETIMEOUT;
}
/*
0: couldn't read
1: OK, with ATS
2: OK, no ATS
3: proprietary Anticollision
*/
uint64_t select_status = resp.oldarg[0];
if (select_status == 0) {
PrintAndLogEx(WARNING, "iso14443a card select failed");
return select_status;
}
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
// reserve memory
uint16_t bytes = block_cnt * MFBLOCK_SIZE;
uint8_t *dump = calloc(bytes, sizeof(uint8_t));
if (dump == NULL) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
for (uint16_t i = 0; i < block_cnt; i++) {
if (mfG3GetBlock(i, dump + (i * MFBLOCK_SIZE)) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Can't get magic card block: %u", i);
PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
free(dump);
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "." NOLF);
fflush(stdout);
}
PrintAndLogEx(NORMAL, "");
mf_print_blocks(block_cnt, dump);
free(dump);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
@ -6059,7 +6163,8 @@ static command_t CommandTable[] = {
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without changing manufacturer block"},
{"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"},
{"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3 GTU") " -----------------------"},
{"gview", CmdHF14AGen3View, IfPm3Iso14443a, "View card"},
// {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{NULL, NULL, NULL, NULL}

View file

@ -984,7 +984,7 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
// Part 4
// tag->session_key = &default_key;
struct desfire_key *p = realloc (tag->session_key,sizeof(struct desfire_key));
struct desfire_key *p = realloc(tag->session_key, sizeof(struct desfire_key));
if (!p) {
PrintAndLogEx(FAILED, "Cannot allocate memory for session keys");
free(tag->session_key);
@ -992,7 +992,7 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
}
tag->session_key = p;
memset (tag->session_key, 0x00, sizeof(struct desfire_key));
memset(tag->session_key, 0x00, sizeof(struct desfire_key));
Desfire_session_key_new(RndA, RndB, key, tag->session_key);
@ -1030,7 +1030,7 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
// If the 3Des key first 8 bytes = 2nd 8 Bytes then we are really using Singe Des
// As such we need to set the session key such that the 2nd 8 bytes = 1st 8 Bytes
if (payload->algo == MFDES_ALGO_3DES) {
if (memcmp(key->data,&key->data[8],8) == 0)
if (memcmp(key->data, &key->data[8], 8) == 0)
memcpy(&tag->session_key->data[8], tag->session_key->data, 8);
}
@ -1285,7 +1285,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
} else if (new_algo == MFDES_ALGO_3K3DES) {
// 3K3Des checksum must cover : C4 <KeyNo> <PrevKey XOR NewKey>
csPkt[0] = MFDES_CHANGE_KEY;
memcpy (&csPkt[1], data, 25);
memcpy(&csPkt[1], data, 25);
desfire_crc32(csPkt, 26, data + 1 + cmdcnt);
} else {
desfire_crc32_append(data + 1, cmdcnt);
@ -1309,10 +1309,10 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
csPkt[0] = MFDES_CHANGE_KEY;
memcpy(&csPkt[1], data, 18);
desfire_crc32(csPkt, 19, data + 1 + cmdcnt);
} else if (new_algo == MFDES_ALGO_3K3DES) {
} else if (new_algo == MFDES_ALGO_3K3DES) {
// 3K3Des checksum must cover : C4 <KeyNo> <Newkey Data>
csPkt[0] = MFDES_CHANGE_KEY;
memcpy (&csPkt[1], data, 25);
memcpy(&csPkt[1], data, 25);
desfire_crc32(csPkt, 26, data + 1 + cmdcnt);
} else {
desfire_crc32_append(data + 1, cmdcnt);
@ -1348,8 +1348,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
size_t sn = recv_len;
if ((new_algo == MFDES_ALGO_AES) || (new_algo == MFDES_ALGO_3K3DES))
{
if ((new_algo == MFDES_ALGO_AES) || (new_algo == MFDES_ALGO_3K3DES)) {
// AES expects us to Calculate CMAC for status byte : OK 0x00 (0x91 00)
// As such if we get this far without an error, we should be good
// Since we are dropping the field, we dont need to maintain the CMAC etc.

View file

@ -539,7 +539,7 @@ static int CmdSetMux(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hw setmux",
"Set the ADC mux to a specific value",
"hw setmux --hiraw -> set HIGH RAW"
"hw setmux --hipkd -> set HIGH PEAK\n"
);
void *argtable[] = {
@ -562,6 +562,13 @@ static int CmdSetMux(const char *Cmd) {
return PM3_EINVARG;
}
#ifdef WITH_FPC_USART
if (loraw || hiraw) {
PrintAndLogEx(INFO, "this ADC mux option is unavailable on RDV4 compiled with FPC USART");
return PM3_EINVARG;
}
#endif
uint8_t arg = 0;
if (lopkd)
arg = 0;

View file

@ -1319,13 +1319,13 @@ int CmdEM4x05Chk(const char *Cmd) {
CLIParserInit(&ctx, "lf em 4x05 chk",
"This command uses a dictionary attack against EM4205/4305/4469/4569",
"lf em 4x05 chk\n"
"lf em 4x05 chk -e 000022B8 -> remember to use 0x for hex\n"
"lf em 4x05 chk -e 000022B8 -> check password 000022B8\n"
"lf em 4x05 chk -f t55xx_default_pwds -> use T55xx default dictionary"
);
void *argtable[] = {
arg_param_begin,
arg_strx0("f", "file", "<*.dic>", "loads a default keys dictionary file <*.dic>"),
arg_str0("f", "file", "<fn>", "loads a default keys dictionary file <*.dic>"),
arg_str0("e", "em", "<EM4100>", "try the calculated password from some cloners based on EM4100 ID"),
arg_param_end
};
@ -1334,7 +1334,18 @@ int CmdEM4x05Chk(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
uint64_t card_id = arg_get_u64_hexstr_def(ctx, 2, 0);
uint64_t card_id = 0;
int res = arg_get_u64_hexstr_def_nlen(ctx, 2, 0, &card_id, 5, true);
if (res == 2) {
CLIParserFree(ctx);
PrintAndLogEx(WARNING, "EM4100 ID must be 5 hex bytes");
return PM3_EINVARG;
}
if (res == 0) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
CLIParserFree(ctx);
if (strlen(filename) == 0) {
@ -1366,7 +1377,7 @@ int CmdEM4x05Chk(const char *Cmd) {
uint32_t keycount = 0;
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) {
PrintAndLogEx(WARNING, "no keys found in file");
if (keyBlock != NULL)
@ -1418,22 +1429,30 @@ int CmdEM4x05Chk(const char *Cmd) {
int CmdEM4x05Brute(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x05 brute",
"This command tries to bruteforce the password of a EM4205/4305/4469/4569\n",
"This command tries to bruteforce the password of a EM4205/4305/4469/4569\n"
"The loop is running on device side, press Proxmark3 button to abort\n",
"Note: if you get many false positives, change position on the antenna"
"lf em 4x05 brute\n"
"lf em 4x05 brute -n 1 -> stop after first candidate found\n"
"lf em 4x05 brute -s 000022B8 -> remember to use 0x for hex"
"lf em 4x05 brute -n 1 -> stop after first candidate found\n"
"lf em 4x05 brute -s 000022AA -> start at 000022AA"
);
void *argtable[] = {
arg_param_begin,
arg_u64_0("s", "start", "<pwd>", "Start bruteforce enumeration from this password value"),
arg_int0("n", NULL, "<digits>", "Stop after having found n candidates. Default: 0 => infinite"),
arg_str0("s", "start", "<hex>", "Start bruteforce enumeration from this password value"),
arg_u64_0("n", NULL, "<dec>", "Stop after having found n candidates. Default: 0 (infinite)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
uint32_t start_pwd = arg_get_u64_hexstr_def(ctx, 1, 0);
uint32_t n = arg_get_int_def(ctx, 2, 0);
uint32_t start_pwd = 0;
int res = arg_get_u32_hexstr_def(ctx, 1, 0, &start_pwd);
if (res != 1) {
CLIParserFree(ctx);
PrintAndLogEx(WARNING, "check `start_pwd` parameter");
return PM3_EINVARG;
}
uint32_t n = arg_get_u32_def(ctx, 2, 0);
CLIParserFree(ctx);
PrintAndLogEx(NORMAL, "");
@ -1449,7 +1468,7 @@ int CmdEM4x05Brute(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X_BF, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_EM4X_BF, &resp, 1000)) {
if (WaitForResponseTimeout(CMD_LF_EM4X_BF, &resp, 1000) == false) {
PrintAndLogEx(WARNING, "(EM4x05 Bruteforce) timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -1857,7 +1876,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
// compute number of bits flipped
PrintAndLogEx(INFO, "Bitflips: %2u events => %s", bitcount32(bitflips), bitstring);
PrintAndLogEx(INFO, "New protection word => " _CYAN_("%08X") "\n", word14b);
PrintAndLogEx(INFO, "Try " _YELLOW_("`lf em 4x05_dump`"));
PrintAndLogEx(INFO, "Try " _YELLOW_("`lf em 4x05 dump`"));
}
if (verbose) {

View file

@ -14,6 +14,7 @@
#include "cmdlfem4x50.h"
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "util_posix.h" // msclock
#include "fileutils.h"
#include "commonutil.h"
#include "pmflash.h"
@ -100,8 +101,6 @@ static void print_info_result(uint8_t *data, bool verbose) {
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
// data section
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, _YELLOW_("EM4x50 data:"));
if (verbose) {
print_result(words, 0, EM4X50_NO_WORDS - 1);
} else {
@ -112,16 +111,16 @@ static void print_info_result(uint8_t *data, bool verbose) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "---- " _CYAN_("Configuration") " ----");
PrintAndLogEx(INFO, "first word read %3i", fwr);
PrintAndLogEx(INFO, "last word read %3i", lwr);
PrintAndLogEx(INFO, "password check %3s", (bpwc) ? _RED_("on") : _GREEN_("off"));
PrintAndLogEx(INFO, "read after write %3s", (braw) ? "on" : "off");
PrintAndLogEx(INFO, "first word read.... " _YELLOW_("%i"), fwr);
PrintAndLogEx(INFO, "last word read..... " _YELLOW_("%i"), lwr);
PrintAndLogEx(INFO, "password check..... %s", (bpwc) ? _RED_("on") : _GREEN_("off"));
PrintAndLogEx(INFO, "read after write... %s", (braw) ? "on" : "off");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--------- " _CYAN_("Protection") " ---------");
PrintAndLogEx(INFO, "first word read protected %3i", fwrp);
PrintAndLogEx(INFO, "last word read protected %3i", lwrp);
PrintAndLogEx(INFO, "first word write inhibited %3i", fwwi);
PrintAndLogEx(INFO, "last word write inhibited %3i", lwwi);
PrintAndLogEx(INFO, "--------- " _CYAN_("Protection") " ------------");
PrintAndLogEx(INFO, "first word read protected.... %i", fwrp);
PrintAndLogEx(INFO, "last word read protected..... %i", lwrp);
PrintAndLogEx(INFO, "first word write inhibited... %i", fwwi);
PrintAndLogEx(INFO, "last word write inhibited.... %i", lwwi);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "zero values may indicate read protection");
PrintAndLogEx(NORMAL, "");
@ -238,7 +237,7 @@ int CmdEM4x50ESave(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "filename", "<fn>", "data filename"),
arg_str0("f", "file", "<fn>", "save filename"),
arg_param_end
};
@ -364,9 +363,9 @@ int CmdEM4x50Login(const char *Cmd) {
int CmdEM4x50Brute(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 brute",
"Tries to bruteforce the password of a EM4x50.\n"
"Tries to bruteforce the password of a EM4x50 card.\n"
"Function can be stopped by pressing pm3 button.",
"lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000\n"
"lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000\n"
);
void *argtable[] = {
@ -408,12 +407,12 @@ int CmdEM4x50Brute(const char *Cmd) {
int dur_m = (dur_s - dur_h * 3600) / 60;
dur_s -= dur_h * 3600 + dur_m * 60;
PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]"
PrintAndLogEx(INFO, "Trying " _YELLOW_("%i") " passwords in range [0x%08x, 0x%08x]"
, no_iter
, etd.password1
, etd.password2
);
PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s);
PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s);
// start
clearCommandBuffer();
@ -423,9 +422,9 @@ int CmdEM4x50Brute(const char *Cmd) {
// print response
if (resp.status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Password " _GREEN_("found") ": 0x%08x", resp.data.asDwords[0]);
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", resp.data.asDwords[0]);
else
PrintAndLogEx(FAILED, "Password: " _RED_("not found"));
PrintAndLogEx(WARNING, "brute pwd failed");
return PM3_SUCCESS;
}
@ -435,14 +434,14 @@ int CmdEM4x50Brute(const char *Cmd) {
int CmdEM4x50Chk(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 chk",
"Dictionary attack against EM4x50.",
"Run dictionary key recovery against EM4x50 card.",
"lf em 4x50 chk -> uses T55xx default dictionary\n"
"lf em 4x50 chk -f my.dic"
);
void *argtable[] = {
arg_param_begin,
arg_str0("f", "filename", "<fn>", "dictionary filename"),
arg_str0("f", "file", "<fn>", "dictionary filename"),
arg_param_end
};
@ -463,6 +462,8 @@ int CmdEM4x50Chk(const char *Cmd) {
PrintAndLogEx(INFO, "treating file as T55xx keys");
}
uint64_t t1 = msclock();
size_t datalen = 0;
// 2021 iceman: how many keys shall we reserv space for? The t55xx dictionary has 139 keys.
@ -510,17 +511,22 @@ int CmdEM4x50Chk(const char *Cmd) {
// print response
if (status == PM3_SUCCESS) {
/*
PrintAndLogEx(SUCCESS, "Key " _GREEN_("found: %02x %02x %02x %02x"),
resp.data.asBytes[3],
resp.data.asBytes[2],
resp.data.asBytes[1],
resp.data.asBytes[0]
);
*/
uint32_t pwd = BYTES2UINT32(resp.data.asBytes);
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", pwd);
} else {
PrintAndLogEx(FAILED, "No key found");
}
PrintAndLogEx(INFO, "Done");
t1 = msclock() - t1;
PrintAndLogEx(SUCCESS, "\ntime in check pwd " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
return PM3_SUCCESS;
}
@ -639,8 +645,8 @@ int CmdEM4x50Info(const char *Cmd) {
CLIParserInit(&ctx, "lf em 4x50 info",
"Tag information EM4x50.",
"lf em 4x50 info\n"
"lf em 4x50 info -v -> show data section\n"
"lf em 4x50 info -p 12345678 -> uses pwd 0x12345678\n"
"lf em 4x50 info -v -> show data section\n"
"lf em 4x50 info -p 12345678 -> uses pwd 0x12345678\n"
);
void *argtable[] = {
@ -752,7 +758,7 @@ int CmdEM4x50Dump(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "filename", "<fn>", "dump filename (bin/eml/json)"),
arg_str0("f", "file", "<fn>", "dump filename (bin/eml/json)"),
arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"),
arg_param_end
};
@ -908,9 +914,9 @@ int CmdEM4x50Write(const char *Cmd) {
// envokes changing the password of EM4x50 tag
int CmdEM4x50WritePwd(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 writepwd",
CLIParserInit(&ctx, "lf em 4x50 wrpwd",
"Writes EM4x50 password.",
"lf em 4x50 writepwd -p 4f22e7ff -n 12345678"
"lf em 4x50 wrpwd -p 4f22e7ff -n 12345678"
);
void *argtable[] = {
@ -1063,7 +1069,7 @@ int CmdEM4x50Restore(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("u", "uid", "<hex>", "uid, 4 hex bytes, msb"),
arg_str0("f", "filename", "<fn>", "dump filename (bin/eml/json)"),
arg_str0("f", "file", "<fn>", "dump filename (bin/eml/json)"),
arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"),
arg_param_end
};
@ -1210,21 +1216,23 @@ int CmdEM4x50Sim(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"},
{"chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"},
{"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"},
{"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"},
{"login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"},
{"rdbl", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"},
{"wrbl", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"},
{"writepwd", CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"},
{"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"},
{"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"},
{"restore", CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"},
{"sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"},
{"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to emulator memory"},
{"esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"},
{"eview", CmdEM4x50EView, IfPm3EM4x50, "view EM4x50 content in emulator memory"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
{"brute", CmdEM4x50Brute, IfPm3EM4x50, "Simple bruteforce attack to find password"},
{"chk", CmdEM4x50Chk, IfPm3EM4x50, "Check passwords from dictionary"},
{"dump", CmdEM4x50Dump, IfPm3EM4x50, "Dump EM4x50 tag"},
{"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"},
{"login", CmdEM4x50Login, IfPm3EM4x50, "Login into EM4x50 tag"},
{"rdbl", CmdEM4x50Read, IfPm3EM4x50, "Read EM4x50 word data"},
{"reader", CmdEM4x50Reader, IfPm3EM4x50, "Show standard read mode data"},
{"restore", CmdEM4x50Restore, IfPm3EM4x50, "Restore EM4x50 dump to tag"},
{"wrbl", CmdEM4x50Write, IfPm3EM4x50, "Write EM4x50 word data"},
{"wrpwd", CmdEM4x50WritePwd, IfPm3EM4x50, "Change EM4x50 password"},
{"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "Wipe EM4x50 tag"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
{"eload", CmdEM4x50ELoad, IfPm3EM4x50, "Upload EM4x50 dump to emulator memory"},
{"esave", CmdEM4x50ESave, IfPm3EM4x50, "Save emulator memory to file"},
{"eview", CmdEM4x50EView, IfPm3EM4x50, "View EM4x50 content in emulator memory"},
{"sim", CmdEM4x50Sim, IfPm3EM4x50, "Simulate EM4x50 tag"},
{NULL, NULL, NULL, NULL}
};

View file

@ -570,8 +570,8 @@ static int CmdLFHitagReader(const char *Cmd) {
}
// sanity checks
if (keylen != 0 && keylen != 4) {
PrintAndLogEx(WARNING, "Wrong KEY len expected 0 or 4, got %d", keylen);
if (keylen != 0 && keylen != 4 && keylen != 6) {
PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
return PM3_EINVARG;
}
@ -657,7 +657,7 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "filename", "<fn w/o ext>", "filename to load from"),
arg_str0("f", "file", "<fn>", "filename to load ( w/o ext )"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

View file

@ -2210,7 +2210,7 @@ static int CmdT55xxDump(const char *Cmd) {
// 1 (help) + 3 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
void *argtable[4 + 5] = {
arg_param_begin,
arg_str0("f", "filename", "<fn>", "filename (default is generated on blk 0)"),
arg_str0("f", "file", "<fn>", "filename (default is generated on blk 0)"),
arg_lit0("o", "override", "override, force pwd read despite danger to card"),
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
};

View file

@ -758,6 +758,7 @@ int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
tlvdb_free(atc_db);
return 9;
}
tlvdb_free(atc_db);
} else {
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);

View file

@ -38,10 +38,10 @@ void SetISODEPState(isodep_state_t state) {
isodep_state = state;
if (APDULogging) {
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s"
, isodep_state == ISODEP_INACTIVE ? "inactive" : ""
, isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : ""
, isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : ""
);
, isodep_state == ISODEP_INACTIVE ? "inactive" : ""
, isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : ""
, isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : ""
);
}
}
@ -79,7 +79,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
*result_len = 0;
if (sw) {
*sw = 0;
*sw = 0;
}
if (activate_field) {
@ -177,30 +177,30 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
int Iso7816Exchange(Iso7816CommandChannel channel, bool leave_field_on, sAPDU apdu, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
return Iso7816ExchangeEx(channel
, false
, leave_field_on
, apdu
, false
, 0
, result
, max_result_len
, result_len
, sw
);
, false
, leave_field_on
, apdu
, false
, 0
, result
, max_result_len
, result_len
, sw
);
}
int Iso7816Select(Iso7816CommandChannel channel, bool activate_field, bool leave_field_on, uint8_t *aid, size_t aid_len,
uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
return Iso7816ExchangeEx(channel
, activate_field
, leave_field_on
, (sAPDU) {0x00, 0xa4, 0x04, 0x00, aid_len, aid}
, (channel == CC_CONTACTLESS)
, 0
, result
, max_result_len
, result_len
, sw
);
, activate_field
, leave_field_on
, (sAPDU) {0x00, 0xa4, 0x04, 0x00, aid_len, aid}
, (channel == CC_CONTACTLESS)
, 0
, result
, max_result_len
, result_len
, sw
);
}

View file

@ -40,13 +40,13 @@ int Iso7816Connect(Iso7816CommandChannel channel);
// exchange
int Iso7816Exchange(Iso7816CommandChannel channel, bool leave_field_on, sAPDU apdu, uint8_t *result, size_t max_result_len,
size_t *result_len, uint16_t *sw);
size_t *result_len, uint16_t *sw);
int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool leave_field_on, sAPDU apdu, bool include_le,
uint16_t le, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw);
uint16_t le, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw);
// search application
int Iso7816Select(Iso7816CommandChannel channel, bool activate_field, bool leave_field_on, uint8_t *aid, size_t aid_len,
uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw);
uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw);
#endif

View file

@ -56,6 +56,8 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
return PM3_EOPABORTED;
}
PrintAndLogEx(INFO, "." NOLF);
// wait cycle
while (true) {
PrintAndLogEx(NORMAL, "." NOLF);
@ -546,7 +548,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
package->block,
package->keytype ? 'B' : 'A',
sprint_hex(resultKey, 6)
sprint_hex_inrow(resultKey, 6)
);
return PM3_SUCCESS;
}
@ -725,7 +727,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
package->block,
package->keytype ? 'B' : 'A',
sprint_hex(resultKey, 6)
sprint_hex_inrow(resultKey, 6)
);
return PM3_SUCCESS;
} else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) {
@ -1050,6 +1052,27 @@ int mfGen3Freeze(void) {
}
}
int mfG3GetBlock(uint8_t blockno, uint8_t *data) {
struct p {
uint8_t blockno;
} PACKED payload;
payload.blockno = blockno;
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G3_RDBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G3_RDBL, &resp, 1500)) {
if (resp.status != PM3_SUCCESS)
return PM3_EUNDEF;
memcpy(data, resp.data.asBytes, 16);
} else {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
return PM3_SUCCESS;
}
// variables
uint32_t cuid = 0; // uid part used for crypto1.

View file

@ -85,6 +85,8 @@ int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid);
int mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock);
int mfGen3Freeze(void);
int mfG3GetBlock(uint8_t blockno, uint8_t *data);
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
int detect_classic_prng(void);

View file

@ -25,6 +25,7 @@
#define NDEF_WIFIAPPL "application/vnd.wfa"
#define NDEF_BLUEAPPL "application/vnd.bluetooth"
#define NDEF_VCARDTEXT "text/vcard"
#define NDEF_XVCARDTEXT "text/x-vcard"
static const char *TypeNameFormat_s[] = {
"Empty Record",
@ -510,14 +511,14 @@ static int ndefDecodeMime_wifi(NDEFHeader_t *ndef) {
static int ndefDecodeMime_vcard(NDEFHeader_t *ndef) {
PrintAndLogEx(INFO, _CYAN_("VCARD details"));
if (ndef->PayloadLen > 1) {
PrintAndLogEx(INFO, "Data... " _YELLOW_("%.*s"), (int)ndef->PayloadLen, ndef->Payload);
PrintAndLogEx(INFO, ">>> decorder, to be implemented <<<");
PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "%.*s", (int)ndef->PayloadLen, ndef->Payload);
}
return PM3_SUCCESS;
}
static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
PrintAndLogEx(INFO, "Type............ " _YELLOW_("%.*s"), (int)ndef->TypeLen, ndef->Type );
PrintAndLogEx(INFO, "Type............ " _YELLOW_("%.*s"), (int)ndef->TypeLen, ndef->Type);
if (ndef->PayloadLen > 1) {
uint16_t ooblen = (ndef->Payload[1] << 8 | ndef->Payload[0]);
PrintAndLogEx(INFO, "OOB data len.... %u", ooblen);
@ -547,9 +548,9 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
break;
}
// Let's check payload[9]. If 0x08 then SHORT_NAME or if 0x09 then COMPLETE_NAME
if (ndef->Payload[9] == 0x08 ) {
if (ndef->Payload[9] == 0x08) {
PrintAndLogEx(INFO, "Short name...... " _YELLOW_("%.*s"), (int)(ndef->PayloadLen - 10), ndef->Payload + 10);
} else if (ndef->Payload[9] == 0x09 ) {
} else if (ndef->Payload[9] == 0x09) {
PrintAndLogEx(INFO, "Complete name... " _YELLOW_("%.*s"), (int)(ndef->PayloadLen - 10), ndef->Payload + 10);
} else {
PrintAndLogEx(INFO, "[ %02x ]", ndef->Payload[9]);
@ -629,20 +630,29 @@ static int ndefDecodePayload(NDEFHeader_t *ndef) {
PrintAndLogEx(INFO, "- decoder to be impl -");
}
break;
case tnfMIMEMediaRecord:
case tnfMIMEMediaRecord: {
PrintAndLogEx(INFO, "MIME Media Record");
if (ndef->TypeLen == 0) {
PrintAndLogEx(INFO, "type length is zero");
break;
}
if (str_startswith((const char *)ndef->Type, NDEF_WIFIAPPL)) {
char begin[ndef->TypeLen];
memcpy(begin, ndef->Type, ndef->TypeLen);
str_lower(begin);
if (str_startswith(begin, NDEF_WIFIAPPL)) {
ndefDecodeMime_wifi(ndef);
}
if (str_startswith((const char *)ndef->Type, NDEF_VCARDTEXT)) {
if (str_startswith(begin, NDEF_VCARDTEXT) || str_startswith(begin, NDEF_XVCARDTEXT)) {
ndefDecodeMime_vcard(ndef);
}
if (str_startswith((const char *)ndef->Type, NDEF_BLUEAPPL)) {
if (str_startswith(begin, NDEF_BLUEAPPL)) {
ndefDecodeMime_bt(ndef);
}
break;
}
case tnfAbsoluteURIRecord:
PrintAndLogEx(INFO, "Absolute URI Record");
PrintAndLogEx(INFO, " payload : %.*s", (int)ndef->PayloadLen, ndef->Payload);
@ -686,7 +696,7 @@ static int ndefRecordDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) {
print_buffer(NDEFHeader.Payload, NDEFHeader.PayloadLen, 1);
}
if (NDEFHeader.TypeLen && NDEFHeader.PayloadLen) {
ndefDecodePayload(&NDEFHeader);
ndefDecodePayload(&NDEFHeader);
}
return PM3_SUCCESS;

View file

@ -973,7 +973,7 @@
},
"help": {
"command": "help",
"description": "help use `<command> help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210618.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save",
"description": "help use `<command> help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log /home/osboxes/.proxmark3/logs/log_20210624.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save",
"notes": [
"auto"
],
@ -1684,67 +1684,67 @@
},
"hf cipurse aread": {
"command": "hf cipurse aread",
"description": "read file attributes by file id with key id and key",
"description": "read file attributes by file id with key id and key. if no key is supplied, default key of 737373...7373 will be used",
"notes": [
"hf cipurse aread -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and read file attributes with id 2ff7",
"hf cipurse aread -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and read file attributes"
"hf cipurse aread --fid 2ff7 -> authenticate with keyid 1, read file attributes with id 2ff7",
"hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2, read file attributes"
],
"offline": false,
"options": [
"-h, --help this help",
"-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data",
"-n, --keyid <dec> key id",
"-k, --key <hex> key for authenticate",
"-f, --file <hex> file id",
"-n <dec> key id",
"-k, --key <hex> auth key",
"--fid <hex> file id",
"--noauth read file attributes without authentication",
"--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader security level",
"--sel-adf show info about adf itself",
"--sel-mf show info about master file"
],
"usage": "hf cipurse aread [-hav] [-n <dec>] [-k <hex>] [-f <hex>] [--noauth] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>] [--sel-adf] [--sel-mf]"
"usage": "hf cipurse aread [-hav] [-n <dec>] [-k <hex>] [--fid <hex>] [--noauth] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>] [--sel-adf] [--sel-mf]"
},
"hf cipurse auth": {
"command": "hf cipurse auth",
"description": "authenticate with key id and key",
"description": "authenticate with key id and key. if no key is supplied, default key of 737373...7373 will be used",
"notes": [
"hf cipurse auth -> authenticate with keyid=1 and key = 7373...7373",
"hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> authenticate with key"
"hf cipurse auth -> authenticate with keyid 1, default key",
"hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> authenticate keyid 2 with key"
],
"offline": false,
"options": [
"-h, --help this help",
"-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data",
"-n, --keyid <dec> key id",
"-k, --key <hex> key for authenticate"
"-n <dec> key id",
"-k, --key <hex> auth key"
],
"usage": "hf cipurse auth [-hav] [-n <dec>] [-k <hex>]"
},
"hf cipurse delete": {
"command": "hf cipurse delete",
"description": "read file by file id with key id and key",
"description": "read file by file id with key id and key. if no key is supplied, default key of 737373...7373 will be used",
"notes": [
"hf cipurse delete -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and delete file with id 2ff7",
"hf cipurse delete -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and delete file"
"hf cipurse delete --fid 2ff7 -> authenticate with keyid 1, delete file with id 2ff7",
"hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2 and delete file"
],
"offline": false,
"options": [
"-h, --help this help",
"-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data",
"-n, --keyid <dec> key id",
"-k, --key <hex> key for authenticate",
"-f, --file <hex> file id",
"-n <dec> key id",
"-k, --key <hex> auth key",
"--fid <hex> file id",
"--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader security level"
],
"usage": "hf cipurse delete [-hav] [-n <dec>] [-k <hex>] [-f <hex>] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>]"
"usage": "hf cipurse delete [-hav] [-n <dec>] [-k <hex>] [--fid <hex>] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>]"
},
"hf cipurse help": {
"command": "hf cipurse help",
"description": "help this help. --------------------------------------------------------------------------------------- hf cipurse info available offline: no get info from cipurse tags",
"description": "help this help. test tests --------------------------------------------------------------------------------------- hf cipurse info available offline: no get info from cipurse tags",
"notes": [
"hf cipurse info"
],
@ -1756,48 +1756,63 @@
},
"hf cipurse read": {
"command": "hf cipurse read",
"description": "read file by file id with key id and key",
"description": "read file by file id with key id and key. if no key is supplied, default key of 737373...7373 will be used",
"notes": [
"hf cipurse read -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and read file with id 2ff7",
"hf cipurse read -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and read file"
"hf cipurse read --fid 2ff7 -> authenticate with keyid 1, read file with id 2ff7",
"hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2 and read file"
],
"offline": false,
"options": [
"-h, --help this help",
"-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data",
"-n, --keyid <dec> key id",
"-k, --key <hex> key for authenticate",
"-f, --file <hex> file id",
"-n <dec> key id",
"-k, --key <hex> auth key",
"--fid <hex> file id",
"-o, --offset <dec> offset for reading data from file",
"--noauth read file without authentication",
"--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader security level"
],
"usage": "hf cipurse read [-hav] [-n <dec>] [-k <hex>] [-f <hex>] [-o <dec>] [--noauth] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>]"
"usage": "hf cipurse read [-hav] [-n <dec>] [-k <hex>] [--fid <hex>] [-o <dec>] [--noauth] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>]"
},
"hf cipurse test": {
"command": "hf cipurse test",
"description": "[=] ------ cipurse tests ------ [=] kvv.............. passed [=] iso9797m2........ passed [=] smi.............. passed [=] mic.............. passed [=] auth............. passed [=] channel mac...... passed [=] channel encdec... passed [=] apdu............. passed [=] --------------------------- [+] tests [ ok ] ======================================================================================= hf epa { german identification card... } --------------------------------------------------------------------------------------- hf epa help available offline: yes help this help --------------------------------------------------------------------------------------- hf epa cnonces available offline: no tries to collect nonces when doing part of pace protocol.",
"notes": [
"hf epa cnonces --size 4 --num 4 --delay 1"
],
"offline": true,
"options": [
"-h, --help this help",
"--size <dec> nonce size",
"--num <dec> number of nonces to collect",
"-d, --delay <dec> delay between attempts"
],
"usage": "hf epa cnonces [-h] --size <dec> --num <dec> -d <dec>"
},
"hf cipurse write": {
"command": "hf cipurse write",
"description": "write file by file id with key id and key",
"description": "write file by file id with key id and key. if no key is supplied, default key of 737373...7373 will be used",
"notes": [
"hf cipurse write -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and write file with id 2ff7",
"hf cipurse write -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and write file"
"hf cipurse write --fid 2ff7 -> authenticate with keyid 1, write file with id 2ff7",
"hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2 and write file"
],
"offline": false,
"options": [
"-h, --help this help",
"-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data",
"-n, --keyid <dec> key id",
"-k, --key <hex> key for authenticate",
"-f, --file <hex> file id",
"-n <dec> key id",
"-k, --key <hex> auth key",
"--fid <hex> file id",
"-o, --offset <dec> offset for reading data from file",
"--noauth read file without authentication",
"--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader security level",
"-c, --content <hex> new file content"
"-d, --data <hex> hex data to write to new file"
],
"usage": "hf cipurse write [-hav] [-n <dec>] [-k <hex>] [-f <hex>] [-o <dec>] [--noauth] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>] [-c <hex>]"
"usage": "hf cipurse write [-hav] [-n <dec>] [-k <hex>] [--fid <hex>] [-o <dec>] [--noauth] [--sreq <plain|mac(default)|encode>] [--sresp <plain|mac(default)|encode>] [-d <hex>]"
},
"hf emrtd help": {
"command": "hf emrtd help",
@ -1854,21 +1869,6 @@
],
"usage": "hf emrtd list [-h1fcrux] [--dict <file>]..."
},
"hf epa help": {
"command": "hf epa help",
"description": "help this help --------------------------------------------------------------------------------------- hf epa cnonces available offline: no tries to collect nonces when doing part of pace protocol.",
"notes": [
"hf epa cnonces --size 4 --num 4 --delay 1"
],
"offline": true,
"options": [
"-h, --help this help",
"--size <dec> nonce size",
"--num <dec> number of nonces to collect",
"-d, --delay <dec> delay between attempts"
],
"usage": "hf epa cnonces [-h] --size <dec> --num <dec> -d <dec>"
},
"hf epa preplay": {
"command": "hf epa preplay",
"description": "perform pace protocol by replaying given apdus",
@ -3491,9 +3491,9 @@
"hf mf fchk --2k -k ffffffffffff -> key recovery against mifare 2k",
"hf mf fchk --4k -k ffffffffffff -> key recovery against mifare 4k",
"hf mf fchk --1k -f mfc_default_keys.dic -> target 1k using default dictionary file",
"hf mf fchk --1k --emu -> target 1k, write to emulator memory",
"hf mf fchk --1k --dump -> target 1k, write to file",
"hf mf fchk --1k --mem -> target 1k, use dictionary from flashmemory"
"hf mf fchk --1k --emu -> target 1k, write keys to emulator memory",
"hf mf fchk --1k --dump -> target 1k, write keys to file",
"hf mf fchk --1k --mem -> target 1k, use dictionary from flash memory"
],
"offline": false,
"options": [
@ -3553,6 +3553,23 @@
],
"usage": "hf mf gen3uid [-h] [-u <hex>]"
},
"hf mf gview": {
"command": "hf mf gview",
"description": "view `magic gen3 gtu` card memory",
"notes": [
"hf mf gview",
"hf mf gview --4k"
],
"offline": false,
"options": [
"-h, --help this help",
"--mini mifare classic mini / s20",
"--1k mifare classic 1k / s50 (def)",
"--2k mifare classic/plus 2k",
"--4k mifare classic 4k / s70"
],
"usage": "hf mf gview [-h] [--mini] [--1k] [--2k] [--4k]"
},
"hf mf hardnested": {
"command": "hf mf hardnested",
"description": "nested attack for hardened mifare classic cards. `--i<x>` set type of simd instructions. without this flag programs autodetect it. or hf mf hardnested -r --tk [known target key] add the known target key to check if it is present in the remaining key space hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk ffffffffffff",
@ -4219,12 +4236,12 @@
],
"usage": "hf mfdes list [-h1fcrux] [--dict <file>]..."
},
"hf mfdes readdata": {
"command": "hf mfdes readdata",
"hf mfdes read": {
"command": "hf mfdes read",
"description": "read data from file make sure to select aid or authenticate aid before running this command.",
"notes": [
"hf mfdes readdata -n 01 -t 0 -o 000000 -l 000000 -a 123456",
"hf mfdes readdata -n 01 -t 0 -> read all data from standard file, fileno 01"
"hf mfdes read -n 1 -t 0 -o 000000 -l 000000 -a 123456",
"hf mfdes read -n 1 -t 0 -> read all data from standard file, fileno 1"
],
"offline": false,
"options": [
@ -4235,7 +4252,7 @@
"-t, --type <dec> file type (0 = standard / backup, 1 = record)",
"-a, --aid <hex> app id to select (3 hex bytes, big endian)"
],
"usage": "hf mfdes readdata [-h] [-n <dec>] [-o <hex>]... [-l <hex>]... [-t <dec>] [-a <hex>]..."
"usage": "hf mfdes read [-h] [-n <dec>] [-o <hex>]... [-l <hex>]... [-t <dec>] [-a <hex>]..."
},
"hf mfdes selectaid": {
"command": "hf mfdes selectaid",
@ -4250,11 +4267,11 @@
],
"usage": "hf mfdes selectaid [-h] [-a <hex>]..."
},
"hf mfdes writedata": {
"command": "hf mfdes writedata",
"hf mfdes write": {
"command": "hf mfdes write",
"description": "write data to file make sure to select aid or authenticate aid before running this command.",
"notes": [
"hf mfdes writedata -n 01 -t 0 -o 000000 -d 3132333435363738"
"hf mfdes write -n 01 -t 0 -o 000000 -d 3132333435363738"
],
"offline": false,
"options": [
@ -4265,7 +4282,7 @@
"-t, --type <dec> file type (0 = standard / backup, 1 = record)",
"-a, --aid <hex> app id to select as hex bytes (3 bytes, big endian)"
],
"usage": "hf mfdes writedata [-h] [-n <dec>] [-o <hex>]... [-d <hex>]... [-t <dec>] [-a <hex>]..."
"usage": "hf mfdes write [-h] [-n <dec>] [-o <hex>]... [-d <hex>]... [-t <dec>] [-a <hex>]..."
},
"hf mfp auth": {
"command": "hf mfp auth",
@ -5061,8 +5078,8 @@
"command": "hw connect",
"description": "connects to a proxmark3 device via specified serial port. baudrate here is only for physical uart or uart-bt, not for usb-cdc or blue shark add-on",
"notes": [
"hw connect -p com3",
"hw connect -p com3 -b 115200"
"hw connect -p /dev/ttyacm0",
"hw connect -p /dev/ttyacm0 -b 115200"
],
"offline": true,
"options": [
@ -5761,7 +5778,7 @@
},
"lf em 4x50 chk": {
"command": "lf em 4x50 chk",
"description": "dictionary attack against em4x50.",
"description": "run dictionary key recovery against em4x50 card.",
"notes": [
"lf em 4x50 chk -> uses t55xx default dictionary",
"lf em 4x50 chk -f my.dic"
@ -5831,7 +5848,7 @@
},
"lf em 4x50 help": {
"command": "lf em 4x50 help",
"description": "help this help --------------------------------------------------------------------------------------- lf em 4x50 brute available offline: no tries to bruteforce the password of a em4x50. function can be stopped by pressing pm3 button.",
"description": "help this help ----------- --------------------- operations --------------------- ----------- --------------------- simulation --------------------- --------------------------------------------------------------------------------------- lf em 4x50 brute available offline: no tries to bruteforce the password of a em4x50 card. function can be stopped by pressing pm3 button.",
"notes": [
"lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000"
],
@ -5962,11 +5979,11 @@
],
"usage": "lf em 4x50 wrbl [-h] -b <dec> -d <hex> [-p <hex>]"
},
"lf em 4x50 writepwd": {
"command": "lf em 4x50 writepwd",
"lf em 4x50 wrpwd": {
"command": "lf em 4x50 wrpwd",
"description": "writes em4x50 password.",
"notes": [
"lf em 4x50 writepwd -p 4f22e7ff -n 12345678"
"lf em 4x50 wrpwd -p 4f22e7ff -n 12345678"
],
"offline": false,
"options": [
@ -5974,7 +5991,7 @@
"-p, --pwd <hex> password, 4 hex bytes, lsb",
"-n, --new <hex> new password, 4 hex bytes, lsb"
],
"usage": "lf em 4x50 writepwd [-h] -p <hex> -n <hex>"
"usage": "lf em 4x50 wrpwd [-h] -p <hex> -n <hex>"
},
"lf em 4x70 auth": {
"command": "lf em 4x70 auth",
@ -6441,17 +6458,18 @@
"command": "lf hitag help",
"description": "help this help list list hitag trace history --------------------------------------------------------------------------------------- lf hitag eload available offline: no loads hitag tag dump into emulator memory on device",
"notes": [
"lf hitag eload -f lf-hitag-11223344-dump.bin"
"lf hitag eload -2 -f lf-hitag-11223344-dump.bin"
],
"offline": true,
"options": [
"-h, --help this help",
"-f, --file <filename> filename of dump",
"-1 simulate hitag1",
"-2 simulate hitag2",
"-s simulate hitags"
"-1 card type hitag1",
"-2 card type hitag2",
"-s card type hitags",
"-m card type hitagm"
],
"usage": "lf hitag eload [-h12s] -f <filename>"
"usage": "lf hitag eload [-h12sm] -f <filename>"
},
"lf hitag info": {
"command": "lf hitag info",
@ -7586,7 +7604,7 @@
},
"lf sniff": {
"command": "lf sniff",
"description": "sniff low frequency signal. - use `lf config` to set parameters. - use `data plot` to look at it",
"description": "sniff low frequency signal. you need to configure the lf part on the proxmark3 device manually. usually a trigger and skip samples is a good thing to set before doing a low frequency sniff. - use `lf config` to set parameters. - use `data plot` to look at sniff signal. - use `lf search -1` to see if signal can be automatic decoded",
"notes": [
"lf sniff -v",
"lf sniff -s 3000 -@ -> oscilloscope style"
@ -9179,8 +9197,8 @@
}
},
"metadata": {
"commands_extracted": 570,
"commands_extracted": 571,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2021-06-18T09:04:45"
"extracted_on": "2021-06-24T17:28:12"
}
}

View file

@ -241,12 +241,13 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`hf cipurse help `|Y |`This help.`
|`hf cipurse info `|N |`Info about Cipurse tag.`
|`hf cipurse auth `|N |`Authentication.`
|`hf cipurse read `|N |`Read binary file.`
|`hf cipurse write `|N |`Write binary file.`
|`hf cipurse aread `|N |`Read file attributes.`
|`hf cipurse delete `|N |`Delete file.`
|`hf cipurse info `|N |`Get info about CIPURSE tag`
|`hf cipurse auth `|N |`Authenticate CIPURSE tag`
|`hf cipurse read `|N |`Read binary file`
|`hf cipurse write `|N |`Write binary file`
|`hf cipurse aread `|N |`Read file attributes`
|`hf cipurse delete `|N |`Delete file`
|`hf cipurse test `|Y |`Tests`
### hf epa
@ -445,6 +446,7 @@ Check column "offline" for their availability.
|`hf mf gen3uid `|N |`Set UID without changing manufacturer block`
|`hf mf gen3blk `|N |`Overwrite manufacturer block`
|`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible`
|`hf mf gview `|N |`View card`
### hf mfp
@ -518,8 +520,8 @@ Check column "offline" for their availability.
|`hf mfdes deletefile `|N |`Create Delete File`
|`hf mfdes dump `|N |`Dump all files`
|`hf mfdes getvalue `|N |`Get value of file`
|`hf mfdes readdata `|N |`Read data from standard/backup/record file`
|`hf mfdes writedata `|N |`Write data to standard/backup/record file`
|`hf mfdes read `|N |`Read data from standard/backup/record file`
|`hf mfdes write `|N |`Write data to standard/backup/record file`
### hf seos
@ -722,21 +724,21 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`lf em 4x50 help `|Y |`This help`
|`lf em 4x50 brute `|N |`guess password of EM4x50`
|`lf em 4x50 chk `|N |`check passwords from dictionary`
|`lf em 4x50 dump `|N |`dump EM4x50 tag`
|`lf em 4x50 info `|N |`tag information EM4x50`
|`lf em 4x50 login `|N |`login into EM4x50`
|`lf em 4x50 rdbl `|N |`read word data from EM4x50`
|`lf em 4x50 wrbl `|N |`write word data to EM4x50`
|`lf em 4x50 writepwd `|N |`change password of EM4x50`
|`lf em 4x50 wipe `|N |`wipe EM4x50 tag`
|`lf em 4x50 reader `|N |`show standard read mode data of EM4x50`
|`lf em 4x50 restore `|N |`restore EM4x50 dump to tag`
|`lf em 4x50 sim `|N |`simulate EM4x50 tag`
|`lf em 4x50 eload `|N |`upload dump of EM4x50 to emulator memory`
|`lf em 4x50 esave `|N |`save emulator memory to file`
|`lf em 4x50 eview `|N |`view EM4x50 content in emulator memory`
|`lf em 4x50 brute `|N |`Simple bruteforce attack to find password`
|`lf em 4x50 chk `|N |`Check passwords from dictionary`
|`lf em 4x50 dump `|N |`Dump EM4x50 tag`
|`lf em 4x50 info `|N |`Tag information`
|`lf em 4x50 login `|N |`Login into EM4x50 tag`
|`lf em 4x50 rdbl `|N |`Read EM4x50 word data`
|`lf em 4x50 reader `|N |`Show standard read mode data`
|`lf em 4x50 restore `|N |`Restore EM4x50 dump to tag`
|`lf em 4x50 wrbl `|N |`Write EM4x50 word data`
|`lf em 4x50 wrpwd `|N |`Change EM4x50 password`
|`lf em 4x50 wipe `|N |`Wipe EM4x50 tag`
|`lf em 4x50 eload `|N |`Upload EM4x50 dump to emulator memory`
|`lf em 4x50 esave `|N |`Save emulator memory to file`
|`lf em 4x50 eview `|N |`View EM4x50 content in emulator memory`
|`lf em 4x50 sim `|N |`Simulate EM4x50 tag`
### lf em 4x70

View file

@ -740,6 +740,9 @@ typedef struct {
#define CMD_HF_MIFARE_GEN3BLK 0x0851
#define CMD_HF_MIFARE_GEN3FREEZ 0x0852
// Gen 3 GTU magic cards
#define CMD_HF_MIFARE_G3_RDBL 0x0860
#define CMD_UNKNOWN 0xFFFF
//Mifare simulation flags

View file

@ -417,6 +417,7 @@ static void *brute_thread(void *arguments) {
if (isOK == false) {
printf(_RED_("<-- not a valid cmd\n"));
pthread_mutex_unlock(&print_lock);
free(revstate);
continue;
}
@ -425,6 +426,7 @@ static void *brute_thread(void *arguments) {
if (isOK == false) {
printf(_RED_("<-- not a valid crc\n"));
pthread_mutex_unlock(&print_lock);
free(revstate);
continue;
} else {
printf("<-- valid cmd\n");

View file

@ -491,6 +491,7 @@ while true; do
if ! $SLOWTESTS; then
if ! CheckExecute "hf iclass loclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification (ok)"; then break; fi
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Test(s) \[ ok"; then break; fi
if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \[ ok"; then break; fi
fi
fi
echo -e "\n------------------------------------------------------------"