Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
Alex 2023-06-16 15:46:49 +02:00 committed by GitHub
commit 78f2d9b958
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 377 additions and 209 deletions

View file

@ -3,6 +3,12 @@ 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]
- Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001)
- Fixed `hf 15693/iclass sniff` trace timings (@nvx)
- Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp)
- Fixed `trace list` - now handles marking of crc bytes w color a bit better (@iceman1001)
- Changed `hf mfu pwdgen -r` - now generates pwd/pack for Philips Sonicare, thanks @ckuenzi, @atc1441 (@iceman1001)
- Changed `hf mfu info` - now detects Philips Sonicare devices (@iceman1001)
- Fixed truncated FPGA upload due to incorrect integer size variable (@d18c7db)
- Changed `usart btfactory` - handles the new BT board with version "BT SPP V3.0" (@iceman1001)
- Changed `hf mf eview --sk` - now can extract keys and save to file (@iceman1001)

View file

@ -1736,14 +1736,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
// no need to try decoding reader data if the tag is sending
if (!tag_is_active) {
if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader)) {
int extra_8s = 1;
if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader) ||
(++extra_8s && Handle15693SampleFromReader(sniffdata & 0x01, &dreader))) {
uint32_t eof_time = dma_start_time + (samples * 16) + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF
if (dreader.byteCount > 0) {
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
// not sure where the extra +8's on the EOF time comes from though, if someone knows update this comment
uint32_t eof_time = dma_start_time + (samples * 16) + (extra_8s * 8) - DELAY_READER_TO_ARM_SNIFF; // end of EOF
uint32_t sof_time = eof_time
- dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers
- 32 * 16 // time for SOF transfer
- 16 * 16; // time for EOF transfer
- dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 1024 : 16384) // time for byte transfers
- 256 // time for SOF transfer (1024/fc / 4)
- 128; // time for EOF transfer (512/fc / 4)
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true);
if (!iclass) { // Those flags don't exist in iClass
@ -1751,52 +1756,38 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH;
}
}
// And ready to receive another command.
//DecodeReaderReset(&dreader); // already reseted
DecodeTagReset(&dtag);
DecodeTagFSKReset(&dtagfsk);
reader_is_active = false;
expect_tag_answer = true;
} else if (Handle15693SampleFromReader(sniffdata & 0x01, &dreader)) {
uint32_t eof_time = dma_start_time + (samples * 16) + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF
if (dreader.byteCount > 0) {
uint32_t sof_time = eof_time
- dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers
- 32 * 16 // time for SOF transfer
- 16 * 16; // time for EOF transfer
LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true);
if (!iclass) { // Those flags don't exist in iClass
expect_fsk_answer = dreader.output[0] & ISO15_REQ_SUBCARRIER_TWO;
expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH;
}
}
// And ready to receive another command
//DecodeReaderReset(&dreader); // already reseted
DecodeTagReset(&dtag);
DecodeTagFSKReset(&dtagfsk);
reader_is_active = false;
expect_tag_answer = true;
} else {
reader_is_active = (dreader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4);
}
}
if (!reader_is_active && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet
// no need to try decoding tag data if the reader is currently sending or no answer expected yet
if (!reader_is_active && expect_tag_answer) {
if (!expect_fsk_answer) {
// single subcarrier tag response
if (Handle15693SamplesFromTag((sniffdata >> 4) << 2, &dtag, expect_fast_answer)) {
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
if (dtag.lastBit == SOF_PART2) {
eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS)
}
uint32_t sof_time = eof_time
- dtag.len * 8 * 8 * 16 // time for byte transfers
- (32 * 16) // time for SOF transfer
- (dtag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer
- dtag.len * 1024 // time for byte transfers (4096/fc / 4)
- 512 // time for SOF transfer (2048/fc / 4)
- (dtag.lastBit != SOF_PART2 ? 512 : 0); // time for EOF transfer (2048/fc / 4)
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
LogTrace_ISO15693(dtag.output, dtag.len, (sof_time * 4), (eof_time * 4), NULL, false);
// And ready to receive another response.
DecodeTagReset(&dtag);
DecodeTagFSKReset(&dtagfsk);
@ -1807,26 +1798,23 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
tag_is_active = (dtag.state >= STATE_TAG_RECEIVING_DATA);
}
} else {
// dual subcarrier tag response
if (FREQ_IS_0((sniffdata >> 2) & 0x3)) // tolerate 1 00
sniffdata = sniffdata_prev;
if (Handle15693FSKSamplesFromTag((sniffdata >> 2) & 0x3, &dtagfsk, expect_fast_answer)) {
expect_fsk_answer = false;
} else {
tag_is_active = (dtagfsk.state >= STATE_FSK_RECEIVING_DATA_484);
}
if (!expect_fsk_answer) {
// FSK answer no more expected: switch back to ASK
if (dtagfsk.len > 0) {
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
if (dtagfsk.lastBit == SOF) {
eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS)
}
uint32_t sof_time = eof_time
- dtagfsk.len * 8 * 8 * 16 // time for byte transfers
- (32 * 16) // time for SOF transfer
- (dtagfsk.lastBit != SOF ? (32 * 16) : 0); // time for EOF transfer
- dtagfsk.len * 1016 // time for byte transfers (4064/fc / 4) - FSK is slightly different
- 512 // time for SOF transfer (2048/fc / 4)
- (dtagfsk.lastBit != SOF ? 512 : 0); // time for EOF transfer (2048/fc / 4)
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
LogTrace_ISO15693(dtagfsk.output, dtagfsk.len, (sof_time * 4), (eof_time * 4), NULL, false);
}
@ -1834,6 +1822,10 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
DecodeReaderReset(&dreader);
expect_tag_answer = false;
tag_is_active = false;
// FSK answer no more expected: switch back to ASK
expect_fsk_answer = false;
} else {
tag_is_active = (dtagfsk.state >= STATE_FSK_RECEIVING_DATA_484);
}
}
}

View file

@ -1,5 +1,5 @@
#
# Mifare Ultralight Default Keys
# Mifare Ultralight C Default Keys
# -- iceman fork version --
# -- contribute to this list, sharing is caring --
#

View file

@ -221,7 +221,7 @@ end
---
-- curency-codes for Legic-Cash-Segments (ISO 4217)
local currency = {
["03d2"]="EUR",
["03D2"]="EUR",
["0348"]="USD",
["033A"]="GBP",
["02F4"]="CHF"
@ -1447,7 +1447,10 @@ function dumpLegicCash(tag, x)
print("--------------------------------\n\tLegic-Cash Values\n--------------------------------")
local limit, curr, balance, rid, tcv
-- currency of balance & limit
curr=currency[tag.SEG[x].data[8]..tag.SEG[x].data[9]]
curr=string.upper(tag.SEG[x].data[8]..tag.SEG[x].data[9])
if currency[curr] ~= nil then
curr = currency[curr]
end
-- maximum balance
limit=string.format("%4.2f", tonumber(tag.SEG[x].data[10]..tag.SEG[x].data[11]..tag.SEG[x].data[12], 16)/100)
-- current balance
@ -1784,17 +1787,17 @@ end
---
-- edit Segment Data
function editSegmentData(data)
function editSegmentData(data, uid)
io.write("\n")
if istable(data) == false then print("no Segment-Data found") end
local lc = check4LegicCash(data)
local lc = check4LegicCash(data, uid)
for i=0, #data-1 do
data[i]=input(accyan.."Data"..i..acoff..": ", data[i])
end
if (lc) then
data = fixLegicCash(data)
data = fixLegicCash(data, uid)
end
return data
end
@ -1917,7 +1920,7 @@ function autoSelectSegment(tag, s)
repeat
io.write(". ")
x=x-1
res=check4LegicCash(tag.SEG[x].data)
res=check4LegicCash(tag.SEG[x].data, uid)
until ( res or x==0 )
end
---
@ -2011,7 +2014,7 @@ end
---
-- edit Legic Cash
function editLegicCash(data)
function editLegicCash(data, uid)
local limit, curr, balance, rid, tcv
-- currency of balance & limit
curr=currency[data[8]..data[9]]
@ -2064,12 +2067,12 @@ function editLegicCash(data)
data[20]=string.sub(rid, 5, 6)
end
return fixLegicCash(data)
return fixLegicCash(data, uid)
end
---
-- chack for signature of a 'Legic-Cash-Segment'
function check4LegicCash(data)
function check4LegicCash(data, uid)
if(#data==32) then
local stamp_len=(#data-25)
local stamp=""
@ -2077,9 +2080,9 @@ function check4LegicCash(data)
stamp=stamp..data[i].." "
end
if (data[7]=="01") then
if (("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12))) == data[13]..data[14]) then
if (("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20))) == data[21]..data[22]) then
if (("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29))) == data[30]..data[31]) then
if (("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 0, 12), uid)) == data[13]..data[14]) then
if (("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 15, 20), uid)) == data[21]..data[22]) then
if (("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 23, 29), uid)) == data[30]..data[31]) then
io.write(accyan.."Legic-Cash Segment detected "..acoff)
return true
end
@ -2156,7 +2159,7 @@ end
---
-- repair / fix crc's of a 'Legic-Cash-Segment'
function fixLegicCash(data)
function fixLegicCash(data, uid)
if(#data==32 and data[7]=="01") then
local crc1, crc2, crc3
-- set shadow-balance equal to balance
@ -2168,9 +2171,9 @@ function fixLegicCash(data)
data[27]=data[19]
data[28]=data[20]
-- calculate all crc's
crc1=("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12)))
crc2=("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20)))
crc3=("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29)))
crc1=("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 0, 12), uid))
crc2=("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 15, 20), uid))
crc3=("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 23, 29), uid))
-- set crc's
data[13]=string.sub(crc1, 1, 2)
data[14]=string.sub(crc1, 3, 4)
@ -2413,7 +2416,7 @@ function modifyMode()
for i=0, #inTAG.SEG do
if(check43rdPartyCash1(uid, inTAG.SEG[i].data)) then
io.write(accyan.."in Segment index: "..inTAG.SEG[i].index ..acoff.. "\n")
elseif(check4LegicCash(inTAG.SEG[i].data)) then
elseif(check4LegicCash(inTAG.SEG[i].data, uid)) then
io.write(accyan.."in Segment index: "..inTAG.SEG[i].index..acoff.."\n")
lc=true;
lci=inTAG.SEG[i].index;
@ -2520,7 +2523,8 @@ function modifyMode()
if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
else sel=selectSegment(inTAG) end
if (istable(inTAG.SEG[sel])) then
inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data)
local uid = inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data, uid)
end
end,
---
@ -2587,13 +2591,15 @@ function modifyMode()
else
x = selectSegment(inTAG)
end
inTAG.SEG[x].data=fixLegicCash(inTAG.SEG[x].data)
local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
inTAG.SEG[x].data=fixLegicCash(inTAG.SEG[x].data, uid)
end,
---
-- edit legic-cash values fixLegicCash(data)
-- edit legic-cash values fixLegicCash(data, uid)
["elc"] = function(x)
x=autoSelectSegment(inTAG, "legiccash")
inTAG.SEG[x].data=editLegicCash(inTAG.SEG[x].data)
local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
inTAG.SEG[x].data=editLegicCash(inTAG.SEG[x].data, uid)
end,
---
-- dump legic-cash human-readable

View file

@ -70,7 +70,7 @@ static uint8_t *gs_mfuc_key = NULL;
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
if (n < 3) return 2;
if (isResponse && (n < 6)) return 2;
if (isResponse && (n == 5)) return 2;
if (d[1] == 0x50 &&
d[0] >= ISO14443A_CMD_ANTICOLL_OR_SELECT &&
d[0] <= ISO14443A_CMD_ANTICOLL_OR_SELECT_3) {

View file

@ -207,7 +207,7 @@ static char GetFormatFromSector(uint8_t sectors) {
}
}
static bool mfc_value(const uint8_t *d, int32_t *val) {
bool mfc_value(const uint8_t *d, int32_t *val) {
// values
int32_t a = (int32_t)MemLeToUint4byte(d);
uint32_t a_inv = MemLeToUint4byte(d + 4);
@ -225,7 +225,7 @@ static bool mfc_value(const uint8_t *d, int32_t *val) {
return val_checks;
}
static void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) {
void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) {
if (blockno == 0) {
PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
} else if (mfIsSectorTrailer(blockno)) {
@ -389,7 +389,7 @@ static void mf_print_values(uint16_t n, uint8_t *d) {
}
*/
static void mf_print_sector_hdr(uint8_t sector) {
void mf_print_sector_hdr(uint8_t sector) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, " # | sector " _GREEN_("%02d") " / " _GREEN_("0x%02X") " | ascii", sector, sector);
PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");

View file

@ -34,6 +34,11 @@ void showSectorTable(sector_t *k_sector, size_t k_sectors_cnt);
void readerAttack(sector_t *k_sector, size_t k_sectors_cnt, nonces_t data, bool setEmulatorMem, bool verbose);
void printKeyTable(size_t sectorscnt, sector_t *e_sector);
void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector);
// void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector, bool singel_sector);
bool mfc_value(const uint8_t *d, int32_t *val);
void mf_print_sector_hdr(uint8_t sector);
void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose);
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len);
#endif

View file

@ -33,6 +33,7 @@
#include "fileutils.h"
#include "protocols.h"
#include "crypto/libpcrypto.h"
#include "cmdhfmf.h" // printblock, header
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
@ -172,7 +173,7 @@ static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature
const ecdsa_publickey_t nxp_plus_public_keys[] = {
{"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"},
{"MIFARE Plus Ev_x", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"},
{"MIFARE Plus Trojka", "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"}
{"MIFARE Plus Troika", "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"}
};
uint8_t i;
@ -766,25 +767,25 @@ static int CmdHFMFPRdbl(const char *Cmd) {
return PM3_ESOFT;
}
uint8_t sector = mfSectorNum(blockn);
mf_print_sector_hdr(sector);
int indx = blockn;
for (int i = 0; i < blocksCount; i++) {
PrintAndLogEx(INFO, "data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16));
mf_print_block_one(indx, data + 1 + (i * MFBLOCK_SIZE), verbose);
indx++;
if (mfIsSectorTrailer(indx) && i != blocksCount - 1) {
PrintAndLogEx(INFO, "data[%03d]: ------------------- trailer -------------------", indx);
indx++;
}
if (memcmp(&data[(blocksCount * 16) + 1], mac, 8)) {
PrintAndLogEx(WARNING, "WARNING: mac not equal...");
PrintAndLogEx(WARNING, "MAC card... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + (blocksCount * MFBLOCK_SIZE)], 8));
PrintAndLogEx(WARNING, "MAC reader... " _YELLOW_("%s"), sprint_hex_inrow(mac, sizeof(mac)));
} else {
if (verbose) {
PrintAndLogEx(INFO, "MAC... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + (blocksCount * MFBLOCK_SIZE)], 8));
}
}
if (memcmp(&data[blocksCount * 16 + 1], mac, 8)) {
PrintAndLogEx(WARNING, "WARNING: mac not equal...");
PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8));
} else {
if (verbose)
PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
@ -849,8 +850,12 @@ static int CmdHFMFPRdsc(const char *Cmd) {
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
for (int n = mfFirstBlockOfSector(sectorNum); n < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); n++) {
res = MFPReadBlock(&mf4session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
mf_print_sector_hdr(sectorNum);
for (int blockno = mfFirstBlockOfSector(sectorNum); blockno < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); blockno++) {
res = MFPReadBlock(&mf4session, plain, blockno & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLogEx(ERR, "Read error: %d", res);
DropField();
@ -862,25 +867,27 @@ static int CmdHFMFPRdsc(const char *Cmd) {
DropField();
return PM3_ESOFT;
}
if (datalen != 1 + 16 + 8 + 2) {
if (datalen != 1 + MFBLOCK_SIZE + 8 + 2) {
PrintAndLogEx(ERR, "Error return length:%d", datalen);
DropField();
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "data[%03d]: %s", n, sprint_hex(&data[1], 16));
mf_print_block_one(blockno, data + 1, verbose);
if (memcmp(&data[1 + 16], mac, 8)) {
PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", n);
PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1 + 16], 8));
PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8));
PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", blockno);
PrintAndLogEx(WARNING, "MAC card... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + MFBLOCK_SIZE], 8));
PrintAndLogEx(WARNING, "MAC reader... " _YELLOW_("%s"), sprint_hex_inrow(mac, sizeof(mac)));
} else {
if (verbose)
PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1 + 16], 8));
if (verbose) {
PrintAndLogEx(INFO, "MAC... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + MFBLOCK_SIZE], 8));
}
}
}
PrintAndLogEx(NORMAL, "");
DropField();
return PM3_SUCCESS;
}
@ -993,7 +1000,7 @@ static int CmdHFMFPWrbl(const char *Cmd) {
#define AES_KEY_LEN 16
#define MAX_KEYS_LIST_LEN 1024
static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
bool verbose) {
int res;
@ -1097,16 +1104,12 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3
}
static int CmdHFMFPChk(const char *Cmd) {
int res;
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
uint32_t keyListLen = 0;
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp chk",
"Checks keys on MIFARE Plus card",
"hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
"hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n"
"hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n"
"hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
"hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n"
"hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00");
@ -1133,6 +1136,10 @@ static int CmdHFMFPChk(const char *Cmd) {
uint8_t startSector = arg_get_int_def(ctx, 3, 0);
uint8_t endSector = arg_get_int_def(ctx, 4, 0);
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
uint32_t keyListLen = 0;
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
uint8_t vkey[16] = {0};
int vkeylen = 0;
CLIGetHexWithReturn(ctx, 5, vkey, &vkeylen);
@ -1201,10 +1208,10 @@ static int CmdHFMFPChk(const char *Cmd) {
uint8_t startKeyAB = 0;
uint8_t endKeyAB = 1;
if (keyA && !keyB)
if (keyA && (keyB == false))
endKeyAB = 0;
if (!keyA && keyB)
if ((keyA == false) && keyB)
startKeyAB = 1;
if (endSector < startSector)
@ -1212,8 +1219,9 @@ static int CmdHFMFPChk(const char *Cmd) {
// 1-byte pattern search mode
if (pattern1b) {
for (int i = 0; i < 0x100; i++)
for (int i = 0; i < 0x100; i++) {
memset(keyList[i], i, 16);
}
keyListLen = 0x100;
}
@ -1222,6 +1230,8 @@ static int CmdHFMFPChk(const char *Cmd) {
if (pattern2b)
Fill2bPattern(keyList, &keyListLen, &startPattern);
int res = PM3_SUCCESS;
// dictionary mode
size_t endFilePosition = 0;
if (dict_filenamelen) {
@ -1236,8 +1246,9 @@ static int CmdHFMFPChk(const char *Cmd) {
if (keyListLen == 0) {
for (int i = 0; i < g_mifare_plus_default_keys_len; i++) {
if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16)
if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) {
break;
}
keyListLen++;
}
@ -1250,21 +1261,26 @@ static int CmdHFMFPChk(const char *Cmd) {
PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " keys", keyListLen);
}
if (verbose == false)
if (verbose == false) {
PrintAndLogEx(INFO, "Search keys");
}
while (true) {
res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose);
if (res == PM3_EOPABORTED)
res = plus_key_check(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose);
if (res == PM3_EOPABORTED) {
break;
}
if (pattern2b && startPattern < 0x10000) {
if (verbose == false)
if (verbose == false) {
PrintAndLogEx(NORMAL, "p" NOLF);
}
keyListLen = 0;
Fill2bPattern(keyList, &keyListLen, &startPattern);
continue;
}
if (dict_filenamelen && endFilePosition) {
if (verbose == false)
PrintAndLogEx(NORMAL, "d" NOLF);
@ -1274,6 +1290,7 @@ static int CmdHFMFPChk(const char *Cmd) {
if (res == PM3_SUCCESS && endFilePosition) {
keyListLen = keycnt;
}
continue;
}
break;
@ -1282,26 +1299,38 @@ static int CmdHFMFPChk(const char *Cmd) {
PrintAndLogEx(NORMAL, "");
// print result
char strA[46 + 1] = {0};
char strB[46 + 1] = {0};
bool printedHeader = false;
for (uint8_t sector = startSector; sector <= endSector; sector++) {
if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) {
if (!printedHeader) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-------+--------------------------------+---------------------------------");
PrintAndLogEx(INFO, "|sector| key A | key B |");
PrintAndLogEx(INFO, "|------+--------------------------------+--------------------------------|");
printedHeader = true;
}
PrintAndLogEx(INFO, "| %02d |%32s|%32s|",
sector,
(foundKeys[0][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[0][sector][1], AES_KEY_LEN),
(foundKeys[1][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[1][sector][1], AES_KEY_LEN));
for (uint8_t s = startSector; s <= endSector; s++) {
if (printedHeader == false) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------");
PrintAndLogEx(INFO, " Sec | key A | key B");
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------");
printedHeader = true;
}
if (foundKeys[0][s][0]) {
snprintf(strA, sizeof(strA), _GREEN_("%s"), sprint_hex_inrow(&foundKeys[0][s][1], AES_KEY_LEN));
} else {
snprintf(strA, sizeof(strA), _RED_("%s"), "--------------------------------");
}
if (foundKeys[1][s][0]) {
snprintf(strB, sizeof(strB), _GREEN_("%s"), sprint_hex_inrow(&foundKeys[1][s][1], AES_KEY_LEN));
} else {
snprintf(strB, sizeof(strB), _RED_("%s"), "--------------------------------");
}
PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB);
}
if (!printedHeader)
if (printedHeader == false)
PrintAndLogEx(INFO, "No keys found(");
else
PrintAndLogEx(INFO, "'------+--------------------------------+--------------------------------'\n");
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n");
// save keys to json
if ((jsonnamelen > 0) && printedHeader) {
@ -1581,7 +1610,7 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "");
if (!datalen) {
if (datalen == 0) {
PrintAndLogEx(ERR, "no NDEF data");
return PM3_SUCCESS;
}
@ -1595,8 +1624,20 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
if (fnlen != 0) {
saveFile(filename, ".bin", data, datalen);
}
NDEFDecodeAndPrint(data, datalen, verbose);
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -vv`") " for more details");
res = NDEFDecodeAndPrint(data, datalen, verbose);
if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header");
res = NDEFRecordsDecodeAndPrint(data, datalen, verbose);
}
if (verbose == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details");
} else {
if (verbose2 == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -vv`") " for more details");
}
}
return PM3_SUCCESS;
}

View file

@ -1305,10 +1305,10 @@ typedef struct {
} mfu_otp_identify_t;
static mfu_otp_identify_t mfu_otp_ident_table[] = {
{ "SALTO", 12, 4, "534C544F", ul_c_otpgenA, NULL },
// { "SAFLOK", 12, 4, NULL, ul_c_otpgenB, NULL },
// { "VINGCARD", 12, 4, NULL, ul_c_otpgenC, NULL },
// { "DORMA KABA", 12, 4, NULL, ul_c_otpgenD, NULL },
{ "SALTO tag", 12, 4, "534C544F", ul_c_otpgenA, NULL },
// { "SAFLOK tag", 12, 4, NULL, ul_c_otpgenB, NULL },
// { "VINGCARD tag", 12, 4, NULL, ul_c_otpgenC, NULL },
// { "DORMA KABA tag", 12, 4, NULL, ul_c_otpgenD, NULL },
{ NULL, 0, 0, NULL, NULL, NULL }
};
@ -1391,6 +1391,18 @@ static mfu_identify_t mfu_ident_table[] = {
"hf mfu dump -k %08x"
},
*/
{
"Philips Toothbrush", "0004040201010F03",
16, 20, "0310D1010C55027068696C6970732E636F6DFE00",
ul_ev1_pwdgen_def, ul_ev1_packgen_def,
"hf mfu pwdgen -r"
},
{
"Philips Toothbrush", "0004040201010F03",
16, 36, "0320D1011C55027068696C6970732E636F6D2F6E6663627275736868656164746170FE00",
ul_ev1_pwdgen_def, ul_ev1_packgen_def,
"hf mfu pwdgen -r"
},
{NULL, NULL, 0, 0, NULL, NULL, NULL, NULL}
};
@ -1412,7 +1424,7 @@ static mfu_identify_t *mfu_match_fingerprint(uint8_t *version, uint8_t *data) {
uint8_t mtmp[40] = {0};
param_gethex_to_eol(mfu_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml);
bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0);
bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0);
if (m2) {
PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_ident_table[i].desc);
return &mfu_ident_table[i];
@ -1815,6 +1827,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
else
locked = true;
mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len);
if ((tagtype & MAGIC)) {
//just read key
uint8_t ulc_deskey[16] = {0x00};
@ -3581,6 +3595,8 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
if (selftest)
return generator_selftest();
uint8_t philips_mfg[10] = {0};
if (use_tag) {
// read uid from tag
int res = ul_read_uid(uid);
@ -3588,6 +3604,19 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
return res;
}
iso14a_card_select_t card;
if (ul_select(&card)) {
// Philips toothbrush needs page 0x21-0x23
uint8_t data[16] = {0x00};
int status = ul_read(0x21, data, sizeof(data));
if (status == -1) {
PrintAndLogEx(DEBUG, "Error: tag didn't answer to READ");
} else if (status == 16) {
memcpy(philips_mfg, data + 2, sizeof(philips_mfg));
}
DropField();
}
} else {
if (u_len != 7) {
PrintAndLogEx(WARNING, "Key must be 7 hex bytes");
@ -3595,24 +3624,28 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
}
}
PrintAndLogEx(INFO, "------------------.---------------");
PrintAndLogEx(INFO, "------------------.------------------");
PrintAndLogEx(INFO, " Using UID 4b: " _YELLOW_("%s"), sprint_hex(uid, 4));
PrintAndLogEx(INFO, " Using UID 7b: " _YELLOW_("%s"), sprint_hex(uid, 7));
PrintAndLogEx(INFO, "----------------------------------");
PrintAndLogEx(INFO, " algo | pwd | pack");
PrintAndLogEx(INFO, "-----------------+----------+-----");
PrintAndLogEx(INFO, " Transport EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid));
PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid));
PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid));
PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid));
PrintAndLogEx(INFO, " Xiaomi purifier | %08X | %04X", ul_ev1_pwdgenE(uid), ul_ev1_packgenE(uid));
PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid));
PrintAndLogEx(INFO, "-----------------+----------+-----");
PrintAndLogEx(INFO, "-------------------------------------");
PrintAndLogEx(INFO, " algo | pwd | pack");
PrintAndLogEx(INFO, "--------------------+----------+-----");
PrintAndLogEx(INFO, " Transport EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid));
PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid));
PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid));
PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid));
PrintAndLogEx(INFO, " Xiaomi purifier | %08X | %04X", ul_ev1_pwdgenE(uid), ul_ev1_packgenE(uid));
PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid));
if (philips_mfg[0] != 0) {
PrintAndLogEx(INFO, " Philips Toothbrush | %08X | %04X", ul_ev1_pwdgenG(uid, philips_mfg), ul_ev1_packgenG(uid, philips_mfg));
}
PrintAndLogEx(INFO, "--------------------+----------+-----");
PrintAndLogEx(INFO, " Vingcard algo");
PrintAndLogEx(INFO, " Saflok algo");
PrintAndLogEx(INFO, " SALTO algo");
PrintAndLogEx(INFO, " Dorma Kaba algo");
PrintAndLogEx(INFO, "----------------------------------");
PrintAndLogEx(INFO, " STiD algo");
PrintAndLogEx(INFO, "-------------------------------------");
return PM3_SUCCESS;
}

View file

@ -570,8 +570,12 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
//1 CRC-command, CRC ok
//2 Not crc-command
//--- Draw the data column
char line[18][160] = {{0}};
// Draw the data column
#define TRACE_MAX_LINES 36
// number of hex bytes to be printed per row (16 data + 2 crc)
#define TRACE_MAX_HEX_BYTES 18
char line[TRACE_MAX_LINES][160] = {{0}};
if (data_len == 0) {
if (protocol == ICLASS && duration == 2048) {
@ -582,9 +586,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
snprintf(line[0], sizeof(line[0]), "<empty trace - possible error>");
}
}
uint8_t partialbytebuff = 0;
uint8_t offset = 0;
for (int j = 0; j < data_len && j / 18 < 18; j++) {
for (int j = 0; j < data_len && (j / TRACE_MAX_HEX_BYTES) < TRACE_MAX_HEX_BYTES; j++) {
uint8_t parityBits = parityBytes[j >> 3];
if (protocol != LEGIC
&& protocol != ISO_14443B
@ -602,11 +607,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
&& (oddparity8(frame[j]) != ((parityBits >> (7 - (j & 0x0007))) & 0x01))) {
snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x! ", frame[j]);
} else if (protocol == ICLASS && hdr->isResponse == false) {
uint8_t parity = 0;
for (int i = 0; i < 6; i++) {
parity ^= ((frame[0] >> i) & 1);
}
if (parity == ((frame[0] >> 7) & 1)) {
snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x ", frame[j]);
} else {
@ -631,10 +639,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
}
uint8_t crc_format_string_offset = 0;
if (markCRCBytes && data_len > 2) {
//CRC-command
// CRC-command
if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) {
// Note that UID REQUEST response has no CRC, but we don't know
// if the response we see is a UID
@ -647,36 +653,42 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
if (crcStatus == 0 || crcStatus == 1) {
char *pos1 = line[(data_len - 2) / 18];
pos1 += (((data_len - 2) % 18) * 4) - 1;
char *pos1 = line[(data_len - 2) / TRACE_MAX_HEX_BYTES];
pos1 += (((data_len - 2) % TRACE_MAX_HEX_BYTES) * 4) - 1;
(*(pos1 + 6 + 1)) = '\0';
char *cb_str = str_dup(pos1 + 1);
if (hdr->isResponse) {
if (g_session.supports_colors) {
if (crcStatus == 0) {
snprintf(pos1, 24, " " _RED_("%s") " ", cb_str);
} else {
snprintf(pos1, 24, " " _GREEN_("%s") " ", cb_str);
}
crc_format_string_offset = 9;
if (g_session.supports_colors) {
if (crcStatus == 0) {
snprintf(pos1, 24, AEND " " _RED_("%s"), cb_str);
} else {
snprintf(pos1, 9, "[%s]", cb_str);
snprintf(pos1, 24, AEND " " _GREEN_("%s"), cb_str);
}
} else {
snprintf(pos1, 9, "[%s]", cb_str);
}
// odd case of second crc byte is alone in a new line
if (strlen(cb_str) < 5) {
free(cb_str);
pos1 = line[((data_len - 2) / TRACE_MAX_HEX_BYTES) + 1];
cb_str = str_dup(pos1);
if (g_session.supports_colors) {
if (crcStatus == 0) {
snprintf(pos1, 24, AEND " " _RED_("%s") " ", cb_str);
snprintf(pos1, 24, _RED_("%s"), cb_str);
} else {
snprintf(pos1, 24, AEND " " _GREEN_("%s") " ", cb_str);
snprintf(pos1, 24, _GREEN_("%s"), cb_str);
}
crc_format_string_offset = 13;
} else {
snprintf(pos1, 9, "[%s]", cb_str);
}
}
free(cb_str);
}
}
@ -688,8 +700,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
// mark short bytes (less than 8 Bit + Parity)
if (protocol == ISO_14443A ||
protocol == PROTO_MIFARE ||
protocol == THINFILM) {
protocol == PROTO_MIFARE ||
protocol == THINFILM) {
// approximated with 128 * (9 * data_len);
uint16_t bitime = 1056 + 32;
@ -791,8 +803,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
}
}
int num_lines = MIN((data_len - 1) / 18 + 1, 18);
int str_padder = 72;
int num_lines = MIN((data_len - 1) / TRACE_MAX_HEX_BYTES + 1, TRACE_MAX_HEX_BYTES);
for (int j = 0; j < num_lines ; j++) {
bool last_line = (j == num_lines - 1);
str_padder = 72;
if (j == 0) {
uint32_t time1 = hdr->timestamp - first_hdr->timestamp;
@ -802,25 +820,30 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
time2 = duration;
}
// ansi codes addes extra chars that needs to be taken in consideration.
if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) {
str_padder = 85;
}
if (hdr->isResponse) {
// tag row
if (use_us) {
PrintAndLogEx(NORMAL, " %10.1f | %10.1f | Tag |%-*s | %s| %s",
(float)time1 / 13.56,
(float)time2 / 13.56,
72 + crc_format_string_offset,
str_padder,
line[j],
(j == num_lines - 1) ? crc : " ",
(j == num_lines - 1) ? explanation : ""
(last_line) ? crc : " ",
(last_line) ? explanation : ""
);
} else {
PrintAndLogEx(NORMAL, " %10u | %10u | Tag |%-*s | %s| %s",
time1,
time2,
72 + crc_format_string_offset,
str_padder,
line[j],
(j == num_lines - 1) ? crc : " ",
(j == num_lines - 1) ? explanation : ""
(last_line) ? crc : " ",
(last_line) ? explanation : ""
);
}
} else {
@ -830,41 +853,51 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
_YELLOW_(" %10.1f") " | " _YELLOW_("%10.1f") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
(float)time1 / 13.56,
(float)time2 / 13.56,
72 + crc_format_string_offset,
str_padder,
line[j],
(j == num_lines - 1) ? crc : " ",
(j == num_lines - 1) ? explanation : ""
(last_line) ? crc : " ",
(last_line) ? explanation : ""
);
} else {
PrintAndLogEx(NORMAL,
_YELLOW_(" %10u") " | " _YELLOW_("%10u") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
time1,
time2,
72 + crc_format_string_offset,
str_padder,
line[j],
(j == num_lines - 1) ? crc : " ",
(j == num_lines - 1) ? explanation : ""
(last_line) ? crc : " ",
(last_line) ? explanation : ""
);
}
}
} else {
if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) {
str_padder = 85;
// odd case of multiline, and last single byte on empty row has been colorised...
if (strlen(line[j]) < 14) {
str_padder = 81;
}
}
if (hdr->isResponse) {
PrintAndLogEx(NORMAL, " | | |%-*s | %s| %s",
72 + crc_format_string_offset,
str_padder,
line[j],
(j == num_lines - 1) ? crc : " ",
(j == num_lines - 1) ? explanation : ""
last_line ? crc : " ",
last_line ? explanation : ""
);
} else {
PrintAndLogEx(NORMAL, " | | |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
72 + crc_format_string_offset,
str_padder,
line[j],
(j == num_lines - 1) ? crc : " ",
(j == num_lines - 1) ? explanation : ""
last_line ? crc : " ",
last_line ? explanation : ""
);
}
}
}
@ -875,8 +908,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
memset(explanation, 0x00, sizeof(explanation));
annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse);
uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen);
//iceman: colorise crc bytes here will need a refactor of code from above.
PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s",
72 + crc_format_string_offset,
str_padder,
sprint_hex_inrow_spaces(mfData, mfDataLen, 2),
(crcc == 0 ? _RED_(" !! ") : (crcc == 1 ? _GREEN_(" ok ") : " ")),
explanation);

View file

@ -1075,10 +1075,11 @@ static int ndefRecordDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen, b
return res;
ndefPrintHeader(&NDEFHeader, verbose);
PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, _CYAN_("Payload info"));
if (verbose) {
PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, _CYAN_("Payload info"));
if (NDEFHeader.TypeLen) {
PrintAndLogEx(INFO, "Type data");
print_buffer(NDEFHeader.Type, NDEFHeader.TypeLen, 1);
@ -1229,7 +1230,9 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) {
break;
}
case 0xFE: {
PrintAndLogEx(SUCCESS, "NDEF Terminator detected");
if (verbose) {
PrintAndLogEx(SUCCESS, "NDEF Terminator detected");
}
return PM3_SUCCESS;
}
default: {

View file

@ -250,16 +250,13 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
if (g_session.incognito) {
PrintAndLogEx(INFO, "No history will be recorded");
} else {
bool loaded_history = false;
if (searchHomeFilePath(&g_session.history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) {
g_session.history_path = NULL;
} else {
loaded_history = (pm3line_load_history(g_session.history_path) == PM3_SUCCESS);
}
if (loaded_history) {
pm3line_install_signals();
} else {
PrintAndLogEx(ERR, "No history will be recorded");
} else {
if (pm3line_load_history(g_session.history_path) != PM3_SUCCESS) {
PrintAndLogEx(INFO, "No previous history could be loaded");
}
}
}

View file

@ -42,10 +42,14 @@ void init_table(CrcType_t crctype) {
case CRC_15693:
case CRC_ICLASS:
case CRC_CRYPTORF:
case CRC_KERMIT:
generate_table(CRC16_POLY_CCITT, true);
break;
case CRC_FELICA:
case CRC_XMODEM:
case CRC_CCITT:
case CRC_11784:
case CRC_PHILIPS:
generate_table(CRC16_POLY_CCITT, false);
break;
case CRC_LEGIC:
@ -54,15 +58,6 @@ void init_table(CrcType_t crctype) {
case CRC_LEGIC_16:
generate_table(CRC16_POLY_LEGIC_16, true);
break;
case CRC_CCITT:
generate_table(CRC16_POLY_CCITT, false);
break;
case CRC_KERMIT:
generate_table(CRC16_POLY_CCITT, true);
break;
case CRC_11784:
generate_table(CRC16_POLY_CCITT, false);
break;
case CRC_NONE:
crc_table_init = false;
current_crc_type = CRC_NONE;
@ -210,6 +205,9 @@ void compute_crc(CrcType_t ct, const uint8_t *d, size_t n, uint8_t *first, uint8
case CRC_LEGIC_16:
// TODO
return;
case CRC_PHILIPS:
crc = crc16_philips(d, n);
break;
case CRC_NONE:
return;
}
@ -244,6 +242,8 @@ uint16_t Crc16ex(CrcType_t ct, const uint8_t *d, size_t n) {
case CRC_LEGIC_16:
// TODO
return 0;
case CRC_PHILIPS:
return crc16_philips(d, n);
case CRC_NONE:
default:
break;
@ -290,6 +290,8 @@ bool check_crc(CrcType_t ct, const uint8_t *d, size_t n) {
case CRC_LEGIC_16:
// TODO
return false;
case CRC_PHILIPS:
return (crc16_philips(d, n) == 0);
case CRC_NONE:
default:
break;
@ -350,3 +352,6 @@ uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc) {
return crc16_fast(d, n, initial, true, false);
}
uint16_t crc16_philips(uint8_t const *d, size_t n) {
return crc16_fast(d, n, 0x49A3, false, false);
}

View file

@ -42,6 +42,7 @@ typedef enum {
CRC_KERMIT,
CRC_XMODEM,
CRC_CRYPTORF,
CRC_PHILIPS,
} CrcType_t;
uint16_t update_crc16_ex(uint16_t crc, uint8_t c, uint16_t polynomial);
@ -78,6 +79,9 @@ uint16_t crc16_iclass(uint8_t const *d, size_t n);
// ie: uidcrc = 0x78 then initial_value == 0x7878
uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc);
// Calculate CRC-16/ Philips.
uint16_t crc16_philips(uint8_t const *d, size_t n);
// table implementation
void init_table(CrcType_t crctype);
void reset_table(void);

View file

@ -195,6 +195,20 @@ uint32_t ul_ev1_pwdgenF(const uint8_t *uid) {
return pwd;
}
// Solution from @atc1441
// https://gist.github.com/atc1441/41af75048e4c22af1f5f0d4c1d94bb56
// Philips Sonicare toothbrush NFC head
uint32_t ul_ev1_pwdgenG(const uint8_t *uid, const uint8_t *mfg) {
init_table(CRC_PHILIPS);
// UID
uint32_t crc1 = crc16_philips(uid, 7);
// MFG string
uint32_t crc2 = crc16_fast(mfg, 10, crc1, false, false);
return (BSWAP_16(crc2) << 16 | BSWAP_16(crc1));
}
// pack generation for algo 1-3
uint16_t ul_ev1_packgenA(const uint8_t *uid) {
uint16_t pack = (uid[0] ^ uid[1] ^ uid[2]) << 8 | (uid[2] ^ 8);
@ -224,13 +238,26 @@ uint16_t ul_ev1_packgenD(const uint8_t *uid) {
p ^= 0x5555;
return BSWAP_16(p & 0xFFFF);
}
uint16_t ul_ev1_packgenE(const uint8_t *uid) {
uint32_t pwd = ul_ev1_pwdgenE(uid);
return (0xAD << 8 | ((pwd >> 24) & 0xFF));
}
uint16_t ul_ev1_packgenG(const uint8_t *uid, const uint8_t *mfg) {
init_table(CRC_PHILIPS);
// UID
uint32_t crc1 = crc16_philips(uid, 7);
// MFG string
uint32_t crc2 = crc16_fast(mfg, 10, crc1, false, false);
// PWD
uint32_t pwd = (BSWAP_16(crc2) << 16 | BSWAP_16(crc1));
uint8_t pb[4];
num_to_bytes(pwd, 4, pb);
return BSWAP_16(crc16_fast(pb, 4, crc2, false, false));
}
// default shims
uint32_t ul_ev1_pwdgen_def(const uint8_t *uid) {
@ -556,7 +583,7 @@ int mfc_algo_touch_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *
int generator_selftest(void) {
#ifndef ON_DEVICE
#define NUM_OF_TEST 8
#define NUM_OF_TEST 9
PrintAndLogEx(INFO, "PWD / KEY generator selftest");
PrintAndLogEx(INFO, "----------------------------");
@ -606,18 +633,27 @@ int generator_selftest(void) {
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid6, 7), pwd6, success ? "OK" : "->A9C4C3C0<--");
uint8_t uid7[] = {0x04, 0x0D, 0x4B, 0x5A, 0xC5, 0x71, 0x81};
uint8_t mfg[] = {0x32, 0x31, 0x30, 0x36, 0x32, 0x38, 0x20, 0x35, 0x32, 0x4D};
uint32_t pwd7 = ul_ev1_pwdgenG(uid7, mfg);
success = (pwd7 == 0xFBCFACC1);
if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid7, 7), pwd7, success ? "OK" : "->FBCFACC1<--");
// uint8_t uid5[] = {0x11, 0x22, 0x33, 0x44};
// uint64_t key1 = mfc_algo_a(uid5);
// success = (key1 == 0xD1E2AA68E39A);
// PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid5, 4), key1, success ? "OK" : "->D1E2AA68E39A<--");
uint8_t uid7[] = {0x74, 0x57, 0xCA, 0xA9};
uint64_t key7 = 0;
mfc_algo_sky_one(uid7, 15, 0, &key7);
success = (key7 == 0x82c7e64bc565);
uint8_t uid8[] = {0x74, 0x57, 0xCA, 0xA9};
uint64_t key8 = 0;
mfc_algo_sky_one(uid8, 15, 0, &key8);
success = (key8 == 0x82c7e64bc565);
if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid7, 4), key7, success ? "OK" : "->82C7E64BC565<--");
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid8, 4), key8, success ? "OK" : "->82C7E64BC565<--");
uint32_t lf_id = lf_t55xx_white_pwdgen(0x00000080);

View file

@ -28,6 +28,7 @@ uint32_t ul_ev1_pwdgenC(const uint8_t *uid);
uint32_t ul_ev1_pwdgenD(const uint8_t *uid);
uint32_t ul_ev1_pwdgenE(const uint8_t *uid);
uint32_t ul_ev1_pwdgenF(const uint8_t *uid);
uint32_t ul_ev1_pwdgenG(const uint8_t *uid, const uint8_t *mfg);
uint16_t ul_ev1_packgen_def(const uint8_t *uid);
uint16_t ul_ev1_packgenA(const uint8_t *uid);
@ -35,6 +36,7 @@ uint16_t ul_ev1_packgenB(const uint8_t *uid);
uint16_t ul_ev1_packgenC(const uint8_t *uid);
uint16_t ul_ev1_packgenD(const uint8_t *uid);
uint16_t ul_ev1_packgenE(const uint8_t *uid);
uint16_t ul_ev1_packgenG(const uint8_t *uid, const uint8_t *mfg);
uint32_t ul_c_otpgenA(const uint8_t *uid);

7
pm3
View file

@ -144,7 +144,8 @@ function get_pm3_list_Windows {
DEV=${DEV/ */}
#prevent soft bricking when using pm3-flash-all on an outdated bootloader
if [ $(basename -- "$0") = "pm3-flash-all" ]; then
if [ ! $(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then
line=$(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}');
if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then
echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
exit 1
fi
@ -189,9 +190,11 @@ function get_pm3_list_WSL {
DEV=$(echo $DEV | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p')
# ttyS counterpart takes some more time to appear
if [ -e "$DEV" ]; then
#prevent soft bricking when using pm3-flash-all on an outdated bootloader
if [ $(basename -- "$0") = "pm3-flash-all" ]; then
if [ ! $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then
line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]');
if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then
echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
exit 1
fi