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
31 changed files with 954 additions and 328 deletions
+10
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...
## [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)
+1 -1
View File
@@ -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: {
+217 -101
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
// 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);
+1 -1
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 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);
+9
View File
@@ -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);
}
+1
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 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
+17 -1
View File
@@ -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
+54 -16
View File
@@ -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
+107 -51
View File
@@ -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")
+156 -60
View File
@@ -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()
+18 -2
View File
@@ -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",
+12 -4
View File
@@ -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);
+17 -6
View File
@@ -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;
}
}
+7 -1
View File
@@ -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;
}
+123 -9
View File
@@ -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"},
+1
View File
@@ -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.");
+91
View File
@@ -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"},
+5 -2
View File
@@ -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) {
+4 -1
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));
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;
}

Some files were not shown because too many files have changed in this diff Show More