Merge branch 'master' into master

Signed-off-by: Iceman <iceman@iuse.se>
This commit is contained in:
Iceman 2024-12-07 05:18:41 +01:00 committed by GitHub
commit 92e8dea093
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 954 additions and 328 deletions

View file

@ -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... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- 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 simulation function to `hf iclass legrec` (@antiklesys)
- Added keys from Momentum firmware projects. (@onovy) - Added keys from Momentum firmware projects. (@onovy)
- Added Dutch Statistics Agency default key (@eagle00789)
## [Orca.4.19552][2024-11-22] ## [Orca.4.19552][2024-11-22]
- Fixed `hf_legic.lua` - removed bit32 commands from the script (@diorch1968) - Fixed `hf_legic.lua` - removed bit32 commands from the script (@diorch1968)

View file

@ -1778,7 +1778,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES: { 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; break;
} }
case CMD_HF_MIFARE_ACQ_NONCES: { case CMD_HF_MIFARE_ACQ_NONCES: {

View file

@ -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 // acquire static encrypted nonces in order to perform the attack described in
// Philippe Teuwen, "MIFARE Classic: exposing the static encrypted nonce variant" // 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 mpcs = {0, 0};
struct Crypto1State *pcs; struct Crypto1State *pcs;
pcs = &mpcs; pcs = &mpcs;
@ -1055,6 +1055,10 @@ int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool
uint8_t buf[MIFARE_BLOCK_SIZE] = {0x00}; uint8_t buf[MIFARE_BLOCK_SIZE] = {0x00};
uint64_t ui64Key = bytes_to_num(key, 6); uint64_t ui64Key = bytes_to_num(key, 6);
bool with_data = flags & 1; bool with_data = flags & 1;
bool without_backdoor = (flags >> 1) & 1;
if (with_data && without_backdoor) {
return PM3_EINVARG;
}
uint32_t cuid = 0; uint32_t cuid = 0;
int16_t isOK = PM3_SUCCESS; int16_t isOK = PM3_SUCCESS;
uint8_t cascade_levels = 0; uint8_t cascade_levels = 0;
@ -1072,121 +1076,230 @@ int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool
LED_C_ON(); LED_C_ON();
for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) { if (without_backdoor) {
uint16_t sec_gap = sec; uint32_t nt1 = 0;
if (sec >= MIFARE_1K_MAXSECTOR) {
// gap between user blocks and advanced verification method blocks iso14a_card_select_t card_info;
sec_gap += 16; 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; switch (card_info.uidlen) {
for (uint8_t keyType = 0; keyType < 2; keyType++) { case 4 :
// Test if the action was cancelled cascade_levels = 1;
if (BUTTON_PRESS()) {
isOK = PM3_EOPABORTED;
break; 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 uint16_t blockNo = sec_gap * 4;
iso14a_card_select_t card_info; for (uint8_t keyType = 0; keyType < 2; keyType++) {
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) { // Test if the action was cancelled
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (ALL)"); if (BUTTON_PRESS()) {
isOK = PM3_ERFTRANS; 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; goto out;
} }
switch (card_info.uidlen) { // store nt_enc
case 4 : memcpy(buf + (keyType * 8) + 4, receivedAnswer, 4);
cascade_levels = 1; nt_enc = bytes_to_num(receivedAnswer, 4);
break; uint8_t nt_par_err = ((((par_enc[0] >> 7) & 1) ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3 |
case 7 : (((par_enc[0] >> 6) & 1) ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2 |
cascade_levels = 2; (((par_enc[0] >> 5) & 1) ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1 |
break; (((par_enc[0] >> 4) & 1) ^ oddparity8((nt_enc >> 0) & 0xFF)));
case 10: // 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);
cascade_levels = 3; // store nt_par_err
break; buf[(keyType * 8) + 2] = nt_par_err;
default: buf[(keyType * 8) + 3] = 0xAA; // extra check to tell we have nt/nt_enc/par_err
break;
} // send some crap to fail auth
have_uid = true; CHK_TIMEOUT();
} else { // no need for anticollision. We can directly select the card
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) { if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)"); if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
isOK = PM3_ERFTRANS; isOK = PM3_ERFTRANS;
goto out; 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; } else {
if (mifare_classic_authex_cmd(pcs, cuid, blockNo, MIFARE_AUTH_KEYA + keyType + 4, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) { for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error"); uint16_t sec_gap = sec;
isOK = PM3_ESOFT; if (sec >= MIFARE_1K_MAXSECTOR) {
goto out; // gap between user blocks and advanced verification method blocks
}; sec_gap += 16;
if ((with_data) && (keyType == 0)) { }
uint8_t data[16]; uint16_t blockNo = sec_gap * 4;
uint8_t blocks = 4; for (uint8_t keyType = 0; keyType < 2; keyType++) {
if (blockNo >= MIFARE_1K_MAXSECTOR * 4) { // Test if the action was cancelled
// special RF08S advanced authentication blocks, let's dump in emulator just in case if (BUTTON_PRESS()) {
blocks = 8; isOK = PM3_EOPABORTED;
break;
} }
for (uint16_t tb = blockNo; tb < blockNo + blocks; tb++) { if (have_uid == false) { // need a full select cycle to get the uid first
memset(data, 0x00, sizeof(data)); iso14a_card_select_t card_info;
int res = mifare_classic_readblock(pcs, tb, data); if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
if (res == 1) { if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (ALL)");
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Read error"); isOK = PM3_ERFTRANS;
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
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; 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) { uint32_t nt1 = 0;
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)"); if (mifare_classic_authex_cmd(pcs, cuid, blockNo, MIFARE_AUTH_KEYA + keyType + 4, ui64Key, AUTH_FIRST, &nt1, NULL, NULL, NULL, false, false)) {
isOK = PM3_ERFTRANS; if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth1 error");
goto out; isOK = PM3_ESOFT;
} 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"); if ((with_data) && (keyType == 0)) {
isOK = PM3_ESOFT; uint8_t data[16];
goto out; 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 if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
len = mifare_sendcmd_short(pcs, AUTH_NESTED, MIFARE_AUTH_KEYA + keyType, blockNo, receivedAnswer, sizeof(receivedAnswer), par_enc, NULL); if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Can't select card (UID)");
if (len != 4) { isOK = PM3_ERFTRANS;
if (g_dbglevel >= DBG_ERROR) Dbprintf("AcquireStaticEncryptedNonces: Auth2 error len=%d", len); goto out;
isOK = PM3_ESOFT; }
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: out:
@ -1194,7 +1307,7 @@ out:
crypto1_deinit(pcs); crypto1_deinit(pcs);
LED_B_ON(); LED_B_ON();
if (reply) { 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(); LED_B_OFF();
@ -3127,7 +3240,8 @@ void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *
goto OUT; goto OUT;
}; };
first_nt_counter++; 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) { if (need_first_auth) {
cuid = 0; cuid = 0;
@ -3204,6 +3318,7 @@ void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *
} }
oldntenc = ntenc; oldntenc = ntenc;
} }
}
data[1] = (cuid >> 24) & 0xFF; data[1] = (cuid >> 24) & 0xFF;
data[2] = (cuid >> 16) & 0xFF; data[2] = (cuid >> 16) & 0xFF;
@ -3367,7 +3482,8 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) {
retval = PM3_ESOFT; retval = PM3_ESOFT;
goto OUT; 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[0];
cmd[ofs++] = card_info->atqa[1]; cmd[ofs++] = card_info->atqa[1];
AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE); AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE);

View file

@ -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 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); 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 MifareAcquireNonces(uint32_t arg0, uint32_t flags);
void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem); void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem);
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);

View file

@ -983,3 +983,12 @@ int nonce_distance(uint32_t from, uint32_t to) {
int nonce16_index(uint16_t nt) { int nonce16_index(uint16_t nt) {
return nonce16_distance(0x0100, nt) + 1; 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);
}

View file

@ -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 nonce_distance(uint32_t from, uint32_t to);
int nonce16_distance(uint16_t x, uint16_t y); int nonce16_distance(uint16_t x, uint16_t y);
int nonce16_index(uint16_t nt); int nonce16_index(uint16_t nt);
uint32_t rewind_nonce(uint32_t from, uint16_t dist);
#endif #endif

View file

@ -2755,7 +2755,8 @@ D37C8F1793F7
543071543071 543071543071
5F01015F0101 5F01015F0101
200510241234 200510241234
# Momentum-Firmware #
# Momentum-Firmware 20241201
AC935925A876 AC935925A876
ADC169F922CB ADC169F922CB
AD00EFD353E4 AD00EFD353E4
@ -3022,3 +3023,18 @@ F833E24C3F1C
93FB38FE585A 93FB38FE585A
96AECCC0F7EB 96AECCC0F7EB
96227EDADBCF 96227EDADBCF
#
# BW Kantine
56cf3acd90ca
542089792be2
5420aeada758
#
# CSC Laundry
212223242555
717273747555
#
# Hotel cards, BETECH brand, Vietnam
AAC34D9A4E65
#
# Dutch Statistics Agency (CBS)
DC7B15AA0938

View file

@ -22,6 +22,8 @@ F9DCEBA0
89A69E60 89A69E60
# ref lock # ref lock
314159E0 314159E0
#Zonsin ZX-COPY10
7B3D5C48
# ref. http://www.proxmark.org/forum/viewtopic.php?pid=28115#p28115 # ref. http://www.proxmark.org/forum/viewtopic.php?pid=28115#p28115
AA55BBBB AA55BBBB
# ref. http://www.proxmark.org/forum/viewtopic.php?pid=33376#p33376 # ref. http://www.proxmark.org/forum/viewtopic.php?pid=33376#p33376

View file

@ -50,20 +50,20 @@ arguments = [[
-c read magic configuration -c read magic configuration
-u UID (8-20 hexsymbols), set UID on tag -u UID (8-20 hexsymbols), set UID on tag
-t tag type to impersonate -t tag type to impersonate
1 = Mifare Mini S20 4-byte 1 = Mifare Mini S20 4-byte | 15 = NTAG 210
2 = Mifare Mini S20 7-byte 15 = NTAG 210 2 = Mifare Mini S20 7-byte | 16 = NTAG 212
3 = Mifare Mini S20 10-byte 16 = NTAG 212 3 = Mifare Mini S20 10-byte | 17 = NTAG 213
4 = Mifare 1k S50 4-byte 17 = NTAG 213 4 = Mifare 1k S50 4-byte | 18 = NTAG 215
5 = Mifare 1k S50 7-byte 18 = NTAG 215 5 = Mifare 1k S50 7-byte | 19 = NTAG 216
6 = Mifare 1k S50 10-byte 19 = NTAG 216 6 = Mifare 1k S50 10-byte | 20 = NTAG I2C 1K
7 = Mifare 4k S70 4-byte 20 = NTAG I2C 1K 7 = Mifare 4k S70 4-byte | 21 = NTAG I2C 2K
8 = Mifare 4k S70 7-byte 21 = NTAG I2C 2K 8 = Mifare 4k S70 7-byte | 22 = NTAG I2C 1K PLUS
9 = Mifare 4k S70 10-byte 22 = NTAG I2C 1K PLUS 9 = Mifare 4k S70 10-byte | 23 = NTAG I2C 2K PLUS
*** 10 = UL - NOT WORKING FULLY 23 = NTAG I2C 2K PLUS *** 10 = UL - NOT WORKING FULLY | 24 = NTAG 213F
*** 11 = UL-C - NOT WORKING FULLY 24 = NTAG 213F *** 11 = UL-C - NOT WORKING FULLY | 25 = NTAG 216F
12 = UL EV1 48b 25 = NTAG 216F 12 = UL EV1 48b |
13 = UL EV1 128b 13 = UL EV1 128b |
*** 14 = UL Plus - NOT WORKING YET *** 14 = UL Plus - NOT WORKING YET |
-p NTAG password (8 hexsymbols), set NTAG password on tag. -p NTAG password (8 hexsymbols), set NTAG password on tag.
-a NTAG pack ( 4 hexsymbols), set NTAG pack 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. -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. -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. -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) -k Ultimate Magic Card Key (IF DIFFERENT THAN DEFAULT 00000000)
]] ]]
--- ---
@ -110,6 +114,7 @@ local function help()
print(usage) print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset) print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments) print(arguments)
print(arguments2)
print(ansicolors.cyan..'Example usage'..ansicolors.reset) print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example) print(example)
end end
@ -186,6 +191,7 @@ local function read_config()
end end
-- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu -- 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) 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 atqaf = atqa1..' '..atqa2
cardtype, cardprotocol, gtustr, atsstr = 'unknown', 'unknown', 'unknown', 'unknown' cardtype, cardprotocol, gtustr, atsstr = 'unknown', 'unknown', 'unknown', 'unknown'
if magicconfig == nil then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end 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(' - Version ', cversion)
print(' - Signature ', signature1..signature2) print(' - Signature ', signature1..signature2)
end end
print(' - Max R/W Block ', maxRWblk)
end end
lib14a.disconnect() lib14a.disconnect()
return true, 'Ok' return true, 'Ok'
@ -637,6 +644,26 @@ local function write_ulm(ulm)
return true, 'Ok' return true, 'Ok'
end 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. -- Set type for magic card presets.
local function set_type(tagtype) local function set_type(tagtype)
-- tagtype checks -- tagtype checks
@ -649,6 +676,7 @@ local function set_type(tagtype)
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900") send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233') write_uid('04112233')
write_maxRWblk('13')
-- Setting Mifare mini S20 7-byte -- Setting Mifare mini S20 7-byte
elseif tagtype == 2 then elseif tagtype == 2 then
print('Setting: Ultimate Magic card to Mifare mini S20 7-byte') print('Setting: Ultimate Magic card to Mifare mini S20 7-byte')
@ -656,6 +684,7 @@ local function set_type(tagtype)
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900") send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_maxRWblk('13')
-- Setting Mifare mini S20 10-byte -- Setting Mifare mini S20 10-byte
elseif tagtype == 3 then elseif tagtype == 3 then
print('Setting: Ultimate Magic card to Mifare mini S20 10-byte') print('Setting: Ultimate Magic card to Mifare mini S20 10-byte')
@ -663,6 +692,7 @@ local function set_type(tagtype)
send("CF".._key.."F000020000000002000978009102DABC19101011121314151684000900") send("CF".._key.."F000020000000002000978009102DABC19101011121314151684000900")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566778899') write_uid('04112233445566778899')
write_maxRWblk('13')
-- Setting Mifare 1k S50 4--byte -- Setting Mifare 1k S50 4--byte
elseif tagtype == 4 then elseif tagtype == 4 then
print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte') print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte')
@ -670,6 +700,7 @@ local function set_type(tagtype)
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800") send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233') write_uid('04112233')
write_maxRWblk('3F')
-- Setting Mifare 1k S50 7-byte -- Setting Mifare 1k S50 7-byte
elseif tagtype == 5 then elseif tagtype == 5 then
print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte') print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte')
@ -677,6 +708,7 @@ local function set_type(tagtype)
send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800") send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_maxRWblk('3F')
-- Setting Mifare 1k S50 10-byte -- Setting Mifare 1k S50 10-byte
elseif tagtype == 6 then elseif tagtype == 6 then
print('Setting: Ultimate Magic card to Mifare 1k S50 10-byte') print('Setting: Ultimate Magic card to Mifare 1k S50 10-byte')
@ -684,6 +716,7 @@ local function set_type(tagtype)
send("CF".._key.."F000020000000002000978009102DABC19101011121314151684000800") send("CF".._key.."F000020000000002000978009102DABC19101011121314151684000800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566778899') write_uid('04112233445566778899')
write_maxRWblk('3F')
-- Setting Mifare 4k S70 4-byte -- Setting Mifare 4k S70 4-byte
elseif tagtype == 7 then elseif tagtype == 7 then
print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte') print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte')
@ -691,6 +724,7 @@ local function set_type(tagtype)
send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800") send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233') write_uid('04112233')
write_maxRWblk('FF')
-- Setting Mifare 4k S70 7-byte -- Setting Mifare 4k S70 7-byte
elseif tagtype == 8 then elseif tagtype == 8 then
print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte') print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte')
@ -698,6 +732,7 @@ local function set_type(tagtype)
send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800") send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566') write_uid('04112233445566')
write_maxRWblk('FF')
-- Setting Mifare 4k S70 10-byte -- Setting Mifare 4k S70 10-byte
elseif tagtype == 9 then elseif tagtype == 9 then
print('Setting: Ultimate Magic card to Mifare 4k S70 10-byte') print('Setting: Ultimate Magic card to Mifare 4k S70 10-byte')
@ -705,6 +740,7 @@ local function set_type(tagtype)
send("CF".._key.."F000020000000002000978009102DABC19101011121314151682001800") send("CF".._key.."F000020000000002000978009102DABC19101011121314151682001800")
lib14a.disconnect() lib14a.disconnect()
write_uid('04112233445566778899') write_uid('04112233445566778899')
write_maxRWblk('FF')
-- Setting UL -- Setting UL
elseif tagtype == 10 then elseif tagtype == 10 then
print('Setting: Ultimate Magic card to UL') print('Setting: Ultimate Magic card to UL')
@ -1016,7 +1052,7 @@ function main(args)
local err, msg local err, msg
if #args == 0 then return help() end if #args == 0 then return help() end
-- Read the parameters -- 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 -- help
if o == "h" then return help() end if o == "h" then return help() end
-- set Ultimate Magic Card Key for read write -- 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 if o == "m" then err, msg = write_ulm(a) end
-- write UL protocol -- write UL protocol
if o == "n" then err, msg = write_ulp(a) end 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 if err == nil then return oops(msg) end
end end
end end

View file

@ -12,62 +12,118 @@ except ModuleNotFoundError:
return str(s) return str(s)
spi = { spi = {
0x68:{
"manufacturer": "Boya",
"jedec" : {
0x40: {
0x15: {
"part": "BY25Q16BS",
"size": "16mbits",
"sizeB": "2MB",
},
},
},
},
0x85:{ 0x85:{
"manufacturer": "Puya", "manufacturer": "Puya",
0x60: { "jedec" : {
0x15: { 0x60: {
"part": "P25Q16H", 0x15: {
"size": "16mbits", "part": "P25Q16H",
"sizeB": "2MB", "size": "16mbits",
"sizeB": "2MB",
},
0x16: {
"part": "P25Q32H",
"size": "32mbits",
"sizeB": "4MB",
},
0x17: {
"part": "P25Q64H",
"size": "64mbits",
"sizeB": "8MB",
},
}, },
}, },
}, },
0xEF:{ 0xEF:{
"manufacturer": "Winbond", "manufacturer": "Winbond",
0x30: { "jedec" : {
0x11: { 0x30: {
"part": "W25X10BV", 0x11: {
"size": "1mbits", "part": "W25X10BV",
"sizeB": "128KB", "size": "1mbits",
"sizeB": "128KB",
},
0x12: {
"part": "W25X20BV",
"size": "2mbits",
"sizeB": "256KB",
},
0x13: {
"part": "W25X40BV",
"size": "4mbits",
"sizeB": "512KB",
},
}, },
0x12: { 0x40: {
"part": "W25X20BV", 0x12: {
"size": "2mbits", "part": "W25Q20BV",
"sizeB": "256KB", "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: { 0x70: {
"part": "W25X40BV", 0x14: {
"size": "4mbits", "part": "W25Q80JV",
"sizeB": "512KB", "size": "8mbits",
}, "sizeB": "1MB",
}, },
0x40: { 0x15: {
0x13: { "part": "W25Q16JV",
"part": "W25Q40BV", "size": "16mbits",
"size": "4mbits", "sizeB": "2MB",
"sizeB": "512KB", },
}, 0x16: {
0x14: { "part": "W25Q32JV",
"part": "W25Q80BV", "size": "32mbits",
"size": "8mbits", "sizeB": "4MB",
"sizeB": "1MB", },
}, 0x17: {
0x15: { "part": "W25Q64JV",
"part": "W25Q16BV", "size": "64mbits",
"size": "16mbits", "sizeB": "8MB",
"sizeB": "2MB", },
}, 0x22: {
0x16: { "part": "W25Q02JV-IM",
"part": "W25Q32BV", "size": "2mbits",
"size": "32mbits", "sizeB": "256KB",
"sizeB": "4MB", },
},
},
0x70: {
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_h = did >> 8
did_l = did & 0xff did_l = did & 0xff
t = None t = None
print(f"\n JEDEC ID....... 0x{mid:X} / 0x{did:X}")
if mid in spi: if mid in spi:
mfr = spi[mid]['manufacturer'] 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") + print("\n Manufacturer... " + color(f"{mfr}", fg="green") +
"\n Device......... " + color(f"{t['part']}", fg="green") + "\n Device......... " + color(f"{t['part']}", fg="green") +
"\n Size........... " + color(f"{t['size']} ({t['sizeB']})", fg="yellow") "\n Size........... " + color(f"{t['size']} ({t['sizeB']})", fg="yellow")

View file

@ -1,81 +1,177 @@
#!/usr/bin/python3 #!/usr/bin/python3
### Parameters import os
import subprocess
import signal
import numpy as np
from pyaudio import PyAudio, paFloat32, paContinue
# Sound output parameters # Sound output parameters
volume = 1.0 volume = 1.0
sample_buf_size = 44 sampling_freq = 44100 # Hz
sampling_freq = 44100 #Hz
# Frequency generator parameters # Frequency generator parameters
min_freq = 200 #Hz min_freq = 100 # Hz
max_freq = 2000 #Hz max_freq = 6000 # Hz
# Proxmark3 parameters # Proxmark3 parameters
pm3_client="/usr/local/bin/proxmark3" pm3_client = "pm3"
pm3_reader_dev_file="/dev/ttyACM0" pm3_tune_cmd = "hf tune --value"
pm3_tune_cmd="hf tune"
frequency = 440
buffer = []
### Modules def find_zero_crossing_index(array):
import numpy for i in range(1, len(array)):
import pyaudio if array[i-1] < 0 and array[i] >= 0:
from select import select return i
from subprocess import Popen, DEVNULL, PIPE return None # Return None if no zero-crossing is found
### Main program def generate_sine_wave(frequency, sample_rate, duration, frame_count):
p = pyaudio.PyAudio() """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 # PyAudio Callback function
min_v = 100.0 def pyaudio_callback(in_data, frame_count, time_info, status):
max_v = 0.0 # if in_data is None:
v = 0 # return (in_data, pyaudio.paContinue)
out_freq = min_freq 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 def silent_pyaudio():
sample_buf = [0.0 for x in range(0, sample_buf_size)] """
i = 0 Lifted and adapted from https://stackoverflow.com/questions/67765911/
sinev = 0 PyAudio is noisy af every time you initialise it, which makes reading the
while True: 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 # Open a pair of null files
if(select([pm3_proc.stdout], [], [], 0)[0]): 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: def run_pm3_cmd(callback):
break; # Start the process
for c in b: process = subprocess.Popen(
if c in "0123456789 mV": [pm3_client, '-c', pm3_tune_cmd],
mv_recbuf += c stdout=subprocess.PIPE,
else: stderr=subprocess.PIPE,
mv_recbuf = "" text=True,
if mv_recbuf[-3:] == " mV": bufsize=1, # Line buffered
v = int(mv_recbuf[:-3]) / 1000 shell=False
if v < min_v: )
min_v = v - 0.001
if v > max_v: # Read the output line by line as it comes
max_v = v 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 # Recalculate the audio frequency to generate
out_freq = (max_freq - min_freq) * (max_v - v) / (max_v - min_v) \ global frequency
+ min_freq 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 # frequency = max_freq - ((max_freq - min_freq) * (v - self.min_v) / (self.max_v - self.min_v) + min_freq)
sinevs = out_freq / sampling_freq * numpy.pi * 2 #frequency = (frequency + new_frequency)/2
sample_buf[i] = sinev
sinev += sinevs
sinev = sinev if sinev < numpy.pi * 2 else sinev - numpy.pi * 2 def main():
i = (i + 1) % sample_buf_size f = foo()
if not i: run_pm3_cmd(f.callback)
stream.write((numpy.sin(sample_buf) * volume).
astype(numpy.float32).tobytes())
if __name__ == "__main__":
main()

View file

@ -1065,10 +1065,10 @@
}, },
{ {
"AID": "DD00DD", "AID": "DD00DD",
"Vendor": "Regional Transporation District (RTD) via masabi justride", "Vendor": "Regional Transporation District (RTD) via Masabi Ltd",
"Country": "US", "Country": "US",
"Name": "MyRide Card (DEN)", "Name": "MyRide Card (DEN)",
"Description": "DEN MyRide Card", "Description": "DEN MyRide Card; Masabi Justride Tap and Ride DESFire Smartcard",
"Type": "transport" "Type": "transport"
}, },
{ {
@ -1151,6 +1151,22 @@
"Description": "FIDs 02: Card Balance; 04: Refill History; 08: Card Information; 0E: Trip History", "Description": "FIDs 02: Card Balance; 04: Refill History; 08: Card Information; 0E: Trip History",
"Type": "transport" "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", "AID": "F21360",
"Vendor": "INIT", "Vendor": "INIT",

View file

@ -264,7 +264,7 @@ static uint8_t card_app2_limit[] = {
0xff, 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 //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 (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}}, {"(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 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 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}}, {"(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 Operations
{"(RESET) - Reset READER to defaults", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {"(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 //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) { 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) { if (check_values) {
PrintAndLogEx(SUCCESS, _GREEN_("CONFIRMED VALID RAW key ") _RED_("%s"), sprint_hex(div_key, 8)); 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; verified = true;
} else { } else {
PrintAndLogEx(INFO, _YELLOW_("Raw Key Invalid")); 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, "debug", "Re-enables tracing for debugging. Limits cycles to 1."),
arg_lit0(NULL, "notest", "Perform real writes on the card!"), 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, "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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -7202,7 +7202,8 @@ static int CmdHf14AGen3Block(const char *Cmd) {
" - You can specify part of manufacturer block as\n" " - You can specify part of manufacturer block as\n"
" 4/7-bytes for UID change only\n" " 4/7-bytes for UID change only\n"
"\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 --> print current data\n"
"hf mf gen3blk -d 01020304 --> set 4 byte uid\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_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", "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_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_str0("f", "file", "<fn>", "Specify a filename for collected data"),
arg_param_end arg_param_end
}; };
@ -9954,9 +9956,18 @@ static int CmdHF14AMfISEN(const char *Cmd) {
if (collect_fm11rf08s_with_data) { if (collect_fm11rf08s_with_data) {
collect_fm11rf08s = 1; 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; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {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); CLIParserFree(ctx);
@ -10005,10 +10016,10 @@ static int CmdHF14AMfISEN(const char *Cmd) {
if (collect_fm11rf08s) { if (collect_fm11rf08s) {
uint64_t t1 = msclock(); uint64_t t1 = msclock();
uint32_t flags = collect_fm11rf08s_with_data; uint32_t flags = collect_fm11rf08s_with_data | (collect_fm11rf08s_without_backdoor << 1);
SendCommandMIX(CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES, flags, 0, 0, key, sizeof(key)); SendCommandMIX(CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES, flags, blockn, keytype, key, sizeof(key));
if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, &resp, 1000)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
if (resp.status == PM3_ESOFT) { if (resp.oldarg[0] != PM3_SUCCESS) {
return NONCE_FAIL; return NONCE_FAIL;
} }
} }

View file

@ -333,10 +333,12 @@ static int CmdHFMFPInfo(const char *Cmd) {
// version check // version check
uint8_t version[30] = {0}; uint8_t version[30] = {0};
uint8_t uid7b[7] = {0};
int version_len = sizeof(version); int version_len = sizeof(version);
if (get_plus_version(version, &version_len) == PM3_SUCCESS) { if (get_plus_version(version, &version_len) == PM3_SUCCESS) {
plus_print_version(version); plus_print_version(version);
supportVersion = true; supportVersion = true;
memcpy(uid7b, version + 14, 7);
} else { } else {
// info about 14a part, historical bytes. // info about 14a part, historical bytes.
infoHF14A(false, false, false); infoHF14A(false, false, false);
@ -346,7 +348,11 @@ static int CmdHFMFPInfo(const char *Cmd) {
uint8_t signature[56] = {0}; uint8_t signature[56] = {0};
int signature_len = sizeof(signature); int signature_len = sizeof(signature);
if (get_plus_signature(signature, &signature_len) == PM3_SUCCESS) { 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; supportSignature = true;
} }

View file

@ -1540,21 +1540,13 @@ static int ulev1_print_version(uint8_t *data) {
} }
static int ntag_print_counter(void) { 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(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counter")); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counter"));
uint8_t tear[1] = {0};
uint8_t counter[3] = {0, 0, 0}; uint8_t counter[3] = {0, 0, 0};
uint16_t len; uint16_t len;
len = ulev1_readTearing(0x02, tear, sizeof(tear));
(void)len;
len = ulev1_readCounter(0x02, counter, sizeof(counter)); len = ulev1_readCounter(0x02, counter, sizeof(counter));
(void)len;
PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3)); PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3));
PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )"
, tear[0]
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
);
return len; return len;
} }
@ -5833,6 +5825,127 @@ out:
return PM3_SUCCESS; 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHF14AMfuList, AlwaysAvailable, "List MIFARE Ultralight / NTAG history"}, {"list", CmdHF14AMfuList, AlwaysAvailable, "List MIFARE Ultralight / NTAG history"},
@ -5845,6 +5958,7 @@ static command_t CommandTable[] = {
{"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight-C - Authentication"}, {"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight-C - Authentication"},
{"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Ultralight-C - Set 3DES key"}, {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Ultralight-C - Set 3DES key"},
{"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"}, {"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"},
{"incr", CmdHF14AMfUIncr, IfPm3Iso14443a, "Increments Ev1/NTAG counter"},
{"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"},
{"ndefread", CmdHF14MfuNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"}, {"ndefread", CmdHF14MfuNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"},
{"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"}, {"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"},

View file

@ -732,6 +732,7 @@ static int CmdEM410xClone(const char *Cmd) {
packet.cmd = HTSF_82xx; packet.cmd = HTSF_82xx;
memcpy(packet.pwd, "\xBB\xDD\x33\x99", HITAGS_PAGE_SIZE); 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)); SendCommandNG(CMD_LF_HITAGS_WRITE, (uint8_t *)&packet, sizeof(packet));
if (WaitForResponseTimeout(CMD_LF_HITAGS_WRITE, &resp, 4000) == false) { if (WaitForResponseTimeout(CMD_LF_HITAGS_WRITE, &resp, 4000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");

View file

@ -444,6 +444,96 @@ static int CmdLFHitagSRead(const char *Cmd) {
return PM3_SUCCESS; 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) { static int CmdLFHitagSWrite(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag hts wrbl", CLIParserInit(&ctx, "lf hitag hts wrbl",
@ -615,6 +705,7 @@ static command_t CommandTable[] = {
{"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("General") " ------------------------"}, {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("General") " ------------------------"},
{"reader", CmdLFHitagSReader, IfPm3Hitag, "Act like a Hitag S reader"}, {"reader", CmdLFHitagSReader, IfPm3Hitag, "Act like a Hitag S reader"},
{"rdbl", CmdLFHitagSRead, IfPm3Hitag, "Read Hitag S page"}, {"rdbl", CmdLFHitagSRead, IfPm3Hitag, "Read Hitag S page"},
{"dump", CmdLFHitagSDump, IfPm3Hitag, "Dump Hitag S pages to a file"},
{"wrbl", CmdLFHitagSWrite, IfPm3Hitag, "Write Hitag S page"}, {"wrbl", CmdLFHitagSWrite, IfPm3Hitag, "Write Hitag S page"},
{"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Simulation") " -----------------------"}, {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Simulation") " -----------------------"},
{"sim", CmdLFHitagSSim, IfPm3Hitag, "Simulate Hitag S transponder"}, {"sim", CmdLFHitagSSim, IfPm3Hitag, "Simulate Hitag S transponder"},

View file

@ -1222,14 +1222,17 @@ static int DesfireAuthenticateEV1(DesfireContext_t *dctx, DesfireSecureChannel s
// - Encrypt our response // - Encrypt our response
if (secureChannel == DACd40) { 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); 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); memcpy(both, encRndA, rndlen);
bin_xor(rotRndB, encRndA, rndlen); bin_xor(rotRndB, encRndA, rndlen);
memset(IV, 0, DESFIRE_MAX_CRYPTO_BLOCK_SIZE); 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); memcpy(both + rndlen, encRndB, rndlen);
} else if (secureChannel == DACEV1) { } else if (secureChannel == DACEV1) {

View file

@ -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)); size_t srcmaclen = padded_data_length(srcdatalen - hdrlen, desfire_get_key_block_length(ctx->keyType));
uint8_t mac[32] = {0}; 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); DesfireCryptoEncDecEx(ctx, DCOSessionKeyMac, data, srcmaclen, NULL, true, true, mac);
if (DesfireEV1D40TransmitMAC(ctx, cmd)) { if (DesfireEV1D40TransmitMAC(ctx, cmd)) {
@ -889,4 +893,3 @@ bool PrintChannelModeWarning(uint8_t cmd, DesfireSecureChannel secureChannel, De
return found; return found;
} }

View file

@ -696,14 +696,18 @@ void print_progress(uint64_t count, uint64_t max, barMode_t style) {
max = (count > max) ? count : max; max = (count > max) ? count : max;
#if defined(HAVE_READLINE) #if defined(HAVE_READLINE)
static int prev_cols = 0; static int prev_cols = 0;
int rows; int tmp_cols;
rl_reset_screen_size(); // refresh Readline idea of the actual screen width rl_get_screen_size(NULL, &tmp_cols);
rl_get_screen_size(&rows, &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) if (cols < 36)
return; return;
}
(void) rows;
if (prev_cols > cols) { if (prev_cols > cols) {
PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ ""); PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ "");
} }

View file

@ -554,8 +554,8 @@ size_t concatbits(uint8_t *dest, int dest_offset, const uint8_t *src, int src_of
end = nbits; end = nbits;
step = 1; step = 1;
} else { } else {
i = nbits; i = nbits - 1;
end = 0; end = -1;
step = -1; step = -1;
} }

View file

@ -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); 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}; uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
@ -442,21 +441,13 @@ bool FlashDetect(void) {
} else { } else {
if (g_dbglevel > 3) Dbprintf("Flash_ReadID failed reading Mfr/Dev (0x90)"); if (g_dbglevel > 3) Dbprintf("Flash_ReadID failed reading Mfr/Dev (0x90)");
} }
// default device is 'unknown' // Check JEDEC data is valid, compare the reported device types and then calculate the number of pages
spi_flash_data.device = SpiFlashTable[0].device; // 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) { if (ret) {
for (int i = 0; i < ARRAYLEN(SpiFlashTable); i++) { if (spi_flash_data.jedec_id > 0 && spi_flash_data.jedec_id < 0xFFFF) {
if (SpiFlashTable[i].manufacturer_id == spi_flash_data.manufacturer_id) { if (((spi_flash_data.device_id + 1) & 0x0F) == (spi_flash_data.jedec_id & 0x000F)) {
if (SpiFlashTable[i].jedec_id == spi_flash_data.jedec_id) { spi_flash_pages64k = 1 << (spi_flash_data.jedec_id & 0x000F);
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;
}
} }
} }
} }

View file

@ -140,36 +140,8 @@ typedef struct {
uint8_t manufacturer_id; uint8_t manufacturer_id;
uint8_t device_id; uint8_t device_id;
uint16_t jedec_id; uint16_t jedec_id;
uint8_t pages64k;
char *device;
} spi_flash_t; } 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; extern uint8_t spi_flash_pages64k;
bool FlashDetect(void); bool FlashDetect(void);

View file

@ -36,22 +36,22 @@ Therefore a flash address can be interpreted as such:
Page 0: Page 0:
* available for user data * 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` * to erase it: `mem wipe p 0`
Page 1: Page 1:
* available for user data * 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` * to erase it: `mem wipe p 1`
Page 2: Page 2:
* available for user data * 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` * to erase it: `mem wipe p 2`
Page 3: Page 3:
* used by Proxmark3 RDV4 specific functions: flash signature and keys dictionaries, see below for details * 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: * 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! * **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. * 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: Page3 is used as follows by the Proxmark3 RDV4 firmware:
* **MF_KEYS** * **MF_KEYS**
* offset: page 3 sector 9 (0x9) @ 3*0x10000+9*0x1000=0x39000 * offset: page 3 sector 5 (0x5) @ 3*0x10000+5*0x1000=0x35000
* length: 2 sectors * length: 6 sectors
* **ICLASS_KEYS** * **ICLASS_KEYS**
* offset: page 3 sector 11 (0xB) @ 3*0x10000+11*0x1000=0x3B000 * offset: page 3 sector 11 (0xB) @ 3*0x10000+11*0x1000=0x3B000

View file

@ -117,6 +117,17 @@ or
proxmark3 /dev/ttyACM0 --flash --unlock-bootloader --image /tmp/my-bootrom.elf --image /tmp/my-fullimage.elf 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 ### The button trick
^[Top](#top) ^[Top](#top)

45
fpga/xc2s50-5-tq144.ucf Normal file
View 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 ;

View file

@ -161,7 +161,7 @@ typedef struct {
uint8_t logdata_1[4]; uint8_t logdata_1[4];
uint8_t nonce[4]; uint8_t nonce[4];
//Hitag s section // Hitag S section
uint8_t mode; uint8_t mode;
} PACKED lf_hitag_data_t; } PACKED lf_hitag_data_t;

View file

@ -28,7 +28,7 @@
// 0x3E000 - 1 4kb sector = settings // 0x3E000 - 1 4kb sector = settings
// 0x3D000 - 1 4kb sector = default T55XX keys dictionary // 0x3D000 - 1 4kb sector = default T55XX keys dictionary
// 0x3B000 - 1 4kb sector = default ICLASS 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 #ifndef FLASH_MEM_BLOCK_SIZE
# define FLASH_MEM_BLOCK_SIZE 256 # 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) # define DEFAULT_ICLASS_KEYS_OFFSET_P(p64k) (DEFAULT_T55XX_KEYS_OFFSET_P(p64k) - DEFAULT_ICLASS_KEYS_LEN)
#endif #endif
// Reserved space for MIFARE Keys = 12 kb // Reserved space for MIFARE Keys = 24 kb
#ifndef DEFAULT_MF_KEYS_OFFSET #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_OFFSET (DEFAULT_ICLASS_KEYS_OFFSET - DEFAULT_MF_KEYS_LEN)
# define DEFAULT_MF_KEYS_MAX ((DEFAULT_MF_KEYS_LEN - 2) / 6) # define DEFAULT_MF_KEYS_MAX ((DEFAULT_MF_KEYS_LEN - 2) / 6)
#endif #endif

View file

@ -12,12 +12,13 @@ from colors import color
debug = False debug = False
def guess_curvename(signature): def guess_curvename(signature):
siglen = (len(signature) // 2) & 0xfe siglen = (len(signature) // 2) & 0xfe
if siglen == 32: if siglen == 32:
curves = ["secp128r1", "secp128r2"] curves = ["secp128r1", "secp128r2"]
elif siglen == 48: elif siglen == 48:
curves = ["secp192k1", "secp192r1"] curves = ["secp192k1", "prime192v1"]
elif siglen == 56: elif siglen == 56:
curves = ["secp224k1", "secp224r1"] curves = ["secp224k1", "secp224r1"]
elif siglen == 64: elif siglen == 64:
@ -31,6 +32,7 @@ def guess_curvename(signature):
raise ValueError("Unsupported signature size %s" % lenstr) raise ValueError("Unsupported signature size %s" % lenstr)
return curves return curves
def recover(data, signature, curvename, alghash=None): def recover(data, signature, curvename, alghash=None):
recovered = set() recovered = set()
try: try:
@ -60,6 +62,7 @@ def recover(data, signature, curvename, alghash=None):
pass pass
return recovered return recovered
def recover_multiple(uids, sigs, curvename, alghash=None): def recover_multiple(uids, sigs, curvename, alghash=None):
recovered = set() recovered = set()
assert len(uids) == len(sigs) assert len(uids) == len(sigs)
@ -82,6 +85,7 @@ def recover_multiple(uids, sigs, curvename, alghash=None):
recovered &= recovered_tmp recovered &= recovered_tmp
return recovered return recovered
def selftests(): def selftests():
tests = [ tests = [
{'name': "Mifare Ultralight EV1", {'name': "Mifare Ultralight EV1",
@ -158,16 +162,16 @@ def selftests():
# 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], # 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"],
# 'pk': ""}, # 'pk': ""},
{'name': "MIFARE Plus Trojka", {'name': "MIFARE Plus Trojka",
# uses secp224r1, None, # uses secp224r1, None,
'samples': ["04B59F6A226F82", "6F577EB7F570D74DB6250477427F68A0088762BD318767537122919A7916597149F9D16D8B135E9BF826FB28AE293F3168661CD4A049FAED", 'samples': ["04B59F6A226F82", "6F577EB7F570D74DB6250477427F68A0088762BD318767537122919A7916597149F9D16D8B135E9BF826FB28AE293F3168661CD4A049FAED",
"04B44A82D80F92", "A0868ECF26733D3C3C838D055968B4559F77693CC3E346E3A4741BC826801F8360FD88857BEC440AAD3A21153D64302DEB6F5ED40B15C3F7"], "04B44A82D80F92", "A0868ECF26733D3C3C838D055968B4559F77693CC3E346E3A4741BC826801F8360FD88857BEC440AAD3A21153D64302DEB6F5ED40B15C3F7"],
'pk': "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"}, 'pk': "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"},
# {'name': "MIFARE Ultralight AES", {'name': "MIFARE Ultralight AES",
# uses NID_secp192r1, OpenSSL doesn't support it. This is commented out until that day. # uses prime192v1, None,
# 'samples': ["045E4CC2451390", "C9BBDA1B99EB6634CDFD8E3251AC5C4742EA5FA507B8A8A8B39B19AB7340D173331589C54C56C49F0CCA6DDBAC1E492A", 'samples': ["045E4CC2451390", "C9BBDA1B99EB6634CDFD8E3251AC5C4742EA5FA507B8A8A8B39B19AB7340D173331589C54C56C49F0CCA6DDBAC1E492A",
# "043F88C2451390", "5C2055A7373F119C3FDD9843020B06AA0E6DE18C16496C425C4AD971A50F05FA1A67B9E39CA60C355EEEEBF8214A84A5"], "043F88C2451390", "5C2055A7373F119C3FDD9843020B06AA0E6DE18C16496C425C4AD971A50F05FA1A67B9E39CA60C355EEEEBF8214A84A5"],
# 'pk': "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"}, 'pk': "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"},
{'name': "MIFARE Classic / QL88", {'name': "MIFARE Classic / QL88",
'samples': ["30933C61", "AEA4DD0B800FAC63D4DE08EE91F4650ED825FD6B4D7DEEE98DBC9BAE10BE003E", 'samples': ["30933C61", "AEA4DD0B800FAC63D4DE08EE91F4650ED825FD6B4D7DEEE98DBC9BAE10BE003E",
@ -234,13 +238,15 @@ def selftests():
print("Tests: ( %s )" % [fail, ok][succeeded]) print("Tests: ( %s )" % [fail, ok][succeeded])
print("") print("")
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) == 2 and sys.argv[1] == "selftests": if len(sys.argv) == 2 and sys.argv[1] == "selftests":
selftests() selftests()
exit(0) exit(0)
if len(sys.argv) < 3 or len(sys.argv) % 2 == 0: if len(sys.argv) < 3 or len(sys.argv) % 2 == 0:
print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[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) exit(1)
uids, sigs = sys.argv[1:][::2], sys.argv[1:][1::2] uids, sigs = sys.argv[1:][::2], sys.argv[1:][1::2]
once = True once = True