mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-15 17:53:01 -07:00
Merge branch 'master' into iclass_MAC_speedup
This commit is contained in:
commit
a1ff338bd5
18 changed files with 1555 additions and 1284 deletions
|
@ -42,6 +42,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Added downlink reference mode option r <mode> [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce`
|
- Added downlink reference mode option r <mode> [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce`
|
||||||
- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password
|
- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password
|
||||||
- `hf mfu info` now checks the NXP Originality Signature if availabe (piwi)
|
- `hf mfu info` now checks the NXP Originality Signature if availabe (piwi)
|
||||||
|
- Added `hf mf personalize` to personalize the UID option of Mifare Classic EV1 cards (piwi)
|
||||||
|
|
||||||
|
|
||||||
## [v3.1.0][2018-10-10]
|
## [v3.1.0][2018-10-10]
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "iso15693.h"
|
#include "iso15693.h"
|
||||||
#include "lfsampling.h"
|
#include "lfsampling.h"
|
||||||
#include "BigBuf.h"
|
#include "BigBuf.h"
|
||||||
|
#include "mifarecmd.h"
|
||||||
#include "mifareutil.h"
|
#include "mifareutil.h"
|
||||||
#include "mifaresim.h"
|
#include "mifaresim.h"
|
||||||
#include "pcf7931.h"
|
#include "pcf7931.h"
|
||||||
|
@ -1243,6 +1244,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
|
||||||
case CMD_MIFARE_WRITEBL:
|
case CMD_MIFARE_WRITEBL:
|
||||||
MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
|
MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
|
||||||
break;
|
break;
|
||||||
|
case CMD_MIFARE_PERSONALIZE_UID:
|
||||||
|
MifarePersonalizeUID(c->arg[0], c->arg[1], c->d.asBytes);
|
||||||
|
break;
|
||||||
//case CMD_MIFAREU_WRITEBL_COMPAT:
|
//case CMD_MIFAREU_WRITEBL_COMPAT:
|
||||||
//MifareUWriteBlockCompat(c->arg[0], c->d.asBytes);
|
//MifareUWriteBlockCompat(c->arg[0], c->d.asBytes);
|
||||||
//break;
|
//break;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "usb_cmd.h"
|
#include "usb_cmd.h"
|
||||||
#include "hitag2.h"
|
|
||||||
#include "hitagS.h"
|
#include "hitagS.h"
|
||||||
#include "mifare.h"
|
#include "mifare.h"
|
||||||
#include "../common/crc32.h"
|
#include "../common/crc32.h"
|
||||||
|
@ -104,33 +103,6 @@ void RAMFUNC SniffMifare(uint8_t param);
|
||||||
void EPA_PACE_Collect_Nonce(UsbCommand * c);
|
void EPA_PACE_Collect_Nonce(UsbCommand * c);
|
||||||
void EPA_PACE_Replay(UsbCommand *c);
|
void EPA_PACE_Replay(UsbCommand *c);
|
||||||
|
|
||||||
// mifarecmd.h
|
|
||||||
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
|
|
||||||
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
|
||||||
void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
|
|
||||||
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
|
|
||||||
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
|
|
||||||
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
|
|
||||||
//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
|
|
||||||
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
|
||||||
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
|
|
||||||
void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
|
|
||||||
void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
|
|
||||||
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
|
||||||
void MifareCIdent(); // is "magic chinese" card?
|
|
||||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
|
||||||
|
|
||||||
//desfire
|
|
||||||
void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
|
|
||||||
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
|
|
||||||
|
|
||||||
// mifaredesfire.h
|
// mifaredesfire.h
|
||||||
bool InitDesfireCard();
|
bool InitDesfireCard();
|
||||||
void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain);
|
void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain);
|
||||||
|
|
514
armsrc/hitag2.c
514
armsrc/hitag2.c
File diff suppressed because it is too large
Load diff
|
@ -16,9 +16,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "hitag.h"
|
#include "hitag.h"
|
||||||
|
|
||||||
void SnoopHitag(uint32_t type);
|
extern void SnoopHitag(uint32_t type);
|
||||||
void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data);
|
extern void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data);
|
||||||
void ReaderHitag(hitag_function htf, hitag_data* htd);
|
extern void ReaderHitag(hitag_function htf, hitag_data* htd);
|
||||||
void WriterHitag(hitag_function htf, hitag_data* htd, int page);
|
extern void WriterHitag(hitag_function htf, hitag_data* htd, int page);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,18 +26,6 @@
|
||||||
#define CRC_PRESET 0xFF
|
#define CRC_PRESET 0xFF
|
||||||
#define CRC_POLYNOM 0x1D
|
#define CRC_POLYNOM 0x1D
|
||||||
|
|
||||||
#define u8 uint8_t
|
|
||||||
#define u32 uint32_t
|
|
||||||
#define u64 uint64_t
|
|
||||||
#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7))
|
|
||||||
#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8))
|
|
||||||
#define rev32(x) (rev16(x)+(rev16(x>>16)<<16))
|
|
||||||
#define rev64(x) (rev32(x)+(rev32(x>>32)<<32))
|
|
||||||
#define bit(x,n) (((x)>>(n))&1)
|
|
||||||
#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1)
|
|
||||||
#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31))
|
|
||||||
#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63)))
|
|
||||||
|
|
||||||
static bool bQuiet;
|
static bool bQuiet;
|
||||||
static bool bSuccessful;
|
static bool bSuccessful;
|
||||||
static struct hitagS_tag tag;
|
static struct hitagS_tag tag;
|
||||||
|
@ -57,17 +45,17 @@ size_t blocknr;
|
||||||
bool end=false;
|
bool end=false;
|
||||||
|
|
||||||
// Single bit Hitag2 functions:
|
// Single bit Hitag2 functions:
|
||||||
#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
|
#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
|
||||||
static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001
|
static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001
|
||||||
static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001
|
static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001
|
||||||
static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
||||||
#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b))
|
#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b))
|
||||||
#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b)))
|
#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b)))
|
||||||
#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c))))
|
#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c))))
|
||||||
#define uf20bs u32
|
#define uf20bs uint32_t
|
||||||
|
|
||||||
static u32 f20(const u64 x) {
|
static uint32_t f20(const uint64_t x) {
|
||||||
u32 i5;
|
uint32_t i5;
|
||||||
|
|
||||||
i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
|
i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
|
||||||
+ ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2
|
+ ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2
|
||||||
|
@ -77,8 +65,19 @@ static u32 f20(const u64 x) {
|
||||||
|
|
||||||
return (ht2_f5c >> i5) & 1;
|
return (ht2_f5c >> i5) & 1;
|
||||||
}
|
}
|
||||||
static u64 hitag2_round(u64 *state) {
|
|
||||||
u64 x = *state;
|
static uint64_t hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) {
|
||||||
|
uint32_t i;
|
||||||
|
uint64_t x = ((key & 0xFFFF) << 32) + serial;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
x >>= 1;
|
||||||
|
x += (uint64_t) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t hitag2_round(uint64_t *state) {
|
||||||
|
uint64_t x = *state;
|
||||||
|
|
||||||
x = (x >> 1)
|
x = (x >> 1)
|
||||||
+ ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8)
|
+ ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8)
|
||||||
|
@ -89,20 +88,12 @@ static u64 hitag2_round(u64 *state) {
|
||||||
*state = x;
|
*state = x;
|
||||||
return f20(x);
|
return f20(x);
|
||||||
}
|
}
|
||||||
static u64 hitag2_init(const u64 key, const u32 serial, const u32 IV) {
|
|
||||||
u32 i;
|
static uint32_t hitag2_byte(uint64_t *x) {
|
||||||
u64 x = ((key & 0xFFFF) << 32) + serial;
|
uint32_t i, c;
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
x >>= 1;
|
|
||||||
x += (u64) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
static u32 hitag2_byte(u64 *x) {
|
|
||||||
u32 i, c;
|
|
||||||
|
|
||||||
for (i = 0, c = 0; i < 8; i++)
|
for (i = 0, c = 0; i < 8; i++)
|
||||||
c += (u32) hitag2_round(x) << (i ^ 7);
|
c += (uint32_t) hitag2_round(x) << (i ^ 7);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,7 +849,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen,
|
||||||
byte_t rx_air[HITAG_FRAME_LEN];
|
byte_t rx_air[HITAG_FRAME_LEN];
|
||||||
byte_t page;
|
byte_t page;
|
||||||
int i;
|
int i;
|
||||||
u64 state;
|
uint64_t state;
|
||||||
unsigned char crc;
|
unsigned char crc;
|
||||||
|
|
||||||
// Copy the (original) received frame how it is send over the air
|
// Copy the (original) received frame how it is send over the air
|
||||||
|
@ -956,8 +947,8 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen,
|
||||||
//challenge message received
|
//challenge message received
|
||||||
Dbprintf("Challenge for UID: %X", temp_uid);
|
Dbprintf("Challenge for UID: %X", temp_uid);
|
||||||
temp2++;
|
temp2++;
|
||||||
state = hitag2_init(rev64(tag.key), rev32(tag.pages[0][0]),
|
state = hitag2_init(REV64(tag.key), REV32(tag.pages[0][0]),
|
||||||
rev32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0])));
|
REV32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0])));
|
||||||
Dbprintf(
|
Dbprintf(
|
||||||
",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}",
|
",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}",
|
||||||
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
|
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
|
||||||
|
@ -1216,7 +1207,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr
|
||||||
unsigned char uid[32];
|
unsigned char uid[32];
|
||||||
byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00;
|
byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00;
|
||||||
unsigned char crc;
|
unsigned char crc;
|
||||||
u64 state;
|
uint64_t state;
|
||||||
byte_t auth_ks[4];
|
byte_t auth_ks[4];
|
||||||
byte_t conf_pages[3];
|
byte_t conf_pages[3];
|
||||||
memcpy(rx_air, rx, nbytes(rxlen));
|
memcpy(rx_air, rx, nbytes(rxlen));
|
||||||
|
@ -1356,11 +1347,11 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr
|
||||||
*txlen = 64;
|
*txlen = 64;
|
||||||
if(end!=true){
|
if(end!=true){
|
||||||
if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY
|
if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY
|
||||||
state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd));
|
state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
|
||||||
/*
|
/*
|
||||||
Dbprintf("key: %02X %02X\n\n", key, rev64(key));
|
Dbprintf("key: %02X %02X\n\n", key, REV64(key));
|
||||||
Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid));
|
Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, REV32(tag.uid));
|
||||||
Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd));
|
Dbprintf("rnd: %02X %02X\n\n", rnd, REV32(rnd));
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
auth_ks[i] = hitag2_byte(&state) ^ 0xff;
|
auth_ks[i] = hitag2_byte(&state) ^ 0xff;
|
||||||
|
@ -1404,7 +1395,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr
|
||||||
pwdl0=0;
|
pwdl0=0;
|
||||||
pwdl1=0;
|
pwdl1=0;
|
||||||
if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY
|
if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY
|
||||||
state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd));
|
state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
hitag2_byte(&state);
|
hitag2_byte(&state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,16 @@
|
||||||
|
|
||||||
#include "mifarecmd.h"
|
#include "mifarecmd.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "proxmark3.h"
|
||||||
|
#include "cmd.h"
|
||||||
|
#include "crapto1/crapto1.h"
|
||||||
|
#include "iso14443a.h"
|
||||||
|
#include "BigBuf.h"
|
||||||
|
#include "mifareutil.h"
|
||||||
|
#include "apps.h"
|
||||||
|
#include "protocols.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "parity.h"
|
#include "parity.h"
|
||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
|
@ -1026,6 +1036,60 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
|
||||||
LED_A_OFF();
|
LED_A_OFF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *data) {
|
||||||
|
|
||||||
|
uint8_t uid[10];
|
||||||
|
uint32_t cuid;
|
||||||
|
struct Crypto1State mpcs = {0, 0};
|
||||||
|
struct Crypto1State *pcs;
|
||||||
|
pcs = &mpcs;
|
||||||
|
|
||||||
|
LED_A_ON();
|
||||||
|
clear_trace();
|
||||||
|
|
||||||
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
|
||||||
|
bool isOK = false;
|
||||||
|
while (true) {
|
||||||
|
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||||
|
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t block_number = 0;
|
||||||
|
uint64_t key = bytes_to_num(data, 6);
|
||||||
|
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) {
|
||||||
|
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
||||||
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
|
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
|
||||||
|
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
isOK = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
LED_D_OFF();
|
||||||
|
|
||||||
|
crypto1_destroy(pcs);
|
||||||
|
|
||||||
|
if (MF_DBGLEVEL >= 2) DbpString("PERSONALIZE UID FINISHED");
|
||||||
|
|
||||||
|
cmd_send(CMD_ACK, isOK, 0, 0, NULL, 0);
|
||||||
|
|
||||||
|
LED_A_OFF();
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// MIFARE commands set debug level
|
// MIFARE commands set debug level
|
||||||
//
|
//
|
||||||
|
@ -1201,13 +1265,13 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
|
||||||
// wipe
|
// wipe
|
||||||
if (needWipe){
|
if (needWipe){
|
||||||
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
|
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1222,16 +1286,16 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
|
||||||
// select commands
|
// select commands
|
||||||
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
|
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
|
||||||
|
|
||||||
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
|
// gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
|
||||||
if (!gen1b) {
|
if (!gen1b) {
|
||||||
|
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1239,7 +1303,7 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
|
||||||
|
|
||||||
// send blocks command
|
// send blocks command
|
||||||
for (int blockNo = 0; blockNo < numBlocks; blockNo++) {
|
for (int blockNo = 0; blockNo < numBlocks; blockNo++) {
|
||||||
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
|
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1257,7 +1321,7 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
|
||||||
|
|
||||||
// send write command
|
// send write command
|
||||||
ReaderTransmit(d_block, sizeof(d_block), NULL);
|
ReaderTransmit(d_block, sizeof(d_block), NULL);
|
||||||
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
|
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1346,13 +1410,13 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
|
||||||
// Wipe command don't work with gen1b
|
// Wipe command don't work with gen1b
|
||||||
if (needWipe && !(workFlags & 0x40)){
|
if (needWipe && !(workFlags & 0x40)){
|
||||||
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
|
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1368,23 +1432,23 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
|
||||||
if (workFlags & 0x02) {
|
if (workFlags & 0x02) {
|
||||||
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
||||||
|
|
||||||
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
|
// gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
|
||||||
if (!(workFlags & 0x40)) {
|
if (!(workFlags & 0x40)) {
|
||||||
|
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
|
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1393,7 +1457,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
|
||||||
AppendCrc14443a(d_block, 16);
|
AppendCrc14443a(d_block, 16);
|
||||||
|
|
||||||
ReaderTransmit(d_block, sizeof(d_block), NULL);
|
ReaderTransmit(d_block, sizeof(d_block), NULL);
|
||||||
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
|
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1461,14 +1525,14 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
|
||||||
while (true) {
|
while (true) {
|
||||||
if (workFlags & 0x02) {
|
if (workFlags & 0x02) {
|
||||||
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
// do no issue for gen1b magic tag
|
// do no issue for gen1b magic tag
|
||||||
if (!(workFlags & 0x40)) {
|
if (!(workFlags & 0x40)) {
|
||||||
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
||||||
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -1533,11 +1597,11 @@ void MifareCIdent(){
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
|
|
||||||
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
ReaderTransmitBitsPar(wupC1,7,0, NULL);
|
||||||
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) {
|
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) {
|
||||||
isOK = 2;
|
isOK = 2;
|
||||||
|
|
||||||
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
||||||
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) {
|
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) {
|
||||||
isOK = 1;
|
isOK = 1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,18 +10,36 @@
|
||||||
// Routines to support ISO 14443 type A.
|
// Routines to support ISO 14443 type A.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef __MIFARECMD_H
|
#ifndef MIFARECMD_H__
|
||||||
#define __MIFARECMD_H
|
#define MIFARECMD_H__
|
||||||
|
|
||||||
#include "proxmark3.h"
|
#include <stdint.h>
|
||||||
#include "apps.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include "iso14443crc.h"
|
extern void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
|
||||||
#include "iso14443a.h"
|
extern void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||||
#include "crapto1/crapto1.h"
|
extern void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
|
||||||
#include "mifareutil.h"
|
extern void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
|
||||||
#include "common.h"
|
extern void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
|
||||||
|
//extern void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
|
||||||
|
extern void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||||
|
extern void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
|
||||||
|
extern void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
|
||||||
|
extern void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
extern void MifareCIdent(); // is "magic chinese" card?
|
||||||
|
extern void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
||||||
|
extern void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *datain);
|
||||||
|
|
||||||
|
//desfire
|
||||||
|
extern void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
|
||||||
|
extern void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -22,6 +22,7 @@
|
||||||
#include "iso14443a.h"
|
#include "iso14443a.h"
|
||||||
#include "crapto1/crapto1.h"
|
#include "crapto1/crapto1.h"
|
||||||
#include "mbedtls/des.h"
|
#include "mbedtls/des.h"
|
||||||
|
#include "protocols.h"
|
||||||
|
|
||||||
int MF_DBGLEVEL = MF_DBG_INFO;
|
int MF_DBGLEVEL = MF_DBG_INFO;
|
||||||
|
|
||||||
|
@ -163,7 +164,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
|
||||||
// Transmit MIFARE_CLASSIC_AUTH
|
// Transmit MIFARE_CLASSIC_AUTH
|
||||||
len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing);
|
len = mifare_sendcmd_short(pcs, isNested, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, timing);
|
||||||
if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len);
|
if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len);
|
||||||
if (len != 4) return 1;
|
if (len != 4) return 1;
|
||||||
|
|
||||||
|
@ -250,7 +251,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
|
||||||
// command MIFARE_CLASSIC_READBLOCK
|
// command MIFARE_CLASSIC_READBLOCK
|
||||||
len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -282,7 +283,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){
|
||||||
|
|
||||||
if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
|
if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
|
||||||
Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]);
|
Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]);
|
||||||
len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL);
|
len = mifare_sendcmd(MIFARE_ULEV1_AUTH, key, sizeof(key), resp, respPar, NULL);
|
||||||
//len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL);
|
//len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL);
|
||||||
if (len != 4) {
|
if (len != 4) {
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len);
|
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len);
|
||||||
|
@ -314,7 +315,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
|
||||||
uint8_t respPar[3] = {0,0,0};
|
uint8_t respPar[3] = {0,0,0};
|
||||||
|
|
||||||
// REQUEST AUTHENTICATION
|
// REQUEST AUTHENTICATION
|
||||||
len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, resp, respPar ,NULL);
|
len = mifare_sendcmd_short(NULL, 1, MIFARE_ULC_AUTH_1, 0x00, resp, respPar ,NULL);
|
||||||
if (len != 11) {
|
if (len != 11) {
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
|
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -364,7 +365,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
|
||||||
);
|
);
|
||||||
|
|
||||||
//len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL);
|
//len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL);
|
||||||
len = mifare_sendcmd(0xAF, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
|
len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
|
||||||
if (len != 11) {
|
if (len != 11) {
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
|
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -421,7 +422,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData)
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
for (retries = 0; retries < MFU_MAX_RETRIES; retries++) {
|
for (retries = 0; retries < MFU_MAX_RETRIES; retries++) {
|
||||||
len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
len = mifare_sendcmd_short(NULL, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||||
result = 1;
|
result = 1;
|
||||||
|
@ -468,7 +469,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
|
||||||
// command MIFARE_CLASSIC_WRITEBLOCK
|
// command MIFARE_CLASSIC_WRITEBLOCK
|
||||||
len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
|
|
||||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||||
|
@ -511,7 +512,7 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData)
|
||||||
uint8_t receivedAnswer[MAX_FRAME_SIZE];
|
uint8_t receivedAnswer[MAX_FRAME_SIZE];
|
||||||
uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
|
uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
|
||||||
|
|
||||||
len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
len = mifare_sendcmd_short(NULL, true, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
|
|
||||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR)
|
if (MF_DBGLEVEL >= MF_DBG_ERROR)
|
||||||
|
@ -563,7 +564,7 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid)
|
||||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
|
||||||
len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL);
|
len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR)
|
if (MF_DBGLEVEL >= MF_DBG_ERROR)
|
||||||
Dbprintf("halt error. response len: %x", len);
|
Dbprintf("halt error. response len: %x", len);
|
||||||
|
@ -579,7 +580,7 @@ int mifare_ultra_halt()
|
||||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
||||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||||
|
|
||||||
len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL);
|
len = mifare_sendcmd_short(NULL, true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL);
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
if (MF_DBGLEVEL >= MF_DBG_ERROR)
|
if (MF_DBGLEVEL >= MF_DBG_ERROR)
|
||||||
Dbprintf("halt error. response len: %x", len);
|
Dbprintf("halt error. response len: %x", len);
|
||||||
|
|
|
@ -152,8 +152,14 @@ bool IsBlock0PCF7931(uint8_t *block) {
|
||||||
|
|
||||||
bool IsBlock1PCF7931(uint8_t *block) {
|
bool IsBlock1PCF7931(uint8_t *block) {
|
||||||
// assuming all RFU bits are set to 0
|
// assuming all RFU bits are set to 0
|
||||||
|
|
||||||
|
uint8_t rb1 = block[14] & 0x80;
|
||||||
|
uint8_t rfb = block[14] & 0x7f;
|
||||||
|
uint8_t rlb = block[15];
|
||||||
|
|
||||||
if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0)
|
if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0)
|
||||||
if((block[14] & 0x7f) <= 9 && block[15] <= 9)
|
// block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled
|
||||||
|
if(rfb <= rlb && rfb <= 9 && rlb <= 9 && ((rfb <= 1 && rlb >= 1) || rb1))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -192,6 +198,7 @@ void ReadPCF7931() {
|
||||||
Dbprintf("Error, no tag or bad tag");
|
Dbprintf("Error, no tag or bad tag");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit if too many errors during reading
|
// exit if too many errors during reading
|
||||||
if (tries > 50 && (2*errors > tries)) {
|
if (tries > 50 && (2*errors > tries)) {
|
||||||
Dbprintf("Error reading the tag");
|
Dbprintf("Error reading the tag");
|
||||||
|
@ -201,9 +208,11 @@ void ReadPCF7931() {
|
||||||
|
|
||||||
// our logic breaks if we don't get at least two blocks
|
// our logic breaks if we don't get at least two blocks
|
||||||
if (n < 2) {
|
if (n < 2) {
|
||||||
|
// skip if all 0s block or no blocks
|
||||||
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
|
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// add block to single blocks list
|
||||||
if (single_blocks_cnt < max_blocks) {
|
if (single_blocks_cnt < max_blocks) {
|
||||||
for (i = 0; i < single_blocks_cnt; ++i) {
|
for (i = 0; i < single_blocks_cnt; ++i) {
|
||||||
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
|
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
|
||||||
|
@ -213,6 +222,7 @@ void ReadPCF7931() {
|
||||||
}
|
}
|
||||||
if (j != 1) {
|
if (j != 1) {
|
||||||
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
|
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
|
||||||
|
print_result("got single block", single_blocks[single_blocks_cnt], 16);
|
||||||
single_blocks_cnt++;
|
single_blocks_cnt++;
|
||||||
}
|
}
|
||||||
j = 0;
|
j = 0;
|
||||||
|
@ -222,6 +232,10 @@ void ReadPCF7931() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
|
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
|
||||||
|
for (i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
print_result("got consecutive blocks", tmp_blocks[i], 16);
|
||||||
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
if(!found_0_1) {
|
if(!found_0_1) {
|
||||||
|
@ -284,7 +298,7 @@ void ReadPCF7931() {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (found_blocks != max_blocks);
|
while (found_blocks < max_blocks);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
Dbprintf("-----------------------------------------");
|
Dbprintf("-----------------------------------------");
|
||||||
|
|
|
@ -21,12 +21,18 @@
|
||||||
#define LED_ORANGE 2
|
#define LED_ORANGE 2
|
||||||
#define LED_GREEN 4
|
#define LED_GREEN 4
|
||||||
#define LED_RED2 8
|
#define LED_RED2 8
|
||||||
|
|
||||||
#define BUTTON_HOLD 1
|
#define BUTTON_HOLD 1
|
||||||
#define BUTTON_NO_CLICK 0
|
#define BUTTON_NO_CLICK 0
|
||||||
#define BUTTON_SINGLE_CLICK -1
|
#define BUTTON_SINGLE_CLICK -1
|
||||||
#define BUTTON_DOUBLE_CLICK -2
|
#define BUTTON_DOUBLE_CLICK -2
|
||||||
#define BUTTON_ERROR -99
|
#define BUTTON_ERROR -99
|
||||||
|
|
||||||
|
#define REV8(x) ((((x)>>7)&1)|((((x)>>6)&1)<<1)|((((x)>>5)&1)<<2)|((((x)>>4)&1)<<3)|((((x)>>3)&1)<<4)|((((x)>>2)&1)<<5)|((((x)>>1)&1)<<6)|(((x)&1)<<7))
|
||||||
|
#define REV16(x) (REV8(x) | (REV8 (x >> 8) << 8))
|
||||||
|
#define REV32(x) (REV16(x) | (REV16(x >> 16) << 16))
|
||||||
|
#define REV64(x) (REV32(x) | (REV32(x >> 32) << 32))
|
||||||
|
|
||||||
void print_result(char *name, uint8_t *buf, size_t len);
|
void print_result(char *name, uint8_t *buf, size_t len);
|
||||||
size_t nbytes(size_t nbits);
|
size_t nbytes(size_t nbits);
|
||||||
uint32_t SwapBits(uint32_t value, int nrbits);
|
uint32_t SwapBits(uint32_t value, int nrbits);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "mifare/mad.h"
|
#include "mifare/mad.h"
|
||||||
#include "mifare/ndef.h"
|
#include "mifare/ndef.h"
|
||||||
#include "emv/dump.h"
|
#include "emv/dump.h"
|
||||||
|
#include "protocols.h"
|
||||||
|
|
||||||
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up
|
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up
|
||||||
|
|
||||||
|
@ -3009,8 +3010,86 @@ int CmdHFMFNDEF(const char *cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] =
|
int CmdHFMFPersonalize(const char *cmd) {
|
||||||
{
|
|
||||||
|
CLIParserInit("hf mf personalize",
|
||||||
|
"Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.",
|
||||||
|
"Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n"
|
||||||
|
"\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n"
|
||||||
|
"\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n"
|
||||||
|
"\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n"
|
||||||
|
"\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("tT", "keytype", "<A|B>", "key type (A or B) to authenticate sector 0 (default: A)"),
|
||||||
|
arg_str0("kK", "key", "<key (hex 6 Bytes)>", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"),
|
||||||
|
arg_str1(NULL, NULL, "<UIDF0|UIDF1|UIDF2|UIDF3>", "Personalization Option"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(cmd, argtable, true);
|
||||||
|
|
||||||
|
char keytypestr[2] = "A";
|
||||||
|
uint8_t keytype = 0x00;
|
||||||
|
int keytypestr_len;
|
||||||
|
int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t*)keytypestr, 1, &keytypestr_len);
|
||||||
|
if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'A' && keytypestr[0] != 'b' && keytypestr[0] != 'B')) {
|
||||||
|
PrintAndLog("ERROR: not a valid key type. Key type must be A or B");
|
||||||
|
CLIParserFree();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (keytypestr[0] == 'B' || keytypestr[0] == 'b') {
|
||||||
|
keytype = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||||
|
int key_len;
|
||||||
|
res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len);
|
||||||
|
if (res || (!res && key_len > 0 && key_len != 6)) {
|
||||||
|
PrintAndLog("ERROR: not a valid key. Key must be 12 hex digits");
|
||||||
|
CLIParserFree();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char pers_optionstr[6];
|
||||||
|
int opt_len;
|
||||||
|
uint8_t pers_option;
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(3), (uint8_t*)pers_optionstr, 5, &opt_len);
|
||||||
|
if (res || (!res && opt_len > 0 && opt_len != 5)
|
||||||
|
|| (strncmp(pers_optionstr, "UIDF0", 5) && strncmp(pers_optionstr, "UIDF1", 5) && strncmp(pers_optionstr, "UIDF2", 5) && strncmp(pers_optionstr, "UIDF3", 5))) {
|
||||||
|
PrintAndLog("ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3");
|
||||||
|
CLIParserFree();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(pers_optionstr, "UIDF0", 5)) {
|
||||||
|
pers_option = MIFARE_EV1_UIDF0;
|
||||||
|
} else if (!strncmp(pers_optionstr, "UIDF1", 5)) {
|
||||||
|
pers_option = MIFARE_EV1_UIDF1;
|
||||||
|
} else if (!strncmp(pers_optionstr, "UIDF2", 5)) {
|
||||||
|
pers_option = MIFARE_EV1_UIDF2;
|
||||||
|
} else {
|
||||||
|
pers_option = MIFARE_EV1_UIDF3;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIParserFree();
|
||||||
|
|
||||||
|
UsbCommand c = {CMD_MIFARE_PERSONALIZE_UID, {keytype, pers_option, 0}};
|
||||||
|
memcpy(c.d.asBytes, key, 6);
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
UsbCommand resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
|
uint8_t isOK = resp.arg[0] & 0xff;
|
||||||
|
PrintAndLog("Personalization %s", isOK ? "FAILED" : "SUCCEEDED");
|
||||||
|
} else {
|
||||||
|
PrintAndLog("Command execute timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, 1, "This help"},
|
{"help", CmdHelp, 1, "This help"},
|
||||||
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
|
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
|
||||||
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
|
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
|
||||||
|
@ -3042,18 +3121,19 @@ static command_t CommandTable[] =
|
||||||
{"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"},
|
{"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"},
|
||||||
{"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"},
|
{"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"},
|
||||||
{"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"},
|
{"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"},
|
||||||
|
{"personalize", CmdHFMFPersonalize, 0, "Personalize UID (Mifare Classic EV1 only)"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
int CmdHFMF(const char *Cmd)
|
|
||||||
{
|
int CmdHFMF(const char *Cmd) {
|
||||||
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
|
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
|
||||||
CmdsParse(CommandTable, Cmd);
|
CmdsParse(CommandTable, Cmd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdHelp(const char *Cmd)
|
|
||||||
{
|
int CmdHelp(const char *Cmd) {
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,12 @@
|
||||||
#include "hitag.h"
|
#include "hitag.h"
|
||||||
#include "cmdmain.h"
|
#include "cmdmain.h"
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static size_t nbytes(size_t nbits) {
|
||||||
|
|
||||||
size_t nbytes(size_t nbits) {
|
|
||||||
return (nbits/8) + ((nbits%8)>0);
|
return (nbits/8) + ((nbits%8)>0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdLFHitagList(const char *Cmd)
|
|
||||||
{
|
static int CmdLFHitagList(const char *Cmd) {
|
||||||
uint8_t *got = malloc(USB_CMD_DATA_SIZE);
|
uint8_t *got = malloc(USB_CMD_DATA_SIZE);
|
||||||
// Query for the actual size of the trace
|
// Query for the actual size of the trace
|
||||||
UsbCommand response;
|
UsbCommand response;
|
||||||
|
@ -168,13 +166,15 @@ int CmdLFHitagList(const char *Cmd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdLFHitagSnoop(const char *Cmd) {
|
|
||||||
|
static int CmdLFHitagSnoop(const char *Cmd) {
|
||||||
UsbCommand c = {CMD_SNOOP_HITAG};
|
UsbCommand c = {CMD_SNOOP_HITAG};
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdLFHitagSim(const char *Cmd) {
|
|
||||||
|
static int CmdLFHitagSim(const char *Cmd) {
|
||||||
|
|
||||||
UsbCommand c = {CMD_SIMULATE_HITAG};
|
UsbCommand c = {CMD_SIMULATE_HITAG};
|
||||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||||
|
@ -207,8 +207,66 @@ int CmdLFHitagSim(const char *Cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool getHitagUid(uint32_t *uid) {
|
||||||
|
// ToDo: this is for Hitag2 only (??)
|
||||||
|
|
||||||
|
UsbCommand c = {CMD_READER_HITAG, {RHT2F_UID_ONLY}};
|
||||||
|
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
UsbCommand resp;
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||||
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.arg[0] == false) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uid)
|
||||||
|
*uid = bytes_to_num(resp.d.asBytes, 4);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int CmdLFHitagInfo(const char *Cmd) {
|
||||||
|
char ctmp = param_getchar(Cmd, 0);
|
||||||
|
if (ctmp != '\0') {
|
||||||
|
PrintAndLog("Usage: lf hitag info [h]");
|
||||||
|
PrintAndLog("Options:");
|
||||||
|
PrintAndLog(" h This help");
|
||||||
|
PrintAndLog("Examples:");
|
||||||
|
PrintAndLog(" lf hitag info");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read UID
|
||||||
|
uint32_t uid = 0;
|
||||||
|
if (getHitagUid(&uid) == false)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "UID: %08X", uid);
|
||||||
|
|
||||||
|
// how to detemine Hitag types?
|
||||||
|
// read block3, get configuration byte.
|
||||||
|
// PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
|
||||||
|
|
||||||
|
// common configurations.
|
||||||
|
// printHitagConfiguration(0x06);
|
||||||
|
//printHitagConfiguration( 0x0E );
|
||||||
|
//printHitagConfiguration( 0x02 );
|
||||||
|
//printHitagConfiguration( 0x00 );
|
||||||
|
//printHitagConfiguration( 0x04 );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int CmdLFHitagReader(const char *Cmd) {
|
int CmdLFHitagReader(const char *Cmd) {
|
||||||
UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}};
|
UsbCommand c = {CMD_READER_HITAG};
|
||||||
hitag_data* htd = (hitag_data*)c.d.asBytes;
|
hitag_data* htd = (hitag_data*)c.d.asBytes;
|
||||||
hitag_function htf = param_get32ex(Cmd, 0, 0, 10);
|
hitag_function htf = param_get32ex(Cmd, 0, 0, 10);
|
||||||
|
|
||||||
|
@ -261,14 +319,15 @@ int CmdLFHitagReader(const char *Cmd) {
|
||||||
PrintAndLog("");
|
PrintAndLog("");
|
||||||
PrintAndLog("Usage: hitag reader <Reader Function #>");
|
PrintAndLog("Usage: hitag reader <Reader Function #>");
|
||||||
PrintAndLog("Reader Functions:");
|
PrintAndLog("Reader Functions:");
|
||||||
PrintAndLog(" HitagS (0*)");
|
PrintAndLog(" HitagS (0*):");
|
||||||
PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag");
|
PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag");
|
||||||
PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag");
|
PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag");
|
||||||
PrintAndLog(" 03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag");
|
PrintAndLog(" 03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag");
|
||||||
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag");
|
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag");
|
||||||
PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)");
|
PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)");
|
||||||
PrintAndLog(" Hitag1 (1*)");
|
PrintAndLog(" Hitag1 (1*):");
|
||||||
PrintAndLog(" Hitag2 (2*)");
|
PrintAndLog(" (not yet implemented)");
|
||||||
|
PrintAndLog(" Hitag2 (2*):");
|
||||||
PrintAndLog(" 21 <password> (password mode)");
|
PrintAndLog(" 21 <password> (password mode)");
|
||||||
PrintAndLog(" 22 <nr> <ar> (authentication)");
|
PrintAndLog(" 22 <nr> <ar> (authentication)");
|
||||||
PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low");
|
PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low");
|
||||||
|
@ -286,10 +345,16 @@ int CmdLFHitagReader(const char *Cmd) {
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
|
|
||||||
UsbCommand resp;
|
UsbCommand resp;
|
||||||
WaitForResponse(CMD_ACK,&resp);
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||||
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the return status, stored in the first argument
|
// Check the return status, stored in the first argument
|
||||||
if (resp.arg[0] == false) return 1;
|
if (resp.arg[0] == false) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t id = bytes_to_num(resp.d.asBytes,4);
|
uint32_t id = bytes_to_num(resp.d.asBytes,4);
|
||||||
|
|
||||||
|
@ -312,12 +377,11 @@ int CmdLFHitagReader(const char *Cmd) {
|
||||||
PrintAndLog("Succesfully saved tag memory to [%s]",filename);
|
PrintAndLog("Succesfully saved tag memory to [%s]",filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CmdLFHitagSimS(const char *Cmd) {
|
static int CmdLFHitagSimS(const char *Cmd) {
|
||||||
UsbCommand c = { CMD_SIMULATE_HITAG_S };
|
UsbCommand c = { CMD_SIMULATE_HITAG_S };
|
||||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||||
FILE* pf;
|
FILE* pf;
|
||||||
|
@ -350,7 +414,8 @@ int CmdLFHitagSimS(const char *Cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdLFHitagCheckChallenges(const char *Cmd) {
|
|
||||||
|
static int CmdLFHitagCheckChallenges(const char *Cmd) {
|
||||||
UsbCommand c = { CMD_TEST_HITAGS_TRACES };
|
UsbCommand c = { CMD_TEST_HITAGS_TRACES };
|
||||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||||
FILE* pf;
|
FILE* pf;
|
||||||
|
@ -384,33 +449,38 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CmdLFHitagWP(const char *Cmd) {
|
static int CmdLFHitagWriter(const char *Cmd) {
|
||||||
UsbCommand c = { CMD_WR_HITAG_S };
|
UsbCommand c = { CMD_WR_HITAG_S };
|
||||||
hitag_data* htd = (hitag_data*)c.d.asBytes;
|
hitag_data* htd = (hitag_data*)c.d.asBytes;
|
||||||
hitag_function htf = param_get32ex(Cmd,0,0,10);
|
hitag_function htf = param_get32ex(Cmd,0,0,10);
|
||||||
switch (htf) {
|
switch (htf) {
|
||||||
case 03: { //WHTSF_CHALLENGE
|
case WHTSF_CHALLENGE: {
|
||||||
num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr);
|
num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr);
|
||||||
c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
|
c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
|
||||||
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data);
|
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data);
|
||||||
} break;
|
} break;
|
||||||
case 04:
|
case WHTSF_KEY:
|
||||||
case 24:
|
case WHT2F_CRYPTO: {
|
||||||
{ //WHTSF_KEY
|
|
||||||
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
|
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
|
||||||
c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
|
c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
|
||||||
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data);
|
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data);
|
||||||
|
} break;
|
||||||
|
case WHT2F_PASSWORD: {
|
||||||
|
num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
|
||||||
|
c.arg[2] = param_get32ex(Cmd, 2, 0, 10);
|
||||||
|
num_to_bytes(param_get32ex(Cmd, 3, 0, 16), 4, htd->crypto.data);
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
PrintAndLog("Error: unkown writer function %d",htf);
|
PrintAndLog("Error: unkown writer function %d",htf);
|
||||||
PrintAndLog("Hitag writer functions");
|
PrintAndLog("Hitag writer functions");
|
||||||
PrintAndLog(" HitagS (0*)");
|
PrintAndLog(" HitagS (0*):");
|
||||||
PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag");
|
PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag");
|
||||||
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
|
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
|
||||||
PrintAndLog(" Hitag1 (1*)");
|
PrintAndLog(" Hitag1 (1*)");
|
||||||
PrintAndLog(" Hitag2 (2*)");
|
PrintAndLog(" (not yet implemented)");
|
||||||
|
PrintAndLog(" Hitag2 (2*):");
|
||||||
PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
|
PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
|
||||||
|
PrintAndLog(" 27 <password> <page> <byte0...byte3> write page on a Hitag2 tag");
|
||||||
return 1;
|
return 1;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -421,35 +491,44 @@ int CmdLFHitagWP(const char *Cmd) {
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
|
|
||||||
UsbCommand resp;
|
UsbCommand resp;
|
||||||
WaitForResponse(CMD_ACK,&resp);
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||||
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the return status, stored in the first argument
|
// Check the return status, stored in the first argument
|
||||||
if (resp.arg[0] == false) return 1;
|
if (resp.arg[0] == false) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
static command_t CommandTable[] =
|
static command_t CommandTable[] =
|
||||||
{
|
{
|
||||||
{"help", CmdHelp, 1, "This help"},
|
{"help", CmdHelp, 1, "This help"},
|
||||||
{"list", CmdLFHitagList, 1, "<outfile> List Hitag trace history"},
|
{"list", CmdLFHitagList, 0, "<outfile> List Hitag trace history"},
|
||||||
{"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"},
|
{"info", CmdLFHitagInfo, 0, "Tag information" },
|
||||||
{"sim", CmdLFHitagSim, 1, "<infile> Simulate Hitag transponder"},
|
{"reader", CmdLFHitagReader, 0, "Act like a Hitag Reader"},
|
||||||
{"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"},
|
{"sim", CmdLFHitagSim, 0, "Simulate Hitag transponder"},
|
||||||
{"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" },
|
{"snoop", CmdLFHitagSnoop, 0, "Eavesdrop Hitag communication"},
|
||||||
{"simS", CmdLFHitagSimS, 1, "<hitagS.hts> Simulate HitagS transponder" },
|
{"writer", CmdLFHitagWriter, 0, "Act like a Hitag Writer" },
|
||||||
{"checkChallenges", CmdLFHitagCheckChallenges, 1, "<challenges.cc> <tagmode> test all challenges" }, {
|
{"simS", CmdLFHitagSimS, 0, "Simulate HitagS transponder" },
|
||||||
NULL,NULL, 0, NULL }
|
{"checkChallenges", CmdLFHitagCheckChallenges, 0, "Test challenges from a file" },
|
||||||
|
{ NULL, NULL, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
int CmdLFHitag(const char *Cmd)
|
|
||||||
{
|
|
||||||
CmdsParse(CommandTable, Cmd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CmdHelp(const char *Cmd)
|
static int CmdHelp(const char *Cmd) {
|
||||||
{
|
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CmdLFHitag(const char *Cmd) {
|
||||||
|
CmdsParse(CommandTable, Cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -11,11 +11,7 @@
|
||||||
#ifndef CMDLFHITAG_H__
|
#ifndef CMDLFHITAG_H__
|
||||||
#define CMDLFHITAG_H__
|
#define CMDLFHITAG_H__
|
||||||
|
|
||||||
int CmdLFHitag(const char *Cmd);
|
extern int CmdLFHitag(const char *Cmd);
|
||||||
|
extern int CmdLFHitagReader(const char *Cmd);
|
||||||
int CmdLFHitagList(const char *Cmd);
|
|
||||||
int CmdLFHitagSnoop(const char *Cmd);
|
|
||||||
int CmdLFHitagSim(const char *Cmd);
|
|
||||||
int CmdLFHitagReader(const char *Cmd);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -125,6 +125,10 @@ NXP/Philips CUSTOM COMMANDS
|
||||||
#define MIFARE_CMD_TRANSFER 0xB0
|
#define MIFARE_CMD_TRANSFER 0xB0
|
||||||
|
|
||||||
#define MIFARE_EV1_PERSONAL_UID 0x40
|
#define MIFARE_EV1_PERSONAL_UID 0x40
|
||||||
|
#define MIFARE_EV1_UIDF0 0x00
|
||||||
|
#define MIFARE_EV1_UIDF1 0x40
|
||||||
|
#define MIFARE_EV1_UIDF2 0x20
|
||||||
|
#define MIFARE_EV1_UIDF3 0x60
|
||||||
#define MIFARE_EV1_SETMODE 0x43
|
#define MIFARE_EV1_SETMODE 0x43
|
||||||
|
|
||||||
#define MIFARE_ULC_WRITE 0xA2
|
#define MIFARE_ULC_WRITE 0xA2
|
||||||
|
@ -232,6 +236,26 @@ NXP/Philips CUSTOM COMMANDS
|
||||||
#define TOPAZ_WRITE_E8 0x54 // Write-with-erase (eight bytes)
|
#define TOPAZ_WRITE_E8 0x54 // Write-with-erase (eight bytes)
|
||||||
#define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes)
|
#define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes)
|
||||||
|
|
||||||
|
// HITAG1 commands
|
||||||
|
#define HITAG1_SET_CCNEW 0xC2 // left 5 bits only
|
||||||
|
#define HITAG1_READ_ID 0x00 // not a real command, consists of 5 bits length, <length> bits partial SN, 8 bits CRC
|
||||||
|
#define HITAG1_SELECT 0x00 // left 5 bits only, followed by 32 bits SN and 8 bits CRC
|
||||||
|
#define HITAG1_WRPPAGE 0x80 // left 4 bits only, followed by 8 bits page and 8 bits CRC
|
||||||
|
#define HITAG1_WRPBLK 0x90 // left 4 bits only, followed by 8 bits block and 8 bits CRC
|
||||||
|
#define HITAG1_WRCPAGE 0xA0 // left 4 bits only, followed by 8 bits page or key information and 8 bits CRC
|
||||||
|
#define HITAG1_WRCBLK 0xB0 // left 4 bits only, followed by 8 bits block and 8 bits CRC
|
||||||
|
#define HITAG1_RDPPAGE 0xC0 // left 4 bits only, followed by 8 bits page and 8 bits CRC
|
||||||
|
#define HITAG1_RDPBLK 0xD0 // left 4 bits only, followed by 8 bits block and 8 bits CRC
|
||||||
|
#define HITAG1_RDCPAGE 0xE0 // left 4 bits only, followed by 8 bits page and 8 bits CRC
|
||||||
|
#define HITAG1_RDCBLK 0xF0 // left 4 bits only, followed by 8 bits block and 8 bits CRC
|
||||||
|
#define HITAG1_HALT 0x70 // left 4 bits only, followed by 8 bits (dummy) page and 8 bits CRC
|
||||||
|
|
||||||
|
// HITAG2 commands
|
||||||
|
#define HITAG2_START_AUTH 0xC0 // left 5 bits only
|
||||||
|
#define HITAG2_READ_PAGE 0xC0 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||||
|
#define HITAG2_READ_PAGE_INVERTED 0x44 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||||
|
#define HITAG2_WRITE_PAGE 0x82 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||||
|
#define HITAG2_HALT 0x00 // left 5 bits only
|
||||||
|
|
||||||
#define ISO_14443A 0
|
#define ISO_14443A 0
|
||||||
#define ICLASS 1
|
#define ICLASS 1
|
||||||
|
|
|
@ -31,6 +31,7 @@ typedef enum {
|
||||||
WHT2F_CRYPTO = 24,
|
WHT2F_CRYPTO = 24,
|
||||||
RHT2F_TEST_AUTH_ATTEMPTS = 25,
|
RHT2F_TEST_AUTH_ATTEMPTS = 25,
|
||||||
RHT2F_UID_ONLY = 26,
|
RHT2F_UID_ONLY = 26,
|
||||||
|
WHT2F_PASSWORD = 27,
|
||||||
} hitag_function;
|
} hitag_function;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -197,17 +197,17 @@ typedef struct{
|
||||||
#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613
|
#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613
|
||||||
|
|
||||||
#define CMD_MIFARE_READBL 0x0620
|
#define CMD_MIFARE_READBL 0x0620
|
||||||
#define CMD_MIFAREU_READBL 0x0720
|
|
||||||
#define CMD_MIFARE_READSC 0x0621
|
#define CMD_MIFARE_READSC 0x0621
|
||||||
#define CMD_MIFAREU_READCARD 0x0721
|
|
||||||
#define CMD_MIFARE_WRITEBL 0x0622
|
#define CMD_MIFARE_WRITEBL 0x0622
|
||||||
|
#define CMD_MIFARE_CHKKEYS 0x0623
|
||||||
|
#define CMD_MIFARE_PERSONALIZE_UID 0x0624
|
||||||
|
#define CMD_MIFARE_SNIFFER 0x0630
|
||||||
|
|
||||||
|
//ultralightC
|
||||||
|
#define CMD_MIFAREU_READBL 0x0720
|
||||||
|
#define CMD_MIFAREU_READCARD 0x0721
|
||||||
#define CMD_MIFAREU_WRITEBL 0x0722
|
#define CMD_MIFAREU_WRITEBL 0x0722
|
||||||
#define CMD_MIFAREU_WRITEBL_COMPAT 0x0723
|
#define CMD_MIFAREU_WRITEBL_COMPAT 0x0723
|
||||||
|
|
||||||
#define CMD_MIFARE_CHKKEYS 0x0623
|
|
||||||
|
|
||||||
#define CMD_MIFARE_SNIFFER 0x0630
|
|
||||||
//ultralightC
|
|
||||||
#define CMD_MIFAREUC_AUTH 0x0724
|
#define CMD_MIFAREUC_AUTH 0x0724
|
||||||
//0x0725 and 0x0726 no longer used
|
//0x0725 and 0x0726 no longer used
|
||||||
#define CMD_MIFAREUC_SETPWD 0x0727
|
#define CMD_MIFAREUC_SETPWD 0x0727
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue