mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
Merge branch 'master' into dev-bruteforce_em4x50
update
This commit is contained in:
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Add lf t55xx chk e <EM4100> option. Checks calculated password based on the EM4100 id from some white cloners forumla by paleopterix (@mwalker33)
|
||||
- Add lf t55xx sniff to allow extracting commands and passwords used be cloners. (@mwalker33)
|
||||
- Add options to `lf read`, `lf cmdread`, `lf sniff` for repeated acquisitions (@doegox)
|
||||
- Change options of `lf read` to match `lf cmdread`, this affects historical `d` and `s` options (@doegox)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
| Releases | Linux & OSX CI | Windows CI | Coverity | Contributors |
|
||||
| ------------------- |:-------------------:| -------------------:| -------------------:| -------------------:|
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.org/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|  |
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.com/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|  |
|
||||
|
||||
|
||||
|
||||
|
||||
+14
-14
@@ -1139,7 +1139,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
||||
/* Sends an APDU to the tag
|
||||
* TODO: check CRC and preamble
|
||||
*/
|
||||
uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen) {
|
||||
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen) {
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t message_frame[message_length + 4];
|
||||
@@ -1158,7 +1158,7 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r
|
||||
uint32_t eof_time = 0;
|
||||
CodeAndTransmit14443bAsReader(message_frame, sizeof(message_frame), &start_time, &eof_time);
|
||||
|
||||
// get response
|
||||
// Get response?
|
||||
if (response == NULL) {
|
||||
LED_A_OFF();
|
||||
return 0;
|
||||
@@ -1170,13 +1170,13 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r
|
||||
|
||||
if (retlen < 3) {
|
||||
LED_A_OFF();
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// VALIDATE CRC
|
||||
if (!check_crc(CRC_14443_B, response, retlen)) {
|
||||
if (DBGLEVEL > DBG_DEBUG) DbpString("CRC fail");
|
||||
return 0;
|
||||
return -2;
|
||||
}
|
||||
|
||||
return retlen;
|
||||
@@ -1185,7 +1185,7 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r
|
||||
/**
|
||||
* SRx Initialise.
|
||||
*/
|
||||
static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
// INITIATE command: wake up the tag using the INITIATE
|
||||
static const uint8_t init_srx[] = { ISO14443B_INITIATE, 0x00, 0x97, 0x5b };
|
||||
uint8_t r_init[3] = {0x0};
|
||||
@@ -1201,7 +1201,7 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen <= 0)
|
||||
return 2;
|
||||
return -1;
|
||||
|
||||
// Randomly generated Chip ID
|
||||
if (card) {
|
||||
@@ -1222,17 +1222,17 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 3) {
|
||||
return 2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check the CRC of the answer:
|
||||
if (!check_crc(CRC_14443_B, r_select, retlen)) {
|
||||
return 3;
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Check response from the tag: should be the same UID as the command we just sent:
|
||||
if (select_srx[1] != r_select[0]) {
|
||||
return 1;
|
||||
return -3;
|
||||
}
|
||||
|
||||
// First get the tag's UID:
|
||||
@@ -1248,12 +1248,12 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen != 10) {
|
||||
return 2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The check the CRC of the answer
|
||||
if (!check_crc(CRC_14443_B, r_papid, retlen)) {
|
||||
return 3;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (card) {
|
||||
@@ -1437,11 +1437,11 @@ void ReadSTMemoryIso14443b(uint16_t numofblocks) {
|
||||
uint8_t *mem = BigBuf_malloc((numofblocks + 1) * 4);
|
||||
|
||||
iso14b_card_select_t card;
|
||||
uint8_t res = iso14443b_select_srx_card(&card);
|
||||
|
||||
int res = iso14443b_select_srx_card(&card);
|
||||
int isOK = PM3_SUCCESS;
|
||||
|
||||
// 0: OK 2: attrib fail, 3:crc fail,
|
||||
if (res > 0) {
|
||||
if (res < 1) {
|
||||
isOK = PM3_ETIMEOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
+2
-2
@@ -27,10 +27,10 @@
|
||||
#endif
|
||||
|
||||
void iso14443b_setup(void);
|
||||
uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen);
|
||||
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen);
|
||||
|
||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||
uint8_t iso14443b_select_card_srx(iso14b_card_select_t *card);
|
||||
int iso14443b_select_card_srx(iso14b_card_select_t *card);
|
||||
|
||||
void SimulateIso14443bTag(uint32_t pupi);
|
||||
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
|
||||
|
||||
@@ -57,6 +57,9 @@ f1d83f964314 # RKF RejskortDanmark KeyB
|
||||
#
|
||||
4b0b20107ccb # TNP3xxx
|
||||
#
|
||||
# Access control system
|
||||
605F5E5D5C5B
|
||||
#
|
||||
# more Keys from mfc_default_keys.lua
|
||||
000000000001
|
||||
000000000002
|
||||
@@ -1199,4 +1202,4 @@ FEE2A3FBC5B6
|
||||
# toru ent
|
||||
# taurus avm
|
||||
#
|
||||
005078565703
|
||||
005078565703
|
||||
|
||||
@@ -1638,6 +1638,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
bool isMifareDESFire = false;
|
||||
bool isMifarePlus = false;
|
||||
bool isMifareUltralight = false;
|
||||
bool isST = false;
|
||||
int nxptype = MTNONE;
|
||||
|
||||
if (card.uidlen <= 4) {
|
||||
@@ -1657,6 +1658,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
|
||||
|
||||
switch (card.uid[0]) {
|
||||
case 0x02: // ST
|
||||
isST = true;
|
||||
break;
|
||||
case 0x04: // NXP
|
||||
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
|
||||
|
||||
@@ -1679,9 +1683,13 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
} else if ((card.uid[1] & 0xF0) == 0x70) {
|
||||
printTag("my-d(tm) move lean SLE 66R01L");
|
||||
}
|
||||
isMifareUltralight = true;
|
||||
isMifareClassic = false;
|
||||
|
||||
if (card.sak == 0x88) {
|
||||
printTag("Infineon MIFARE CLASSIC 1K");
|
||||
isMifareUltralight = false;
|
||||
isMifareClassic = true;
|
||||
}
|
||||
getTagLabel(card.uid[0], card.uid[1]);
|
||||
break;
|
||||
@@ -2018,6 +2026,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
if (isMifareDESFire && isMagic == 0)
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
|
||||
|
||||
if (isST)
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`"));
|
||||
|
||||
DropField();
|
||||
return select_status;
|
||||
}
|
||||
|
||||
+386
-214
File diff suppressed because it is too large
Load Diff
+19
-10
@@ -321,6 +321,7 @@ typedef enum {
|
||||
DESFIRE_EV3,
|
||||
DESFIRE_LIGHT,
|
||||
PLUS_EV1,
|
||||
NTAG413DNA,
|
||||
} nxp_cardtype_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -347,9 +348,9 @@ static char *getCardSizeStr(uint8_t fsize) {
|
||||
|
||||
// is LSB set?
|
||||
if (fsize & 1)
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d - %d bytes") ")", fsize, usize, lsize);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d bytes") ")", fsize, lsize);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -377,18 +378,22 @@ static char *getVersionStr(uint8_t major, uint8_t minor) {
|
||||
char *retStr = buf;
|
||||
|
||||
if (major == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor);
|
||||
else if (major == 0x01 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor);
|
||||
else if (major == 0x12 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor);
|
||||
else if (major == 0x33 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor);
|
||||
else if (major == 0x30 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor);
|
||||
else if (major == 0x10 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("NTAG413DNA") ")", major, minor);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor);
|
||||
return buf;
|
||||
|
||||
//04 01 01 01 00 1A 05
|
||||
}
|
||||
|
||||
static int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
|
||||
@@ -648,9 +653,10 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
|
||||
return DESFIRE_EV3;
|
||||
if (major == 0x30 && minor == 0x00)
|
||||
return DESFIRE_LIGHT;
|
||||
if (major == 0x11 && minor == 0x00)
|
||||
if (major == 0x11 && minor == 0x00)
|
||||
return PLUS_EV1;
|
||||
|
||||
if (major == 0x10 && minor == 0x00)
|
||||
return NTAG413DNA;
|
||||
return DESFIRE_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -3318,7 +3324,10 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||
if (major == 0 && minor == 2)
|
||||
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
|
||||
|
||||
if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3) {
|
||||
if (cardtype == DESFIRE_EV2 ||
|
||||
cardtype == DESFIRE_LIGHT ||
|
||||
cardtype == DESFIRE_EV3 ||
|
||||
cardtype == NTAG413DNA) {
|
||||
// Signature originality check
|
||||
uint8_t signature[56] = {0};
|
||||
size_t signature_len = 0;
|
||||
|
||||
+20
-7
@@ -272,14 +272,16 @@ uint32_t UL_TYPES_ARRAY[] = {
|
||||
UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG,
|
||||
NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216,
|
||||
MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL,
|
||||
UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT
|
||||
UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT,
|
||||
NTAG_213_C
|
||||
};
|
||||
|
||||
uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
|
||||
MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203,
|
||||
MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, MAX_NTAG_215, MAX_NTAG_216,
|
||||
MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS,
|
||||
MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K, MAX_NTAG_213
|
||||
MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K, MAX_NTAG_213,
|
||||
MAX_NTAG_213
|
||||
};
|
||||
|
||||
//------------------------------------
|
||||
@@ -685,6 +687,8 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, "");
|
||||
else if (tagtype & NTAG_213_F)
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, "");
|
||||
else if (tagtype & NTAG_213_C)
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces, "");
|
||||
else if (tagtype & NTAG_213_TT)
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, "");
|
||||
else if (tagtype & NTAG_215)
|
||||
@@ -1112,6 +1116,7 @@ uint32_t GetHF14AMfU_Type(void) {
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = NTAG_210; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = NTAG_215; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213_F; break; }
|
||||
@@ -1338,7 +1343,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
}
|
||||
|
||||
// NTAG counters?
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
if (ntag_print_counter()) {
|
||||
// failed - re-select
|
||||
if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
|
||||
@@ -1346,7 +1351,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
}
|
||||
|
||||
// Read signature
|
||||
if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) {
|
||||
if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) {
|
||||
uint8_t ulev1_signature[32] = {0x00};
|
||||
status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature));
|
||||
if (status == -1) {
|
||||
@@ -1461,12 +1466,20 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
if (len < 1) PrintAndLogEx(WARNING, _YELLOW_("password not known"));
|
||||
if (len < 1) {
|
||||
PrintAndLogEx(WARNING, _YELLOW_("password not known"));
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions");
|
||||
}
|
||||
}
|
||||
out:
|
||||
DropField();
|
||||
if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info");
|
||||
if (locked) {
|
||||
PrintAndLogEx(INFO, "\nTag appears to be locked, try using the key to get more info");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
@@ -2032,7 +2045,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
uint8_t n = 0;
|
||||
|
||||
// NTAG has 1 counter, at 0x02
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
n = 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef enum TAGTYPE_UL {
|
||||
UL_EV1 = 0x1000000,
|
||||
UL_NANO_40 = 0x2000000,
|
||||
NTAG_213_TT = 0x4000000,
|
||||
NTAG_213_C = 0x8000000,
|
||||
UL_MAGIC = UL | MAGIC,
|
||||
UL_C_MAGIC = UL_C | MAGIC,
|
||||
UL_ERROR = 0xFFFFFF,
|
||||
|
||||
+13
-11
@@ -715,18 +715,20 @@ void pm3_version(bool verbose, bool oneliner) {
|
||||
PrintAndLogEx(NORMAL, "%s", temp);
|
||||
PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH);
|
||||
|
||||
if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) {
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3 RDV4") " ]");
|
||||
PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3 RDV4 Extras") " ]");
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
|
||||
if (IfPm3FpcUsartDevFromUsb()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present"));
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
|
||||
if (IfPm3Rdv4Fw() == false ){
|
||||
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3OTHER"));
|
||||
if (IfPm3FpcUsartHost()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", _GREEN_("present"));
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3RDV4"));
|
||||
PrintAndLogEx(NORMAL, " external flash...................%s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " smartcard reader.................%s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
}
|
||||
if (IfPm3FpcUsartDevFromUsb()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for developer..........%s", _GREEN_("present"));
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
+39
-3
@@ -29,6 +29,7 @@
|
||||
#include "fileutils.h" // loadDictionary
|
||||
#include "util_posix.h"
|
||||
#include "cmdlf.h" // for lf sniff
|
||||
#include "generator.h"
|
||||
|
||||
// Some defines for readability
|
||||
#define T55XX_DLMODE_FIXED 0 // Default Mode
|
||||
@@ -254,16 +255,18 @@ static int usage_t55xx_chk(void) {
|
||||
PrintAndLogEx(NORMAL, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
PrintAndLogEx(NORMAL, _RED_("WARNING:") " this may brick non-password protected chips!");
|
||||
PrintAndLogEx(NORMAL, "Try to reading block 7 before\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx chk [h] [m] [r <mode>] [f <*.dic>]");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx chk [h] [m] [r <mode>] [f <*.dic>] [e <em4100 id>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " m - use dictionary from flashmemory\n");
|
||||
print_usage_t55xx_downloadlink(T55XX_DLMODE_ALL, T55XX_DLMODE_ALL);
|
||||
PrintAndLogEx(NORMAL, " f <*.dic> - loads a default keys dictionary file <*.dic>");
|
||||
PrintAndLogEx(NORMAL, " e <EM4100> - will try the calculated password from some cloners based on EM4100 ID");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk m"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk f t55xx_default_pwds"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk e aa11223344"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
@@ -3003,6 +3006,9 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
int dl_mode; // to try each downlink mode for each password
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
bool useCardPassword = false;
|
||||
uint32_t cardPassword = 0x00;
|
||||
uint64_t cardID = 0x00;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
@@ -3028,6 +3034,14 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
use_pwd_file = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'e':
|
||||
// White cloner password based on EM4100 ID
|
||||
useCardPassword = true;
|
||||
cardID = param_get64ex(Cmd,cmdp + 1,0,16);
|
||||
uint32_t card32Bit = cardID & 0xFFFFFFFF;
|
||||
cardPassword = lf_t55xx_white_pwdgen (card32Bit);
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
@@ -3090,7 +3104,28 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (use_pwd_file) {
|
||||
// try calculated password
|
||||
if (useCardPassword) {
|
||||
|
||||
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)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
|
||||
dl_mode = 4; // Exit other downlink mode checks
|
||||
}
|
||||
|
||||
if (!try_all_dl_modes) // Exit loop if not trying all downlink modes
|
||||
dl_mode = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!found) && (use_pwd_file)) {
|
||||
uint32_t keycount = 0;
|
||||
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
@@ -3135,9 +3170,10 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
dl_mode = 4;
|
||||
}
|
||||
}
|
||||
if (!found) PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
}
|
||||
|
||||
if (!found) PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
|
||||
free(keyBlock);
|
||||
|
||||
out:
|
||||
|
||||
@@ -26,6 +26,12 @@ bool IfPm3Present(void) {
|
||||
return session.pm3_present;
|
||||
}
|
||||
|
||||
bool IfPm3Rdv4Fw(void) {
|
||||
if (!IfPm3Present())
|
||||
return false;
|
||||
return (pm3_capabilities.compiled_with_flash) || (pm3_capabilities.compiled_with_smartcard);
|
||||
}
|
||||
|
||||
bool IfPm3Flash(void) {
|
||||
if (!IfPm3Present())
|
||||
return false;
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct command_s {
|
||||
// helpers for command_t IsAvailable
|
||||
bool AlwaysAvailable(void);
|
||||
bool IfPm3Present(void);
|
||||
bool IfPm3Rdv4Fw(void);
|
||||
bool IfPm3Flash(void);
|
||||
bool IfPm3Smartcard(void);
|
||||
bool IfPm3FpcUsart(void);
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include "flash.h"
|
||||
#include "preferences.h"
|
||||
|
||||
#define BANNERMSG1 ""
|
||||
#define BANNERMSG2 " :snowflake: bleeding edge :coffee:"
|
||||
#define BANNERMSG1 " Iceman :coffee:"
|
||||
#define BANNERMSG2 " :snowflake: bleeding edge"
|
||||
#define BANNERMSG3 " https://github.com/rfidresearchgroup/proxmark3/"
|
||||
|
||||
typedef enum LogoMode { UTF8, ANSI, ASCII } LogoMode;
|
||||
|
||||
+1
-1
@@ -479,7 +479,7 @@ int generator_selftest(void) {
|
||||
|
||||
|
||||
uint32_t lf_id = lf_t55xx_white_pwdgen(0x00000080);
|
||||
success = (lf_id = 0x00018383);
|
||||
success = (lf_id == 0x00018383);
|
||||
if (success)
|
||||
testresult++;
|
||||
PrintAndLogEx(success ? SUCCESS : WARNING, "ID | 0x00000080 | %08"PRIx32 " - %s", lf_id, success ? "OK" : "->00018383<--");
|
||||
|
||||
@@ -227,6 +227,7 @@ while true; do
|
||||
if ! CheckExecute "findbits test" "tools/findbits.py 73 0110010101110011" "Match at bit 9: 011001010"; then break; fi
|
||||
if ! CheckExecute "findbits_test test" "tools/findbits_test.py 2>&1" "OK"; then break; fi
|
||||
if ! CheckExecute "pm3_eml_mfd test" "tools/pm3_eml_mfd_test.py 2>&1" "OK"; then break; fi
|
||||
if ! CheckExecute "recover_pk test" "tools/recover_pk.py selftests 2>&1" "Tests:.*\[OK\]"; then break; fi
|
||||
fi
|
||||
if $TESTALL || $TESTBOOTROM; then
|
||||
echo -e "\n${C_BLUE}Testing bootrom:${C_NC}"
|
||||
|
||||
+388
-21
@@ -1,26 +1,318 @@
|
||||
#!/usr/bin/env python3
|
||||
# MIT License
|
||||
# Copyright (c) 2020 @doegox
|
||||
|
||||
# @doegox -- 2020
|
||||
|
||||
import sslcrypto
|
||||
import binascii
|
||||
import sys
|
||||
|
||||
debug = False
|
||||
|
||||
#######################################################################
|
||||
# Using external sslcrypto library:
|
||||
# import sslcrypto
|
||||
# ... sslcrypto.ecc.get_curve()
|
||||
# But to get this script autonomous, i.e. for CI, we embedded the
|
||||
# code snippets we needed:
|
||||
#######################################################################
|
||||
# code snippets from JacobianCurve:
|
||||
# This code is public domain. Everyone has the right to do whatever they want with it for any purpose.
|
||||
# Copyright (c) 2013 Vitalik Buterin
|
||||
|
||||
class JacobianCurve:
|
||||
def __init__(self, p, n, a, b, g):
|
||||
self.p = p
|
||||
self.n = n
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.g = g
|
||||
self.n_length = len(bin(self.n).replace("0b", ""))
|
||||
|
||||
|
||||
def to_jacobian(self, p):
|
||||
return p[0], p[1], 1
|
||||
|
||||
|
||||
def jacobian_double(self, p):
|
||||
if not p[1]:
|
||||
return 0, 0, 0
|
||||
ysq = (p[1] ** 2) % self.p
|
||||
s = (4 * p[0] * ysq) % self.p
|
||||
m = (3 * p[0] ** 2 + self.a * p[2] ** 4) % self.p
|
||||
nx = (m ** 2 - 2 * s) % self.p
|
||||
ny = (m * (s - nx) - 8 * ysq ** 2) % self.p
|
||||
nz = (2 * p[1] * p[2]) % self.p
|
||||
return nx, ny, nz
|
||||
|
||||
|
||||
def jacobian_add(self, p, q):
|
||||
if not p[1]:
|
||||
return q
|
||||
if not q[1]:
|
||||
return p
|
||||
u1 = (p[0] * q[2] ** 2) % self.p
|
||||
u2 = (q[0] * p[2] ** 2) % self.p
|
||||
s1 = (p[1] * q[2] ** 3) % self.p
|
||||
s2 = (q[1] * p[2] ** 3) % self.p
|
||||
if u1 == u2:
|
||||
if s1 != s2:
|
||||
return (0, 0, 1)
|
||||
return self.jacobian_double(p)
|
||||
h = u2 - u1
|
||||
r = s2 - s1
|
||||
h2 = (h * h) % self.p
|
||||
h3 = (h * h2) % self.p
|
||||
u1h2 = (u1 * h2) % self.p
|
||||
nx = (r ** 2 - h3 - 2 * u1h2) % self.p
|
||||
ny = (r * (u1h2 - nx) - s1 * h3) % self.p
|
||||
nz = (h * p[2] * q[2]) % self.p
|
||||
return (nx, ny, nz)
|
||||
|
||||
|
||||
def from_jacobian(self, p):
|
||||
z = inverse(p[2], self.p)
|
||||
return (p[0] * z ** 2) % self.p, (p[1] * z ** 3) % self.p
|
||||
|
||||
|
||||
def jacobian_shamir(self, a, n, b, m):
|
||||
ab = self.jacobian_add(a, b)
|
||||
if n < 0 or n >= self.n:
|
||||
n %= self.n
|
||||
if m < 0 or m >= self.n:
|
||||
m %= self.n
|
||||
res = 0, 0, 1 # point on infinity
|
||||
for i in range(self.n_length - 1, -1, -1):
|
||||
res = self.jacobian_double(res)
|
||||
has_n = n & (1 << i)
|
||||
has_m = m & (1 << i)
|
||||
if has_n:
|
||||
if has_m == 0:
|
||||
res = self.jacobian_add(res, a)
|
||||
if has_m != 0:
|
||||
res = self.jacobian_add(res, ab)
|
||||
else:
|
||||
if has_m == 0:
|
||||
res = self.jacobian_add(res, (0, 0, 1)) # Try not to leak
|
||||
if has_m != 0:
|
||||
res = self.jacobian_add(res, b)
|
||||
return res
|
||||
|
||||
def fast_shamir(self, a, n, b, m):
|
||||
return self.from_jacobian(self.jacobian_shamir(self.to_jacobian(a), n, self.to_jacobian(b), m))
|
||||
|
||||
#######################################################################
|
||||
# code snippets from sslcrypto
|
||||
# MIT License
|
||||
# Copyright (c) 2019 Ivan Machugovskiy
|
||||
|
||||
import hmac
|
||||
import os
|
||||
import hashlib
|
||||
import struct
|
||||
|
||||
def int_to_bytes(raw, length):
|
||||
data = []
|
||||
for _ in range(length):
|
||||
data.append(raw % 256)
|
||||
raw //= 256
|
||||
return bytes(data[::-1])
|
||||
|
||||
|
||||
def bytes_to_int(data):
|
||||
raw = 0
|
||||
for byte in data:
|
||||
raw = raw * 256 + byte
|
||||
return raw
|
||||
|
||||
def legendre(a, p):
|
||||
res = pow(a, (p - 1) // 2, p)
|
||||
if res == p - 1:
|
||||
return -1
|
||||
else:
|
||||
return res
|
||||
|
||||
def inverse(a, n):
|
||||
if a == 0:
|
||||
return 0
|
||||
lm, hm = 1, 0
|
||||
low, high = a % n, n
|
||||
while low > 1:
|
||||
r = high // low
|
||||
nm, new = hm - lm * r, high - low * r
|
||||
lm, low, hm, high = nm, new, lm, low
|
||||
return lm % n
|
||||
|
||||
def square_root_mod_prime(n, p):
|
||||
if n == 0:
|
||||
return 0
|
||||
if p == 2:
|
||||
return n # We should never get here but it might be useful
|
||||
if legendre(n, p) != 1:
|
||||
raise ValueError("No square root")
|
||||
# Optimizations
|
||||
if p % 4 == 3:
|
||||
return pow(n, (p + 1) // 4, p)
|
||||
# 1. By factoring out powers of 2, find Q and S such that p - 1 =
|
||||
# Q * 2 ** S with Q odd
|
||||
q = p - 1
|
||||
s = 0
|
||||
while q % 2 == 0:
|
||||
q //= 2
|
||||
s += 1
|
||||
# 2. Search for z in Z/pZ which is a quadratic non-residue
|
||||
z = 1
|
||||
while legendre(z, p) != -1:
|
||||
z += 1
|
||||
m, c, t, r = s, pow(z, q, p), pow(n, q, p), pow(n, (q + 1) // 2, p)
|
||||
while True:
|
||||
if t == 0:
|
||||
return 0
|
||||
elif t == 1:
|
||||
return r
|
||||
# Use repeated squaring to find the least i, 0 < i < M, such
|
||||
# that t ** (2 ** i) = 1
|
||||
t_sq = t
|
||||
i = 0
|
||||
for i in range(1, m):
|
||||
t_sq = t_sq * t_sq % p
|
||||
if t_sq == 1:
|
||||
break
|
||||
else:
|
||||
raise ValueError("Should never get here")
|
||||
# Let b = c ** (2 ** (m - i - 1))
|
||||
b = pow(c, 2 ** (m - i - 1), p)
|
||||
m = i
|
||||
c = b * b % p
|
||||
t = t * b * b % p
|
||||
r = r * b % p
|
||||
return r
|
||||
|
||||
# name: (nid, p, n, a, b, (Gx, Gy)),
|
||||
CURVES = {
|
||||
"secp128r1": (
|
||||
706,
|
||||
0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFE0000000075A30D1B9038A115,
|
||||
0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC,
|
||||
0xE87579C11079F43DD824993C2CEE5ED3,
|
||||
(
|
||||
0x161FF7528B899B2D0C28607CA52C5B86,
|
||||
0xCF5AC8395BAFEB13C02DA292DDED7A83
|
||||
)
|
||||
),
|
||||
"secp224r1": (
|
||||
713,
|
||||
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001,
|
||||
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D,
|
||||
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE,
|
||||
0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4,
|
||||
(
|
||||
0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21,
|
||||
0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
def get_curve(name):
|
||||
if name not in CURVES:
|
||||
raise ValueError("Unknown curve {}".format(name))
|
||||
nid, p, n, a, b, g = CURVES[name]
|
||||
params = {"p": p, "n": n, "a": a, "b": b, "g": g}
|
||||
return EllipticCurve(nid, p, n, a, b, g)
|
||||
|
||||
class EllipticCurve:
|
||||
def __init__(self, nid, p, n, a, b, g):
|
||||
self.p, self.n, self.a, self.b, self.g = p, n, a, b, g
|
||||
self.jacobian = JacobianCurve(self.p, self.n, self.a, self.b, self.g)
|
||||
self.public_key_length = (len(bin(p).replace("0b", "")) + 7) // 8
|
||||
self.order_bitlength = len(bin(n).replace("0b", ""))
|
||||
|
||||
|
||||
def _int_to_bytes(self, raw, len=None):
|
||||
return int_to_bytes(raw, len or self.public_key_length)
|
||||
|
||||
|
||||
def _subject_to_int(self, subject):
|
||||
return bytes_to_int(subject[:(self.order_bitlength + 7) // 8])
|
||||
|
||||
|
||||
def recover(self, signature, data, hash="sha256"):
|
||||
# Sanity check: is this signature recoverable?
|
||||
if len(signature) != 1 + 2 * self.public_key_length:
|
||||
raise ValueError("Cannot recover an unrecoverable signature")
|
||||
subject = self._digest(data, hash)
|
||||
z = self._subject_to_int(subject)
|
||||
|
||||
recid = signature[0] - 27 if signature[0] < 31 else signature[0] - 31
|
||||
r = bytes_to_int(signature[1:self.public_key_length + 1])
|
||||
s = bytes_to_int(signature[self.public_key_length + 1:])
|
||||
|
||||
# Verify bounds
|
||||
if not 0 <= recid < 2 * (self.p // self.n + 1):
|
||||
raise ValueError("Invalid recovery ID")
|
||||
if r >= self.n:
|
||||
raise ValueError("r is out of bounds")
|
||||
if s >= self.n:
|
||||
raise ValueError("s is out of bounds")
|
||||
|
||||
rinv = inverse(r, self.n)
|
||||
u1 = (-z * rinv) % self.n
|
||||
u2 = (s * rinv) % self.n
|
||||
|
||||
# Recover R
|
||||
rx = r + (recid // 2) * self.n
|
||||
if rx >= self.p:
|
||||
raise ValueError("Rx is out of bounds")
|
||||
|
||||
# Almost copied from decompress_point
|
||||
ry_square = (pow(rx, 3, self.p) + self.a * rx + self.b) % self.p
|
||||
try:
|
||||
ry = square_root_mod_prime(ry_square, self.p)
|
||||
except Exception:
|
||||
raise ValueError("Invalid recovered public key") from None
|
||||
|
||||
# Ensure the point is correct
|
||||
if ry % 2 != recid % 2:
|
||||
# Fix Ry sign
|
||||
ry = self.p - ry
|
||||
|
||||
x, y = self.jacobian.fast_shamir(self.g, u1, (rx, ry), u2)
|
||||
x, y = self._int_to_bytes(x), self._int_to_bytes(y)
|
||||
|
||||
is_compressed = signature[0] >= 31
|
||||
if is_compressed:
|
||||
return bytes([0x02 + (y[-1] % 2)]) + x
|
||||
else:
|
||||
return bytes([0x04]) + x + y
|
||||
|
||||
def _digest(self, data, hash):
|
||||
if hash is None:
|
||||
return data
|
||||
elif callable(hash):
|
||||
return hash(data)
|
||||
elif hash == "sha1":
|
||||
return hashlib.sha1(data).digest()
|
||||
elif hash == "sha256":
|
||||
return hashlib.sha256(data).digest()
|
||||
elif hash == "sha512":
|
||||
return hashlib.sha512(data).digest()
|
||||
else:
|
||||
raise ValueError("Unknown hash/derivation method")
|
||||
|
||||
#######################################################################
|
||||
|
||||
def recover(data, signature, alghash=None):
|
||||
recovered = set()
|
||||
if len(signature) == 32:
|
||||
curve = sslcrypto.ecc.get_curve("secp128r1")
|
||||
curve = get_curve("secp128r1")
|
||||
recoverable = False
|
||||
elif len(signature) == 33:
|
||||
curve = sslcrypto.ecc.get_curve("secp128r1")
|
||||
curve = get_curve("secp128r1")
|
||||
recoverable = True
|
||||
elif len(signature) == 56:
|
||||
curve = sslcrypto.ecc.get_curve("secp224r1")
|
||||
curve = get_curve("secp224r1")
|
||||
recoverable = False
|
||||
elif len(signature) == 57:
|
||||
curve = sslcrypto.ecc.get_curve("secp224r1")
|
||||
curve = get_curve("secp224r1")
|
||||
recoverable = True
|
||||
else:
|
||||
print("Unsupported signature size %i" % len(signature))
|
||||
@@ -67,18 +359,93 @@ def recover_multiple(uids, sigs, alghash=None):
|
||||
recovered &= recovered_tmp
|
||||
return recovered
|
||||
|
||||
if len(sys.argv) < 3 or len(sys.argv) % 2 == 0:
|
||||
print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[0])
|
||||
print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0])
|
||||
exit(1)
|
||||
def selftests():
|
||||
tests = [
|
||||
{'name': "Mifare Ultralight EV1",
|
||||
'samples': ["04C1285A373080", "CEA2EB0B3C95D0844A95B824A7553703B3702378033BF0987899DB70151A19E7",
|
||||
"04C2285A373080", "A561506723D422D29ED9F93E60D20B9ED1E05CC1BF81DA19FE500CA0B81CC0ED"],
|
||||
'pk': "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8" },
|
||||
{'name': "NTAG21x",
|
||||
'samples': ["04E10CDA993C80", "8B76052EE42F5567BEB53238B3E3F9950707C0DCC956B5C5EFCFDB709B2D82B3",
|
||||
"04DB0BDA993C80", "6048EFD9417CD10F6B7F1818D471A7FE5B46868D2EABDC6307A1E0AAE139D8D0"],
|
||||
'pk': "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61" },
|
||||
{'name': "Mifare Classic EV1",
|
||||
'samples': ["0433619AB35780", "B9FAE369EC21C980650D87ED9AE9B1610E859131B4B8699C647548AB68D249BB",
|
||||
"524374E2", "F8758CE30A58553A9985C458FB9C7D340FCFB04847B928A0667939272BC58B5E",
|
||||
"53424B8A", "B4F533E8C06C021E242EFE8558C1672ED7022E5AE4E7AA2D46113B0AB6928AFC"],
|
||||
'pk': "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF" },
|
||||
{'name': "DESFire Light",
|
||||
'samples': ["0439556ACB6480", "D5BD0978106E1E38B513642335966AB21E9F950DCFCFAB45FF13D0DC3CA4C2AE7E0D671DF1240937D040DAC4601C5F66ED62C546EE03ED08",
|
||||
"043B156ACB6480", "76B46932BF2FCF4931A24C755F5CB1686B914F1856177686B864BDAD58EFA6A7493E5C2232F3ADDAA434EA4647BFD1D385BDA6115E77D74C"],
|
||||
'pk': "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D" },
|
||||
{'name': "DESFire EV2",
|
||||
'samples': ["042A41CAE45380", "B2769F8DDB575AEA2A680ADCA8FFED4FAB81A1E9908E2B82FE0FABB697BBD9B23835C416970E75768F12902ACA491349E94E6589EAF4F508",
|
||||
"045640CAE45380", "D34B53A8C2C100D700DEA1C4C0D0DE4409F3A418CD8D57C4F41F146E42AD9A55F014199ABBF5CA259C7799DB0AE20D5E77D4950AC7E95D33"],
|
||||
'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A" },
|
||||
# TODO one more Mifare Plus EV1...
|
||||
{'name': "Mifare Plus EV1",
|
||||
'samples': ["042A2B221C5080", "BAC40CD88E9193C58ADA5055350C4F648EB5A7AEC4FCF9BD4CDD7B1C558DE5F59C6636F26286ED48622AAA2331D4DF1CEE23B57B94BDA631"],
|
||||
'pk': "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E" },
|
||||
{'name': "NTAG413DNA",
|
||||
'samples': ["042468222F5C80", "B9211E320F321BD1D0E158E10FF15109B389638BAE15D9909D7725BF1250ED236D66F1AF75C94D60330E4E92535F5E6997675281A5687173",
|
||||
"042938222F5C80", "18B642797D1FD71806146A7A6EC778D3FDD04F39C4A3B36A592BD1A114DC44E5528380FA766C0B7EA32B284AFBE84300B620369F0686D8CC"],
|
||||
'pk': "04bb5d514f7050025c7d0f397310360eec91eaf792e96fc7e0f496cb4e669d414f877b7b27901fe67c2e3b33cd39d1c797715189ac951c2add" },
|
||||
{'name': "NTAG424DNA",
|
||||
'samples': ["0463474AA26A80", "27E9A50E6CA4BA9037C02F7D20A80D0284D0C1D83C67F5A5AC1D8A4EF86C9508417E4E9C6F85AA7920F0ABDED984CAF20467D66EA54BBF08",
|
||||
"04C46C222A6380", "344A806EBF704C05C19215D2F840529CE365AAD2D08A469A95896D75D477D9FAB02A0C827E9F215BD8EB0E56A3A9A008FB75D706AABBD4DA"],
|
||||
'pk': "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410" },
|
||||
{'name': "Vivokey Spark1",
|
||||
# ! tag signature bytes output by pm3 must be read right to left: echo $sig |sed 's/\(..\)/\1\n/g'|tac|tr -d '\n' (and it uses a SHA256)
|
||||
'samples': ["E0040118009C870C", "4B4E03E1211952EF6A5F9D84AB218CD4D7549D0CDF8CA8779F9AD16C9A9CBF3B",
|
||||
"E0040118009B4D62", "25CF13747C3389EC7889DE916E3747584978511CC78B51CFB1883B494CBED7AB"],
|
||||
'pk': "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a" },
|
||||
# ! tag UID is considered inversed: E0040118009B5FEE => EE5F9B00180104E0
|
||||
# TODO one more ICODE-DNA...
|
||||
{'name': "ICODE DNA, ICODE SLIX2",
|
||||
'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"],
|
||||
'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" },
|
||||
]
|
||||
succeeded = True
|
||||
for t in tests:
|
||||
print("Testing %-25s" % (t['name']+":"), end="")
|
||||
recovered = recover_multiple(t['samples'][::2], t['samples'][1::2])
|
||||
recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], alghash="sha256")
|
||||
if (len(recovered) == 1):
|
||||
pk = recovered.pop()
|
||||
pk = binascii.hexlify(pk).decode('utf8')
|
||||
if pk.lower() == t['pk'].lower():
|
||||
print("[OK]")
|
||||
else:
|
||||
succeeded = False
|
||||
print("[FAIL]")
|
||||
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]")
|
||||
else:
|
||||
succeeded = False
|
||||
print("[FAIL]")
|
||||
print("Tests: [%s]" % ["FAIL", "OK"][succeeded])
|
||||
|
||||
print("Assuming no hash was used in the signature generation:")
|
||||
recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2])
|
||||
print("Possible uncompressed Pk(s):")
|
||||
for pk in list(recovered):
|
||||
print(binascii.hexlify(pk).decode('utf8'))
|
||||
print("Assuming SHA-256 was used in the signature generation:")
|
||||
recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2], alghash="sha256")
|
||||
print("Possible uncompressed Pk(s):")
|
||||
for pk in list(recovered):
|
||||
print(binascii.hexlify(pk).decode('utf8'))
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "selftests":
|
||||
selftests()
|
||||
exit(0)
|
||||
if len(sys.argv) < 3 or len(sys.argv) % 2 == 0:
|
||||
print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[0])
|
||||
print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0])
|
||||
exit(1)
|
||||
|
||||
print("Assuming no hash was used in the signature generation:")
|
||||
recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2])
|
||||
print("Possible uncompressed Pk(s):")
|
||||
for pk in list(recovered):
|
||||
print(binascii.hexlify(pk).decode('utf8'))
|
||||
print("Assuming SHA-256 was used in the signature generation:")
|
||||
recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2], alghash="sha256")
|
||||
print("Possible uncompressed Pk(s):")
|
||||
for pk in list(recovered):
|
||||
print(binascii.hexlify(pk).decode('utf8'))
|
||||
|
||||
Reference in New Issue
Block a user