mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 02:27:26 -07:00
Merge branch 'master' into master
Signed-off-by: Iceman <iceman@iuse.se>
This commit is contained in:
commit
92e8dea093
31 changed files with 954 additions and 328 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -3,8 +3,18 @@ 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]
|
||||
- Extended area for Mifare keys in SPI flash to hold 4095 keys (@piotrva)
|
||||
- Fixed DESFire D40 secure channel crypto (@nvx)
|
||||
- Fixed `hf mfp info` fix signature check on 4b UID cards (@doegox)
|
||||
- Automatically set maximum read/write block when using predefined types in `hf_mf_ultimatecard` script (@piotrva)
|
||||
- Changed SPI flash detection to calculate the size instead of table lookup, updated spi_flash_decode.py script with more ICs (@ANTodorov)
|
||||
- Fixed `hf/lf tune` segfault when called from script (@doegox)
|
||||
- Added option to set and get maximum read/write block number using `hf_mf_ultimatecard` script (@piotrva)
|
||||
- Added JEDEC information for SPI flash W25Q64JV (@ANTodorov)
|
||||
- Added special iclass legacy config cards in `hf iclass configcard` (@antiklesys)
|
||||
- Added simulation function to `hf iclass legrec` (@antiklesys)
|
||||
- Added keys from Momentum firmware projects. (@onovy)
|
||||
- Added Dutch Statistics Agency default key (@eagle00789)
|
||||
|
||||
## [Orca.4.19552][2024-11-22]
|
||||
- Fixed `hf_legic.lua` - removed bit32 commands from the script (@diorch1968)
|
||||
|
|
|
@ -1778,7 +1778,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES: {
|
||||
MifareAcquireStaticEncryptedNonces(packet->oldarg[0], packet->data.asBytes, true);
|
||||
MifareAcquireStaticEncryptedNonces(packet->oldarg[0], packet->data.asBytes, true, packet->oldarg[1], packet->oldarg[2]);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_ACQ_NONCES: {
|
||||
|
|
|
@ -1036,7 +1036,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
// acquire static encrypted nonces in order to perform the attack described in
|
||||
// Philippe Teuwen, "MIFARE Classic: exposing the static encrypted nonce variant"
|
||||
//-----------------------------------------------------------------------------
|
||||
int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool reply) {
|
||||
int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool reply, uint8_t first_block_no, uint8_t first_key_type) {
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
|
@ -1055,6 +1055,10 @@ int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool
|
|||
uint8_t buf[MIFARE_BLOCK_SIZE] = {0x00};
|
||||
uint64_t ui64Key = bytes_to_num(key, 6);
|
||||
bool with_data = flags & 1;
|
||||
bool without_backdoor = (flags >> 1) & 1;
|
||||
if (with_data && without_backdoor) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
uint32_t cuid = 0;
|
||||
int16_t isOK = PM3_SUCCESS;
|
||||
uint8_t cascade_levels = 0;
|
||||
|
@ -1072,121 +1076,230 @@ int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool
|
|||
|
||||
LED_C_ON();
|
||||
|
||||
for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) {
|
||||
uint16_t sec_gap = sec;
|
||||
if (sec >= MIFARE_1K_MAXSECTOR) {
|
||||
// gap between user blocks and advanced verification method blocks
|
||||
sec_gap += 16;
|
||||
if (without_backdoor) {
|
||||
uint32_t nt1 = 0;
|
||||
|
||||
iso14a_card_select_t card_info;
|
||||
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (ALL)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
uint16_t blockNo = sec_gap * 4;
|
||||
for (uint8_t keyType = 0; keyType < 2; keyType++) {
|
||||
// Test if the action was cancelled
|
||||
if (BUTTON_PRESS()) {
|
||||
isOK = PM3_EOPABORTED;
|
||||
switch (card_info.uidlen) {
|
||||
case 4 :
|
||||
cascade_levels = 1;
|
||||
break;
|
||||
case 7 :
|
||||
cascade_levels = 2;
|
||||
break;
|
||||
case 10:
|
||||
cascade_levels = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, first_block_no, MIFARE_AUTH_KEYA + first_key_type, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
|
||||
uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + first_key_type, first_block_no, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL);
|
||||
if (len != 4) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len);
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
uint32_t nt_enc = bytes_to_num(receivedAnswer, 4);
|
||||
|
||||
// send some crap to fail auth
|
||||
CHK_TIMEOUT();
|
||||
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, first_block_no, MIFARE_AUTH_KEYA + first_key_type, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
// Recover clear nt
|
||||
struct Crypto1State mpcs_tmp = {0, 0};
|
||||
struct Crypto1State *pcs_tmp = &mpcs_tmp;
|
||||
crypto1_init(pcs_tmp, ui64Key);
|
||||
uint32_t nt = crypto1_word(pcs_tmp, nt_enc ^ cuid, 1) ^ nt_enc;
|
||||
int dist = nonce_distance(nt, nt1);
|
||||
// ref dist is not always stable. Adjust physical distance to maximise ref dist, and try values around estimated nonces...
|
||||
Dbprintf("Block %2i key %i nested nT=%08x first nT=%08x dist=%i", first_block_no, first_key_type, nt, nt1, dist);
|
||||
|
||||
for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) {
|
||||
uint16_t sec_gap = sec;
|
||||
if (sec >= MIFARE_1K_MAXSECTOR) {
|
||||
// gap between user blocks and advanced verification method blocks
|
||||
sec_gap += 16;
|
||||
}
|
||||
if (have_uid == false) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (ALL)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
uint16_t blockNo = sec_gap * 4;
|
||||
for (uint8_t keyType = 0; keyType < 2; keyType++) {
|
||||
// Test if the action was cancelled
|
||||
if (BUTTON_PRESS()) {
|
||||
isOK = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + keyType, blockNo, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL);
|
||||
if (len != 4) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len);
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
switch (card_info.uidlen) {
|
||||
case 4 :
|
||||
cascade_levels = 1;
|
||||
break;
|
||||
case 7 :
|
||||
cascade_levels = 2;
|
||||
break;
|
||||
case 10:
|
||||
cascade_levels = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
// store nt_enc
|
||||
memcpy(buf + (keyType * 8) + 4, receivedAnswer, 4);
|
||||
nt_enc = bytes_to_num(receivedAnswer, 4);
|
||||
uint8_t nt_par_err = ((((par_enc[0] >> 7) & 1) ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3 |
|
||||
(((par_enc[0] >> 6) & 1) ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2 |
|
||||
(((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 |
|
||||
(((par_enc[0] >> 4) & 1) ^ oddparity8((nt_enc >> 0) & 0xFF)));
|
||||
// Dbprintf("Sec %2i key %i {nT}=%02x%02x%02x%02x perr=%x", sec, keyType, receivedAnswer[0], receivedAnswer[1], receivedAnswer[2], receivedAnswer[3], nt_par_err);
|
||||
// store nt_par_err
|
||||
buf[(keyType * 8) + 2] = nt_par_err;
|
||||
buf[(keyType * 8) + 3] = 0xAA; // extra check to tell we have nt/nt_enc/par_err
|
||||
|
||||
// send some crap to fail auth
|
||||
CHK_TIMEOUT();
|
||||
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, first_block_no, MIFARE_AUTH_KEYA + first_key_type, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
nt1 = rewind_nonce(nt1, dist);
|
||||
num_to_bytes(nt1 >> 16, 2, buf + (keyType * 8));
|
||||
emlSetMem_xt(buf, (CARD_MEMORY_RF08S_OFFSET / MIFARE_BLOCK_SIZE) + sec, 1, MIFARE_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
uint32_t nt1 = 0;
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, blockNo, MIFARE_AUTH_KEYA + keyType + 4, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
if ((with_data) && (keyType == 0)) {
|
||||
uint8_t data[16];
|
||||
uint8_t blocks = 4;
|
||||
if (blockNo >= MIFARE_1K_MAXSECTOR * 4) {
|
||||
// special RF08S advanced authentication blocks, let's dump in emulator just in case
|
||||
blocks = 8;
|
||||
}
|
||||
} else {
|
||||
for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) {
|
||||
uint16_t sec_gap = sec;
|
||||
if (sec >= MIFARE_1K_MAXSECTOR) {
|
||||
// gap between user blocks and advanced verification method blocks
|
||||
sec_gap += 16;
|
||||
}
|
||||
uint16_t blockNo = sec_gap * 4;
|
||||
for (uint8_t keyType = 0; keyType < 2; keyType++) {
|
||||
// Test if the action was cancelled
|
||||
if (BUTTON_PRESS()) {
|
||||
isOK = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
for (uint16_t tb = blockNo; tb < blockNo + blocks; tb++) {
|
||||
memset(data, 0x00, sizeof(data));
|
||||
int res = mifare_classic_readblock(pcs, tb, data);
|
||||
if (res == 1) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error");
|
||||
isOK = PM3_ESOFT;
|
||||
if (have_uid == false) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (ALL)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
switch (card_info.uidlen) {
|
||||
case 4 :
|
||||
cascade_levels = 1;
|
||||
break;
|
||||
case 7 :
|
||||
cascade_levels = 2;
|
||||
break;
|
||||
case 10:
|
||||
cascade_levels = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
emlSetMem_xt(data, tb, 1, 16);
|
||||
}
|
||||
}
|
||||
// nested authentication
|
||||
uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + keyType + 4, blockNo, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL);
|
||||
if (len != 4) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len);
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
uint32_t nt_enc = bytes_to_num(receivedAnswer, 4);
|
||||
crypto1_init(pcs, ui64Key);
|
||||
uint32_t nt = crypto1_word(pcs, nt_enc ^ cuid, 1) ^ nt_enc;
|
||||
// Dbprintf("Sec %2i key %i nT=%08x", sec, keyType + 4, nt);
|
||||
// store nt (first half)
|
||||
num_to_bytes(nt >> 16, 2, buf + (keyType * 8));
|
||||
// send some crap to fail auth
|
||||
uint8_t nack[] = {0x04};
|
||||
ReaderTransmit(nack, sizeof(nack), NULL);
|
||||
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, blockNo, MIFARE_AUTH_KEYA + keyType + 4, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
uint32_t nt1 = 0;
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, blockNo, MIFARE_AUTH_KEYA + keyType + 4, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
if ((with_data) && (keyType == 0)) {
|
||||
uint8_t data[16];
|
||||
uint8_t blocks = 4;
|
||||
if (blockNo >= MIFARE_1K_MAXSECTOR * 4) {
|
||||
// special RF08S advanced authentication blocks, let's dump in emulator just in case
|
||||
blocks = 8;
|
||||
}
|
||||
for (uint16_t tb = blockNo; tb < blockNo + blocks; tb++) {
|
||||
memset(data, 0x00, sizeof(data));
|
||||
int res = mifare_classic_readblock(pcs, tb, data);
|
||||
if (res == 1) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
emlSetMem_xt(data, tb, 1, 16);
|
||||
}
|
||||
}
|
||||
// nested authentication
|
||||
uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + keyType + 4, blockNo, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL);
|
||||
if (len != 4) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len);
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
uint32_t nt_enc = bytes_to_num(receivedAnswer, 4);
|
||||
crypto1_init(pcs, ui64Key);
|
||||
uint32_t nt = crypto1_word(pcs, nt_enc ^ cuid, 1) ^ nt_enc;
|
||||
// Dbprintf("Sec %2i key %i nT=%08x", sec, keyType + 4, nt);
|
||||
// store nt (first half)
|
||||
num_to_bytes(nt >> 16, 2, buf + (keyType * 8));
|
||||
// send some crap to fail auth
|
||||
CHK_TIMEOUT();
|
||||
|
||||
// nested authentication on regular keytype
|
||||
len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + keyType, blockNo, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL);
|
||||
if (len != 4) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len);
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
|
||||
isOK = PM3_ERFTRANS;
|
||||
goto out;
|
||||
}
|
||||
if (mifare_classic_authex_cmd(pcs, cuid, blockNo, MIFARE_AUTH_KEYA + keyType + 4, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
};
|
||||
|
||||
// nested authentication on regular keytype
|
||||
len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + keyType, blockNo, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL);
|
||||
if (len != 4) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len);
|
||||
isOK = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
// store nt_enc
|
||||
memcpy(buf + (keyType * 8) + 4, receivedAnswer, 4);
|
||||
nt_enc = bytes_to_num(receivedAnswer, 4);
|
||||
uint8_t nt_par_err = ((((par_enc[0] >> 7) & 1) ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3 |
|
||||
(((par_enc[0] >> 6) & 1) ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2 |
|
||||
(((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 |
|
||||
(((par_enc[0] >> 4) & 1) ^ oddparity8((nt_enc >> 0) & 0xFF)));
|
||||
// Dbprintf("Sec %2i key %i {nT}=%02x%02x%02x%02x perr=%x", sec, keyType, receivedAnswer[0], receivedAnswer[1], receivedAnswer[2], receivedAnswer[3], nt_par_err);
|
||||
// store nt_par_err
|
||||
buf[(keyType * 8) + 2] = nt_par_err;
|
||||
buf[(keyType * 8) + 3] = 0xAA; // extra check to tell we have nt/nt_enc/par_err
|
||||
emlSetMem_xt(buf, (CARD_MEMORY_RF08S_OFFSET / MIFARE_BLOCK_SIZE) + sec, 1, MIFARE_BLOCK_SIZE);
|
||||
// send some crap to fail auth
|
||||
CHK_TIMEOUT();
|
||||
}
|
||||
// store nt_enc
|
||||
memcpy(buf + (keyType * 8) + 4, receivedAnswer, 4);
|
||||
nt_enc = bytes_to_num(receivedAnswer, 4);
|
||||
uint8_t nt_par_err = ((((par_enc[0] >> 7) & 1) ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3 |
|
||||
(((par_enc[0] >> 6) & 1) ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2 |
|
||||
(((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 |
|
||||
(((par_enc[0] >> 4) & 1) ^ oddparity8((nt_enc >> 0) & 0xFF)));
|
||||
// Dbprintf("Sec %2i key %i {nT}=%02x%02x%02x%02x perr=%x", sec, keyType, receivedAnswer[0], receivedAnswer[1], receivedAnswer[2], receivedAnswer[3], nt_par_err);
|
||||
// store nt_par_err
|
||||
buf[(keyType * 8) + 2] = nt_par_err;
|
||||
buf[(keyType * 8) + 3] = 0xAA; // extra check to tell we have nt/nt_enc/par_err
|
||||
emlSetMem_xt(buf, (CARD_MEMORY_RF08S_OFFSET / MIFARE_BLOCK_SIZE) + sec, 1, MIFARE_BLOCK_SIZE);
|
||||
// send some crap to fail auth
|
||||
ReaderTransmit(nack, sizeof(nack), NULL);
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
@ -1194,7 +1307,7 @@ out:
|
|||
crypto1_deinit(pcs);
|
||||
LED_B_ON();
|
||||
if (reply) {
|
||||
reply_old(CMD_ACK, isOK, cuid, 0, BigBuf_get_EM_addr() + CARD_MEMORY_RF08S_OFFSET, MIFARE_BLOCK_SIZE * (MIFARE_1K_MAXSECTOR + 1));
|
||||
reply_mix(CMD_ACK, isOK, cuid, 0, BigBuf_get_EM_addr() + CARD_MEMORY_RF08S_OFFSET, MIFARE_BLOCK_SIZE * (MIFARE_1K_MAXSECTOR + 1));
|
||||
}
|
||||
LED_B_OFF();
|
||||
|
||||
|
@ -3127,7 +3240,8 @@ void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *
|
|||
goto OUT;
|
||||
};
|
||||
first_nt_counter++;
|
||||
} else for (uint8_t i = 0; i < nr_nested; i++) {
|
||||
} else {
|
||||
for (uint8_t i = 0; i < nr_nested; i++) {
|
||||
if (need_first_auth) {
|
||||
cuid = 0;
|
||||
|
||||
|
@ -3204,6 +3318,7 @@ void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *
|
|||
}
|
||||
oldntenc = ntenc;
|
||||
}
|
||||
}
|
||||
|
||||
data[1] = (cuid >> 24) & 0xFF;
|
||||
data[2] = (cuid >> 16) & 0xFF;
|
||||
|
@ -3367,7 +3482,8 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) {
|
|||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
cmd[ofs++] = card_info->sak;
|
||||
cmd[ofs] = block_len <= card_info->uidlen ? card_info->sak : cmd[ofs];
|
||||
ofs++;
|
||||
cmd[ofs++] = card_info->atqa[0];
|
||||
cmd[ofs++] = card_info->atqa[1];
|
||||
AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE);
|
||||
|
|
|
@ -37,7 +37,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key);
|
||||
|
||||
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
|
||||
int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool reply);
|
||||
int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool reply, uint8_t first_block_no, uint8_t first_key_type);
|
||||
void MifareAcquireNonces(uint32_t arg0, uint32_t flags);
|
||||
void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem);
|
||||
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||
|
|
|
@ -983,3 +983,12 @@ int nonce_distance(uint32_t from, uint32_t to) {
|
|||
int nonce16_index(uint16_t nt) {
|
||||
return nonce16_distance(0x0100, nt) + 1;
|
||||
}
|
||||
|
||||
uint32_t rewind_nonce(uint32_t from, uint16_t dist) {
|
||||
uint16_t x = from >> 16;
|
||||
for (uint16_t i = 0; i < dist; i++) {
|
||||
x = ((x << 1 | x >> 15) & 0xffff) ^ ((x >> 1 ^ x >> 2 ^ x >> 4) & 0x100);
|
||||
}
|
||||
uint32_t nt = x;
|
||||
return nt << 16 | prng_successor(nt, 16);
|
||||
}
|
||||
|
|
|
@ -128,4 +128,5 @@ bool validate_parity_nonce(uint32_t ntenc, uint8_t ntparenc, uint32_t nt);
|
|||
int nonce_distance(uint32_t from, uint32_t to);
|
||||
int nonce16_distance(uint16_t x, uint16_t y);
|
||||
int nonce16_index(uint16_t nt);
|
||||
uint32_t rewind_nonce(uint32_t from, uint16_t dist);
|
||||
#endif
|
||||
|
|
|
@ -2755,7 +2755,8 @@ D37C8F1793F7
|
|||
543071543071
|
||||
5F01015F0101
|
||||
200510241234
|
||||
# Momentum-Firmware
|
||||
#
|
||||
# Momentum-Firmware 20241201
|
||||
AC935925A876
|
||||
ADC169F922CB
|
||||
AD00EFD353E4
|
||||
|
@ -3022,3 +3023,18 @@ F833E24C3F1C
|
|||
93FB38FE585A
|
||||
96AECCC0F7EB
|
||||
96227EDADBCF
|
||||
#
|
||||
# BW Kantine
|
||||
56cf3acd90ca
|
||||
542089792be2
|
||||
5420aeada758
|
||||
#
|
||||
# CSC Laundry
|
||||
212223242555
|
||||
717273747555
|
||||
#
|
||||
# Hotel cards, BETECH brand, Vietnam
|
||||
AAC34D9A4E65
|
||||
#
|
||||
# Dutch Statistics Agency (CBS)
|
||||
DC7B15AA0938
|
|
@ -22,6 +22,8 @@ F9DCEBA0
|
|||
89A69E60
|
||||
# ref lock
|
||||
314159E0
|
||||
#Zonsin ZX-COPY10
|
||||
7B3D5C48
|
||||
# ref. http://www.proxmark.org/forum/viewtopic.php?pid=28115#p28115
|
||||
AA55BBBB
|
||||
# ref. http://www.proxmark.org/forum/viewtopic.php?pid=33376#p33376
|
||||
|
|
|
@ -50,20 +50,20 @@ arguments = [[
|
|||
-c read magic configuration
|
||||
-u UID (8-20 hexsymbols), set UID on tag
|
||||
-t tag type to impersonate
|
||||
1 = Mifare Mini S20 4-byte
|
||||
2 = Mifare Mini S20 7-byte 15 = NTAG 210
|
||||
3 = Mifare Mini S20 10-byte 16 = NTAG 212
|
||||
4 = Mifare 1k S50 4-byte 17 = NTAG 213
|
||||
5 = Mifare 1k S50 7-byte 18 = NTAG 215
|
||||
6 = Mifare 1k S50 10-byte 19 = NTAG 216
|
||||
7 = Mifare 4k S70 4-byte 20 = NTAG I2C 1K
|
||||
8 = Mifare 4k S70 7-byte 21 = NTAG I2C 2K
|
||||
9 = Mifare 4k S70 10-byte 22 = NTAG I2C 1K PLUS
|
||||
*** 10 = UL - NOT WORKING FULLY 23 = NTAG I2C 2K PLUS
|
||||
*** 11 = UL-C - NOT WORKING FULLY 24 = NTAG 213F
|
||||
12 = UL EV1 48b 25 = NTAG 216F
|
||||
13 = UL EV1 128b
|
||||
*** 14 = UL Plus - NOT WORKING YET
|
||||
1 = Mifare Mini S20 4-byte | 15 = NTAG 210
|
||||
2 = Mifare Mini S20 7-byte | 16 = NTAG 212
|
||||
3 = Mifare Mini S20 10-byte | 17 = NTAG 213
|
||||
4 = Mifare 1k S50 4-byte | 18 = NTAG 215
|
||||
5 = Mifare 1k S50 7-byte | 19 = NTAG 216
|
||||
6 = Mifare 1k S50 10-byte | 20 = NTAG I2C 1K
|
||||
7 = Mifare 4k S70 4-byte | 21 = NTAG I2C 2K
|
||||
8 = Mifare 4k S70 7-byte | 22 = NTAG I2C 1K PLUS
|
||||
9 = Mifare 4k S70 10-byte | 23 = NTAG I2C 2K PLUS
|
||||
*** 10 = UL - NOT WORKING FULLY | 24 = NTAG 213F
|
||||
*** 11 = UL-C - NOT WORKING FULLY | 25 = NTAG 216F
|
||||
12 = UL EV1 48b |
|
||||
13 = UL EV1 128b |
|
||||
*** 14 = UL Plus - NOT WORKING YET |
|
||||
|
||||
-p NTAG password (8 hexsymbols), set NTAG password on tag.
|
||||
-a NTAG pack ( 4 hexsymbols), set NTAG pack on tag.
|
||||
|
@ -75,7 +75,11 @@ arguments = [[
|
|||
-z ATS (<1b length><0-16 ATS> hexsymbols), Configure ATS. Length set to 00 will disable ATS.
|
||||
-w Wipe tag. 0 for Mifare or 1 for UL. Fills tag with zeros and put default values for type selected.
|
||||
-m Ultralight mode (00 UL EV1, 01 NTAG, 02 UL-C, 03 UL) Set type of UL.
|
||||
-n Ultralight protocol (00 MFC, 01 UL), switches between UL and MFC mode
|
||||
-n Ultralight protocol (00 MFC, 01 UL), switches between UL and MFC mode]]
|
||||
-- Need to split because reached maximum string length processed by lua
|
||||
arguments2 = [[
|
||||
-b Set maximum read/write blocks (2 hexsymbols)
|
||||
NOTE: Ultralight EV1 and NTAG Version info and Signature are stored respectively in blocks 250-251 and 242-249
|
||||
-k Ultimate Magic Card Key (IF DIFFERENT THAN DEFAULT 00000000)
|
||||
]]
|
||||
---
|
||||
|
@ -110,6 +114,7 @@ local function help()
|
|||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(arguments2)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
|
@ -186,6 +191,7 @@ local function read_config()
|
|||
end
|
||||
-- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu
|
||||
ulprotocol, uidlength, readpass, gtumode, ats, atqa1, atqa2, sak, ulmode = magicconfig:sub(1,2), magicconfig:sub(3,4), magicconfig:sub(5,12), magicconfig:sub(13,14), magicconfig:sub(15,48), magicconfig:sub(51,52), magicconfig:sub(49,50), magicconfig:sub(53,54), magicconfig:sub(55,56)
|
||||
maxRWblk = magicconfig:sub(57, 58)
|
||||
atqaf = atqa1..' '..atqa2
|
||||
cardtype, cardprotocol, gtustr, atsstr = 'unknown', 'unknown', 'unknown', 'unknown'
|
||||
if magicconfig == nil then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end
|
||||
|
@ -291,6 +297,7 @@ local function read_config()
|
|||
print(' - Version ', cversion)
|
||||
print(' - Signature ', signature1..signature2)
|
||||
end
|
||||
print(' - Max R/W Block ', maxRWblk)
|
||||
end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
|
@ -637,6 +644,26 @@ local function write_ulm(ulm)
|
|||
return true, 'Ok'
|
||||
end
|
||||
---
|
||||
-- Write maximum read/write block number,
|
||||
local function write_maxRWblk(data)
|
||||
-- input number check
|
||||
if data == nil then return nil, 'empty block number' end
|
||||
if #data == 0 then return nil, 'empty block number' end
|
||||
if #data ~= 2 then return nil, 'block number wrong length. Should be 1 hex byte' end
|
||||
|
||||
print('Set max R/W block', data)
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
local resp
|
||||
-- set maximum read/write block
|
||||
resp = send("CF".._key.."6B"..data)
|
||||
lib14a.disconnect()
|
||||
if resp ~= '9000FD07' then return nil, 'Failed to write maximum read/write block'
|
||||
else
|
||||
return true, 'Ok'
|
||||
end
|
||||
end
|
||||
---
|
||||
-- Set type for magic card presets.
|
||||
local function set_type(tagtype)
|
||||
-- tagtype checks
|
||||
|
@ -649,6 +676,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233')
|
||||
write_maxRWblk('13')
|
||||
-- Setting Mifare mini S20 7-byte
|
||||
elseif tagtype == 2 then
|
||||
print('Setting: Ultimate Magic card to Mifare mini S20 7-byte')
|
||||
|
@ -656,6 +684,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_maxRWblk('13')
|
||||
-- Setting Mifare mini S20 10-byte
|
||||
elseif tagtype == 3 then
|
||||
print('Setting: Ultimate Magic card to Mifare mini S20 10-byte')
|
||||
|
@ -663,6 +692,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000020000000002000978009102DABC19101011121314151684000900")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566778899')
|
||||
write_maxRWblk('13')
|
||||
-- Setting Mifare 1k S50 4--byte
|
||||
elseif tagtype == 4 then
|
||||
print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte')
|
||||
|
@ -670,6 +700,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233')
|
||||
write_maxRWblk('3F')
|
||||
-- Setting Mifare 1k S50 7-byte
|
||||
elseif tagtype == 5 then
|
||||
print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte')
|
||||
|
@ -677,6 +708,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_maxRWblk('3F')
|
||||
-- Setting Mifare 1k S50 10-byte
|
||||
elseif tagtype == 6 then
|
||||
print('Setting: Ultimate Magic card to Mifare 1k S50 10-byte')
|
||||
|
@ -684,6 +716,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000020000000002000978009102DABC19101011121314151684000800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566778899')
|
||||
write_maxRWblk('3F')
|
||||
-- Setting Mifare 4k S70 4-byte
|
||||
elseif tagtype == 7 then
|
||||
print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte')
|
||||
|
@ -691,6 +724,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233')
|
||||
write_maxRWblk('FF')
|
||||
-- Setting Mifare 4k S70 7-byte
|
||||
elseif tagtype == 8 then
|
||||
print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte')
|
||||
|
@ -698,6 +732,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566')
|
||||
write_maxRWblk('FF')
|
||||
-- Setting Mifare 4k S70 10-byte
|
||||
elseif tagtype == 9 then
|
||||
print('Setting: Ultimate Magic card to Mifare 4k S70 10-byte')
|
||||
|
@ -705,6 +740,7 @@ local function set_type(tagtype)
|
|||
send("CF".._key.."F000020000000002000978009102DABC19101011121314151682001800")
|
||||
lib14a.disconnect()
|
||||
write_uid('04112233445566778899')
|
||||
write_maxRWblk('FF')
|
||||
-- Setting UL
|
||||
elseif tagtype == 10 then
|
||||
print('Setting: Ultimate Magic card to UL')
|
||||
|
@ -1016,7 +1052,7 @@ function main(args)
|
|||
local err, msg
|
||||
if #args == 0 then return help() end
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hck:u:t:p:a:s:o:v:q:g:z:n:m:w:') do
|
||||
for o, a in getopt.getopt(args, 'hck:u:t:p:a:s:o:v:q:g:z:n:m:w:b:') do
|
||||
-- help
|
||||
if o == "h" then return help() end
|
||||
-- set Ultimate Magic Card Key for read write
|
||||
|
@ -1049,6 +1085,8 @@ function main(args)
|
|||
if o == "m" then err, msg = write_ulm(a) end
|
||||
-- write UL protocol
|
||||
if o == "n" then err, msg = write_ulp(a) end
|
||||
-- write max r/w block
|
||||
if o == "b" then err, msg = write_maxRWblk(a) end
|
||||
if err == nil then return oops(msg) end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,62 +12,118 @@ except ModuleNotFoundError:
|
|||
return str(s)
|
||||
|
||||
spi = {
|
||||
0x68:{
|
||||
"manufacturer": "Boya",
|
||||
"jedec" : {
|
||||
0x40: {
|
||||
0x15: {
|
||||
"part": "BY25Q16BS",
|
||||
"size": "16mbits",
|
||||
"sizeB": "2MB",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
0x85:{
|
||||
"manufacturer": "Puya",
|
||||
0x60: {
|
||||
0x15: {
|
||||
"part": "P25Q16H",
|
||||
"size": "16mbits",
|
||||
"sizeB": "2MB",
|
||||
"jedec" : {
|
||||
0x60: {
|
||||
0x15: {
|
||||
"part": "P25Q16H",
|
||||
"size": "16mbits",
|
||||
"sizeB": "2MB",
|
||||
},
|
||||
0x16: {
|
||||
"part": "P25Q32H",
|
||||
"size": "32mbits",
|
||||
"sizeB": "4MB",
|
||||
},
|
||||
0x17: {
|
||||
"part": "P25Q64H",
|
||||
"size": "64mbits",
|
||||
"sizeB": "8MB",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
0xEF:{
|
||||
"manufacturer": "Winbond",
|
||||
0x30: {
|
||||
0x11: {
|
||||
"part": "W25X10BV",
|
||||
"size": "1mbits",
|
||||
"sizeB": "128KB",
|
||||
"jedec" : {
|
||||
0x30: {
|
||||
0x11: {
|
||||
"part": "W25X10BV",
|
||||
"size": "1mbits",
|
||||
"sizeB": "128KB",
|
||||
},
|
||||
0x12: {
|
||||
"part": "W25X20BV",
|
||||
"size": "2mbits",
|
||||
"sizeB": "256KB",
|
||||
},
|
||||
0x13: {
|
||||
"part": "W25X40BV",
|
||||
"size": "4mbits",
|
||||
"sizeB": "512KB",
|
||||
},
|
||||
},
|
||||
0x12: {
|
||||
"part": "W25X20BV",
|
||||
"size": "2mbits",
|
||||
"sizeB": "256KB",
|
||||
0x40: {
|
||||
0x12: {
|
||||
"part": "W25Q20BV",
|
||||
"size": "2mbits",
|
||||
"sizeB": "256KB",
|
||||
},
|
||||
0x13: {
|
||||
"part": "W25Q40BV",
|
||||
"size": "4mbits",
|
||||
"sizeB": "512KB",
|
||||
},
|
||||
0x14: {
|
||||
"part": "W25Q80BV",
|
||||
"size": "8mbits",
|
||||
"sizeB": "1MB",
|
||||
},
|
||||
0x15: {
|
||||
"part": "W25Q16BV",
|
||||
"size": "16mbits",
|
||||
"sizeB": "2MB",
|
||||
},
|
||||
0x16: {
|
||||
"part": "W25Q32BV",
|
||||
"size": "32mbits",
|
||||
"sizeB": "4MB",
|
||||
},
|
||||
0x17: {
|
||||
"part": "W25Q64BV",
|
||||
"size": "64mbits",
|
||||
"sizeB": "8MB",
|
||||
},
|
||||
},
|
||||
0x13: {
|
||||
"part": "W25X40BV",
|
||||
"size": "4mbits",
|
||||
"sizeB": "512KB",
|
||||
},
|
||||
},
|
||||
0x40: {
|
||||
0x13: {
|
||||
"part": "W25Q40BV",
|
||||
"size": "4mbits",
|
||||
"sizeB": "512KB",
|
||||
},
|
||||
0x14: {
|
||||
"part": "W25Q80BV",
|
||||
"size": "8mbits",
|
||||
"sizeB": "1MB",
|
||||
},
|
||||
0x15: {
|
||||
"part": "W25Q16BV",
|
||||
"size": "16mbits",
|
||||
"sizeB": "2MB",
|
||||
},
|
||||
0x16: {
|
||||
"part": "W25Q32BV",
|
||||
"size": "32mbits",
|
||||
"sizeB": "4MB",
|
||||
},
|
||||
},
|
||||
0x70: {
|
||||
0x22: {
|
||||
"part": "W25Q02JV-IM",
|
||||
"size": "2mbits",
|
||||
"sizeB": "256KB",
|
||||
0x70: {
|
||||
0x14: {
|
||||
"part": "W25Q80JV",
|
||||
"size": "8mbits",
|
||||
"sizeB": "1MB",
|
||||
},
|
||||
0x15: {
|
||||
"part": "W25Q16JV",
|
||||
"size": "16mbits",
|
||||
"sizeB": "2MB",
|
||||
},
|
||||
0x16: {
|
||||
"part": "W25Q32JV",
|
||||
"size": "32mbits",
|
||||
"sizeB": "4MB",
|
||||
},
|
||||
0x17: {
|
||||
"part": "W25Q64JV",
|
||||
"size": "64mbits",
|
||||
"sizeB": "8MB",
|
||||
},
|
||||
0x22: {
|
||||
"part": "W25Q02JV-IM",
|
||||
"size": "2mbits",
|
||||
"sizeB": "256KB",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -90,16 +146,16 @@ for line in p.grabbed_output.split('\n'):
|
|||
did_h = did >> 8
|
||||
did_l = did & 0xff
|
||||
t = None
|
||||
|
||||
print(f"\n JEDEC ID....... 0x{mid:X} / 0x{did:X}")
|
||||
if mid in spi:
|
||||
|
||||
mfr = spi[mid]['manufacturer']
|
||||
|
||||
if did_h in spi[mid]:
|
||||
if did_h in spi[mid]['jedec']:
|
||||
|
||||
if did_l in spi[mid][did_h]:
|
||||
if did_l in spi[mid]['jedec'][did_h]:
|
||||
|
||||
t = spi[mid][did_h][did_l]
|
||||
t = spi[mid]['jedec'][did_h][did_l]
|
||||
print("\n Manufacturer... " + color(f"{mfr}", fg="green") +
|
||||
"\n Device......... " + color(f"{t['part']}", fg="green") +
|
||||
"\n Size........... " + color(f"{t['size']} ({t['sizeB']})", fg="yellow")
|
||||
|
|
|
@ -1,81 +1,177 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
### Parameters
|
||||
import os
|
||||
import subprocess
|
||||
import signal
|
||||
import numpy as np
|
||||
from pyaudio import PyAudio, paFloat32, paContinue
|
||||
|
||||
# Sound output parameters
|
||||
volume = 1.0
|
||||
sample_buf_size = 44
|
||||
sampling_freq = 44100 #Hz
|
||||
sampling_freq = 44100 # Hz
|
||||
|
||||
# Frequency generator parameters
|
||||
min_freq = 200 #Hz
|
||||
max_freq = 2000 #Hz
|
||||
min_freq = 100 # Hz
|
||||
max_freq = 6000 # Hz
|
||||
|
||||
# Proxmark3 parameters
|
||||
pm3_client="/usr/local/bin/proxmark3"
|
||||
pm3_reader_dev_file="/dev/ttyACM0"
|
||||
pm3_tune_cmd="hf tune"
|
||||
pm3_client = "pm3"
|
||||
pm3_tune_cmd = "hf tune --value"
|
||||
|
||||
frequency = 440
|
||||
buffer = []
|
||||
|
||||
|
||||
### Modules
|
||||
import numpy
|
||||
import pyaudio
|
||||
from select import select
|
||||
from subprocess import Popen, DEVNULL, PIPE
|
||||
def find_zero_crossing_index(array):
|
||||
for i in range(1, len(array)):
|
||||
if array[i-1] < 0 and array[i] >= 0:
|
||||
return i
|
||||
return None # Return None if no zero-crossing is found
|
||||
|
||||
|
||||
### Main program
|
||||
p = pyaudio.PyAudio()
|
||||
def generate_sine_wave(frequency, sample_rate, duration, frame_count):
|
||||
"""Generate a sine wave at a given frequency."""
|
||||
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
|
||||
wave = np.sin(2 * np.pi * frequency * t)
|
||||
return wave[:frame_count]
|
||||
|
||||
# For paFloat32 sample values must be in range [-1.0, 1.0]
|
||||
stream = p.open(format=pyaudio.paFloat32,
|
||||
channels=1,
|
||||
rate=sampling_freq,
|
||||
output=True)
|
||||
|
||||
# Initial voltage to frequency values
|
||||
min_v = 100.0
|
||||
max_v = 0.0
|
||||
v = 0
|
||||
out_freq = min_freq
|
||||
# PyAudio Callback function
|
||||
def pyaudio_callback(in_data, frame_count, time_info, status):
|
||||
# if in_data is None:
|
||||
# return (in_data, pyaudio.paContinue)
|
||||
global frequency
|
||||
global buffer
|
||||
wave = generate_sine_wave(frequency, sampling_freq, 0.01, frame_count*2)
|
||||
i = find_zero_crossing_index(buffer)
|
||||
if i is None:
|
||||
buffer = wave
|
||||
else:
|
||||
buffer = np.concatenate((buffer[:i], wave))
|
||||
data = (buffer[:frame_count] * volume).astype(np.float32).tobytes()
|
||||
buffer = buffer[frame_count:]
|
||||
return (data, paContinue)
|
||||
# pyaudio.paComplete
|
||||
|
||||
# Spawn the Proxmark3 client
|
||||
pm3_proc = Popen([pm3_client, pm3_reader_dev_file, "-c", pm3_tune_cmd], bufsize=0, env={}, stdin=DEVNULL, stdout=PIPE, stderr=DEVNULL)
|
||||
mv_recbuf = ""
|
||||
|
||||
# Read voltages from the Proxmark3, generate the sine wave, output to soundcard
|
||||
sample_buf = [0.0 for x in range(0, sample_buf_size)]
|
||||
i = 0
|
||||
sinev = 0
|
||||
while True:
|
||||
def silent_pyaudio():
|
||||
"""
|
||||
Lifted and adapted from https://stackoverflow.com/questions/67765911/
|
||||
PyAudio is noisy af every time you initialise it, which makes reading the
|
||||
log output rather difficult. The output appears to be being made by the
|
||||
C internals, so we can't even redirect the logs with Python's logging
|
||||
facility. Therefore the nuclear option was selected: swallow all stderr
|
||||
and stdout for the duration of PyAudio's use.
|
||||
"""
|
||||
|
||||
# Read Proxmark3 client's stdout and extract voltage values
|
||||
if(select([pm3_proc.stdout], [], [], 0)[0]):
|
||||
# Open a pair of null files
|
||||
null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)]
|
||||
# Save the actual stdout (1) and stderr (2) file descriptors.
|
||||
save_fds = [os.dup(1), os.dup(2)]
|
||||
# Assign the null pointers to stdout and stderr.
|
||||
os.dup2(null_fds[0], 1)
|
||||
os.dup2(null_fds[1], 2)
|
||||
pyaudio = PyAudio()
|
||||
os.dup2(save_fds[0], 1)
|
||||
os.dup2(save_fds[1], 2)
|
||||
# Close all file descriptors
|
||||
for fd in null_fds + save_fds:
|
||||
os.close(fd)
|
||||
return pyaudio
|
||||
|
||||
b = pm3_proc.stdout.read(256).decode("ascii")
|
||||
if "Done" in b:
|
||||
break;
|
||||
for c in b:
|
||||
if c in "0123456789 mV":
|
||||
mv_recbuf += c
|
||||
else:
|
||||
mv_recbuf = ""
|
||||
if mv_recbuf[-3:] == " mV":
|
||||
v = int(mv_recbuf[:-3]) / 1000
|
||||
if v < min_v:
|
||||
min_v = v - 0.001
|
||||
if v > max_v:
|
||||
max_v = v
|
||||
|
||||
def run_pm3_cmd(callback):
|
||||
# Start the process
|
||||
process = subprocess.Popen(
|
||||
[pm3_client, '-c', pm3_tune_cmd],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1, # Line buffered
|
||||
shell=False
|
||||
)
|
||||
|
||||
# Read the output line by line as it comes
|
||||
try:
|
||||
with process.stdout as pipe:
|
||||
for line in pipe:
|
||||
# Process each line
|
||||
l = line.strip() # Strip to remove any extraneous newline characters
|
||||
callback(l)
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
finally:
|
||||
# Ensure the subprocess is properly terminated
|
||||
process.terminate()
|
||||
process.wait()
|
||||
|
||||
|
||||
def linear_to_exponential_freq(v, min_v, max_v, min_freq, max_freq):
|
||||
# First, map v to a range between 0 and 1
|
||||
if max_v != min_v:
|
||||
normalized_v = (v - min_v) / (max_v - min_v)
|
||||
else:
|
||||
normalized_v = 0.5
|
||||
normalized_v = 1 - normalized_v
|
||||
|
||||
# Calculate the ratio of the max frequency to the min frequency
|
||||
freq_ratio = max_freq / min_freq
|
||||
|
||||
# Calculate the exponential frequency using the mapped v
|
||||
freq = min_freq * (freq_ratio ** normalized_v)
|
||||
return freq
|
||||
|
||||
|
||||
class foo():
|
||||
def __init__(self):
|
||||
self.p = silent_pyaudio()
|
||||
# For paFloat32 sample values must be in range [-1.0, 1.0]
|
||||
self.stream = self.p.open(format=paFloat32,
|
||||
channels=1,
|
||||
rate=sampling_freq,
|
||||
output=True,
|
||||
stream_callback=pyaudio_callback)
|
||||
|
||||
# Initial voltage to frequency values
|
||||
self.min_v = 50000.0
|
||||
self.max_v = 0.0
|
||||
|
||||
# Setting the signal handler for SIGINT (Ctrl+C)
|
||||
signal.signal(signal.SIGINT, self.signal_handler)
|
||||
|
||||
# Start the stream
|
||||
self.stream.start_stream()
|
||||
|
||||
def __exit__(self):
|
||||
self.stream.stop_stream()
|
||||
self.stream.close()
|
||||
self.p.terminate()
|
||||
|
||||
def signal_handler(self, sig, frame):
|
||||
print("\nYou pressed Ctrl+C! Press Enter")
|
||||
self.__exit__()
|
||||
|
||||
def callback(self, line):
|
||||
if 'mV' not in line:
|
||||
return
|
||||
v = int(line.split(' ')[1])
|
||||
if v == 0:
|
||||
return
|
||||
self.min_v = min(self.min_v, v)
|
||||
self.max_v = max(self.max_v, v)
|
||||
|
||||
# Recalculate the audio frequency to generate
|
||||
out_freq = (max_freq - min_freq) * (max_v - v) / (max_v - min_v) \
|
||||
+ min_freq
|
||||
global frequency
|
||||
frequency = linear_to_exponential_freq(v, self.min_v, self.max_v, min_freq, max_freq)
|
||||
|
||||
# Generate the samples and write them to the soundcard
|
||||
sinevs = out_freq / sampling_freq * numpy.pi * 2
|
||||
sample_buf[i] = sinev
|
||||
sinev += sinevs
|
||||
sinev = sinev if sinev < numpy.pi * 2 else sinev - numpy.pi * 2
|
||||
i = (i + 1) % sample_buf_size
|
||||
if not i:
|
||||
stream.write((numpy.sin(sample_buf) * volume).
|
||||
astype(numpy.float32).tobytes())
|
||||
# frequency = max_freq - ((max_freq - min_freq) * (v - self.min_v) / (self.max_v - self.min_v) + min_freq)
|
||||
#frequency = (frequency + new_frequency)/2
|
||||
|
||||
|
||||
def main():
|
||||
f = foo()
|
||||
run_pm3_cmd(f.callback)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1065,10 +1065,10 @@
|
|||
},
|
||||
{
|
||||
"AID": "DD00DD",
|
||||
"Vendor": "Regional Transporation District (RTD) via masabi justride",
|
||||
"Vendor": "Regional Transporation District (RTD) via Masabi Ltd",
|
||||
"Country": "US",
|
||||
"Name": "MyRide Card (DEN)",
|
||||
"Description": "DEN MyRide Card",
|
||||
"Description": "DEN MyRide Card; Masabi Justride Tap and Ride DESFire Smartcard",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
|
@ -1151,6 +1151,22 @@
|
|||
"Description": "FIDs 02: Card Balance; 04: Refill History; 08: Card Information; 0E: Trip History",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21201",
|
||||
"Vendor": "Green Bay Metro Transit via Genfare",
|
||||
"Country": "US",
|
||||
"Name": "Tap-N-Go Card (GRB)",
|
||||
"Description": "GRB Tap-N-Go Card",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21202",
|
||||
"Vendor": "Green Bay Metro Transit via Genfare",
|
||||
"Country": "US",
|
||||
"Name": "Tap-N-Go Card (GRB)",
|
||||
"Description": "GRB Tap-N-Go Card",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "F21360",
|
||||
"Vendor": "INIT",
|
||||
|
|
|
@ -264,7 +264,7 @@ static uint8_t card_app2_limit[] = {
|
|||
0xff,
|
||||
};
|
||||
|
||||
static iclass_config_card_item_t iclass_config_options[30] = {
|
||||
static iclass_config_card_item_t iclass_config_options[33] = {
|
||||
//Byte A8 - LED Operations
|
||||
{"(LED) - Led idle (Off) / Led read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
||||
{"(LED) - Led idle (Red) / Led read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
||||
|
@ -300,11 +300,18 @@ static iclass_config_card_item_t iclass_config_options[30] = {
|
|||
{"(ELITE Key) - Set ELITE Key and Enable Dual key (Elite + Standard)", {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
|
||||
{"(ELITE Key) - Set ELITE Key and ENABLE Keyrolling", {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
|
||||
{"(ELITE Key) - Set ELITE Key and DISABLE Standard Key", {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
|
||||
//Erroneous / incorrect reader behaviors
|
||||
//Erroneous / incorrect reader behaviors (read below)
|
||||
//Elite Bugger:
|
||||
//Sets block 3 of card 0 presented to the reader to 0, sets block 3 of card 1 presented to the reader to the original value of card 0's block 3
|
||||
//Continues setting block 3 of presented cards to block 3 of the previous card the reader scanned
|
||||
//This renders cards unreadable and hardly recoverable unless the order of the scanned cards is known.
|
||||
{"(ELITE Bugger) - Renders cards unusable." , {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
|
||||
//Reset Operations
|
||||
{"(RESET) - Reset READER to defaults", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
||||
{"(RESET) - Reset ENROLLER to defaults", {0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}}
|
||||
{"(RESET) - Reset ENROLLER to defaults", {0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}},
|
||||
//Reader Master Key Operations
|
||||
{"(MASTER Key) - Change Reader Master Key to Custom Key", {0x28, 0xCB, 0x91, 0x9D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
||||
{"(MASTER Key) - Restore Reader Master Key to Factory Defaults", {0x28, 0xCB, 0x91, 0x9D, 0x00, 0x00, 0x00, 0x1C, 0xE0, 0x5C, 0x91, 0xCF, 0x63, 0x34, 0x23, 0xB9}}
|
||||
};
|
||||
|
||||
static const iclass_config_card_item_t *get_config_card_item(int idx) {
|
||||
|
@ -4145,6 +4152,7 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) {
|
|||
}
|
||||
if (check_values) {
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("CONFIRMED VALID RAW key ") _RED_("%s"), sprint_hex(div_key, 8));
|
||||
PrintAndLogEx(INFO, "You can now run -> "_YELLOW_("hf iclass unhash -k %s")" <-to find the pre-images.", sprint_hex(div_key, 8));
|
||||
verified = true;
|
||||
} else {
|
||||
PrintAndLogEx(INFO, _YELLOW_("Raw Key Invalid"));
|
||||
|
@ -4280,7 +4288,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
|
|||
arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."),
|
||||
arg_lit0(NULL, "notest", "Perform real writes on the card!"),
|
||||
arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."),
|
||||
arg_lit0(NULL, "sim", "Runs a simulation based on the card's CSN assuming standard key."),
|
||||
arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key."),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
|
|
@ -7202,7 +7202,8 @@ static int CmdHf14AGen3Block(const char *Cmd) {
|
|||
" - You can specify part of manufacturer block as\n"
|
||||
" 4/7-bytes for UID change only\n"
|
||||
"\n"
|
||||
"NOTE: BCC, SAK, ATQA will be calculated automatically"
|
||||
"NOTE: BCC and ATQA will be calculated automatically\n"
|
||||
"SAK will be automatically set to default values if not specified"
|
||||
,
|
||||
"hf mf gen3blk --> print current data\n"
|
||||
"hf mf gen3blk -d 01020304 --> set 4 byte uid\n"
|
||||
|
@ -9883,6 +9884,7 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
|||
arg_rem("FM11RF08S specific options:", "Incompatible with above options, except -k; output in JSON"),
|
||||
arg_lit0(NULL, "collect_fm11rf08s", "collect all nT/{nT}/par_err."),
|
||||
arg_lit0(NULL, "collect_fm11rf08s_with_data", "collect all nT/{nT}/par_err and data blocks."),
|
||||
arg_lit0(NULL, "collect_fm11rf08s_without_backdoor", "collect all nT/{nT}/par_err without backdoor. Requires first auth keytype and block"),
|
||||
arg_str0("f", "file", "<fn>", "Specify a filename for collected data"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -9954,9 +9956,18 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
|||
if (collect_fm11rf08s_with_data) {
|
||||
collect_fm11rf08s = 1;
|
||||
}
|
||||
bool collect_fm11rf08s_without_backdoor = arg_get_lit(ctx, 23);
|
||||
if (collect_fm11rf08s_without_backdoor) {
|
||||
collect_fm11rf08s = 1;
|
||||
}
|
||||
if (collect_fm11rf08s_with_data && collect_fm11rf08s_without_backdoor) {
|
||||
CLIParserFree(ctx);
|
||||
PrintAndLogEx(WARNING, "Don't mix with_data and without_backdoor options");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 23), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 24), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -10005,10 +10016,10 @@ static int CmdHF14AMfISEN(const char *Cmd) {
|
|||
|
||||
if (collect_fm11rf08s) {
|
||||
uint64_t t1 = msclock();
|
||||
uint32_t flags = collect_fm11rf08s_with_data;
|
||||
SendCommandMIX(CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES, flags, 0, 0, key, sizeof(key));
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, &resp, 1000)) {
|
||||
if (resp.status == PM3_ESOFT) {
|
||||
uint32_t flags = collect_fm11rf08s_with_data | (collect_fm11rf08s_without_backdoor << 1);
|
||||
SendCommandMIX(CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES, flags, blockn, keytype, key, sizeof(key));
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
|
||||
if (resp.oldarg[0] != PM3_SUCCESS) {
|
||||
return NONCE_FAIL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -333,10 +333,12 @@ static int CmdHFMFPInfo(const char *Cmd) {
|
|||
|
||||
// version check
|
||||
uint8_t version[30] = {0};
|
||||
uint8_t uid7b[7] = {0};
|
||||
int version_len = sizeof(version);
|
||||
if (get_plus_version(version, &version_len) == PM3_SUCCESS) {
|
||||
plus_print_version(version);
|
||||
supportVersion = true;
|
||||
memcpy(uid7b, version + 14, 7);
|
||||
} else {
|
||||
// info about 14a part, historical bytes.
|
||||
infoHF14A(false, false, false);
|
||||
|
@ -346,7 +348,11 @@ static int CmdHFMFPInfo(const char *Cmd) {
|
|||
uint8_t signature[56] = {0};
|
||||
int signature_len = sizeof(signature);
|
||||
if (get_plus_signature(signature, &signature_len) == PM3_SUCCESS) {
|
||||
plus_print_signature(card.uid, card.uidlen, signature, signature_len);
|
||||
if (supportVersion) {
|
||||
plus_print_signature(uid7b, 7, signature, signature_len);
|
||||
} else {
|
||||
plus_print_signature(card.uid, card.uidlen, signature, signature_len);
|
||||
}
|
||||
supportSignature = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1540,21 +1540,13 @@ static int ulev1_print_version(uint8_t *data) {
|
|||
}
|
||||
|
||||
static int ntag_print_counter(void) {
|
||||
// NTAG has one counter/tearing. At address 0x02.
|
||||
// NTAG has one counter. At address 0x02. With no tearing.
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counter"));
|
||||
uint8_t tear[1] = {0};
|
||||
uint8_t counter[3] = {0, 0, 0};
|
||||
uint16_t len;
|
||||
len = ulev1_readTearing(0x02, tear, sizeof(tear));
|
||||
(void)len;
|
||||
len = ulev1_readCounter(0x02, counter, sizeof(counter));
|
||||
(void)len;
|
||||
PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3));
|
||||
PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )"
|
||||
, tear[0]
|
||||
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -5833,6 +5825,127 @@ out:
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14AMfUIncr(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfu incr",
|
||||
"Increment a MIFARE Ultralight Ev1 counter\n"
|
||||
"Will read but not increment counter if NTAG is detected",
|
||||
"hf mfu incr -c 0 -v 1337\n"
|
||||
"hf mfu incr -c 2 -v 0 -p FFFFFFFF");
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1("c", "cnt", "<dec>", "Counter index from 0"),
|
||||
arg_int1("v", "val", "<dec>", "Value to increment by (0-16777215)"),
|
||||
arg_str0("p", "pwd", "<hex>", "PWD to authenticate with"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
uint8_t counter = arg_get_int_def(ctx, 1, 3);
|
||||
uint32_t value = arg_get_u32_def(ctx, 2, 16777216);
|
||||
|
||||
int pwd_len;
|
||||
uint8_t pwd[4] = { 0x00 };
|
||||
CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len);
|
||||
bool has_key = false;
|
||||
if (pwd_len) {
|
||||
has_key = true;
|
||||
if (pwd_len != 4) {
|
||||
PrintAndLogEx(WARNING, "incorrect PWD length");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (counter > 2) {
|
||||
PrintAndLogEx(WARNING, "Counter index must be in range 0-2");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (value > 16777215) {
|
||||
PrintAndLogEx(WARNING, "Value to increment must be in range 0-16777215");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t increment_cmd[6] = { MIFARE_ULEV1_INCR_CNT, counter, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
increment_cmd[i + 2] = (value >> (8 * i)) & 0xff;
|
||||
}
|
||||
|
||||
iso14a_card_select_t card;
|
||||
if (ul_select(&card) == false) {
|
||||
PrintAndLogEx(FAILED, "failed to select card, exiting...");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint64_t tagtype = GetHF14AMfU_Type();
|
||||
uint64_t tags_with_counter_ul = MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1;
|
||||
uint64_t tags_with_counter_ntag = MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C | MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216;
|
||||
if ((tagtype & (tags_with_counter_ul | tags_with_counter_ntag)) == 0) {
|
||||
PrintAndLogEx(WARNING, "tag type does not have counters");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
bool is_ntag = (tagtype & tags_with_counter_ntag) != 0;
|
||||
if (is_ntag && (counter != 2)) {
|
||||
PrintAndLogEx(WARNING, "NTAG only has one counter at index 2");
|
||||
DropField();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t pack[4] = { 0, 0, 0, 0 };
|
||||
if (has_key) {
|
||||
if (ulev1_requestAuthentication(pwd, pack, sizeof(pack)) == PM3_EWRONGANSWER) {
|
||||
PrintAndLogEx(FAILED, "authentication failed UL-EV1/NTAG");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t current_counter[3] = { 0, 0, 0 };
|
||||
int len = ulev1_readCounter(counter, current_counter, sizeof(current_counter));
|
||||
if (len != sizeof(current_counter)) {
|
||||
PrintAndLogEx(FAILED, "failed to read old counter");
|
||||
if (is_ntag) {
|
||||
PrintAndLogEx(HINT, "NTAG detected, try reading with PWD");
|
||||
}
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint32_t current_counter_num = current_counter[0] | (current_counter[1] << 8) | (current_counter[2] << 16);
|
||||
PrintAndLogEx(INFO, "Current counter... " _GREEN_("%8d") " - " _GREEN_("%s"), current_counter_num, sprint_hex(current_counter, 3));
|
||||
|
||||
if ((tagtype & tags_with_counter_ntag) != 0) {
|
||||
PrintAndLogEx(WARNING, "NTAG detected, unable to manually increment counter");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t resp[1] = { 0x00 };
|
||||
if (ul_send_cmd_raw(increment_cmd, sizeof(increment_cmd), resp, sizeof(resp)) < 0) {
|
||||
PrintAndLogEx(FAILED, "failed to increment counter");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t new_counter[3] = { 0, 0, 0 };
|
||||
int new_len = ulev1_readCounter(counter, new_counter, sizeof(new_counter));
|
||||
if (new_len != sizeof(current_counter)) {
|
||||
PrintAndLogEx(FAILED, "failed to read new counter");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint32_t new_counter_num = new_counter[0] | (new_counter[1] << 8) | (new_counter[2] << 16);
|
||||
PrintAndLogEx(INFO, "New counter....... " _GREEN_("%8d") " - " _GREEN_("%s"), new_counter_num, sprint_hex(new_counter, 3));
|
||||
|
||||
DropField();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14AMfuList, AlwaysAvailable, "List MIFARE Ultralight / NTAG history"},
|
||||
|
@ -5845,6 +5958,7 @@ static command_t CommandTable[] = {
|
|||
{"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight-C - Authentication"},
|
||||
{"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Ultralight-C - Set 3DES key"},
|
||||
{"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"},
|
||||
{"incr", CmdHF14AMfUIncr, IfPm3Iso14443a, "Increments Ev1/NTAG counter"},
|
||||
{"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"ndefread", CmdHF14MfuNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||
{"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"},
|
||||
|
|
|
@ -732,6 +732,7 @@ static int CmdEM410xClone(const char *Cmd) {
|
|||
|
||||
packet.cmd = HTSF_82xx;
|
||||
memcpy(packet.pwd, "\xBB\xDD\x33\x99", HITAGS_PAGE_SIZE);
|
||||
packet.mode = HITAGS_UID_REQ_FADV;
|
||||
SendCommandNG(CMD_LF_HITAGS_WRITE, (uint8_t *)&packet, sizeof(packet));
|
||||
if (WaitForResponseTimeout(CMD_LF_HITAGS_WRITE, &resp, 4000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
|
|
|
@ -444,6 +444,96 @@ static int CmdLFHitagSRead(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFHitagSDump(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hitag hts dump",
|
||||
"Read all Hitag S memory and save to file\n"
|
||||
" Crypto mode: \n"
|
||||
" - key format ISK high + ISK low\n"
|
||||
" - default key 4F4E4D494B52 (ONMIKR)\n\n"
|
||||
" 8268/8310 password mode: \n"
|
||||
" - default password BBDD3399\n",
|
||||
"lf hitag hts dump --82xx -k BBDD3399 -> pwd mode\n"
|
||||
"lf hitag hts dump --crypto -> use def crypto\n"
|
||||
"lf hitag hts dump -k 4F4E4D494B52 -> crypto mode\n"
|
||||
"lf hitag hts dump --nrar 0102030411223344\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("8", "82xx", "8268/8310 mode"),
|
||||
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
|
||||
arg_lit0(NULL, "crypto", "crypto mode"),
|
||||
arg_str0("k", "key", "<hex>", "pwd or key, 4 or 6 hex bytes"),
|
||||
arg_int0("m", "mode", "<dec>", "response protocol mode. 0 (Standard 00110), 1 (Advanced 11000), 2 (Advanced 11001), 3 (Fast Advanced 11010) (def: 3)"),
|
||||
arg_str0("f", "file", "<fn>", "specify file name"),
|
||||
arg_lit0(NULL, "ns", "no save to file"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
lf_hitag_data_t packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
if (process_hitags_common_args(ctx, &packet) < 0) {
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
bool nosave = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// read all pages
|
||||
packet.page = 0;
|
||||
packet.page_count = 0;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HITAGS_READ, (uint8_t *) &packet, sizeof(packet));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_LF_HITAGS_READ, &resp, 5000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
print_error(resp.reason);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
lf_hts_read_response_t *card = (lf_hts_read_response_t *)resp.data.asBytes;
|
||||
|
||||
const int hts_mem_sizes[] = {1, 8, 64, 64};
|
||||
int mem_size = hts_mem_sizes[card->config_page.s.MEMT] * HITAGS_PAGE_SIZE;
|
||||
|
||||
hitags_config_t config = card->config_page.s;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
hitags_config_print(config);
|
||||
|
||||
if (nosave) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Called with no save option");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (fnlen < 1) {
|
||||
char *fptr = filename;
|
||||
fptr += snprintf(filename, sizeof(filename), "lf-hitags-");
|
||||
FillFileNameByUID(fptr, card->pages[HITAGS_UID_PADR], "-dump", HITAGS_PAGE_SIZE);
|
||||
}
|
||||
|
||||
pm3_save_dump(filename, (uint8_t *)card->pages, mem_size, jsfHitag);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFHitagSWrite(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hitag hts wrbl",
|
||||
|
@ -615,6 +705,7 @@ static command_t CommandTable[] = {
|
|||
{"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("General") " ------------------------"},
|
||||
{"reader", CmdLFHitagSReader, IfPm3Hitag, "Act like a Hitag S reader"},
|
||||
{"rdbl", CmdLFHitagSRead, IfPm3Hitag, "Read Hitag S page"},
|
||||
{"dump", CmdLFHitagSDump, IfPm3Hitag, "Dump Hitag S pages to a file"},
|
||||
{"wrbl", CmdLFHitagSWrite, IfPm3Hitag, "Write Hitag S page"},
|
||||
{"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Simulation") " -----------------------"},
|
||||
{"sim", CmdLFHitagSSim, IfPm3Hitag, "Simulate Hitag S transponder"},
|
||||
|
|
|
@ -1222,14 +1222,17 @@ static int DesfireAuthenticateEV1(DesfireContext_t *dctx, DesfireSecureChannel s
|
|||
|
||||
// - Encrypt our response
|
||||
if (secureChannel == DACd40) {
|
||||
// Original DESFire (MF3ICD40) silicon can only do encryption operations, so all PCD
|
||||
// side operations must be decrypt, even when encrypting when doing D40 compatible
|
||||
// secure channel operations
|
||||
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, RndA, rndlen, encRndA, true, true, IV);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, RndA, rndlen, encRndA, true, false, IV);
|
||||
|
||||
memcpy(both, encRndA, rndlen);
|
||||
bin_xor(rotRndB, encRndA, rndlen);
|
||||
|
||||
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, rotRndB, rndlen, encRndB, true, true, IV);
|
||||
DesfireCryptoEncDecEx(dctx, DCOMainKey, rotRndB, rndlen, encRndB, true, false, IV);
|
||||
|
||||
memcpy(both + rndlen, encRndB, rndlen);
|
||||
} else if (secureChannel == DACEV1) {
|
||||
|
|
|
@ -313,6 +313,10 @@ static void DesfireSecureChannelEncodeD40(DesfireContext_t *ctx, uint8_t cmd, ui
|
|||
size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType));
|
||||
|
||||
uint8_t mac[32] = {0};
|
||||
PrintAndLogEx(DEBUG, "MACing");
|
||||
// Even though original DESFire (MF3ICD40) silicon can only encrypt which means normally
|
||||
// every PCD operation must be decrypt, verifying a MAC involves the same operation on both
|
||||
// sides so this is still encrypt here
|
||||
DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, srcmaclen, NULL, true, true, mac);
|
||||
|
||||
if (DesfireEV1D40TransmitMAC(ctx, cmd)) {
|
||||
|
@ -889,4 +893,3 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De
|
|||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
|
|
@ -696,14 +696,18 @@ void print_progress(uint64_t count, uint64_t max, barMode_t style) {
|
|||
max = (count > max) ? count : max;
|
||||
#if defined(HAVE_READLINE)
|
||||
static int prev_cols = 0;
|
||||
int rows;
|
||||
rl_reset_screen_size(); // refresh Readline idea of the actual screen width
|
||||
rl_get_screen_size(&rows, &cols);
|
||||
int tmp_cols;
|
||||
rl_get_screen_size(NULL, &tmp_cols);
|
||||
// if cols==0: impossible to get screen size, e.g. when scripted
|
||||
if (tmp_cols != 0) {
|
||||
// don't call it if cols==0, it would segfault
|
||||
rl_reset_screen_size(); // refresh Readline idea of the actual screen width
|
||||
rl_get_screen_size(NULL, &cols);
|
||||
|
||||
if (cols < 36)
|
||||
return;
|
||||
if (cols < 36)
|
||||
return;
|
||||
}
|
||||
|
||||
(void) rows;
|
||||
if (prev_cols > cols) {
|
||||
PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ "");
|
||||
}
|
||||
|
|
|
@ -554,8 +554,8 @@ size_t concatbits(uint8_t *dest, int dest_offset, const uint8_t *src, int src_of
|
|||
end = nbits;
|
||||
step = 1;
|
||||
} else {
|
||||
i = nbits;
|
||||
end = 0;
|
||||
i = nbits - 1;
|
||||
end = -1;
|
||||
step = -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -366,7 +366,6 @@ void Flashmem_print_status(void) {
|
|||
);
|
||||
}
|
||||
|
||||
Dbprintf(" Device.................. " _YELLOW_("%s"), spi_flash_data.device);
|
||||
Dbprintf(" Memory size............. " _YELLOW_("%d kB (%d pages * 64k)"), spi_flash_pages64k * 64, spi_flash_pages64k);
|
||||
|
||||
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
@ -442,21 +441,13 @@ bool FlashDetect(void) {
|
|||
} else {
|
||||
if (g_dbglevel > 3) Dbprintf("Flash_ReadID failed reading Mfr/Dev (0x90)");
|
||||
}
|
||||
// default device is 'unknown'
|
||||
spi_flash_data.device = SpiFlashTable[0].device;
|
||||
|
||||
// Check JEDEC data is valid, compare the reported device types and then calculate the number of pages
|
||||
// It is covering the most (known) cases of devices but probably there are vendors with different data
|
||||
// They will be handled when there is such cases
|
||||
if (ret) {
|
||||
for (int i = 0; i < ARRAYLEN(SpiFlashTable); i++) {
|
||||
if (SpiFlashTable[i].manufacturer_id == spi_flash_data.manufacturer_id) {
|
||||
if (SpiFlashTable[i].jedec_id == spi_flash_data.jedec_id) {
|
||||
spi_flash_pages64k = SpiFlashTable[i].pages64k;
|
||||
spi_flash_data.device = SpiFlashTable[i].device;
|
||||
break;
|
||||
}
|
||||
if (SpiFlashTable[i].device_id == spi_flash_data.device_id) {
|
||||
spi_flash_data.device = SpiFlashTable[i].device;
|
||||
break;
|
||||
}
|
||||
if (spi_flash_data.jedec_id > 0 && spi_flash_data.jedec_id < 0xFFFF) {
|
||||
if (((spi_flash_data.device_id + 1) & 0x0F) == (spi_flash_data.jedec_id & 0x000F)) {
|
||||
spi_flash_pages64k = 1 << (spi_flash_data.jedec_id & 0x000F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,36 +140,8 @@ typedef struct {
|
|||
uint8_t manufacturer_id;
|
||||
uint8_t device_id;
|
||||
uint16_t jedec_id;
|
||||
uint8_t pages64k;
|
||||
char *device;
|
||||
} spi_flash_t;
|
||||
|
||||
static const spi_flash_t SpiFlashTable[] = {
|
||||
// first element is the default of 4 * 64kB pages (256kB)
|
||||
{ 0x00, 0x00, 0x0000, 4, "unknown" }, // 256k
|
||||
// Manufacturer: Puya
|
||||
{ 0x85, 0x00, 0x6015, 32, "P25Q16H" }, // 2048k
|
||||
/// Manufacturer: Renesas
|
||||
{ 0x1F, 0x46, 0x0000, 32, "AT25XE161D" }, // 2048k
|
||||
{ 0x1F, 0x47, 0x0000, 64, "AT25XE321D" }, // 4096k
|
||||
// Manufacturer: Winbond
|
||||
{ 0xEF, 0x00, 0x3012, 4, "W25X20BV" }, // 256k
|
||||
{ 0xEF, 0x00, 0x3013, 8, "W25X40BV" }, // 512k
|
||||
|
||||
{ 0xEF, 0x00, 0x4013, 8, "W25Q40BV" }, // 512k
|
||||
{ 0xEF, 0x00, 0x4014, 16, "W25Q80BV" }, // 1024k
|
||||
{ 0xEF, 0x14, 0x4015, 32, "W25Q16BV" }, // 2048k
|
||||
{ 0xEF, 0x15, 0x4016, 64, "W25Q32BV" }, // 4096k
|
||||
|
||||
{ 0xEF, 0x21, 0x7022, 4, "W25Q02JV" },
|
||||
// identified by Manufacturer /Device ID
|
||||
// { 0xEF, 0x05, 0x0000, 1, "Winbond!!!" },
|
||||
{ 0xEF, 0x10, 0x0000, 2, "W25*10BV!!!" }, // 128k
|
||||
{ 0xEF, 0x11, 0x0000, 4, "W25*20BV" }, // 256k
|
||||
{ 0xEF, 0x12, 0x0000, 8, "W25*40BV" }, // 512k
|
||||
{ 0xEF, 0x13, 0x0000, 16, "W25*80BV" } // 1024k
|
||||
};
|
||||
|
||||
extern uint8_t spi_flash_pages64k;
|
||||
|
||||
bool FlashDetect(void);
|
||||
|
|
|
@ -36,22 +36,22 @@ Therefore a flash address can be interpreted as such:
|
|||
|
||||
Page 0:
|
||||
* available for user data
|
||||
* to dump it: `mem dump f page0_dump o 0 l 65536`
|
||||
* to dump it: `mem dump -f page0_dump -o 0 -l 65536`
|
||||
* to erase it: `mem wipe p 0`
|
||||
|
||||
Page 1:
|
||||
* available for user data
|
||||
* to dump it: `mem dump f page1_dump o 65536 l 65536`
|
||||
* to dump it: `mem dump -f page1_dump -o 65536 -l 65536`
|
||||
* to erase it: `mem wipe p 1`
|
||||
|
||||
Page 2:
|
||||
* available for user data
|
||||
* to dump it: `mem dump f page2_dump o 131072 l 65536`
|
||||
* to dump it: `mem dump -f page2_dump -o 131072 -l 65536`
|
||||
* to erase it: `mem wipe p 2`
|
||||
|
||||
Page 3:
|
||||
* used by Proxmark3 RDV4 specific functions: flash signature and keys dictionaries, see below for details
|
||||
* to dump it: `mem dump f page3_dump o 196608 l 65536`
|
||||
* to dump it: `mem dump -f page3_dump -o 196608 -l 65536`
|
||||
* to erase it:
|
||||
* **Beware** it will erase your flash signature so better to back it up first as you won't be able to regenerate it by yourself!
|
||||
* edit the source code to enable Page 3 as a valid input in the `mem wipe` command.
|
||||
|
@ -63,8 +63,8 @@ Page 3:
|
|||
Page3 is used as follows by the Proxmark3 RDV4 firmware:
|
||||
|
||||
* **MF_KEYS**
|
||||
* offset: page 3 sector 9 (0x9) @ 3*0x10000+9*0x1000=0x39000
|
||||
* length: 2 sectors
|
||||
* offset: page 3 sector 5 (0x5) @ 3*0x10000+5*0x1000=0x35000
|
||||
* length: 6 sectors
|
||||
|
||||
* **ICLASS_KEYS**
|
||||
* offset: page 3 sector 11 (0xB) @ 3*0x10000+11*0x1000=0x3B000
|
||||
|
|
|
@ -117,6 +117,17 @@ or
|
|||
proxmark3 /dev/ttyACM0 --flash --unlock-bootloader --image /tmp/my-bootrom.elf --image /tmp/my-fullimage.elf
|
||||
```
|
||||
|
||||
## Updating SPI flash structure and contents (RDV4.x, some PM3 Easy variants)
|
||||
^[Top](#top)
|
||||
|
||||
For the devices equipped with external SPI flash memory chip in some cases it might be essential to update the memory structure as well as to upload new keys from the dictionaries. To do so execute following command inside the client:
|
||||
|
||||
```
|
||||
[usb] pm3 --> script run init_rdv4
|
||||
```
|
||||
|
||||
For more details prease refer to [this doc](./2_Configuration-and-Verification.md).
|
||||
|
||||
### The button trick
|
||||
^[Top](#top)
|
||||
|
||||
|
|
45
fpga/xc2s50-5-tq144.ucf
Normal file
45
fpga/xc2s50-5-tq144.ucf
Normal file
|
@ -0,0 +1,45 @@
|
|||
# See the schematic for the pin assignment.
|
||||
|
||||
NET "adc_d<0>" LOC = "P54" ;
|
||||
NET "adc_d<1>" LOC = "P57" ;
|
||||
NET "adc_d<2>" LOC = "P59" ;
|
||||
NET "adc_d<3>" LOC = "P60" ;
|
||||
NET "adc_d<4>" LOC = "P62" ;
|
||||
NET "adc_d<5>" LOC = "P63" ;
|
||||
NET "adc_d<6>" LOC = "P65" ;
|
||||
NET "adc_d<7>" LOC = "P67" ;
|
||||
#NET "cross_hi" LOC = "P88" ;
|
||||
#NET "miso" LOC = "P40" ;
|
||||
NET "adc_clk" LOC = "P75" ;
|
||||
NET "adc_noe" LOC = "P74" ;
|
||||
NET "ck_1356meg" LOC = "P15" ;
|
||||
NET "ck_1356megb" LOC = "P12" ;
|
||||
NET "cross_lo" LOC = "P19" ;
|
||||
NET "dbg" LOC = "P112" ;
|
||||
NET "mosi" LOC = "P80" ;
|
||||
NET "ncs" LOC = "P79" ;
|
||||
NET "pck0" LOC = "P91" ;
|
||||
NET "pwr_hi" LOC = "P31" ;
|
||||
NET "pwr_lo" LOC = "P30" ;
|
||||
NET "pwr_oe1" LOC = "P28" ;
|
||||
NET "pwr_oe2" LOC = "P27" ;
|
||||
NET "pwr_oe3" LOC = "P26" ;
|
||||
NET "pwr_oe4" LOC = "P21" ;
|
||||
NET "spck" LOC = "P88" ;
|
||||
NET "ssp_clk" LOC = "P43" ;
|
||||
NET "ssp_din" LOC = "P99" ;
|
||||
NET "ssp_dout" LOC = "P94" ;
|
||||
NET "ssp_frame" LOC = "P100" ;
|
||||
|
||||
# definition of Clock nets:
|
||||
NET "ck_1356meg" TNM_NET = "clk_net_1356" ;
|
||||
NET "ck_1356megb" TNM_NET = "clk_net_1356b";
|
||||
NET "pck0" TNM_NET = "clk_net_pck0" ;
|
||||
NET "spck" TNM_NET = "clk_net_spck" ;
|
||||
|
||||
# Timing specs of clock nets:
|
||||
TIMEGRP "clk_net_1356_all" = "clk_net_1356" "clk_net_1356b" ;
|
||||
TIMESPEC "TS_1356MHz" = PERIOD "clk_net_1356_all" 74 ns HIGH 37 ns ;
|
||||
TIMESPEC "TS_24MHz" = PERIOD "clk_net_pck0" 42 ns HIGH 21 ns ;
|
||||
TIMESPEC "TS_4MHz" = PERIOD "clk_net_spck" 250 ns HIGH 125 ns ;
|
||||
|
|
@ -161,7 +161,7 @@ typedef struct {
|
|||
uint8_t logdata_1[4];
|
||||
uint8_t nonce[4];
|
||||
|
||||
//Hitag s section
|
||||
// Hitag S section
|
||||
uint8_t mode;
|
||||
} PACKED lf_hitag_data_t;
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
// 0x3E000 - 1 4kb sector = settings
|
||||
// 0x3D000 - 1 4kb sector = default T55XX keys dictionary
|
||||
// 0x3B000 - 1 4kb sector = default ICLASS keys dictionary
|
||||
// 0x38000 - 3 4kb sectors = default MFC keys dictionary
|
||||
// 0x35000 - 6 4kb sectors = default MFC keys dictionary
|
||||
//
|
||||
#ifndef FLASH_MEM_BLOCK_SIZE
|
||||
# define FLASH_MEM_BLOCK_SIZE 256
|
||||
|
@ -95,9 +95,9 @@
|
|||
# define DEFAULT_ICLASS_KEYS_OFFSET_P(p64k) (DEFAULT_T55XX_KEYS_OFFSET_P(p64k) - DEFAULT_ICLASS_KEYS_LEN)
|
||||
#endif
|
||||
|
||||
// Reserved space for MIFARE Keys = 12 kb
|
||||
// Reserved space for MIFARE Keys = 24 kb
|
||||
#ifndef DEFAULT_MF_KEYS_OFFSET
|
||||
# define DEFAULT_MF_KEYS_LEN (0x3000)
|
||||
# define DEFAULT_MF_KEYS_LEN (0x6000)
|
||||
# define DEFAULT_MF_KEYS_OFFSET (DEFAULT_ICLASS_KEYS_OFFSET - DEFAULT_MF_KEYS_LEN)
|
||||
# define DEFAULT_MF_KEYS_MAX ((DEFAULT_MF_KEYS_LEN - 2) / 6)
|
||||
#endif
|
||||
|
|
|
@ -12,12 +12,13 @@ from colors import color
|
|||
|
||||
debug = False
|
||||
|
||||
|
||||
def guess_curvename(signature):
|
||||
siglen = (len(signature) // 2) & 0xfe
|
||||
if siglen == 32:
|
||||
curves = ["secp128r1", "secp128r2"]
|
||||
elif siglen == 48:
|
||||
curves = ["secp192k1", "secp192r1"]
|
||||
curves = ["secp192k1", "prime192v1"]
|
||||
elif siglen == 56:
|
||||
curves = ["secp224k1", "secp224r1"]
|
||||
elif siglen == 64:
|
||||
|
@ -31,6 +32,7 @@ def guess_curvename(signature):
|
|||
raise ValueError("Unsupported signature size %s" % lenstr)
|
||||
return curves
|
||||
|
||||
|
||||
def recover(data, signature, curvename, alghash=None):
|
||||
recovered = set()
|
||||
try:
|
||||
|
@ -60,6 +62,7 @@ def recover(data, signature, curvename, alghash=None):
|
|||
pass
|
||||
return recovered
|
||||
|
||||
|
||||
def recover_multiple(uids, sigs, curvename, alghash=None):
|
||||
recovered = set()
|
||||
assert len(uids) == len(sigs)
|
||||
|
@ -82,6 +85,7 @@ def recover_multiple(uids, sigs, curvename, alghash=None):
|
|||
recovered &= recovered_tmp
|
||||
return recovered
|
||||
|
||||
|
||||
def selftests():
|
||||
tests = [
|
||||
{'name': "Mifare Ultralight EV1",
|
||||
|
@ -158,16 +162,16 @@ def selftests():
|
|||
# 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"],
|
||||
# 'pk': ""},
|
||||
{'name': "MIFARE Plus Trojka",
|
||||
# uses secp224r1, None,
|
||||
'samples': ["04B59F6A226F82", "6F577EB7F570D74DB6250477427F68A0088762BD318767537122919A7916597149F9D16D8B135E9BF826FB28AE293F3168661CD4A049FAED",
|
||||
"04B44A82D80F92", "A0868ECF26733D3C3C838D055968B4559F77693CC3E346E3A4741BC826801F8360FD88857BEC440AAD3A21153D64302DEB6F5ED40B15C3F7"],
|
||||
'pk': "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"},
|
||||
# uses secp224r1, None,
|
||||
'samples': ["04B59F6A226F82", "6F577EB7F570D74DB6250477427F68A0088762BD318767537122919A7916597149F9D16D8B135E9BF826FB28AE293F3168661CD4A049FAED",
|
||||
"04B44A82D80F92", "A0868ECF26733D3C3C838D055968B4559F77693CC3E346E3A4741BC826801F8360FD88857BEC440AAD3A21153D64302DEB6F5ED40B15C3F7"],
|
||||
'pk': "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"},
|
||||
|
||||
# {'name': "MIFARE Ultralight AES",
|
||||
# uses NID_secp192r1, OpenSSL doesn't support it. This is commented out until that day.
|
||||
# 'samples': ["045E4CC2451390", "C9BBDA1B99EB6634CDFD8E3251AC5C4742EA5FA507B8A8A8B39B19AB7340D173331589C54C56C49F0CCA6DDBAC1E492A",
|
||||
# "043F88C2451390", "5C2055A7373F119C3FDD9843020B06AA0E6DE18C16496C425C4AD971A50F05FA1A67B9E39CA60C355EEEEBF8214A84A5"],
|
||||
# 'pk': "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"},
|
||||
{'name': "MIFARE Ultralight AES",
|
||||
# uses prime192v1, None,
|
||||
'samples': ["045E4CC2451390", "C9BBDA1B99EB6634CDFD8E3251AC5C4742EA5FA507B8A8A8B39B19AB7340D173331589C54C56C49F0CCA6DDBAC1E492A",
|
||||
"043F88C2451390", "5C2055A7373F119C3FDD9843020B06AA0E6DE18C16496C425C4AD971A50F05FA1A67B9E39CA60C355EEEEBF8214A84A5"],
|
||||
'pk': "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"},
|
||||
|
||||
{'name': "MIFARE Classic / QL88",
|
||||
'samples': ["30933C61", "AEA4DD0B800FAC63D4DE08EE91F4650ED825FD6B4D7DEEE98DBC9BAE10BE003E",
|
||||
|
@ -234,13 +238,15 @@ def selftests():
|
|||
print("Tests: ( %s )" % [fail, ok][succeeded])
|
||||
print("")
|
||||
|
||||
|
||||
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])
|
||||
print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b"
|
||||
% sys.argv[0])
|
||||
exit(1)
|
||||
uids, sigs = sys.argv[1:][::2], sys.argv[1:][1::2]
|
||||
once = True
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue