Merge branch 'master' into allin

update 201031
This commit is contained in:
tharexde 2020-10-31 14:56:23 +01:00
commit d977902fd8
52 changed files with 1959206 additions and 276 deletions

View file

@ -1220,7 +1220,11 @@ static void PacketReceived(PacketCommandNG *packet) {
#ifdef WITH_ISO14443b
case CMD_HF_SRI_READ: {
ReadSTMemoryIso14443b(packet->oldarg[0]);
struct p {
uint8_t blockno;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
ReadSTBlock(payload->blockno);
break;
}
case CMD_HF_ISO14443B_SNIFF: {

View file

@ -2623,9 +2623,10 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
// PICC compliant with iso14443a-4 ---> (SAK & 0x20 != 0)
if ((sak & 0x20) == 0) return 2;
} else if (hf14aconfig.forcerats == 2) {
if ((sak & 0x20) != 0) Dbprintf("Skipping RATS according to hf 14a config");
return 2;
} // else force RATS
if ((sak & 0x20) == 0) Dbprintf("Forcing RATS according to hf 14a config");
// RATS, Request for answer to select
if (no_rats == false) {
uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0

View file

@ -1540,7 +1540,8 @@ void iso14443b_setup(void) {
//
// I tried to be systematic and check every answer of the tag, every CRC, etc...
//-----------------------------------------------------------------------------
static bool ReadSTBlock(uint8_t blocknr, uint8_t *block) {
static int read_srx_block(uint8_t blocknr, uint8_t *block) {
uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00};
AddCrc14B(cmd, 2);
@ -1557,60 +1558,50 @@ static bool ReadSTBlock(uint8_t blocknr, uint8_t *block) {
// Check if we got an answer from the tag
if (retlen != 6) {
DbpString("[!] expected 6 bytes from tag, got less...");
return false;
return PM3_EWRONGANSWER;
}
// The check the CRC of the answer
if (!check_crc(CRC_14443_B, r_block, retlen)) {
if (check_crc(CRC_14443_B, r_block, retlen) == false) {
DbpString("CRC fail");
return false;
return PM3_ECRC;
}
if (block) {
memcpy(block, r_block, 4);
}
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("Address=%02x, Contents=%08x, CRC=%04x",
blocknr,
(r_block[3] << 24) + (r_block[2] << 16) + (r_block[1] << 8) + r_block[0],
(r_block[4] << 8) + r_block[5]);
(r_block[4] << 8) + r_block[5]
);
}
return true;
return PM3_SUCCESS;
}
void ReadSTMemoryIso14443b(uint16_t numofblocks) {
void ReadSTBlock(uint8_t blocknr) {
iso14443b_setup();
uint8_t *mem = BigBuf_malloc((numofblocks + 1) * 4);
iso14b_card_select_t card;
int res = iso14443b_select_srx_card(&card);
int isOK = PM3_SUCCESS;
// 0: OK 2: attrib fail, 3:crc fail,
if (res < 1) {
isOK = PM3_ETIMEOUT;
// 0: OK -1 wrong len, -2: attrib fail, -3:crc fail,
switch(res) {
case -1:
case -3: {
reply_ng(CMD_HF_SRI_READ, PM3_EWRONGANSWER, NULL, 0);
goto out;
}
++numofblocks;
for (uint8_t i = 0; i < numofblocks; i++) {
if (ReadSTBlock(i, mem + (i * 4)) == false) {
isOK = PM3_ETIMEOUT;
break;
case -2: {
reply_ng(CMD_HF_SRI_READ, PM3_ECRC, NULL, 0);
goto out;
}
}
// System area block (0xFF)
if (ReadSTBlock(0xFF, mem + (numofblocks * 4)) == false)
isOK = PM3_ETIMEOUT;
uint8_t *data = BigBuf_malloc(4);
res = read_srx_block(blocknr, data);
reply_ng(CMD_HF_SRI_READ, res, data, 4);
out:
reply_ng(CMD_HF_SRI_READ, isOK, mem, numofblocks * 4);
BigBuf_free();
switch_off();
}

View file

@ -34,7 +34,7 @@ int iso14443b_select_card_srx(iso14b_card_select_t *card);
void SimulateIso14443bTag(uint8_t *pupi);
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
void ReadSTMemoryIso14443b(uint16_t numofblocks);
void ReadSTBlock(uint8_t blocknr);
void SniffIso14443b(void);
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
void SendRawCommand14443B_Ex(PacketCommandNG *c);

View file

@ -2247,6 +2247,11 @@ void MifareCIdent(bool is_mfc) {
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *uid = BigBuf_malloc(10);
memset(par, 0x00, MAX_PARITY_SIZE);
memset(buf, 0x00, PM3_CMD_DATA_SIZE);
memset(uid, 0x00, 10);
uint32_t cuid = 0;
uint8_t data[1] = {0x00};
@ -2278,6 +2283,8 @@ void MifareCIdent(bool is_mfc) {
ReaderTransmit(rats, sizeof(rats), NULL);
res = ReaderReceive(buf, par);
if (res ) {
// test for some MFC gen2
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
@ -2296,6 +2303,7 @@ void MifareCIdent(bool is_mfc) {
// test for some MFC 7b gen2
if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
isGen = MAGIC_GEN_2;
goto OUT;
}
// test for Ultralight magic gen2
if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
@ -2322,8 +2330,9 @@ void MifareCIdent(bool is_mfc) {
isGen = MAGIC_GEN_2;
goto OUT;
}
}
if (! is_mfc) {
if (is_mfc == false) {
// magic ntag test
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
@ -2336,8 +2345,7 @@ void MifareCIdent(bool is_mfc) {
isGen = MAGIC_NTAG21X;
}
}
}
if (is_mfc) {
} else {
// magic MFC Gen3 test
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
@ -2767,6 +2775,8 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(1);
switch_off();
LEDsoff();
return;
};
@ -2775,6 +2785,6 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
LED_D_ON();
SpinDelayUsPrecision(tearoff_time);
switch_off();
LEDsoff();
reply_ng(CMD_HF_MFU_COUNTER_TEAROFF, PM3_SUCCESS, NULL, 0);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
0000000000000001
0000000000000002
0000000000000003
0000000000000004
0000000000000005
0000000000000006
0000000000000007
0000000000000008
0000000000000009
000000000000000a
000000000000000b
000000000000000c
000000000000000d
000000000000000e
000000000000000f
1000000000000000
2000000000000000
3000000000000000
4000000000000000
5000000000000000
6000000000000000
7000000000000000
8000000000000000
9000000000000000
A000000000000000
B000000000000000
C000000000000000
D000000000000000
E000000000000000
F000000000000000
aaaabbbbccccdddd
1010101010101010
0101010101010101
1122334455667788
2233445566778899
33445566778899AA
445566778899AABB
5566778899AABBCC
66778899AABBCCDD
778899AABBCCDDEE
8899AABBCCDDEEFF
6969696969696969
1212121212121212
1234567887654321
1111111122222222
1313131313131313
2000000020000000
a0a1a2a3a4a5a6a7
b0b1b2b3b4b5b6b7
c0c1c2c3c4c5c6c7
d0d1d2d3d4d5d6d7
e0e1e2e3e4e5e6e7
f0f1f2f3f4f5f6f7
d3f7d3f7d3f7d3f7
0102030405060708
0001020304050607
0f0e0d0c0b0a0908
0123456789ABCDEF
100f0e0d0c0b0a09
4041424344454647
3031323334353637
605F5E5D5C5B5A59
0000000000000000
1111111111111111
2222222222222222
3333333333333333
4444444444444444
5555555555555555
6666666666666666
7777777777777777
8888888888888888
9999999999999999
AAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEE
FFFFFFFFFFFFFFFF
deadbeefdeadbeef

View file

@ -0,0 +1,67 @@
These are text password lists that can be used to brute force RFID passwords. There are a lot better ways to find a password, but I haven't seen anyone talk about using normal password lists against RFID tags or publishing a list exclusively for this purpose.
_byte_most_common_password.dic files are extracted from the top 10 million password list.
_byte_words_uppercase files are extracted from a common English dictionary.
Since most evidence (how ever small) shows that uppercase passwords are normally used with RFID these lists have been coverted to upper case added.
Two sets for ascii numnber lists have also been in the event the password is an ascii number.
**A better dictionary to use is:**
https://github.com/RfidResearchGroup/proxmark3/tree/master/client/dictionaries
These are shorter lists and known default keys. My lists are to be used after the dictionary lists have been exhausted, and after other possible attacks have failed.
**Some examples on what my lists could be used for:**
T55xx and the em4305 chips use a 4 character password
Mifare Classic uses a 6 characters password (which will be added soon)
iClass uses an 8 characters password
Mifare Pluse uses a 16 characters password
**Examples where my list could have helped find:**
```
50524F58 spells out PROX
50415353 spells out PASS
```
These wouldn't be found in the most common password list, but they would be in the upercase dictionary. Again, the more efficent way to do this would have been to run the t55xx_default_pwds.dic from https://github.com/RfidResearchGroup/proxmark3/tree/master/client/dictionaries. If they had not published that great default password list, then we still would have been able to find these passwords without needing to try all possiblities which could take years.
When looking at the Mifare Plus list in mfp_default_keys.dic, we see that there is some corresponding to ASCII with the passwords:
```
404142434445464748494a4b4c4d4e4f = @ABCDEFGHIJKLMNO
303132333435363738393a3b3c3d3e3f = 0123456789:;<=>?
605F5E5D5C5B5A59605F5E5D5C5B5A59 = `_^]\[ZY`_^]\[ZY
```
Those would not appear in any of the above lists, but this just shows more evidence of an ASCII collocation.
**iClass_Other.dic**
When reviewing default passwords from other lists you start seeing common password schemes being using. For example:
```
a0a1a2a3a4a5
b0b1b2b3b4b5
from mfc_default_keys.dic
a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7
b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7
from mfp_default_keys.dic
```
As you can see there are some common themes in the above case its a0 then a1 ect. In these default password lists I took those themes and expanded them to fit the iClass key space. If you combine this with the other list https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/iclass_default_keys.dic It still only takes 1 second to run through all 86 keys.

View file

@ -653,7 +653,7 @@ C01FC822C6E5
# More keys:
8a19d40cf2b5
ae8587108640
135b88a94b8b, SafLock standalone door locks.
135b88a94b8b # SafLock standalone door locks.
#
# Russian Troika card
08B386463229

View file

@ -1645,6 +1645,7 @@ int CmdTuneSamples(const char *Cmd) {
int timeout = 0;
int timeout_max = 20;
PrintAndLogEx(INFO, "REMINDER: " _YELLOW_("'hw tune' doesn't actively tune your antennas") ", it's only informative");
PrintAndLogEx(INFO, "Measuring antenna characteristics, please wait...");
clearCommandBuffer();

View file

@ -28,7 +28,7 @@
#include "util_posix.h" // msclock
#include "aidsearch.h"
#include "cmdhf.h" // handle HF plot
#include "protocols.h" // MAGIC_GEN_1A
bool APDUInFramingEnable = true;
@ -1491,96 +1491,132 @@ typedef enum {
MTOTHER = 32
} nxp_mifare_type_t;
// According to NXP AN10833 Rev 3.6 MIFARE Type Identification, Table 6
static int detect_nxp_card(uint8_t sak, uint16_t atqa) {
// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
int type = MTNONE;
PrintAndLogEx(SUCCESS, "Possible types:");
if (sak == 0x00) {
printTag("NTAG 20x / 21x / 21x TT / I2C plus");
printTag("MIFARE Ultralight / C / EV1 / Nano");
type = MTULTRALIGHT;
}
if (sak == 0x01) {
printTag("TNP3xxx (Activision Game Appliance)");
type = MTCLASSIC;
}
if ((sak & 0x04) == 0x04) {
printTag("Any MIFARE CL1 / NTAG424DNA");
type |= MTDESFIRE;
}
if ((sak & 0x08) == 0x08) {
printTag("MIFARE Classic 1K / Classic 1K CL2");
printTag("MIFARE Plus 2K / Plus EV1 2K");
printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 2K");
if ((sak & 0x02) != 0x02) {
if ((sak & 0x19) == 0x19) {
printTag("MIFARE Classic 2K");
type |= MTCLASSIC;
type |= MTPLUS;
} else if ((sak & 0x38) == 0x38) {
printTag("SmartMX with MIFARE Classic 4K");
type |= MTCLASSIC;
} else if ((sak & 0x18) == 0x18) {
if (select_status == 1) {
if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Plus EV1 4K CL2 in SL1");
printTag("MIFARE Plus S 4K CL2 in SL1");
printTag("MIFARE Plus X 4K CL2 in SL1");
} else {
printTag("MIFARE Plus EV1 4K in SL1");
printTag("MIFARE Plus S 4K in SL1");
printTag("MIFARE Plus X 4K in SL1");
}
type |= MTPLUS;
} else {
if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Classic 4K CL2");
} else {
printTag("MIFARE Classic 4K");
}
type |= MTCLASSIC;
}
} else if ((sak & 0x09) == 0x09) {
if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Mini 0.3K CL2");
} else {
printTag("MIFARE Mini 0.3K");
}
if ((sak & 0x09) == 0x09) {
printTag("MIFARE Mini 0.3K / Mini CL2 0.3K");
type |= MTMINI;
} else if ((sak & 0x28) == 0x28) {
printTag("SmartMX with MIFARE Classic 1K");
type |= MTCLASSIC;
} else if ((sak & 0x08) == 0x08) {
if (select_status == 1) {
if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Plus EV1 2K CL2 in SL1");
printTag("MIFARE Plus S 2K CL2 in SL1");
printTag("MIFARE Plus X 2K CL2 in SL1");
printTag("MIFARE Plus SE 1K CL2");
} else {
printTag("MIFARE Plus EV1 2K in SL1");
printTag("MIFARE Plus S 2K in SL1");
printTag("MIFARE Plus X 2K in SL1");
printTag("MIFARE Plus SE 1K");
}
if ((sak & 0x10) == 0x10) {
printTag("MIFARE Plus 2K / Plus CL2 2K");
type |= MTPLUS;
}
if ((sak & 0x11) == 0x11) {
printTag("MIFARE Plus 4K / Plus CL2 4K");
type |= MTPLUS;
}
if ((sak & 0x18) == 0x18) {
if (atqa == 0x0042) {
printTag("MIFARE Plus 4K / Plus EV1 4K");
printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K");
type |= MTPLUS;
} else {
printTag("MIFARE Classic 4K / Classic 4K CL2");
if ((atqa & 0x0040) == 0x0040) {
printTag("MIFARE Classic 1K CL2");
} else {
printTag("MIFARE Classic 1K");
}
type |= MTCLASSIC;
}
}
if ((sak & 0x20) == 0x20) {
if (atqa == 0x0344) {
printTag("MIFARE DESFire MF3ICD40");
printTag("MIFARE DESFire EV1 2K/4K/8K / DESFire EV1 CL2 2K/4K/8K");
printTag("MIFARE NTAG424DNA");
type |= MTDESFIRE;
} else if (atqa == 0x0304) {
printTag("MIFARE NTAG424DNA (Random ID feature)");
} else if ((sak & 0x11) == 0x11) {
printTag("MIFARE Plus 4K in SL2");
type |= MTPLUS;
} else if ((sak & 0x10) == 0x10) {
printTag("MIFARE Plus 2K in SL2");
type |= MTPLUS;
} else if ((sak & 0x01) == 0x01) {
printTag("TNP3xxx (TagNPlay, Activision Game Appliance)");
type |= MTCLASSIC;
} else if ((sak & 0x24) == 0x24) {
printTag("MIFARE DESFire CL1");
printTag("MIFARE DESFire EV1 CL1");
type |= MTDESFIRE;
} else if ((sak & 0x20) == 0x20) {
if (select_status == 1) {
if ((atqa & 0x0040) == 0x0040) {
if ((atqa & 0x0300) == 0x0300) {
printTag("MIFARE DESFire CL2");
printTag("MIFARE DESFire EV1 256B/2K/4K/8K CL2");
printTag("MIFARE DESFire EV2 2K/4K/8K/16K/32K");
printTag("MIFARE DESFire Light 640B");
} else {
printTag("MIFARE Plus 2K/4K / Plus EV1 2K/4K");
printTag("MIFARE Plus CL2 2K/4K / Plus CL2 EV1 2K/4K");
printTag("MIFARE Plus EV1 2K/4K CL2 in SL3");
printTag("MIFARE Plus S 2K/4K CL2 in SL3");
printTag("MIFARE Plus X 2K/4K CL2 in SL3");
printTag("MIFARE Plus SE 1K CL2");
type |= MTPLUS;
}
} else {
printTag("MIFARE Plus EV1 2K/4K in SL3");
printTag("MIFARE Plus S 2K/4K in SL3");
printTag("MIFARE Plus X 2K/4K in SL3");
printTag("MIFARE Plus SE 1K");
type |= MTPLUS;
}
if ((sak & 0x24) == 0x24) {
if (atqa == 0x0344) {
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
printTag("NTAG 4xx");
type |= MTDESFIRE;
}
}
if ((sak & 0x28) == 0x28) {
if (atqa == 0x0344) {
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
} else if ((sak & 0x04) == 0x04) {
printTag("Any MIFARE CL1");
type |= MTDESFIRE;
} else {
printTag("MIFARE Ultralight");
printTag("MIFARE Ultralight C");
printTag("MIFARE Ultralight EV1");
printTag("MIFARE Ultralight Nano");
printTag("MIFARE Hospitality");
printTag("NTAG 2xx");
type |= MTULTRALIGHT;
}
}
if (type == MTNONE) {
PrintAndLogEx(WARNING, " failed to fingerprint");
}
return type;
}
@ -1666,7 +1702,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
int nxptype = MTNONE;
if (card.uidlen <= 4) {
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status);
isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
@ -1686,7 +1722,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isST = true;
break;
case 0x04: // NXP
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status);
isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
@ -2060,7 +2096,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isMagic = detect_mf_magic(true);
}
if (isMifareUltralight) {
isMagic = detect_mf_magic(false);
isMagic = (detect_mf_magic(false) == MAGIC_NTAG21X);
}
if (isMifareClassic) {
int res = detect_classic_static_nonce();

View file

@ -959,25 +959,25 @@ static int CmdHF14BReader(const char *Cmd) {
return readHF14B(verbose);
}
/* New command to read the contents of a SRI512|SRIX4K tag
* SRI* tags are ISO14443-B modulated memory tags,
* this command just dumps the contents of the memory/
*/
static int CmdHF14BReadSri(const char *Cmd) {
// Read SRI512|SRIX4K block
static int CmdHF14BSriRdBl(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 14b sriread",
"Read contents of a SRI512 | SRIX4K tag",
"hf 14b sriread\n"
CLIParserInit(&ctx, "hf 14b rdbl",
"Read SRI512 | SRIX4K block",
"hf 14b rdbl -b 06\n"
);
void *argtable[] = {
arg_param_begin,
arg_int0("b", "block", "<dec>", "block number"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIExecWithReturn(ctx, Cmd, argtable, false);
int blockno = arg_get_int_def(ctx, 1, -1);
CLIParserFree(ctx);
/*
iso14b_card_select_t card;
if (get_14b_UID(&card) == false) {
PrintAndLogEx(WARNING, "no tag found");
@ -985,7 +985,7 @@ static int CmdHF14BReadSri(const char *Cmd) {
}
if (card.uidlen != 8) {
PrintAndLogEx(FAILED, "current dump command only work with SRI4K / SRI512 tags");
PrintAndLogEx(FAILED, "current read command only work with SRI4K / SRI512 tags");
return PM3_SUCCESS;
}
@ -994,22 +994,33 @@ static int CmdHF14BReadSri(const char *Cmd) {
// 2 = 512
uint8_t cardtype = get_st_cardsize(card.uid);
uint8_t blocks = (cardtype == 1) ? 0x7F : 0x0F;
*/
struct {
uint8_t blockno;
} PACKED payload;
payload.blockno = blockno;
PacketResponseNG resp;
clearCommandBuffer();
SendCommandMIX(CMD_HF_SRI_READ, blocks, 0, 0, NULL, 0);
// iceman: should download read data and print in client.
return PM3_SUCCESS;
SendCommandNG(CMD_HF_SRI_READ, (uint8_t*)&payload, sizeof(payload));
if (WaitForResponseTimeout(CMD_HF_SRI_READ, &resp, TIMEOUT) == false) {
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "block %02u : " _GREEN_("%s") " | " _GREEN_("%s"), blockno, sprint_hex(resp.data.asBytes, resp.length), sprint_ascii(resp.data.asBytes, resp.length));
}
return resp.status;
}
// New command to write a SRI512/SRIX4K tag.
static int CmdHF14BWriteSri(const char *Cmd) {
/*
* For SRIX4K blocks 00 - 7F
* hf 14b raw -c -k 09 $srix4kwblock $srix4kwdata
* hf 14b raw --sr -c --data [09 $srix4kwblock $srix4kwdata
*
* For SR512 blocks 00 - 0F
* hf 14b raw -c -k 09 $sr512wblock $sr512wdata
* hf 14b raw --sr -c --data [09 $sr512wblock $sr512wdata]
*
* Special block FF = otp_lock_reg block.
* Data len 4 bytes-
@ -1064,7 +1075,7 @@ static int CmdHF14BWriteSri(const char *Cmd) {
);
}
sprintf(str, "--ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]);
sprintf(str, "--sr -c --data %02x%02x%02x%02x%02x%02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]);
return CmdHF14BCmdRaw(str);
}
@ -1787,7 +1798,7 @@ static command_t CommandTable[] = {
{"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a 14443B reader to identify a tag"},
{"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO 14443B tag"},
{"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO 14443B"},
{"sriread", CmdHF14BReadSri, IfPm3Iso14443b, "Read contents of a SRI512 | SRIX4K tag"},
{"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4x block"},
{"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 | SRIX4K tag"},
// {"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"},
{NULL, NULL, NULL, NULL}

View file

@ -1853,10 +1853,10 @@ static int CmdHF15Restore(const char *Cmd) {
if (addressed_mode) {
char uidhex[17] = {0x00};
hex_to_buffer((uint8_t *)uidhex, uid, sizeof(uid), sizeof(uidhex) - 1, 0, false, true);
hex_to_buffer((uint8_t *)hex, data + i, blocksize, sizeof(hex) - 1, 0, false, true);
hex_to_buffer((uint8_t *)hex, data + bytes, blocksize, sizeof(hex) - 1, 0, false, true);
snprintf(tmpCmd, sizeof(tmpCmd), "%s %s %u %s", newPrefix, uidhex, i, hex);
} else {
hex_to_buffer((uint8_t *)hex, data + i, blocksize, sizeof(hex) - 1, 0, false, true);
hex_to_buffer((uint8_t *)hex, data + bytes, blocksize, sizeof(hex) - 1, 0, false, true);
snprintf(tmpCmd, sizeof(tmpCmd), "%s u %u %s", newPrefix, i, hex);
}

View file

@ -1360,7 +1360,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96);
mfLastKey = GetCrypto1ProbableKey(&AuthData);
PrintAndLogEx(NORMAL, " | | * |%48s %012"PRIx64" prng %s | |",
PrintAndLogEx(NORMAL, " | | * |%49s " _GREEN_("%012" PRIX64) " prng %s | |",
"key",
mfLastKey,
validate_prng_nonce(AuthData.nt) ? _GREEN_("WEAK") : _YELLOW_("HARD"));
@ -1377,7 +1377,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
// check last used key
if (mfLastKey) {
if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) {
PrintAndLogEx(NORMAL, " | | * |%60s %012"PRIx64"| |", "last used key", mfLastKey);
PrintAndLogEx(NORMAL, " | | * |%60s " _GREEN_("%012" PRIX64) "| |", "last used key", mfLastKey);
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
};
}
@ -1386,7 +1386,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
if (!traceCrypto1) {
for (int i = 0; i < ARRAYLEN(g_mifare_default_keys); i++) {
if (NestedCheckKey(g_mifare_default_keys[i], &AuthData, cmd, cmdsize, parity)) {
PrintAndLogEx(NORMAL, " | | * |%61s %012"PRIx64"| |", "key", g_mifare_default_keys[i]);
PrintAndLogEx(NORMAL, " | | * |%61s " _GREEN_("%012" PRIX64) "| |", "key", g_mifare_default_keys[i]);
mfLastKey = g_mifare_default_keys[i];
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
@ -1414,7 +1414,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
AuthData.ks3 = ks3;
AuthData.nt = ntx;
mfLastKey = GetCrypto1ProbableKey(&AuthData);
PrintAndLogEx(NORMAL, " | | * | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |",
PrintAndLogEx(NORMAL, " | | * | nested probable key: " _GREEN_("%012" PRIX64) " ks2:%08x ks3:%08x | |",
mfLastKey,
AuthData.ks2,
AuthData.ks3);

View file

@ -25,6 +25,9 @@
#include "protocols.h"
#include "util_posix.h" // msclock
#include "cmdhfmfhard.h"
#include "des.h" // des ecb
#include "crapto1/crapto1.h" // prng_successor
#include "cmdhf14a.h" // exchange APDU
#define MFBLOCK_SIZE 16
@ -627,7 +630,6 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) {
}
}
static uint16_t NumOfBlocks(char card) {
switch (card) {
case '0' :
@ -696,7 +698,6 @@ static char GetFormatFromSector(uint8_t sectorNo) {
}
}
static int CmdHF14AMfDarkside(const char *Cmd) {
uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA;
uint64_t key = 0;
@ -2014,7 +2015,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
char ctmp;
// Nested and Hardnested returned status
uint64_t foundkey = 0;
int16_t isOK = 0;
int isOK = 0;
int current_sector_i = 0, current_key_type_i = 0;
// Dumping and transfere to simulater memory
uint8_t block[16] = {0x00};
@ -2372,8 +2373,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
}
isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64);
isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType + 0x60, &key64);
switch (isOK) {
case -1 :
@ -2393,17 +2393,18 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
PrintAndLogEx(WARNING, "\nAborted via keyboard.");
goto noValidKeyFound;
default :
PrintAndLogEx(SUCCESS, "\nFound valid key: %012" PRIx64 "\n", key64);
PrintAndLogEx(SUCCESS, "\nFound valid key: [ " _GREEN_("%012" PRIx64) " ]\n", key64);
break;
}
// Store the keys
num_to_bytes(key64, 6, key);
e_sector[blockNo].Key[keyType] = key64;
e_sector[blockNo].foundKey[keyType] = 'S';
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%012" PRIx64) " ] (used for nested / hardnested attack)",
blockNo,
keyType ? 'B' : 'A',
sprint_hex(key, sizeof(key))
key64
);
} else {
noValidKeyFound:
@ -3692,7 +3693,6 @@ static int CmdHF14AMfEGetSc(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14AMfEClear(const char *Cmd) {
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h') return usage_hf14_eclr();
@ -5266,6 +5266,147 @@ static int CmdHf14AGen3Freeze(const char *Cmd) {
return PM3_SUCCESS;
}
static void des_decrypt(void *out, const void *in, const void *key) {
mbedtls_des_context ctx;
mbedtls_des_setkey_dec(&ctx, key);
mbedtls_des_crypt_ecb(&ctx, in, out);
}
static int CmdHf14AMfSuperCard(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf supercard",
"Extract info from a `super card`",
"hf mf supercard");
void *argtable[] = {
arg_param_begin,
arg_lit0("r", "reset", "reset card"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool reset_card = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
bool activate_field = true;
bool keep_field_on = true;
int res = 0;
if (reset_card) {
keep_field_on = false;
uint8_t response[6];
int resplen = 0;
// --------------- RESET CARD ----------------
uint8_t aRESET[] = { 0x00, 0xa6, 0xc0, 0x00 };
res = ExchangeAPDU14a(aRESET, sizeof(aRESET), activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res) {
PrintAndLogEx(FAILED, "Super card reset [ " _RED_("fail") " ]");
DropField();
return res;
}
PrintAndLogEx(SUCCESS, "Super card reset [ " _GREEN_("ok") " ]");
return PM3_SUCCESS;
}
uint8_t responseA[22];
uint8_t responseB[22];
int respAlen = 0;
int respBlen = 0;
// --------------- First ----------------
uint8_t aFIRST[] = { 0x00, 0xa6, 0xb0, 0x00, 0x10 };
res = ExchangeAPDU14a(aFIRST, sizeof(aFIRST), activate_field, keep_field_on, responseA, sizeof(responseA), &respAlen);
if (res) {
DropField();
return res;
}
// --------------- Second ----------------
activate_field = false;
keep_field_on = false;
uint8_t aSECOND[] = { 0x00, 0xa6, 0xb0, 0x01, 0x10 };
res = ExchangeAPDU14a(aSECOND, sizeof(aSECOND), activate_field, keep_field_on, responseB, sizeof(responseB), &respBlen);
if (res) {
DropField();
return res;
}
// uint8_t inA[] = { 0x72, 0xD7, 0xF4, 0x3E, 0xFD, 0xAB, 0xF2, 0x35, 0xFD, 0x49, 0xEE, 0xDC, 0x44, 0x95, 0x43, 0xC4};
// uint8_t inB[] = { 0xF0, 0xA2, 0x67, 0x6A, 0x04, 0x6A, 0x72, 0x12, 0x76, 0xA4, 0x1D, 0x02, 0x1F, 0xEA, 0x20, 0x85};
uint8_t outA[16] = {0};
uint8_t outB[16] = {0};
uint8_t key[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
for (uint8_t i = 0; i < 16; i += 8) {
des_decrypt(outA + i, responseA + i, key);
des_decrypt(outB + i, responseB + i, key);
}
PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseA, respAlen));
PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outA, sizeof(outA)));
PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseB, respAlen));
PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outB, sizeof(outB)));
if (memcmp(outA, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
PrintAndLogEx(INFO, "No trace recorded");
return PM3_SUCCESS;
}
// second trace?
if (memcmp(outB, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
PrintAndLogEx(INFO, "Only one trace recorded");
return PM3_SUCCESS;
}
nonces_t data;
// first
uint16_t NT0 = (outA[6] << 8) | outA[7];
data.cuid = bytes_to_num(outA, 4);
data.nonce = prng_successor(NT0, 31);
data.nr = bytes_to_num(outA + 8, 4);
data.ar = bytes_to_num(outA + 12, 4);
data.at = 0;
// second
NT0 = (outB[6] << 8) | outB[7];
data.nonce2 = prng_successor(NT0, 31);;
data.nr2 = bytes_to_num(outB + 8, 4);
data.ar2 = bytes_to_num(outB + 12, 4);
data.sector = GetSectorFromBlockNo(outA[5]);
data.keytype = outA[4];
data.state = FIRST;
PrintAndLogEx(DEBUG, "A Sector %02x", data.sector);
PrintAndLogEx(DEBUG, "A NT %08x", data.nonce);
PrintAndLogEx(DEBUG, "A NR %08x", data.nr);
PrintAndLogEx(DEBUG, "A AR %08x", data.ar);
PrintAndLogEx(DEBUG, "");
PrintAndLogEx(DEBUG, "B NT %08x", data.nonce2);
PrintAndLogEx(DEBUG, "B NR %08x", data.nr2);
PrintAndLogEx(DEBUG, "B AR %08x", data.ar2);
uint64_t key64 = -1;
res = mfkey32_moebius(&data, &key64);
if (res) {
PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ " _GREEN_("%12" PRIX64) " ]"
, sprint_hex_inrow(outA, 4)
, data.sector
, (data.keytype == 0x60) ? 'A' : 'B'
, key64);
} else {
PrintAndLogEx(FAILED, "failed to recover any key");
}
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
@ -5280,6 +5421,7 @@ static command_t CommandTable[] = {
{"chk", CmdHF14AMfChk, IfPm3Iso14443a, "Check keys"},
{"fchk", CmdHF14AMfChk_fast, IfPm3Iso14443a, "Check keys fast, targets all keys on card"},
{"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace"},
{"supercard", CmdHf14AMfSuperCard, IfPm3Iso14443a, "Extract info from a `super card`"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"},
{"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
{"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"},

View file

@ -32,6 +32,7 @@
#include "fileutils.h"
#include "mifare/mifaredefault.h" // default keys
#include "mifare/ndef.h" // NDEF
#include "mifare/mad.h"
#define MAX_KEY_LEN 24
#define MAX_KEYS_LIST_LEN 1024
@ -63,6 +64,9 @@ typedef struct {
uint8_t keyno;
uint8_t keylen;
uint8_t key[24];
uint8_t kdfAlgo;
uint8_t kdfInputLen;
uint8_t kdfInput[31];
} PACKED mfdes_authinput_t;
static mfdes_authinput_t currentauth[0xF] = {{.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}, {.keyno = -1}};
@ -706,6 +710,13 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
Desfire_3k3des_key_new_with_version(keybytes, key);
}
if (payload->kdfAlgo == MFDES_KDF_ALGO_AN10922) {
mifare_kdf_an10922(key, payload->kdfInput, payload->kdfInputLen);
if (g_debugMode) {
PrintAndLogEx(INFO, " Derrived key: " _GREEN_("%s"), sprint_hex(key->data, key_block_size(key)));
}
}
uint8_t subcommand = MFDES_AUTHENTICATE;
tag->authentication_scheme = AS_LEGACY;
@ -918,7 +929,7 @@ static int handler_desfire_auth(mfdes_authinput_t *payload, mfdes_auth_res_t *rp
memset(tag->ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
tag->authenticated_key_no = payload->keyno;
if (tag->authentication_scheme == AS_NEW) {
cmac_generate_subkeys(tag->session_key);
cmac_generate_subkeys(tag->session_key, MCD_RECEIVE);
}
return PM3_SUCCESS;
}
@ -1169,14 +1180,14 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat
PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
return PM3_EINVARG;
}
// DESFire Ev3 - wanted
// ref: MIFARE Desfire Originality Signature Validation
// See tools/recover_pk.py to recover Pk from UIDs and signatures
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57
const ecdsa_publickey_t nxp_desfire_public_keys[] = {
{"NTAG424DNA, DESFire EV2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"},
{"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
{"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
{"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"},
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
{"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
@ -1987,7 +1998,7 @@ static void swap16(uint8_t *data) {
data[1] = tmp;
};
static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, mfdes_auth_res_t *rpayload) {
static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid, uint8_t *key, int cmdKeyNo, uint8_t cmdKdfAlgo, uint8_t kdfInputLen, uint8_t *kdfInput, mfdes_auth_res_t *rpayload) {
switch (cmdAuthMode) {
case MFDES_AUTH_DES:
if (cmdAuthAlgo != MFDES_ALGO_DES && cmdAuthAlgo != MFDES_ALGO_3DES) {
@ -2036,6 +2047,25 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid,
break;
}
switch (cmdKdfAlgo) {
case MFDES_KDF_ALGO_AN10922:
// TODO: 2TDEA and 3TDEA keys use an input length of 1-15 bytes
if (cmdAuthAlgo != MFDES_ALGO_AES) {
PrintAndLogEx(FAILED, "Crypto algo not valid for the KDF AN10922 algo.");
return PM3_EINVARG;
}
if (kdfInputLen < 1 || kdfInputLen > 31) {
PrintAndLogEx(FAILED, "KDF AN10922 algo requires an input of length 1-31 bytes.");
return PM3_EINVARG;
}
case MFDES_KDF_ALGO_NONE:
break;
default:
PrintAndLogEx(WARNING, "KDF algo %d is not supported.", cmdKdfAlgo);
return PM3_EINVARG;
break;
}
// KEY
int res = handler_desfire_select_application(aid);
if (res != PM3_SUCCESS) return res;
@ -2053,6 +2083,9 @@ static int desfire_authenticate(int cmdAuthMode, int cmdAuthAlgo, uint8_t *aid,
payload.mode = cmdAuthMode;
payload.algo = cmdAuthAlgo;
payload.keyno = cmdKeyNo;
payload.kdfAlgo = cmdKdfAlgo;
payload.kdfInputLen = kdfInputLen;
memcpy(payload.kdfInput, kdfInput, kdfInputLen);
int error = handler_desfire_auth(&payload, rpayload);
if (error == PM3_SUCCESS) {
@ -3539,8 +3572,12 @@ static int CmdHF14ADesDump(const char *Cmd) {
aid[2] = app_ids[i + 2];
PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]);
PrintAndLogEx(SUCCESS, " AID Function Cluster 0x%02X: " _YELLOW_("%s"), aid[2], cluster_to_text(aid[2]));
if ((aid[2] >> 4) == 0xF) {
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
MADDFDecodeAndPrint(short_aid);
}
for (uint8_t m = 0; m < dfname_count; m++) {
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name);
@ -3705,8 +3742,12 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
}
PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X%02X%02X"), aid[2], aid[1], aid[0]);
PrintAndLogEx(SUCCESS, " AID Function Cluster 0x%02X: " _YELLOW_("%s"), aid[2], cluster_to_text(aid[2]));
if ((aid[2] >> 4) == 0xF) {
uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4);
PrintAndLogEx(SUCCESS, " AID mapped to MIFARE Classic AID (MAD): " _YELLOW_("%02X"), short_aid);
PrintAndLogEx(SUCCESS, " MAD AID Cluster 0x%02X : " _YELLOW_("%s"), short_aid >> 8, cluster_to_text(short_aid >> 8));
MADDFDecodeAndPrint(short_aid);
}
for (uint8_t m = 0; m < dfname_count; m++) {
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X%02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[1], dfnames[m].fid[0], dfnames[m].name);
@ -3870,6 +3911,8 @@ static int CmdHF14ADesAuth(const char *Cmd) {
arg_strx0("a", "aid", "<aid>", "AID used for authentification (HEX 3 bytes)"),
arg_int0("n", "keyno", "<keyno>", "Key number used for authentification"),
arg_str0("k", "key", "<Key>", "Key for checking (HEX 8-24 bytes)"),
arg_int0("d", "kdf", "<kdf>", "Key Derivation Function (KDF) (0=None, 1=AN10922)"),
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -3886,6 +3929,13 @@ static int CmdHF14ADesAuth(const char *Cmd) {
uint8_t key[24] = {0};
int keylen = 0;
CLIGetHexWithReturn(ctx, 5, key, &keylen);
// Get KDF input
uint8_t kdfInput[31] = {0};
int kdfInputLen = 0;
uint8_t cmdKDFAlgo = arg_get_int_def(ctx, 6, 0);
CLIGetHexWithReturn(ctx, 7, kdfInput, &kdfInputLen);
CLIParserFree(ctx);
if (cmdAuthAlgo == MFDES_ALGO_AES) {
@ -3931,7 +3981,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
}
mfdes_auth_res_t rpayload;
int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, &rpayload);
int error = desfire_authenticate(cmdAuthMode, cmdAuthAlgo, aid, key, cmdKeyNo, cmdKDFAlgo, kdfInputLen, kdfInput, &rpayload);
if (error == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, " Key : " _GREEN_("%s"), sprint_hex(key, keylength));
PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(rpayload.sessionkey, keylength));
@ -4078,7 +4128,7 @@ static int AuthCheckDesfire(uint8_t *aid,
if (usedkeys[keyno] == 1 && foundKeys[0][keyno][0] == 0) {
for (uint32_t curkey = 0; curkey < deskeyListLen; curkey++) {
mfdes_auth_res_t rpayload;
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, &rpayload);
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_DES, aid, deskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
if (error == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8));
foundKeys[0][keyno][0] = 0x01;
@ -4110,7 +4160,7 @@ static int AuthCheckDesfire(uint8_t *aid,
if (usedkeys[keyno] == 1 && foundKeys[1][keyno][0] == 0) {
for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) {
mfdes_auth_res_t rpayload;
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, &rpayload);
error = desfire_authenticate(MFDES_AUTH_DES, MFDES_ALGO_3DES, aid, aeskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
if (error == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3DES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16));
foundKeys[1][keyno][0] = 0x01;
@ -4142,7 +4192,7 @@ static int AuthCheckDesfire(uint8_t *aid,
if (usedkeys[keyno] == 1 && foundKeys[2][keyno][0] == 0) {
for (uint32_t curkey = 0; curkey < aeskeyListLen; curkey++) {
mfdes_auth_res_t rpayload;
error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, &rpayload);
error = desfire_authenticate(MFDES_AUTH_AES, MFDES_ALGO_AES, aid, aeskeyList[curkey], keyno, 0, 0, NULL, &rpayload);
if (error == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found AES Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16));
foundKeys[2][keyno][0] = 0x01;
@ -4174,7 +4224,7 @@ static int AuthCheckDesfire(uint8_t *aid,
if (usedkeys[keyno] == 1 && foundKeys[3][keyno][0] == 0) {
for (uint32_t curkey = 0; curkey < k3kkeyListLen; curkey++) {
mfdes_auth_res_t rpayload;
error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, &rpayload);
error = desfire_authenticate(MFDES_AUTH_ISO, MFDES_ALGO_3K3DES, aid, k3kkeyList[curkey], keyno, 0, 0, NULL, &rpayload);
if (error == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3K3 Key %u : " _GREEN_("%s"), curaid, keyno, sprint_hex(k3kkeyList[curkey], 24));
foundKeys[3][keyno][0] = 0x01;

View file

@ -98,11 +98,13 @@ static em_tech_type_t em_get_card_type(uint32_t config) {
uint8_t t = (config >> 1) & 0xF;
switch (t) {
case 4:
return EM_4X69;
return EM_4469;
case 8:
return EM_4205;
case 9:
return EM_4305;
case 12:
return EM_4369;
}
return EM_UNKNOWN;
}
@ -111,10 +113,12 @@ static const char *em_get_card_str(uint32_t config) {
switch (em_get_card_type(config)) {
case EM_4305:
return "EM4305";
case EM_4X69:
case EM_4469:
return "EM4469";
case EM_4205:
return "EM4205";
case EM_4369:
return "EM4369";
case EM_UNKNOWN:
break;
}
@ -562,7 +566,7 @@ int CmdEM4x05Dump(const char *Cmd) {
uint32_t word = 0;
const char *info[] = {"Info/User", "UID", "Password", "User", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "Lock", "Lock"};
const char *info4x69 [] = {"Info", "UID", "Password", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
const char *info4x69 [] = {"Info", "UID", "Password", "Lock", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
// EM4305 vs EM4469
em_tech_type_t card_type = em_get_card_type(block0);
@ -659,16 +663,14 @@ int CmdEM4x05Dump(const char *Cmd) {
data[14] = BSWAP_32(data[14]);
data[15] = BSWAP_32(data[15]);
} else if (card_type == EM_4X69) {
} else if (card_type == EM_4369 || card_type == EM_4469) {
// To flag any blocks locked we need to read blocks 14 and 15 first
// To flag any blocks locked we need to read block 3 first
// dont swap endian until we get block lock flags.
status14 = em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
if (status14 == PM3_SUCCESS) {
if ((word & 0x00008000) != 0x00) {
lock_bits = word;
gotLockBits = true;
}
data[EM4469_PROT_BLOCK] = word;
} else {
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
@ -676,8 +678,8 @@ int CmdEM4x05Dump(const char *Cmd) {
uint32_t lockbit;
for (; addr < 15; addr++) {
lockbit = (lock_bits >> addr) & 1;
for (; addr < 16; addr++) {
lockbit = (lock_bits >> (addr * 2)) & 3;
if (addr == 2) {
if (usePwd) {
data[addr] = BSWAP_32(pwd);
@ -712,15 +714,17 @@ int CmdEM4x05Dump(const char *Cmd) {
// saveFile (binary) passes in the .bin extension.
if (strcmp(filename, "") == 0) {
if (card_type == EM_4X69) {
sprintf(filename, "lf-4x69-%08X-dump", BSWAP_32(data[1]));
if (card_type == EM_4369) {
sprintf(filename, "lf-4369-%08X-dump", BSWAP_32(data[1]));
} else if (card_type == EM_4469) {
sprintf(filename, "lf-4469-%08X-dump", BSWAP_32(data[1]));
} else {
sprintf(filename, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
}
}
PrintAndLogEx(NORMAL, "");
saveFileJSON(filename, (card_type == EM_4X69) ? jsfEM4x69 : jsfEM4x05, (uint8_t *)data, 16 * sizeof(uint32_t), NULL);
saveFileJSON(filename, (card_type == EM_4369 || card_type == EM_4469) ? jsfEM4x69 : jsfEM4x05, (uint8_t *)data, 16 * sizeof(uint32_t), NULL);
saveFileEML(filename, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
saveFile(filename, ".bin", data, sizeof(data));
@ -971,7 +975,7 @@ static const char *printEM4x05_known(uint32_t word) {
return "";
}
static void printEM4x05config(uint32_t wordData) {
static void printEM4x05config(em_tech_type_t card_type, uint32_t wordData) {
uint16_t datarate = (((wordData & 0x3F) + 1) * 2);
uint8_t encoder = ((wordData >> 6) & 0xF);
char enc[14];
@ -1057,7 +1061,8 @@ static void printEM4x05config(uint32_t wordData) {
uint8_t raw = (wordData & EM4x05_READ_AFTER_WRITE) >> 22;
uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED) >> 23;
uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST) >> 24;
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
uint8_t invert = (wordData & EM4x05_INVERT) >> 25;
uint8_t pigeon = (wordData & EM4x05_PIGEON) >> 26;
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ------------------------");
@ -1065,17 +1070,46 @@ static void printEM4x05config(uint32_t wordData) {
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
if (card_type == EM_4369 || card_type == EM_4469) {
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf);
} else if (PSKcf != 0) {
PrintAndLogEx(INFO, "co10..c011: %u | %s", PSKcf, _RED_("Not used, must be set to logic 0"));
}
if (card_type == EM_4305) {
PrintAndLogEx(INFO, " Delay: %u | %s", delay, cdelay);
} else if (delay != 0) {
PrintAndLogEx(INFO, "co12..c013: %u | %s", delay, _RED_("Not used, must be set to logic 0"));
}
PrintAndLogEx(INFO, " LastWordR: %02u | Address of last word for default read - meaning %u blocks are output", LWR, numblks);
PrintAndLogEx(INFO, " ReadLogin: %u | Read login is %s", readLogin, readLogin ? _YELLOW_("required") : _GREEN_("not required"));
PrintAndLogEx(INFO, " ReadHKL: %u | Read housekeeping words login is %s", readHKL, readHKL ? _YELLOW_("required") : _GREEN_("not required"));
if (card_type == EM_4369 || card_type == EM_4469) {
PrintAndLogEx(INFO, " ReadHKL: %u | Read housekeeping words (3,4) login is %s", readHKL, readHKL ? _YELLOW_("required") : _GREEN_("not required"));
} else if (readHKL != 0) {
PrintAndLogEx(INFO, " c019: %u | %s", readHKL, _RED_("Not used, must be set to logic 0"));
}
PrintAndLogEx(INFO, "WriteLogin: %u | Write login is %s", writeLogin, writeLogin ? _YELLOW_("required") : _GREEN_("not required"));
PrintAndLogEx(INFO, " WriteHKL: %u | Write housekeeping words login is %s", writeHKL, writeHKL ? _YELLOW_("required") : _GREEN_("not Required"));
if (card_type == EM_4369 || card_type == EM_4469) {
PrintAndLogEx(INFO, " WriteHKL: %u | Write housekeeping words (2,3,4) login is %s", writeHKL, writeHKL ? _YELLOW_("required") : _GREEN_("not Required"));
} else if (writeHKL != 0) {
PrintAndLogEx(INFO, " c021: %u | %s", writeHKL, _RED_("Not used, must be set to logic 0"));
}
if (card_type == EM_4369 || card_type == EM_4469) {
PrintAndLogEx(INFO, " R.A.W.: %u | Read after write is %s", raw, raw ? "on" : "off");
} else if (raw != 0) {
PrintAndLogEx(INFO, " c022: %u | %s", raw, _RED_("Not used, must be set to logic 0"));
}
PrintAndLogEx(INFO, " Disable: %u | Disable command is %s", disable, disable ? "accepted" : "not accepted");
PrintAndLogEx(INFO, " R.T.F.: %u | Reader talk first is %s", rtf, rtf ? _YELLOW_("enabled") : "disabled");
if (card_type == EM_4369) {
PrintAndLogEx(INFO, " Invert: %u | Invert data? %s", invert, invert ? _YELLOW_("yes") : "no");
} else if (invert != 0) {
PrintAndLogEx(INFO, " c025: %u | %s", invert, _RED_("Not used, must be set to logic 0"));
}
if (card_type == EM_4305) {
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s", pigeon, pigeon ? _YELLOW_("enabled") : "disabled");
} else if (pigeon != 0) {
PrintAndLogEx(INFO, " c026: %u | %s", pigeon, _RED_("Not used, must be set to logic 0"));
}
}
static void printEM4x05info(uint32_t block0, uint32_t serial) {
@ -1165,7 +1199,7 @@ int CmdEM4x05Info(const char *Cmd) {
return PM3_ESOFT;
// based on Block0 , decide type.
int card_type = em_get_card_type(block0);
em_tech_type_t card_type = em_get_card_type(block0);
// read word 1 (serial #) doesn't need pwd
// continue if failed, .. non blocking fail.
@ -1180,7 +1214,7 @@ int CmdEM4x05Info(const char *Cmd) {
return PM3_ESOFT;
}
printEM4x05config(word);
printEM4x05config(card_type, word);
// if 4469 read EM4469_PROT_BLOCK
// if 4305 read 14,15
@ -1202,7 +1236,7 @@ int CmdEM4x05Info(const char *Cmd) {
return PM3_SUCCESS;
}
}
} else if (card_type == EM_4X69) {
} else if (card_type == EM_4369 || card_type == EM_4469) {
// read word 3 to see which is being used for the protection bits
if (em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
return PM3_ESOFT;
@ -1265,7 +1299,7 @@ int CmdEM4x05Chk(const char *Cmd) {
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", pwd);
found = true;
} else if (status != PM3_EFAILED) {
PrintAndLogEx(WARNING, "No answer from tag");
PrintAndLogEx(WARNING, "no answer from tag");
}
}
@ -1273,8 +1307,6 @@ int CmdEM4x05Chk(const char *Cmd) {
uint8_t *keyBlock = NULL;
if (found == false) {
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
uint32_t keycount = 0;
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
@ -1286,6 +1318,8 @@ int CmdEM4x05Chk(const char *Cmd) {
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
for (uint32_t c = 0; c < keycount; ++c) {
if (!session.pm3_present) {
@ -1309,7 +1343,7 @@ int CmdEM4x05Chk(const char *Cmd) {
found = true;
break;
} else if (status != PM3_EFAILED) {
PrintAndLogEx(WARNING, "No answer from tag");
PrintAndLogEx(WARNING, "no answer from tag");
}
}
}

View file

@ -55,7 +55,8 @@ typedef enum {
EM_UNKNOWN,
EM_4205,
EM_4305,
EM_4X69,
EM_4369,
EM_4469,
} em_tech_type_t;
int CmdLFEM4X05(const char *Cmd);

View file

@ -197,7 +197,7 @@ int demodNedap(bool verbose) {
badgeId = r1 * 10000 + r2 * 1000 + r3 * 100 + r4 * 10 + r5;
PrintAndLogEx(SUCCESS, "NEDAP - Card: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%03x") ", Raw: %s", badgeId, subtype, customerCode, sprint_hex(data, size / 8));
PrintAndLogEx(SUCCESS, "NEDAP - Card: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%03x") ", Raw: " _YELLOW_("%s"), badgeId, subtype, customerCode, sprint_hex_inrow(data, size / 8));
PrintAndLogEx(DEBUG, "Checksum (%s) 0x%04X", _GREEN_("ok"), checksum);
} else {

View file

@ -196,7 +196,7 @@ int demodPyramid(bool verbose) {
PrintAndLogEx(SUCCESS, "Pyramid - len: " _GREEN_("%d") " -unknown- Card: " _GREEN_("%d") ", Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo);
}
PrintAndLogEx(DEBUG, "DEBUG: Pyramid: checksum : 0x%02X - %02X - %s"
PrintAndLogEx(DEBUG, "DEBUG: Pyramid: checksum : 0x%02X - 0x%02X - %s"
, checksum
, checkCS
, (checksum == checkCS) ? _GREEN_("ok") : _RED_("fail")

View file

@ -3040,8 +3040,14 @@ static int CmdT55xxChkPwds(const char *Cmd) {
}
}
if (errors || cmdp == 0) return usage_t55xx_chk();
if (errors) return usage_t55xx_chk();
if (strlen(filename) == 0){
snprintf(filename, sizeof(filename), "t55xx_default_pwds");
use_pwd_file = true;
}
PrintAndLogEx(NORMAL, "");
/*
// block 7, page1 = false, usepwd = false, override = false, pwd = 00000000
if ( T55xxReadBlock(7, false, false, false, 0x00000000) == PM3_SUCCESS) {
@ -3064,7 +3070,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
timeout++;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 180) {
PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
PrintAndLogEx(WARNING, "\nno response from Proxmark3. Aborting...");
return PM3_ENODATA;
}
}
@ -3076,21 +3082,21 @@ static int CmdT55xxChkPwds(const char *Cmd) {
struct p *packet = (struct p *)resp.data.asBytes;
if (packet->found) {
PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
PrintAndLogEx(SUCCESS, "\nfound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, packet->candidate, downlink_mode)) {
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
} else {
PrintAndLogEx(WARNING, "Check pwd failed");
PrintAndLogEx(WARNING, "check pwd failed");
}
} else {
PrintAndLogEx(WARNING, "Check pwd failed");
PrintAndLogEx(WARNING, "check pwd failed");
}
} else {
PrintAndLogEx(WARNING, "Check pwd failed");
PrintAndLogEx(WARNING, "check pwd failed");
}
goto out;
}
@ -3098,7 +3104,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
// try calculated password
if (useCardPassword) {
PrintAndLogEx(INFO, "Testing %08"PRIX32" generated ", cardPassword);
PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", cardPassword);
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, cardPassword, dl_mode)) {
@ -3107,7 +3113,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
PrintAndLogEx(SUCCESS, "found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
dl_mode = 4; // Exit other downlink mode checks
}
@ -3116,22 +3122,24 @@ static int CmdT55xxChkPwds(const char *Cmd) {
}
}
if ((!found) && (use_pwd_file)) {
if ((found == false) && use_pwd_file) {
uint32_t keycount = 0;
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
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)
free(keyBlock);
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
for (uint32_t c = 0; c < keycount; ++c) {
if (!session.pm3_present) {
PrintAndLogEx(WARNING, "Device offline\n");
PrintAndLogEx(WARNING, "device offline\n");
free(keyBlock);
return PM3_ENODATA;
}
@ -3143,7 +3151,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
uint32_t curr_password = bytes_to_num(keyBlock + 4 * c, 4);
PrintAndLogEx(INFO, "Testing %08"PRIX32, curr_password);
PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password);
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password, dl_mode)) {
@ -3152,7 +3160,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
PrintAndLogEx(SUCCESS, "found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
dl_mode = 4; // Exit other downlink mode checks
c = keycount; // Exit loop
}
@ -3163,7 +3171,8 @@ static int CmdT55xxChkPwds(const char *Cmd) {
}
}
if (!found) PrintAndLogEx(WARNING, "Check pwd failed");
if (found == false)
PrintAndLogEx(WARNING, "check pwd failed");
free(keyBlock);

View file

@ -734,7 +734,8 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_
fflush(f);
fclose(f);
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")"--> 0xffffffffffff has been inserted for unknown keys.", fileName);
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s"), fileName);
PrintAndLogEx(INFO, " OBS! --> 0xFFFFFFFFFFFF <-- has been inserted for unknown keys.");
free(fileName);
return PM3_SUCCESS;
}

View file

@ -251,7 +251,7 @@ static void xor(const uint8_t *ivect, uint8_t *data, const size_t len) {
}
}
void cmac_generate_subkeys(desfirekey_t key) {
void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction) {
int kbs = key_block_size(key);
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
@ -261,7 +261,7 @@ void cmac_generate_subkeys(desfirekey_t key) {
uint8_t ivect[kbs];
memset(ivect, 0, kbs);
mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER);
mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, direction, MCO_ENCYPHER);
bool xor = false;
@ -306,6 +306,45 @@ void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t le
free(buffer);
}
// This function is almot like cmac(...). but with some key differences.
void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t len) {
int kbs = key_block_size(key);
int kbs2 = kbs * 2;
if (key == NULL || kbs == 0 || data == NULL || len < 1 || len > 31) {
return;
}
cmac_generate_subkeys(key, MCD_SEND);
uint8_t *buffer = malloc(kbs2);
uint8_t *ivect = malloc(kbs);
memset(ivect, 0, kbs);
buffer[0] = 0x01;
memcpy(&buffer[1], data, len++);
if (len != (kbs2)) {
buffer[len++] = 0x80;
while (len % kbs2) {
buffer[len++] = 0x00;
}
xor(key->cmac_sk2, buffer + kbs, kbs);
} else {
xor(key->cmac_sk1, buffer + kbs, kbs);
}
mbedtls_aes_context actx;
mbedtls_aes_init(&actx);
mbedtls_aes_setkey_enc(&actx, key->data, kbs * 8);
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, kbs2, ivect, buffer, buffer);
mbedtls_aes_free(&actx);
memcpy(key->data, buffer + kbs, kbs);
free(ivect);
free(buffer);
}
size_t key_block_size(const desfirekey_t key) {
if (key == NULL)
return 0;

View file

@ -126,9 +126,11 @@ size_t key_block_size(const desfirekey_t key);
size_t padded_data_length(const size_t nbytes, const size_t block_size);
size_t maced_data_length(const desfirekey_t key, const size_t nbytes);
size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings);
void cmac_generate_subkeys(desfirekey_t key);
void cmac_generate_subkeys(desfirekey_t key, MifareCryptoDirection direction);
void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
void mifare_kdf_an10922(const desfirekey_t key, const uint8_t *data, size_t dataLen);
void desfire_crc32(const uint8_t *data, const size_t len, uint8_t *crc);
void desfire_crc32_append(uint8_t *data, const size_t len);
void iso14443a_crc_append(uint8_t *data, size_t len);

View file

@ -372,3 +372,13 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
return PM3_SUCCESS;
}
int MADDFDecodeAndPrint(uint32_t short_aid) {
open_mad_file(&mad_known_aids, false);
char fmt[50];
sprintf(fmt, " MAD AID Function 0x%04X :" _YELLOW_("%s"), short_aid, "%s");
print_aid_description(mad_known_aids, short_aid, fmt, false);
close_mad_file(mad_known_aids);
return PM3_SUCCESS;
}

View file

@ -17,6 +17,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2);
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad);
int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2);
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose);
int MADDFDecodeAndPrint(uint32_t short_aid);
int MADCardHolderInfoDecode(uint8_t *data, size_t dataLen, bool verbose);
#endif // _MAD_H_

View file

@ -240,11 +240,13 @@ static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) {
if (packed->Length != 34) return false; // Wrong length? Stop here.
card->CardNumber = (packed->Bot >> 1) & 0xFFFF;
card->FacilityCode = ((packed->Mid & 1) << 15) | ((packed->Bot >> 17) & 0xFF);
card->FacilityCode = get_linear_field(packed, 1, 16);
card->CardNumber = get_linear_field(packed, 17, 16);
card->ParityValid =
((evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) == ((packed->Mid >> 1) & 1)) &&
((oddparity32(packed->Bot & 0x0001FFFE) & 1) == ((packed->Bot & 1)));
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
(get_bit_by_position(packed, 33) == oddparity32(get_linear_field(packed, 17, 16)));
return true;
}
@ -580,16 +582,135 @@ static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) {
return true;
}
static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFFFFFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 40; // Set number of bits
set_linear_field(packed, card->CardNumber, 1, 38);
return add_HID_header(packed);
}
static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 40) return false; // Wrong length? Stop here.
card->CardNumber = get_linear_field(packed, 1, 38);
return true;
}
static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x3FF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 34; // Set number of bits
set_linear_field(packed, card->CardNumber, 1, 16);
set_linear_field(packed, card->FacilityCode, 22, 11);
return add_HID_header(packed);
}
static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 34) return false; // Wrong length? Stop here.
card->CardNumber = get_linear_field(packed, 1, 16);
card->FacilityCode = get_linear_field(packed, 22, 11);
return true;
}
static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0x3FF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0x7) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 34; // Set number of bits
set_linear_field(packed, card->FacilityCode, 1, 13);
set_linear_field(packed, card->IssueLevel, 14, 3);
set_linear_field(packed, card->CardNumber, 17, 16);
return add_HID_header(packed);
}
static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 34) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 1, 13);
card->IssueLevel = get_linear_field(packed, 14, 3);
card->CardNumber = get_linear_field(packed, 17, 16);
return true;
}
static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed) {
memset(packed, 0, sizeof(wiegand_message_t));
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
if (card->CardNumber > 0xFFFFFF) return false; // Can't encode CN.
if (card->IssueLevel > 0) return false; // Not used in this format
if (card->OEM > 0) return false; // Not used in this format
packed->Length = 34; // Set number of bits
set_linear_field(packed, card->FacilityCode, 1, 8);
set_linear_field(packed, card->CardNumber, 9, 24);
set_bit_by_position(packed,
evenparity32(get_linear_field(packed, 1, 16))
, 0);
set_bit_by_position(packed,
oddparity32(get_linear_field(packed, 17, 16))
, 33);
return add_HID_header(packed);
}
static bool Unpack_bqt(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 34) return false; // Wrong length? Stop here.
card->FacilityCode = get_linear_field(packed, 1, 8);
card->CardNumber = get_linear_field(packed, 9, 24);
card->ParityValid =
(get_bit_by_position(packed, 0) == evenparity32(get_linear_field(packed, 1, 16))) &&
(get_bit_by_position(packed, 33) == oddparity32(get_linear_field(packed, 17, 16)));
return true;
}
static const cardformat_t FormatTable[] = {
{"H10301", Pack_H10301, Unpack_H10301, "HID H10301 26-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"Tecom27", Pack_Tecom27, Unpack_Tecom27, "Tecom 27-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"2804W", Pack_2804W, Unpack_2804W, "2804 Wiegand 28-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"ATSW30", Pack_ATSW30, Unpack_ATSW30, "ATS Wiegand 30-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"ADT31", Pack_ADT31, Unpack_ADT31, "HID ADT 31-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"Kastle", Pack_Kastle, Unpack_Kastle, "Kastle 32-bit", {1, 1, 1, 0, 1}}, // from @xilni; PR #23 on RfidResearchGroup/proxmark3
{"D10202", Pack_D10202, Unpack_D10202, "HID D10202 33-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"Optus34", Pack_Optus, Unpack_Optus, "Indala Optus 34-bit", {1, 1, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"Smartpass", Pack_Smartpass, Unpack_Smartpass, "Cardkey Smartpass 34-bit", {1, 1, 1, 0, 0}}, // from cardinfo.barkweb.com.au
{"BQT", Pack_bqt, Unpack_bqt, "BQT 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
{"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"C15001", Pack_C15001, Unpack_C15001, "HID KeyScan 36-bit", {1, 1, 0, 1, 1}}, // from Proxmark forums
{"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", {1, 1, 1, 0, 1}}, // from cardinfo.barkweb.com.au
@ -598,6 +719,7 @@ static const cardformat_t FormatTable[] = {
{"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", {1, 0, 0, 0, 1}}, // from Proxmark forums
{"H10304", Pack_H10304, Unpack_H10304, "HID H10304 37-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{"P10001", Pack_P10001, Unpack_P10001, "HID P10001 Honeywell 40-bit", {1, 1, 0, 1, 0}}, // from cardinfo.barkweb.com.au
{"Casi40", Pack_CasiRusco40, Unpack_CasiRusco40, "Casi-Rusco 40-bit", {1, 0, 0, 0, 0}}, // from cardinfo.barkweb.com.au
{"C1k48s", Pack_C1k48s, Unpack_C1k48s, "HID Corporate 1000 48-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
{NULL, NULL, NULL, NULL, {0, 0, 0, 0, 0}} // Must null terminate array
};

View file

@ -94,6 +94,11 @@ typedef enum {
MFDES_ALGO_AES = 4
} mifare_des_authalgo_t;
typedef enum {
MFDES_KDF_ALGO_NONE = 0,
MFDES_KDF_ALGO_AN10922 = 1,
} mifare_des_kdf_algo_t;
//-----------------------------------------------------------------------------
// "hf 14a sim x", "hf mf sim x" attacks
//-----------------------------------------------------------------------------

View file

@ -802,6 +802,9 @@ typedef struct {
// tearoff occured client/pm3: when a tearoff hook was called and a tearoff actually happened
#define PM3_ETEAROFF -23
// Got bad CRC client/pm3: error in transfer of data, crc mismatch.
#define PM3_ECRC -24
// No data pm3: no data available, no host frame available (not really an error)
#define PM3_ENODATA -98
// Quit program client: reserved, order to quit the program

View file

@ -566,6 +566,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define EM4x05_READ_AFTER_WRITE (1 << 22)
#define EM4x05_DISABLE_ALLOWED (1 << 23)
#define EM4x05_READER_TALK_FIRST (1 << 24)
#define EM4x05_INVERT (1 << 25)
#define EM4x05_PIGEON (1 << 26)
// FeliCa protocol

View file

@ -382,6 +382,10 @@ def selftests():
'samples': ["042A41CAE45380", "B2769F8DDB575AEA2A680ADCA8FFED4FAB81A1E9908E2B82FE0FABB697BBD9B23835C416970E75768F12902ACA491349E94E6589EAF4F508",
"045640CAE45380", "D34B53A8C2C100D700DEA1C4C0D0DE4409F3A418CD8D57C4F41F146E42AD9A55F014199ABBF5CA259C7799DB0AE20D5E77D4950AC7E95D33"],
'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A" },
{'name': "DESFire EV3",
'samples': ["04448BD2DB6B80", "5CBB5632795C8F15263FEFB095B51C7B541AFD914A1AE44EF6FB8AF605EDF13DBFEE6C3A2DB372245E671DFE0D42CB1F0D0B8FE67A89D2F6",
"04445DD2DB6B80", "166BFD9F9BFAA451172566101580DF9894F582C4A4E258C15037AD2F35A475CF1D7FB817618623A6569F991931AFB2766984E21A18512A6D"],
'pk': "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743" },
# TODO one more Mifare Plus EV1...
{'name': "Mifare Plus EV1",
'samples': ["042A2B221C5080", "BAC40CD88E9193C58ADA5055350C4F648EB5A7AEC4FCF9BD4CDD7B1C558DE5F59C6636F26286ED48622AAA2331D4DF1CEE23B57B94BDA631"],
@ -417,14 +421,14 @@ def selftests():
print("[OK]")
else:
succeeded = False
print("[FAIL]")
print("[FAIL], got %s" % pk.lower())
elif len(t['samples'])//2 == 1:
pks = [binascii.hexlify(pk).decode('utf8').lower() for pk in list(recovered)]
if t['pk'].lower() in pks:
print("[OK] (partial)")
else:
succeeded = False
print("[FAIL]")
print("[FAIL], got %s" % pks)
else:
succeeded = False
print("[FAIL]")