mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-30 19:40:37 -07:00
Merge branch 'master' into allin
update 201031
This commit is contained in:
commit
d977902fd8
52 changed files with 1959206 additions and 276 deletions
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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]);
|
||||
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]
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
++numofblocks;
|
||||
|
||||
for (uint8_t i = 0; i < numofblocks; i++) {
|
||||
|
||||
if (ReadSTBlock(i, mem + (i * 4)) == false) {
|
||||
isOK = PM3_ETIMEOUT;
|
||||
break;
|
||||
// 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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,52 +2283,56 @@ void MifareCIdent(bool is_mfc) {
|
|||
|
||||
ReaderTransmit(rats, sizeof(rats), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
// test for some MFC gen2
|
||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
|
||||
if (res ) {
|
||||
|
||||
// super card ident
|
||||
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
ReaderTransmit(super, sizeof(super), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 22) {
|
||||
isGen = MAGIC_SUPER;
|
||||
// test for some MFC gen2
|
||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
|
||||
|
||||
// super card ident
|
||||
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
ReaderTransmit(super, sizeof(super), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 22) {
|
||||
isGen = MAGIC_SUPER;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// 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) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for NTAG213 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
// test for Ultralight magic gen2
|
||||
if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for NTAG213 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||
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);
|
||||
}
|
||||
|
|
15892
client/dictionaries/extras/12_byte_most_common_password.dic
Normal file
15892
client/dictionaries/extras/12_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
15892
client/dictionaries/extras/12_byte_most_common_password_uppercase.dic
Normal file
15892
client/dictionaries/extras/12_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
29124
client/dictionaries/extras/12_byte_words.dic
Normal file
29124
client/dictionaries/extras/12_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
29124
client/dictionaries/extras/12_byte_words_uppercase.dic
Normal file
29124
client/dictionaries/extras/12_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
2765
client/dictionaries/extras/16_byte_most_common_password.dic
Normal file
2765
client/dictionaries/extras/16_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
5182
client/dictionaries/extras/16_byte_words.dic
Normal file
5182
client/dictionaries/extras/16_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
5182
client/dictionaries/extras/16_byte_words_uppercase.dic
Normal file
5182
client/dictionaries/extras/16_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
10000
client/dictionaries/extras/4_byte_ascii_numbers.dic
Normal file
10000
client/dictionaries/extras/4_byte_ascii_numbers.dic
Normal file
File diff suppressed because it is too large
Load diff
26830
client/dictionaries/extras/4_byte_most_common_password.dic
Normal file
26830
client/dictionaries/extras/4_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
26830
client/dictionaries/extras/4_byte_most_common_password_uppercase.dic
Normal file
26830
client/dictionaries/extras/4_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
7186
client/dictionaries/extras/4_byte_words.dic
Normal file
7186
client/dictionaries/extras/4_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
7186
client/dictionaries/extras/4_byte_words_uppercase.dic
Normal file
7186
client/dictionaries/extras/4_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
531441
client/dictionaries/extras/6_byte_ascii_numbers.dic
Normal file
531441
client/dictionaries/extras/6_byte_ascii_numbers.dic
Normal file
File diff suppressed because it is too large
Load diff
248824
client/dictionaries/extras/6_byte_most_common_password.dic
Normal file
248824
client/dictionaries/extras/6_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
248824
client/dictionaries/extras/6_byte_most_common_password_uppercase.dic
Normal file
248824
client/dictionaries/extras/6_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
15918
client/dictionaries/extras/6_byte_words.dic
Normal file
15918
client/dictionaries/extras/6_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
15918
client/dictionaries/extras/6_byte_words_uppercase.dic
Normal file
15918
client/dictionaries/extras/6_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
305084
client/dictionaries/extras/8_byte_most_common_password.dic
Normal file
305084
client/dictionaries/extras/8_byte_most_common_password.dic
Normal file
File diff suppressed because it is too large
Load diff
305084
client/dictionaries/extras/8_byte_most_common_password_uppercase.dic
Normal file
305084
client/dictionaries/extras/8_byte_most_common_password_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
51627
client/dictionaries/extras/8_byte_words.dic
Normal file
51627
client/dictionaries/extras/8_byte_words.dic
Normal file
File diff suppressed because it is too large
Load diff
51627
client/dictionaries/extras/8_byte_words_uppercase.dic
Normal file
51627
client/dictionaries/extras/8_byte_words_uppercase.dic
Normal file
File diff suppressed because it is too large
Load diff
79
client/dictionaries/extras/iclass_other.dic
Normal file
79
client/dictionaries/extras/iclass_other.dic
Normal 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
|
67
client/dictionaries/extras/readme.md
Normal file
67
client/dictionaries/extras/readme.md
Normal 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.
|
|
@ -653,7 +653,7 @@ C01FC822C6E5
|
|||
# More keys:
|
||||
8a19d40cf2b5
|
||||
ae8587108640
|
||||
135b88a94b8b, SafLock standalone door locks.
|
||||
135b88a94b8b # SafLock standalone door locks.
|
||||
#
|
||||
# Russian Troika card
|
||||
08B386463229
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
type |= MTCLASSIC;
|
||||
type |= MTPLUS;
|
||||
}
|
||||
|
||||
if ((sak & 0x09) == 0x09) {
|
||||
printTag("MIFARE Mini 0.3K / Mini CL2 0.3K");
|
||||
type |= MTMINI;
|
||||
}
|
||||
|
||||
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 ((sak & 0x02) != 0x02) {
|
||||
if ((sak & 0x19) == 0x19) {
|
||||
printTag("MIFARE Classic 2K");
|
||||
type |= MTCLASSIC;
|
||||
}
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
|
||||
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 |= 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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
type |= MTPLUS;
|
||||
} else {
|
||||
if ((atqa & 0x0040) == 0x0040) {
|
||||
printTag("MIFARE Classic 1K CL2");
|
||||
} else {
|
||||
printTag("MIFARE Classic 1K");
|
||||
}
|
||||
|
||||
type |= MTCLASSIC;
|
||||
}
|
||||
} 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 (atqa == 0x0304) {
|
||||
printTag("MIFARE NTAG424DNA (Random ID feature)");
|
||||
} 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 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;
|
||||
}
|
||||
|
||||
printTag("NTAG 4xx");
|
||||
type |= MTDESFIRE;
|
||||
}
|
||||
} else if ((sak & 0x04) == 0x04) {
|
||||
printTag("Any MIFARE CL1");
|
||||
type |= MTDESFIRE;
|
||||
} else {
|
||||
printTag("MIFARE Plus 2K/4K / Plus EV1 2K/4K");
|
||||
printTag("MIFARE Plus CL2 2K/4K / Plus CL2 EV1 2K/4K");
|
||||
type |= MTPLUS;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sak & 0x24) == 0x24) {
|
||||
if (atqa == 0x0344) {
|
||||
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
|
||||
type |= MTDESFIRE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sak & 0x28) == 0x28) {
|
||||
if (atqa == 0x0344) {
|
||||
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
|
||||
type |= MTDESFIRE;
|
||||
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();
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -18,13 +18,16 @@
|
|||
#include "cmdtrace.h"
|
||||
#include "emv/dump.h"
|
||||
#include "mifare/mifaredefault.h" // mifare default key array
|
||||
#include "cliparser.h" // argtable
|
||||
#include "cliparser.h" // argtable
|
||||
#include "hardnested_bf_core.h" // SetSIMDInstr
|
||||
#include "mifare/mad.h"
|
||||
#include "mifare/ndef.h"
|
||||
#include "protocols.h"
|
||||
#include "util_posix.h" // msclock
|
||||
#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"},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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);
|
||||
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf);
|
||||
PrintAndLogEx(INFO, " Delay: %u | %s", delay, cdelay);
|
||||
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"));
|
||||
PrintAndLogEx(INFO, " R.A.W.: %u | Read after write is %s", raw, raw ? "on" : "off");
|
||||
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");
|
||||
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s", pigeon, pigeon ? _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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue