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... 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] ## [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) - Added Standalone mode for nexwatch ID credentials (@Guilhem7, @MaximeBosca)
- Fix `lf em 4x50/4x70 *` reverted a missunderstanding in byte order macros (@iceman1001) - Fix `lf em 4x50/4x70 *` reverted a missunderstanding in byte order macros (@iceman1001)
- Added more keys (@equipter) - Added more keys (@equipter)

View file

@ -131,7 +131,7 @@ The [public roadmap](https://github.com/RfidResearchGroup/proxmark3/wiki/Public-
## Supported operative systems ## Supported operative systems
This repo compiles nicely on This repo compiles nicely on
- WSL1 on Windows 10 - 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 - Windows/MinGW environment
- Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian - Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian
- Android / Termux - Android / Termux
@ -155,7 +155,7 @@ We don't maintain any precompiled binaries in this repo. There is community effo
## Official channels ## Official channels
Where do you find the community? Where do you find the community?
- [RFID Hacking community discord server](https://discord.gg/QfPvGFRQxH) - [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 sub reddit](https://www.reddit.com/r/proxmark3/)
- [Proxmark3 forum](http://www.proxmark.org/forum/index.php) - [Proxmark3 forum](http://www.proxmark.org/forum/index.php)

View file

@ -1568,6 +1568,14 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareGen3Freez(); MifareGen3Freez();
break; 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: { case CMD_HF_MIFARE_PERSONALIZE_UID: {
struct p { struct p {
uint8_t keytype; uint8_t keytype;

View file

@ -1148,6 +1148,9 @@ void SniffHitag2(void) {
// Enable and reset counter // Enable and reset counter
AT91C_BASE_TC1->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;
int frame_count = 0, response = 0, overflow = 0, lastbit = 1, tag_sof = 4; int frame_count = 0, response = 0, overflow = 0, lastbit = 1, tag_sof = 4;
bool rising_edge = false, reader_frame = false, bSkip = true; bool rising_edge = false, reader_frame = false, bSkip = true;
uint8_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN];
@ -1293,11 +1296,15 @@ void SniffHitag2(void) {
// Reset the timer to restart while-loop that receives frames // 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;
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(); LEDsoff();
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false); 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_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->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 // Prepare data trace
uint32_t bufsize = 10000; uint32_t bufsize = 10000;

View file

@ -2594,6 +2594,42 @@ OUT:
BigBuf_free(); 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) { void MifareSetMod(uint8_t *datain) {
uint8_t mod = datain[0]; 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 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 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 MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key); void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);

View file

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

View file

@ -125,6 +125,8 @@ void StartCountUS(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->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; AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV > 0); 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/iso7816/iso7816core.c
${PM3_ROOT}/client/src/cipurse/cipursecrypto.c ${PM3_ROOT}/client/src/cipurse/cipursecrypto.c
${PM3_ROOT}/client/src/cipurse/cipursecore.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/cipher.c
${PM3_ROOT}/client/src/loclass/cipherutils.c ${PM3_ROOT}/client/src/loclass/cipherutils.c
${PM3_ROOT}/client/src/loclass/elite_crack.c ${PM3_ROOT}/client/src/loclass/elite_crack.c

View file

@ -559,6 +559,7 @@ SRCS = aiddesfire.c \
fido/fidocore.c \ fido/fidocore.c \
cipurse/cipursecore.c \ cipurse/cipursecore.c \
cipurse/cipursecrypto.c \ cipurse/cipursecrypto.c \
cipurse/cipursetest.c \
fileutils.c \ fileutils.c \
flash.c \ flash.c \
generator.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); CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen);
//PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(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; micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH;
memcpy(micdata, buf, buflen); memcpy(micdata, buf, buflen);
memcpy(&micdata[micdatalen], &buf[buflen - 2], 2); 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,10 +91,12 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, " Searching for ISO14443-A tag..."); PrintAndLogEx(INPLACE, " Searching for ISO14443-A tag...");
if (IfPm3Iso14443a()) { 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"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO 14443-A tag") " found\n");
res = PM3_SUCCESS; res = PM3_SUCCESS;
if (sel_state == 1)
infoHF14A4Applications(verbose); infoHF14A4Applications(verbose);
} }
} }

View file

@ -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]); memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]);
card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes 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 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) { if ((card.sak & 0x20) == 0x20) {
PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--"); PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--");
} }
if (select_status == 1)
select_status = 2;
} }
int isMagic = 0; 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); int res = Iso7816Select(CC_CONTACTLESS, ActivateField, true, (uint8_t *)hintAIDList[i].aid, hintAIDList[i].aid_length, result, sizeof(result), &resultlen, &sw);
ActivateField = false; ActivateField = false;
if (res) if (res)
continue; break;
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
if (!found) { if (!found) {

View file

@ -25,6 +25,7 @@
#include "cmdhfcipurse.h" #include "cmdhfcipurse.h"
#include "cipurse/cipursecore.h" #include "cipurse/cipursecore.h"
#include "cipurse/cipursecrypto.h" #include "cipurse/cipursecrypto.h"
#include "cipurse/cipursetest.h"
#include "ui.h" #include "ui.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "cmdtrace.h" #include "cmdtrace.h"
@ -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) { 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}; uint8_t hdata[250] = {0};
int hdatalen = sizeof(hdata); 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) { if (hdatalen && hdatalen != 16) {
PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only"); PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only");
return PM3_EINVARG; return PM3_EINVARG;
@ -186,7 +189,9 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
char cdata[250] = {0}; char cdata[250] = {0};
int cdatalen = sizeof(cdata); int cdatalen = sizeof(cdata);
cdatalen--; // for trailer 0x00 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) { if (cdatalen) {
str_lower(cdata); str_lower(cdata);
if (strcmp(cdata, "plain") == 0) if (strcmp(cdata, "plain") == 0)
@ -204,7 +209,9 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
cdatalen = sizeof(cdata); cdatalen = sizeof(cdata);
memset(cdata, 0, cdatalen); memset(cdata, 0, cdatalen);
cdatalen--; // for trailer 0x00 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) { if (cdatalen) {
str_lower(cdata); str_lower(cdata);
if (strcmp(cdata, "plain") == 0) if (strcmp(cdata, "plain") == 0)
@ -226,7 +233,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse read", CLIParserInit(&ctx, "hf cipurse read",
"Read file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", "Read file 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"); "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and read file\n");
void *argtable[] = { void *argtable[] = {
@ -338,7 +345,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse write", CLIParserInit(&ctx, "hf cipurse write",
"Write file by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", "Write file 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"); "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and write file\n");
void *argtable[] = { void *argtable[] = {
@ -463,7 +470,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse aread", CLIParserInit(&ctx, "hf cipurse aread",
"Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used", "Read file attributes by file ID with key ID and key. If no key is supplied, default key of 737373...7373 will be used",
"hf cipurse aread -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"); "hf cipurse aread -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2, read file attributes\n");
void *argtable[] = { void *argtable[] = {
@ -592,7 +599,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cipurse delete", 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", "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"); "hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> Authenticate keyID 2 and delete file\n");
void *argtable[] = { void *argtable[] = {
@ -682,7 +689,6 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
bool CheckCardCipurse(void) { bool CheckCardCipurse(void) {
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0; size_t len = 0;
@ -692,6 +698,11 @@ bool CheckCardCipurse(void) {
return (res == 0 && sw == 0x9000); return (res == 0 && sw == 0x9000);
} }
static int CmdHFCipurseTest(const char *Cmd) {
CIPURSETest(true);
return PM3_SUCCESS;
}
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help."}, {"help", CmdHelp, AlwaysAvailable, "This help."},
{"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Get info about CIPURSE tag"}, {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Get info about CIPURSE tag"},
@ -700,6 +711,7 @@ static command_t CommandTable[] = {
{"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file"}, {"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file"},
{"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes"}, {"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes"},
{"delete", CmdHFCipurseDeleteFile, IfPm3Iso14443a, "Delete file"}, {"delete", CmdHFCipurseDeleteFile, IfPm3Iso14443a, "Delete file"},
{"test", CmdHFCipurseTest, AlwaysAvailable, "Tests"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

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

View file

@ -37,6 +37,9 @@
#define ICLASS_AUTH_RETRY 10 #define ICLASS_AUTH_RETRY 10
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" #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 picopass_hdr_t iclass_last_known_card;
static void iclass_set_last_known_card(picopass_hdr_t *card) { static void iclass_set_last_known_card(picopass_hdr_t *card) {
memcpy(&iclass_last_known_card, card, sizeof(picopass_hdr_t)); 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; uint16_t bytes_remaining = n;
while (bytes_remaining > 0) { 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) { if (bytes_in_packet == bytes_remaining) {
// Disable fast mode on last packet // Disable fast mode on last packet
conn.block_after_ACK = false; 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) { static void print_config_card(const iclass_config_card_item_t *o) {
if (check_config_card(o)) { if (check_config_card(o)) {
PrintAndLogEx(INFO, "description... %s", o->desc); PrintAndLogEx(INFO, "description... " _YELLOW_("%s"), o->desc);
PrintAndLogEx(INFO, "data....... " _YELLOW_("%s"), sprint_hex_inrow(o->data, sizeof(o->data))); 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) { if (check_config_card(o) == false) {
return PM3_EINVARG; 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 // 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.."); PrintAndLogEx(INFO, "trying to read a card..");
int res = read_iclass_csn(false, false); int res = read_iclass_csn(false, false);
if (res != PM3_SUCCESS) { if (res == PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Put a card on antenna and try again..."); cc = &iclass_last_known_card;
return res; // 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 // 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 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 // normal size
uint8_t *data = calloc(1, tot_bytes); uint8_t *data = calloc(1, tot_bytes);
if (data == NULL) { 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; return PM3_EMALLOC;
} }
memcpy(data, cc, sizeof(picopass_hdr_t));
// calc diversified key for selected card print_picopass_header(cc);
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));
// Keyrolling configuration cards are special. // Keyrolling configuration cards are special.
if (strstr(o->desc, "Keyroll") != NULL) { 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.."); PrintAndLogEx(WARNING, "Adapting applimit1 for KEY rolling..");
app1_limit = 0x16; app1_limit = 0x16;
iclass_last_known_card.conf.app_limit = 0x16; cc->conf.app_limit = 0x16;
tot_bytes = (app1_limit + 1) * 8; tot_bytes = (app1_limit + 1) * 8;
uint8_t *p = realloc(data, tot_bytes); 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); memset(data, 0xFF, tot_bytes);
} }
// need to encrypt // KEYROLL need to encrypt
PrintAndLogEx(INFO, "Detecting cardhelper...");
if (IsCardHelperPresent(false) == false) {
PrintAndLogEx(FAILED, "failed to detect cardhelper");
free(data);
return PM3_ENODATA;
}
uint8_t ffs[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t ffs[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if (Encrypt(ffs, ffs) == false) { if (Encrypt(ffs, ffs) == false) {
PrintAndLogEx(WARNING, "failed to encrypt FF"); PrintAndLogEx(WARNING, "failed to encrypt FF");
} }
// local key copy
uint8_t lkey[8];
memcpy(lkey, key, sizeof(lkey));
uint8_t enckey1[8]; uint8_t enckey1[8];
if (Encrypt(key, enckey1) == false) { if (Encrypt(lkey, enckey1) == false) {
PrintAndLogEx(WARNING, "failed to encrypt key1"); 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)); memcpy(data + (6 * 8), o->data, sizeof(o->data));
// encrypted keyroll key 0D // 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 // encrypted partial keyroll key 14
uint8_t foo[8] = {0x15}; uint8_t foo[8] = {0x15};
memcpy(foo + 1, key, 7); memcpy(foo + 1, lkey, 7);
uint8_t enckey2[8]; uint8_t enckey2[8];
if (Encrypt(foo, enckey2) == false) { if (Encrypt(foo, enckey2) == false) {
PrintAndLogEx(WARNING, "failed to encrypt partial 1"); 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 // encrypted partial keyroll key 15
memset(foo, 0xFF, sizeof(foo)); memset(foo, 0xFF, sizeof(foo));
foo[0] = key[7]; foo[0] = lkey[7];
if (Encrypt(foo, enckey2) == false) { if (Encrypt(foo, enckey2) == false) {
PrintAndLogEx(WARNING, "failed to encrypt partial 2"); 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)); memcpy(data + (i * 8), ffs, sizeof(ffs));
} }
// revert potential modified app1_limit // revert potential modified app1_limit
iclass_last_known_card.conf.app_limit = old_limit; cc->conf.app_limit = old_limit;
} else { } 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)); 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") " --------------------"); PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------");
fuse_config(hdr); fuse_config(hdr);
mem_app_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(INFO, "--------------------------- " _CYAN_("card") " ---------------------------");
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); 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))); 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 // SR | 6,7,8,9, | AA1, Access control payload | 2
// | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) | // | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) |
// SEOS | | | // SEOS | | |
// MFC SIO| | |
// DESFIRE| | |
//} //}
int info_iclass(void) { int info_iclass(void) {

View file

@ -762,7 +762,7 @@ static int CmdLegicDump(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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_lit0(NULL, "de", "deobfuscate dump data (xor with MCC)"),
arg_param_end arg_param_end
}; };
@ -1032,7 +1032,7 @@ static int CmdLegicESave(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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_int0("t", "type", "<dec>", "Tag type"),
arg_lit0(NULL, "deobfuscate", "De-obfuscate dump data (xor with MCC)"), arg_lit0(NULL, "deobfuscate", "De-obfuscate dump data (xor with MCC)"),
arg_param_end arg_param_end

View file

@ -650,7 +650,7 @@ static int CmdHfLTODump(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); 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, "4k", "MIFARE Classic 4k / S70"),
arg_lit0(NULL, "emu", "Fill simulator keys from found keys"), arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
arg_lit0(NULL, "dump", "Dump found keys to binary file"), 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -5031,7 +5031,7 @@ static int CmdHF14AMfice(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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_u64_0(NULL, "limit", "<dec>", "nonces to be collected"),
arg_param_end arg_param_end
}; };
@ -6007,6 +6007,110 @@ static int CmdHF14AMfView(const char *Cmd) {
return PM3_SUCCESS; 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"}, {"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
@ -6059,7 +6163,8 @@ static command_t CommandTable[] = {
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without changing manufacturer block"}, {"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without changing manufacturer block"},
{"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"}, {"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"},
{"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"}, {"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3 GTU") " -----------------------"},
{"gview", CmdHF14AGen3View, IfPm3Iso14443a, "View card"},
// {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"}, // {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"}, // {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}

View file

@ -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; 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) // 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 // 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. // 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; CLIParserContext *ctx;
CLIParserInit(&ctx, "hw setmux", CLIParserInit(&ctx, "hw setmux",
"Set the ADC mux to a specific value", "Set the ADC mux to a specific value",
"hw setmux --hiraw -> set HIGH RAW" "hw setmux --hipkd -> set HIGH PEAK\n"
); );
void *argtable[] = { void *argtable[] = {
@ -562,6 +562,13 @@ static int CmdSetMux(const char *Cmd) {
return PM3_EINVARG; 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; uint8_t arg = 0;
if (lopkd) if (lopkd)
arg = 0; arg = 0;

View file

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

View file

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

View file

@ -570,8 +570,8 @@ static int CmdLFHitagReader(const char *Cmd) {
} }
// sanity checks // sanity checks
if (keylen != 0 && keylen != 4) { if (keylen != 0 && keylen != 4 && keylen != 6) {
PrintAndLogEx(WARNING, "Wrong KEY len expected 0 or 4, got %d", keylen); PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -657,7 +657,7 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); 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) // 1 (help) + 3 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
void *argtable[4 + 5] = { void *argtable[4 + 5] = {
arg_param_begin, 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_lit0("o", "override", "override, force pwd read despite danger to card"),
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"), 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); tlvdb_free(atc_db);
return 9; return 9;
} }
tlvdb_free(atc_db);
} else { } else {
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);

View file

@ -56,6 +56,8 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
return PM3_EOPABORTED; return PM3_EOPABORTED;
} }
PrintAndLogEx(INFO, "." NOLF);
// wait cycle // wait cycle
while (true) { while (true) {
PrintAndLogEx(NORMAL, "." NOLF); 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") "]", PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
package->block, package->block,
package->keytype ? 'B' : 'A', package->keytype ? 'B' : 'A',
sprint_hex(resultKey, 6) sprint_hex_inrow(resultKey, 6)
); );
return PM3_SUCCESS; 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") "]", PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
package->block, package->block,
package->keytype ? 'B' : 'A', package->keytype ? 'B' : 'A',
sprint_hex(resultKey, 6) sprint_hex_inrow(resultKey, 6)
); );
return PM3_SUCCESS; return PM3_SUCCESS;
} else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) { } 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 // variables
uint32_t cuid = 0; // uid part used for crypto1. 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 mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock);
int mfGen3Freeze(void); 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 tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
int detect_classic_prng(void); int detect_classic_prng(void);

View file

@ -25,6 +25,7 @@
#define NDEF_WIFIAPPL "application/vnd.wfa" #define NDEF_WIFIAPPL "application/vnd.wfa"
#define NDEF_BLUEAPPL "application/vnd.bluetooth" #define NDEF_BLUEAPPL "application/vnd.bluetooth"
#define NDEF_VCARDTEXT "text/vcard" #define NDEF_VCARDTEXT "text/vcard"
#define NDEF_XVCARDTEXT "text/x-vcard"
static const char *TypeNameFormat_s[] = { static const char *TypeNameFormat_s[] = {
"Empty Record", "Empty Record",
@ -510,8 +511,8 @@ static int ndefDecodeMime_wifi(NDEFHeader_t *ndef) {
static int ndefDecodeMime_vcard(NDEFHeader_t *ndef) { static int ndefDecodeMime_vcard(NDEFHeader_t *ndef) {
PrintAndLogEx(INFO, _CYAN_("VCARD details")); PrintAndLogEx(INFO, _CYAN_("VCARD details"));
if (ndef->PayloadLen > 1) { if (ndef->PayloadLen > 1) {
PrintAndLogEx(INFO, "Data... " _YELLOW_("%.*s"), (int)ndef->PayloadLen, ndef->Payload); PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, ">>> decorder, to be implemented <<<"); PrintAndLogEx(INFO, "%.*s", (int)ndef->PayloadLen, ndef->Payload);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -629,20 +630,29 @@ static int ndefDecodePayload(NDEFHeader_t *ndef) {
PrintAndLogEx(INFO, "- decoder to be impl -"); PrintAndLogEx(INFO, "- decoder to be impl -");
} }
break; break;
case tnfMIMEMediaRecord: case tnfMIMEMediaRecord: {
PrintAndLogEx(INFO, "MIME Media Record"); 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); 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); ndefDecodeMime_vcard(ndef);
} }
if (str_startswith((const char *)ndef->Type, NDEF_BLUEAPPL)) { if (str_startswith(begin, NDEF_BLUEAPPL)) {
ndefDecodeMime_bt(ndef); ndefDecodeMime_bt(ndef);
} }
break; break;
}
case tnfAbsoluteURIRecord: case tnfAbsoluteURIRecord:
PrintAndLogEx(INFO, "Absolute URI Record"); PrintAndLogEx(INFO, "Absolute URI Record");
PrintAndLogEx(INFO, " payload : %.*s", (int)ndef->PayloadLen, ndef->Payload); PrintAndLogEx(INFO, " payload : %.*s", (int)ndef->PayloadLen, ndef->Payload);

View file

@ -973,7 +973,7 @@
}, },
"help": { "help": {
"command": "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": [ "notes": [
"auto" "auto"
], ],
@ -1684,67 +1684,67 @@
}, },
"hf cipurse aread": { "hf cipurse aread": {
"command": "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": [ "notes": [
"hf cipurse aread -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and read file attributes with id 2ff7", "hf cipurse aread --fid 2ff7 -> authenticate with keyid 1, 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 -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2, read file attributes"
], ],
"offline": false, "offline": false,
"options": [ "options": [
"-h, --help this help", "-h, --help this help",
"-a, --apdu show apdu requests and responses", "-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data", "-v, --verbose show technical data",
"-n, --keyid <dec> key id", "-n <dec> key id",
"-k, --key <hex> key for authenticate", "-k, --key <hex> auth key",
"-f, --file <hex> file id", "--fid <hex> file id",
"--noauth read file attributes without authentication", "--noauth read file attributes without authentication",
"--sreq <plain|mac(default)|encode> communication reader-picc security level", "--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader security level", "--sresp <plain|mac(default)|encode> communication picc-reader security level",
"--sel-adf show info about adf itself", "--sel-adf show info about adf itself",
"--sel-mf show info about master file" "--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": { "hf cipurse auth": {
"command": "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": [ "notes": [
"hf cipurse auth -> authenticate with keyid=1 and key = 7373...7373", "hf cipurse auth -> authenticate with keyid 1, default key",
"hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> authenticate with key" "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> authenticate keyid 2 with key"
], ],
"offline": false, "offline": false,
"options": [ "options": [
"-h, --help this help", "-h, --help this help",
"-a, --apdu show apdu requests and responses", "-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data", "-v, --verbose show technical data",
"-n, --keyid <dec> key id", "-n <dec> key id",
"-k, --key <hex> key for authenticate" "-k, --key <hex> auth key"
], ],
"usage": "hf cipurse auth [-hav] [-n <dec>] [-k <hex>]" "usage": "hf cipurse auth [-hav] [-n <dec>] [-k <hex>]"
}, },
"hf cipurse delete": { "hf cipurse delete": {
"command": "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": [ "notes": [
"hf cipurse delete -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and delete file with id 2ff7", "hf cipurse delete --fid 2ff7 -> authenticate with keyid 1, delete file with id 2ff7",
"hf cipurse delete -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and delete file" "hf cipurse delete -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2 and delete file"
], ],
"offline": false, "offline": false,
"options": [ "options": [
"-h, --help this help", "-h, --help this help",
"-a, --apdu show apdu requests and responses", "-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data", "-v, --verbose show technical data",
"-n, --keyid <dec> key id", "-n <dec> key id",
"-k, --key <hex> key for authenticate", "-k, --key <hex> auth key",
"-f, --file <hex> file id", "--fid <hex> file id",
"--sreq <plain|mac(default)|encode> communication reader-picc security level", "--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader 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": { "hf cipurse help": {
"command": "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": [ "notes": [
"hf cipurse info" "hf cipurse info"
], ],
@ -1756,48 +1756,63 @@
}, },
"hf cipurse read": { "hf cipurse read": {
"command": "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": [ "notes": [
"hf cipurse read -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and read file with id 2ff7", "hf cipurse read --fid 2ff7 -> authenticate with keyid 1, read file with id 2ff7",
"hf cipurse read -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and read file" "hf cipurse read -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2 and read file"
], ],
"offline": false, "offline": false,
"options": [ "options": [
"-h, --help this help", "-h, --help this help",
"-a, --apdu show apdu requests and responses", "-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data", "-v, --verbose show technical data",
"-n, --keyid <dec> key id", "-n <dec> key id",
"-k, --key <hex> key for authenticate", "-k, --key <hex> auth key",
"-f, --file <hex> file id", "--fid <hex> file id",
"-o, --offset <dec> offset for reading data from file", "-o, --offset <dec> offset for reading data from file",
"--noauth read file without authentication", "--noauth read file without authentication",
"--sreq <plain|mac(default)|encode> communication reader-picc security level", "--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader 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": { "hf cipurse write": {
"command": "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": [ "notes": [
"hf cipurse write -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and write file with id 2ff7", "hf cipurse write --fid 2ff7 -> authenticate with keyid 1, write file with id 2ff7",
"hf cipurse write -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and write file" "hf cipurse write -n 2 -k 65656565656565656565656565656565 --fid 2ff7 -> authenticate keyid 2 and write file"
], ],
"offline": false, "offline": false,
"options": [ "options": [
"-h, --help this help", "-h, --help this help",
"-a, --apdu show apdu requests and responses", "-a, --apdu show apdu requests and responses",
"-v, --verbose show technical data", "-v, --verbose show technical data",
"-n, --keyid <dec> key id", "-n <dec> key id",
"-k, --key <hex> key for authenticate", "-k, --key <hex> auth key",
"-f, --file <hex> file id", "--fid <hex> file id",
"-o, --offset <dec> offset for reading data from file", "-o, --offset <dec> offset for reading data from file",
"--noauth read file without authentication", "--noauth read file without authentication",
"--sreq <plain|mac(default)|encode> communication reader-picc security level", "--sreq <plain|mac(default)|encode> communication reader-picc security level",
"--sresp <plain|mac(default)|encode> communication picc-reader 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": { "hf emrtd help": {
"command": "hf emrtd help", "command": "hf emrtd help",
@ -1854,21 +1869,6 @@
], ],
"usage": "hf emrtd list [-h1fcrux] [--dict <file>]..." "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": { "hf epa preplay": {
"command": "hf epa preplay", "command": "hf epa preplay",
"description": "perform pace protocol by replaying given apdus", "description": "perform pace protocol by replaying given apdus",
@ -3491,8 +3491,8 @@
"hf mf fchk --2k -k ffffffffffff -> key recovery against mifare 2k", "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 --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 -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 --emu -> target 1k, write keys to emulator memory",
"hf mf fchk --1k --dump -> target 1k, write to file", "hf mf fchk --1k --dump -> target 1k, write keys to file",
"hf mf fchk --1k --mem -> target 1k, use dictionary from flash memory" "hf mf fchk --1k --mem -> target 1k, use dictionary from flash memory"
], ],
"offline": false, "offline": false,
@ -3553,6 +3553,23 @@
], ],
"usage": "hf mf gen3uid [-h] [-u <hex>]" "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": { "hf mf hardnested": {
"command": "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", "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>]..." "usage": "hf mfdes list [-h1fcrux] [--dict <file>]..."
}, },
"hf mfdes readdata": { "hf mfdes read": {
"command": "hf mfdes readdata", "command": "hf mfdes read",
"description": "read data from file make sure to select aid or authenticate aid before running this command.", "description": "read data from file make sure to select aid or authenticate aid before running this command.",
"notes": [ "notes": [
"hf mfdes readdata -n 01 -t 0 -o 000000 -l 000000 -a 123456", "hf mfdes read -n 1 -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 -> read all data from standard file, fileno 1"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -4235,7 +4252,7 @@
"-t, --type <dec> file type (0 = standard / backup, 1 = record)", "-t, --type <dec> file type (0 = standard / backup, 1 = record)",
"-a, --aid <hex> app id to select (3 hex bytes, big endian)" "-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": { "hf mfdes selectaid": {
"command": "hf mfdes selectaid", "command": "hf mfdes selectaid",
@ -4250,11 +4267,11 @@
], ],
"usage": "hf mfdes selectaid [-h] [-a <hex>]..." "usage": "hf mfdes selectaid [-h] [-a <hex>]..."
}, },
"hf mfdes writedata": { "hf mfdes write": {
"command": "hf mfdes writedata", "command": "hf mfdes write",
"description": "write data to file make sure to select aid or authenticate aid before running this command.", "description": "write data to file make sure to select aid or authenticate aid before running this command.",
"notes": [ "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, "offline": false,
"options": [ "options": [
@ -4265,7 +4282,7 @@
"-t, --type <dec> file type (0 = standard / backup, 1 = record)", "-t, --type <dec> file type (0 = standard / backup, 1 = record)",
"-a, --aid <hex> app id to select as hex bytes (3 bytes, big endian)" "-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": { "hf mfp auth": {
"command": "hf mfp auth", "command": "hf mfp auth",
@ -5061,8 +5078,8 @@
"command": "hw connect", "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", "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": [ "notes": [
"hw connect -p com3", "hw connect -p /dev/ttyacm0",
"hw connect -p com3 -b 115200" "hw connect -p /dev/ttyacm0 -b 115200"
], ],
"offline": true, "offline": true,
"options": [ "options": [
@ -5761,7 +5778,7 @@
}, },
"lf em 4x50 chk": { "lf em 4x50 chk": {
"command": "lf em 4x50 chk", "command": "lf em 4x50 chk",
"description": "dictionary attack against em4x50.", "description": "run dictionary key recovery against em4x50 card.",
"notes": [ "notes": [
"lf em 4x50 chk -> uses t55xx default dictionary", "lf em 4x50 chk -> uses t55xx default dictionary",
"lf em 4x50 chk -f my.dic" "lf em 4x50 chk -f my.dic"
@ -5831,7 +5848,7 @@
}, },
"lf em 4x50 help": { "lf em 4x50 help": {
"command": "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": [ "notes": [
"lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000" "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>]" "usage": "lf em 4x50 wrbl [-h] -b <dec> -d <hex> [-p <hex>]"
}, },
"lf em 4x50 writepwd": { "lf em 4x50 wrpwd": {
"command": "lf em 4x50 writepwd", "command": "lf em 4x50 wrpwd",
"description": "writes em4x50 password.", "description": "writes em4x50 password.",
"notes": [ "notes": [
"lf em 4x50 writepwd -p 4f22e7ff -n 12345678" "lf em 4x50 wrpwd -p 4f22e7ff -n 12345678"
], ],
"offline": false, "offline": false,
"options": [ "options": [
@ -5974,7 +5991,7 @@
"-p, --pwd <hex> password, 4 hex bytes, lsb", "-p, --pwd <hex> password, 4 hex bytes, lsb",
"-n, --new <hex> new 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": { "lf em 4x70 auth": {
"command": "lf em 4x70 auth", "command": "lf em 4x70 auth",
@ -6441,17 +6458,18 @@
"command": "lf hitag help", "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", "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": [ "notes": [
"lf hitag eload -f lf-hitag-11223344-dump.bin" "lf hitag eload -2 -f lf-hitag-11223344-dump.bin"
], ],
"offline": true, "offline": true,
"options": [ "options": [
"-h, --help this help", "-h, --help this help",
"-f, --file <filename> filename of dump", "-f, --file <filename> filename of dump",
"-1 simulate hitag1", "-1 card type hitag1",
"-2 simulate hitag2", "-2 card type hitag2",
"-s simulate hitags" "-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": { "lf hitag info": {
"command": "lf hitag info", "command": "lf hitag info",
@ -7586,7 +7604,7 @@
}, },
"lf sniff": { "lf sniff": {
"command": "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": [ "notes": [
"lf sniff -v", "lf sniff -v",
"lf sniff -s 3000 -@ -> oscilloscope style" "lf sniff -s 3000 -@ -> oscilloscope style"
@ -9179,8 +9197,8 @@
} }
}, },
"metadata": { "metadata": {
"commands_extracted": 570, "commands_extracted": 571,
"extracted_by": "PM3Help2JSON v1.00", "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 |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf cipurse help `|Y |`This help.` |`hf cipurse help `|Y |`This help.`
|`hf cipurse info `|N |`Info about Cipurse tag.` |`hf cipurse info `|N |`Get info about CIPURSE tag`
|`hf cipurse auth `|N |`Authentication.` |`hf cipurse auth `|N |`Authenticate CIPURSE tag`
|`hf cipurse read `|N |`Read binary file.` |`hf cipurse read `|N |`Read binary file`
|`hf cipurse write `|N |`Write binary file.` |`hf cipurse write `|N |`Write binary file`
|`hf cipurse aread `|N |`Read file attributes.` |`hf cipurse aread `|N |`Read file attributes`
|`hf cipurse delete `|N |`Delete file.` |`hf cipurse delete `|N |`Delete file`
|`hf cipurse test `|Y |`Tests`
### hf epa ### hf epa
@ -445,6 +446,7 @@ Check column "offline" for their availability.
|`hf mf gen3uid `|N |`Set UID without changing manufacturer block` |`hf mf gen3uid `|N |`Set UID without changing manufacturer block`
|`hf mf gen3blk `|N |`Overwrite manufacturer block` |`hf mf gen3blk `|N |`Overwrite manufacturer block`
|`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible` |`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible`
|`hf mf gview `|N |`View card`
### hf mfp ### hf mfp
@ -518,8 +520,8 @@ Check column "offline" for their availability.
|`hf mfdes deletefile `|N |`Create Delete File` |`hf mfdes deletefile `|N |`Create Delete File`
|`hf mfdes dump `|N |`Dump all files` |`hf mfdes dump `|N |`Dump all files`
|`hf mfdes getvalue `|N |`Get value of file` |`hf mfdes getvalue `|N |`Get value of file`
|`hf mfdes readdata `|N |`Read data from standard/backup/record file` |`hf mfdes read `|N |`Read data from standard/backup/record file`
|`hf mfdes writedata `|N |`Write data to standard/backup/record file` |`hf mfdes write `|N |`Write data to standard/backup/record file`
### hf seos ### hf seos
@ -722,21 +724,21 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`lf em 4x50 help `|Y |`This help` |`lf em 4x50 help `|Y |`This help`
|`lf em 4x50 brute `|N |`guess password of EM4x50` |`lf em 4x50 brute `|N |`Simple bruteforce attack to find password`
|`lf em 4x50 chk `|N |`check passwords from dictionary` |`lf em 4x50 chk `|N |`Check passwords from dictionary`
|`lf em 4x50 dump `|N |`dump EM4x50 tag` |`lf em 4x50 dump `|N |`Dump EM4x50 tag`
|`lf em 4x50 info `|N |`tag information EM4x50` |`lf em 4x50 info `|N |`Tag information`
|`lf em 4x50 login `|N |`login into EM4x50` |`lf em 4x50 login `|N |`Login into EM4x50 tag`
|`lf em 4x50 rdbl `|N |`read word data from EM4x50` |`lf em 4x50 rdbl `|N |`Read EM4x50 word data`
|`lf em 4x50 wrbl `|N |`write word data to EM4x50` |`lf em 4x50 reader `|N |`Show standard read mode data`
|`lf em 4x50 writepwd `|N |`change password of EM4x50` |`lf em 4x50 restore `|N |`Restore EM4x50 dump to tag`
|`lf em 4x50 wipe `|N |`wipe EM4x50 tag` |`lf em 4x50 wrbl `|N |`Write EM4x50 word data`
|`lf em 4x50 reader `|N |`show standard read mode data of EM4x50` |`lf em 4x50 wrpwd `|N |`Change EM4x50 password`
|`lf em 4x50 restore `|N |`restore EM4x50 dump to tag` |`lf em 4x50 wipe `|N |`Wipe EM4x50 tag`
|`lf em 4x50 sim `|N |`simulate EM4x50 tag` |`lf em 4x50 eload `|N |`Upload EM4x50 dump to emulator memory`
|`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 esave `|N |`save emulator memory to file` |`lf em 4x50 eview `|N |`View EM4x50 content in emulator memory`
|`lf em 4x50 eview `|N |`view EM4x50 content in emulator memory` |`lf em 4x50 sim `|N |`Simulate EM4x50 tag`
### lf em 4x70 ### lf em 4x70

View file

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

View file

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

View file

@ -491,6 +491,7 @@ while true; do
if ! $SLOWTESTS; then if ! $SLOWTESTS; then
if ! CheckExecute "hf iclass loclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification (ok)"; then break; fi 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 "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
fi fi
echo -e "\n------------------------------------------------------------" echo -e "\n------------------------------------------------------------"