Merge branch 'master' into purring-basilisk

Signed-off-by: JLitewski <hackhalotwo@gmail.com>
This commit is contained in:
JLitewski 2024-04-22 06:42:45 -04:00 committed by GitHub
commit 6097c531c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 1544 additions and 1560 deletions

View file

@ -98,7 +98,7 @@ jobs:
steps: steps:
- name: WSL setup - name: WSL setup
uses: Vampire/setup-wsl@v2 uses: Vampire/setup-wsl@v3
with: with:
distribution: Ubuntu-22.04 distribution: Ubuntu-22.04
update: "true" update: "true"

View file

@ -5,7 +5,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased] ## [unreleased][unreleased]
- Removed `save_restoreDB` - replaced by `buffer_savestate_t` implementation (@HACKhalo2) - Removed `save_restoreDB` - replaced by `buffer_savestate_t` implementation (@HACKhalo2)
- Removed `save_restoreGB` - replaced by `buffer_savestate_t` implementation (@HACKhalo2) - Removed `save_restoreGB` - replaced by `buffer_savestate_t` implementation (@HACKhalo2)
- Changed `hf mfp info` to identify Ev2 (@iceman1001)
- Updated Graph Markers implementation to include temporary markers and marker labels (@HACKhalo2) - Updated Graph Markers implementation to include temporary markers and marker labels (@HACKhalo2)
- Updated to SWIG 4.2.1 (@iceman1001) - Updated to SWIG 4.2.1 (@iceman1001)
- Removed `data bin2hex` - replaced by `data num` (@iceman1001) - Removed `data bin2hex` - replaced by `data num` (@iceman1001)
@ -416,9 +415,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Changed `hf 15 sim` - now supports reader writes (@markus-oehme-pg40) - Changed `hf 15 sim` - now supports reader writes (@markus-oehme-pg40)
- Added `hf 15 eload` - specify memory image for ISO15693 simulation (@markus-oehme-pg40) - Added `hf 15 eload` - specify memory image for ISO15693 simulation (@markus-oehme-pg40)
- Added `hf 15 sim --blocksize` - configure block size for simulation (@markus-oehme-pg40) - Added `hf 15 sim --blocksize` - configure block size for simulation (@markus-oehme-pg40)
- Fixed buffer overflow in mfu ndef decode (@mwalker) - Fixed buffer overflow in mfu ndef decode (@mwalker33)
- Changed spiffs write/append to send in 8192 chunks to ensure its eraised (@mwalker) - Changed spiffs write/append to send in 8192 chunks to ensure its eraised (@mwalker33)
- Fixed spiffs dump to ensure to fails correctly if no big_buff was allocated (@mwalker) - Fixed spiffs dump to ensure to fails correctly if no big_buff was allocated (@mwalker33)
- Change Client Makefile to respect global flags (@blshkv) - Change Client Makefile to respect global flags (@blshkv)
- Change Makefile, honors global CC values (@blshkv) - Change Makefile, honors global CC values (@blshkv)
- Fixed bad memory handling in MifareSim device side (@iceman1001) - Fixed bad memory handling in MifareSim device side (@iceman1001)
@ -624,7 +623,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fixed `hf fido` commands now works correctly (@merlokk) - Fixed `hf fido` commands now works correctly (@merlokk)
- Moved / renamed `client/resource/fido2_defparams.json` -> `client/resource/hf_fido2_defparams.json` (@merlokk) - Moved / renamed `client/resource/fido2_defparams.json` -> `client/resource/hf_fido2_defparams.json` (@merlokk)
- Added `hf cipurse` commands to work with cipurse transport cards (@merlokk) - Added `hf cipurse` commands to work with cipurse transport cards (@merlokk)
- Added `--gap` option to lf em 410x sim for more control over sim data (@mwalker) - Added `--gap` option to lf em 410x sim for more control over sim data (@mwalker33)
- Changed `hf fido` - refactored load/save json objects (@iceman1001) - Changed `hf fido` - refactored load/save json objects (@iceman1001)
- Moved / renamed `fido2.json` -> `client/resource/fido2_defparams.json` (@iceman1001) - Moved / renamed `fido2.json` -> `client/resource/fido2_defparams.json` (@iceman1001)
- Added openocd shikra support based on @ninjastyle82 patch to deprecated iceman fork (@iceman1001) - Added openocd shikra support based on @ninjastyle82 patch to deprecated iceman fork (@iceman1001)

View file

@ -1364,6 +1364,14 @@ static void PacketReceived(PacketCommandNG *packet) {
SetTag15693Uid(payload->uid); SetTag15693Uid(payload->uid);
break; break;
} }
case CMD_HF_ISO15693_CSETUID_V2: {
struct p {
uint8_t uid[8];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
SetTag15693Uid_v2(payload->uid);
break;
}
case CMD_HF_ISO15693_SLIX_DISABLE_EAS: { case CMD_HF_ISO15693_SLIX_DISABLE_EAS: {
struct p { struct p {
uint8_t pwd[4]; uint8_t pwd[4];

View file

@ -29,7 +29,8 @@
// FeliCa timings // FeliCa timings
// minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56MHz) cycles // minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56MHz) cycles
#ifndef FELICA_REQUEST_GUARD_TIME #ifndef FELICA_REQUEST_GUARD_TIME
# define FELICA_REQUEST_GUARD_TIME (6800/16 + 1) // 426 //# define FELICA_REQUEST_GUARD_TIME (6800 / 16 + 1) // 426
# define FELICA_REQUEST_GUARD_TIME ((512 + 0 * 256) * 64 / 16 + 1)
#endif #endif
// FRAME DELAY TIME 2672 carrier cycles // FRAME DELAY TIME 2672 carrier cycles
#ifndef FELICA_FRAME_DELAY_TIME #ifndef FELICA_FRAME_DELAY_TIME
@ -64,6 +65,11 @@ static uint32_t iso18092_get_timeout(void) {
#define FELICA_MAX_FRAME_SIZE 260 #define FELICA_MAX_FRAME_SIZE 260
#endif #endif
//structure to hold outgoing NFC frame //structure to hold outgoing NFC frame
static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE + 4]; static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE + 4];
@ -122,39 +128,46 @@ static void shiftInByte(uint8_t bt) {
} }
static void Process18092Byte(uint8_t bt) { static void Process18092Byte(uint8_t bt) {
switch (FelicaFrame.state) { switch (FelicaFrame.state) {
case STATE_UNSYNCD: { case STATE_UNSYNCD: {
//almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not always the case // almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not always the case
if (bt > 0) { if (bt > 0) {
FelicaFrame.shiftReg = reflect8(bt); FelicaFrame.shiftReg = reflect8(bt);
FelicaFrame.state = STATE_TRYING_SYNC; FelicaFrame.state = STATE_TRYING_SYNC;
} }
break; break;
} }
case STATE_TRYING_SYNC: { case STATE_TRYING_SYNC: {
if (bt == 0) { if (bt == 0) {
//desync // desync
FelicaFrame.shiftReg = bt; FelicaFrame.shiftReg = bt;
FelicaFrame.state = STATE_UNSYNCD; FelicaFrame.state = STATE_UNSYNCD;
} else { } else {
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
if (FelicaFrame.shiftReg == SYNC_16BIT) { if (FelicaFrame.shiftReg == SYNC_16BIT) {
//SYNC done! // SYNC done!
FelicaFrame.state = STATE_GET_LENGTH; FelicaFrame.state = STATE_GET_LENGTH;
FelicaFrame.framebytes[0] = 0xb2; FelicaFrame.framebytes[0] = 0xb2;
FelicaFrame.framebytes[1] = 0x4d; FelicaFrame.framebytes[1] = 0x4d;
FelicaFrame.byte_offset = i; FelicaFrame.byte_offset = i;
//shift in remaining byte, slowly...
// shift in remaining byte, slowly...
for (uint8_t j = i; j < 8; j++) { for (uint8_t j = i; j < 8; j++) {
FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1); FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1);
bt >>= 1; bt >>= 1;
} }
FelicaFrame.posCnt = 2; FelicaFrame.posCnt = 2;
if (i == 0) if (i == 0) {
break; break;
} }
}
FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1); FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1);
bt >>= 1; bt >>= 1;
} }
@ -351,16 +364,21 @@ static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t
} }
static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, uint8_t power, uint8_t highspeed) { static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, uint8_t power, uint8_t highspeed) {
if (NYI_timing_NYI != NULL) { if (NYI_timing_NYI != NULL) {
Dbprintf("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI"); Dbprintf("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI");
return; return;
} }
uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092; uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
if (power)
if (power) {
flags |= FPGA_HF_ISO18092_FLAG_READER; flags |= FPGA_HF_ISO18092_FLAG_READER;
if (highspeed) }
if (highspeed) {
flags |= FPGA_HF_ISO18092_FLAG_424K; flags |= FPGA_HF_ISO18092_FLAG_424K;
}
FpgaWriteConfWord(flags); FpgaWriteConfWord(flags);
@ -419,9 +437,13 @@ static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const
// stop when button is pressed // stop when button is pressed
// or return TRUE when command is captured // or return TRUE when command is captured
bool WaitForFelicaReply(uint16_t maxbytes) { bool WaitForFelicaReply(uint16_t maxbytes) {
if (g_dbglevel >= DBG_DEBUG)
if (g_dbglevel >= DBG_DEBUG) {
Dbprintf("WaitForFelicaReply Start"); Dbprintf("WaitForFelicaReply Start");
}
uint32_t c = 0; uint32_t c = 0;
// power, no modulation // power, no modulation
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
FelicaFrameReset(); FelicaFrameReset();
@ -433,12 +455,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
uint32_t timeout = iso18092_get_timeout(); uint32_t timeout = iso18092_get_timeout();
for (;;) { for (;;) {
WDT_HIT(); WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
Process18092Byte(b); Process18092Byte(b);
if (FelicaFrame.state == STATE_FULL) { if (FelicaFrame.state == STATE_FULL) {
felica_nexttransfertime = MAX(felica_nexttransfertime,
felica_nexttransfertime = MAX(
felica_nexttransfertime,
(GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME); (GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME);
LogTrace( LogTrace(
@ -449,10 +478,15 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
NULL, NULL,
false false
); );
if (g_dbglevel >= DBG_DEBUG) Dbprintf("All bytes received! STATE_FULL"); if (g_dbglevel >= DBG_DEBUG) Dbprintf("All bytes received! STATE_FULL");
return true; return true;
} else if (c++ > timeout && (FelicaFrame.state == STATE_UNSYNCD || FelicaFrame.state == STATE_TRYING_SYNC)) { } else if (c++ > timeout && (FelicaFrame.state == STATE_UNSYNCD || FelicaFrame.state == STATE_TRYING_SYNC)) {
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD"); if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD");
return false; return false;
} }
} }
@ -478,8 +512,9 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
// DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); // DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE)); FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; // 418
iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card // iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card
iso18092_set_timeout(1060); // 106 * 10ms maximum start-up time of card
init_table(CRC_FELICA); init_table(CRC_FELICA);

356
armsrc/hitag2_crack.c Normal file
View file

@ -0,0 +1,356 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// This coode has been converted from RFIDler source code to work with Proxmark3.
// https://github.com/AdamLaurie/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/hitag2crack.c
#include "hitag2_crack.h"
#include "hitag2_crypto.h"
#include "hitag2.h"
#include "proxmark3_arm.h"
#include "commonutil.h"
#include "dbprint.h"
#include "util.h"
#include "string.h"
#include "BigBuf.h"
#include "cmd.h"
const static uint8_t ERROR_RESPONSE[] = { 0xF4, 0x02, 0x88, 0x9C };
// #define READP0CMD "1100000111"
const static uint8_t read_p0_cmd[] = {1,1,0,0,0,0,0,1,1,1};
// hitag2crack_xor XORs the source with the pad to produce the target.
// source, target and pad are binarrays of length len.
static void hitag2crack_xor(uint8_t *target, const uint8_t *source, const uint8_t *pad, uint16_t len) {
for (uint16_t i = 0; i < len; i++) {
target[i] = source[i] ^ pad[i];
}
}
// hitag2crack_send_e_cmd replays the auth and sends the given encrypted
// command.
// responsestr is the hexstring of the response to the command;
// nrar is the 64 bit binarray of the nR aR pair;
// cmd is the binarray of the encrypted command to send;
// len is the length of the encrypted command.
static bool hitag2crack_send_e_cmd(uint8_t *resp, uint8_t *nrar, uint8_t *cmd, int len) {
memset(resp, 0, 4);
// Get UID
uint8_t uid[4];
if (ht2_read_uid(uid, false, false, true) != PM3_SUCCESS) {
return false;
}
// send nrar and receive (useless) encrypted page 3 value
uint8_t e_page3[4];
size_t n = 0;
if (ht2_tx_rx(nrar, 64, e_page3, &n, true, true) != PM3_SUCCESS) {
return false;
}
// send encrypted command
n = 0;
ht2_tx_rx(cmd, len, resp, &n, true, false);
if (n == 32) {
return true;
}
return false;
}
// hitag2crack_read_page uses the supplied key stream and nrar pair to read the
// given page, returning the response as a hexstring.
// responsestr is the returned hexstring;
// pagenum is the page number to read;
// nrar is the 64 bit binarray of the nR aR pair;
// keybits is the binarray of the key stream.
static bool hitag2crack_read_page(uint8_t *resp, uint8_t pagenum, uint8_t *nrar, uint8_t *keybits) {
if (pagenum > 7) {
return false;
}
// create cmd
uint8_t cmd[10];
memcpy(cmd, read_p0_cmd, sizeof(read_p0_cmd));
if (pagenum & 0x1) {
cmd[9] = !cmd[9];
cmd[4] = !cmd[4];
}
if (pagenum & 0x2) {
cmd[8] = !cmd[8];
cmd[3] = !cmd[3];
}
if (pagenum & 0x4) {
cmd[7] = !cmd[7];
cmd[2] = !cmd[2];
}
// encrypt command
uint8_t e_cmd[10] = {0};
hitag2crack_xor(e_cmd, cmd, keybits, 10);
// send encrypted command
uint8_t e_resp[4];
if (hitag2crack_send_e_cmd(e_resp, nrar, e_cmd, 10)) {
// check if it is valid OBS!
if (memcmp(e_resp, ERROR_RESPONSE, 4)) {
uint8_t e_response[32];
uint8_t response[32];
// convert to binarray
hex2binarray((char*)e_response, (char*)e_resp);
// decrypt response
hitag2crack_xor(response, e_response, keybits + 10, 32);
// convert to hexstring
binarray2hex(response, 32, resp);
return true;
}
}
return false;
}
// hitag2crack_test_e_p0cmd XORs the message (command + response) with the
// encrypted version to retrieve the key stream. It then uses this key stream
// to encrypt an extended version of the READP0CMD and tests if the response
// is valid.
// keybits is the returned binarray of the key stream;
// nrar is the 64 bit binarray of nR aR pair;
// e_cmd is the binarray of the encrypted command;
// uid is the binarray of the card UID;
// e_uid is the binarray of the encrypted version of the UID.
static bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid) {
uint8_t cipherbits[42];
memcpy(cipherbits, e_cmd, 10); // copy encrypted cmd to cipherbits
memcpy(cipherbits + 10, e_uid, 32); // copy encrypted uid to cipherbits
uint8_t plainbits[42];
memcpy(plainbits, read_p0_cmd, sizeof(read_p0_cmd)); // copy cmd to plainbits
memcpy(plainbits + 10, uid, 32); // copy uid to plainbits
// xor the plainbits with the cipherbits to get keybits
hitag2crack_xor(keybits, plainbits, cipherbits, 42);
// create extended cmd -> 4 * READP0CMD = 40 bits
uint8_t ext_cmd[40];
memcpy(ext_cmd, read_p0_cmd, sizeof(read_p0_cmd));
memcpy(ext_cmd + 10, read_p0_cmd, sizeof(read_p0_cmd));
memcpy(ext_cmd + 20, read_p0_cmd, sizeof(read_p0_cmd));
memcpy(ext_cmd + 30, read_p0_cmd, sizeof(read_p0_cmd));
// xor extended cmd with keybits
uint8_t e_ext_cmd[40];
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40);
// send extended encrypted cmd
uint8_t resp[4];
if (hitag2crack_send_e_cmd(resp, nrar, e_ext_cmd, 40)) {
// test if it was valid
if (memcmp(resp, ERROR_RESPONSE, 4)) {
return true;
}
}
return false;
}
// hitag2crack_find_e_page0_cmd tries all bit-flipped combinations of the
// valid encrypted command and tests the results by attempting an extended
// command version of the command to see if that produces a valid response.
// keybits is the returned binarray of the recovered key stream;
// e_page0cmd is the returned binarray of the encrypted 'read page 0' command;
// e_firstcmd is the binarray of the first valid encrypted command found;
// nrar is the binarray of the 64 bit nR aR pair;
// uid is the binarray of the 32 bit UID.
static bool hitag2crack_find_e_page0_cmd(uint8_t *keybits, uint8_t *e_firstcmd, uint8_t *nrar, uint8_t *uid) {
// we're going to brute the missing 4 bits of the valid encrypted command
for (uint8_t a = 0; a < 2; a++) {
for (uint8_t b = 0; b < 2; b++) {
for (uint8_t c = 0; c < 2; c++) {
for (uint8_t d = 0; d < 2; d++) {
// create our guess by bit flipping the pattern of bits
// representing the inverted bit and the 3 page bits
// in both the non-inverted and inverted parts of the
// encrypted command.
uint8_t guess[10];
memcpy(guess, e_firstcmd, 10);
if (a) {
guess[5] = !guess[5];
guess[0] = !guess[0];
}
if (b) {
guess[7] = !guess[7];
guess[2] = !guess[2];
}
if (c) {
guess[8] = !guess[8];
guess[3] = !guess[3];
}
if (d) {
guess[9] = !guess[9];
guess[4] = !guess[4];
}
// try the guess
uint8_t resp[4];
if (hitag2crack_send_e_cmd(resp, nrar, guess, 10)) {
// check if it was valid
if (memcmp(resp, ERROR_RESPONSE, 4)) {
// convert response to binarray
uint8_t e_uid[32];
hex2binarray((char*)e_uid, (char*)resp);
// test if the guess was 'read page 0' command
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) {
return true;
}
}
}
}
}
}
}
return false;
}
// hitag2crack_find_valid_e_cmd repeatedly replays the auth protocol each
// with a different sequential encrypted command value in order to find one
// that returns a valid response.
// e_cmd is the returned binarray of the valid encrypted command;
// nrar is the binarray of the 64 bit nR aR pair.
static bool hitag2crack_find_valid_e_cmd(uint8_t *e_cmd, uint8_t *nrar) {
// we're going to hold bits 5, 7, 8 and 9 and brute force the rest
// e.g. x x x x x 0 x 0 0 0
for (uint8_t a = 0; a < 2; a++) {
for (uint8_t b = 0; b < 2; b++) {
for (uint8_t c = 0; c < 2; c++) {
for (uint8_t d = 0; d < 2; d++) {
for (uint8_t e = 0; e < 2; e++) {
for (uint8_t g = 0; g < 2; g++) {
// build binarray
//uint8_t guess[10] = { a, b, c, d, e, 0, g, 0, 0, 0 };
uint8_t guess[10];
guess[0] = a;
guess[1] = b;
guess[2] = c;
guess[3] = d;
guess[4] = e;
guess[5] = 0;
guess[6] = g;
guess[7] = 0;
guess[8] = 0;
guess[9] = 0;
// send guess
uint8_t resp[4];
if (hitag2crack_send_e_cmd(resp, nrar, guess, sizeof(guess))) {
// check if it was valid
if (memcmp(resp, ERROR_RESPONSE, 4)) {
// return the guess as the encrypted command
memcpy(e_cmd, guess, 10);
return true;
}
}
}
}
}
}
}
}
return false;
}
// hitag2_crack implements the first crack algorithm described in the paper,
// Gone In 360 Seconds by Verdult, Garcia and Balasch.
// response is a multi-line text response containing the 8 pages of the cracked tag
// nrarhex is a string containing hex representations of the 32 bit nR and aR values
void ht2_crack(uint8_t *nrar_hex) {
clear_trace();
lf_hitag_crack_response_t packet;
memset((uint8_t*)&packet, 0x00, sizeof(lf_hitag_crack_response_t));
int res = PM3_SUCCESS;
// get uid as hexstring
uint8_t uid_hex[4];
if (ht2_read_uid(uid_hex, false, false, false) != PM3_SUCCESS) {
packet.status = -1;
res = PM3_EFAILED;
goto out;
}
// convert to binarray
uint8_t nrar[64] = {0};
hex2binarray_n((char*)nrar, (char*)nrar_hex, 8);
// find a valid encrypted command
uint8_t e_firstcmd[10];
if (hitag2crack_find_valid_e_cmd(e_firstcmd, nrar) == false) {
packet.status = -2;
res = PM3_EFAILED;
goto out;
}
// now we got a first encrypted command inside e_firstcmd
uint8_t uid[32];
hex2binarray_n((char*)uid, (char*)uid_hex, 4);
// find the 'read page 0' command and recover key stream
uint8_t keybits[42];
if (hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid) == false) {
packet.status = -3;
res = PM3_EFAILED;
goto out;
}
// read all pages using key stream
for (uint8_t i = 1; i < 8; i++) {
hitag2crack_read_page(packet.data + (i * 4), i, nrar, keybits);
}
// copy UID since we already have it...
memcpy(packet.data, uid_hex, 4);
packet.status = 1;
out:
reply_ng(CMD_LF_HITAG2_CRACK, res, (uint8_t*)&packet, sizeof(lf_hitag_crack_response_t));
}

27
armsrc/hitag2_crack.h Normal file
View file

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// Hitag2 crack implementeation
//-----------------------------------------------------------------------------
#ifndef _HITAG2_CRACK__H_
#define _HITAG2_CRACK__H_
#include <stdbool.h>
#include "common.h"
void ht2_crack(uint8_t *nrar_hex);
#endif

View file

@ -1,840 +0,0 @@
//-----------------------------------------------------------------------------
// Borrowed initially from https://github.com/factoritbv/hitag2hell
// and https://github.com/AdamLaurie/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/hitag2crack.c
// Copyright (C) Kevin Sheldrake <kev@headhacking.com>, Aug 2018
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// hitag2 attack functions
//-----------------------------------------------------------------------------
#include "hitag2_crypto.h"
#include "hitag2crack.h"
#define READP0CMD "1100000111"
#define ERROR_RESPONSE "F402889C"
static const uint8_t Hitag2Sync[5];
static bool CryptoActive;
static Hitag_State Hitag_Crypto_State;
// hitag2_crack implements the first crack algorithm described in the paper,
// Gone In 360 Seconds by Verdult, Garcia and Balasch.
// response is a multi-line text response containing the 8 pages of the
// cracked tag;
// nrarhex is a string containing hex representations of the 32 bit nR and aR
// values (separated by a space) snooped using SNIFF-PWM.
bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) {
uint8_t uidhex[9];
uint8_t uid[32];
uint8_t nrar[64];
uint8_t e_firstcmd[10];
// uint8_t e_page0cmd[10];
uint8_t keybits[42];
uint8_t pagehex[9];
uint8_t temp[20];
int i;
uint8_t *spaceptr = NULL;
// get uid as hexstring
if (!hitag2_get_uid(uidhex)) {
UserMessage("Cannot get UID\r\n");
return false;
}
// convert uid hexstring to binarray
hextobinarray(uid, uidhex);
// convert nR and aR hexstrings to binarray
spaceptr = strchr(nrarhex, ' ');
if (!spaceptr) {
UserMessage("Please supply a valid nR aR pair\r\n");
return false;
}
*spaceptr = 0x00;
if (hextobinarray(nrar, nrarhex) != 32) {
UserMessage("nR is not 32 bits long\r\n");
return false;
}
if (hextobinarray(nrar + 32, spaceptr + 1) != 32) {
UserMessage("aR is not 32 bits long\r\n");
return false;
}
// find a valid encrypted command
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) {
UserMessage("Cannot find a valid encrypted command\r\n");
return false;
}
// find the 'read page 0' command and recover key stream
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) {
UserMessage("Cannot find encrypted 'read page0' command\r\n");
return false;
}
// empty the response string
response[0] = 0x00;
// read all pages using key stream
for (i = 0; i < 8; i++) {
if (hitag2crack_read_page(pagehex, i, nrar, keybits)) {
sprintf(temp, "%1d: %s\r\n", i, pagehex);
} else {
sprintf(temp, "%1d:\r\n", i);
}
// add page string to response
strcat(response, temp);
}
return true;
}
// hitag2crack_find_valid_e_cmd repeatedly replays the auth protocol each
// with a different sequential encrypted command value in order to find one
// that returns a valid response.
// e_cmd is the returned binarray of the valid encrypted command;
// nrar is the binarray of the 64 bit nR aR pair.
bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]) {
uint8_t guess[10];
uint8_t responsestr[9];
// UserMessage("Finding valid encrypted command:");
// we're going to hold bits 5, 7, 8 and 9 and brute force the rest
// e.g. x x x x x 0 x 0 0 0
for (uint8_t a = 0; a < 2; a++) {
for (uint8_t b = 0; b < 2; b++) {
for (uint8_t c = 0; c < 2; c++) {
for (uint8_t d = 0; d < 2; d++) {
for (uint8_t e = 0; e < 2; e++) {
for (uint8_t g = 0; g < 2; g++) {
// build binarray
guess[0] = a;
guess[1] = b;
guess[2] = c;
guess[3] = d;
guess[4] = e;
guess[5] = 0;
guess[6] = g;
guess[7] = 0;
guess[8] = 0;
guess[9] = 0;
// send guess
if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) {
// check if it was valid
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
// return the guess as the encrypted command
memcpy(e_cmd, guess, 10);
return true;
}
} else {
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_find_valid_e_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
#endif
}
UserMessage(".");
}
}
}
}
}
}
// UserMessage("hitag2crack_find_valid_e_cmd:\r\n no valid encrypted command found\r\n");
return false;
}
// hitag2crack_find_e_page0_cmd tries all bit-flipped combinations of the
// valid encrypted command and tests the results by attempting an extended
// command version of the command to see if that produces a valid response.
// keybits is the returned binarray of the recovered key stream;
// e_page0cmd is the returned binarray of the encrypted 'read page 0' command;
// e_firstcmd is the binarray of the first valid encrypted command found;
// nrar is the binarray of the 64 bit nR aR pair;
// uid is the binarray of the 32 bit UID.
bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8_t nrar[], uint8_t uid[]) {
uint8_t a, b, c, d;
uint8_t guess[10];
uint8_t responsestr[9];
uint8_t e_uid[32];
UserMessage("Finding 'read page 0' command:");
// we're going to brute the missing 4 bits of the valid encrypted command
for (a = 0; a < 2; a++) {
for (b = 0; b < 2; b++) {
for (c = 0; c < 2; c++) {
for (d = 0; d < 2; d++) {
// create our guess by bit flipping the pattern of bits
// representing the inverted bit and the 3 page bits
// in both the non-inverted and inverted parts of the
// encrypted command.
memcpy(guess, e_firstcmd, 10);
if (a) {
guess[5] = !guess[5];
guess[0] = !guess[0];
}
if (b) {
guess[7] = !guess[7];
guess[2] = !guess[2];
}
if (c) {
guess[8] = !guess[8];
guess[3] = !guess[3];
}
if (d) {
guess[9] = !guess[9];
guess[4] = !guess[4];
}
// try the guess
if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) {
// check if it was valid
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
// convert response to binarray
hextobinarray(e_uid, responsestr);
// test if the guess was 'read page 0' command
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) {
return true;
}
} else {
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
#endif
}
} else {
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
#endif
}
UserMessage(".");
}
}
}
}
UserMessage("hitag2crack_find_e_page0_cmd:\r\n could not find encrypted 'read page 0' command\r\n");
return false;
}
// hitag2crack_test_e_p0cmd XORs the message (command + response) with the
// encrypted version to retrieve the key stream. It then uses this key stream
// to encrypt an extended version of the READP0CMD and tests if the response
// is valid.
// keybits is the returned binarray of the key stream;
// nrar is the 64 bit binarray of nR aR pair;
// e_cmd is the binarray of the encrypted command;
// uid is the binarray of the card UID;
// e_uid is the binarray of the encrypted version of the UID.
bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid) {
uint8_t cipherbits[42];
uint8_t plainbits[42];
uint8_t ext_cmd[40];
uint8_t e_ext_cmd[40];
uint8_t responsestr[9];
int i;
// copy encrypted cmd to cipherbits
memcpy(cipherbits, e_cmd, 10);
// copy encrypted uid to cipherbits
memcpy(cipherbits + 10, e_uid, 32);
// copy cmd to plainbits
binstringtobinarray(plainbits, READP0CMD);
// copy uid to plainbits
memcpy(plainbits + 10, uid, 32);
// xor the plainbits with the cipherbits to get keybits
hitag2crack_xor(keybits, plainbits, cipherbits, 42);
// create extended cmd -> 4 * READP0CMD = 40 bits
for (i = 0; i < 4; i++) {
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
}
// xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40);
// send extended encrypted cmd
if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40)) {
// test if it was valid
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
return true;
}
} else {
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
#endif
}
return false;
}
// hitag2crack_xor XORs the source with the pad to produce the target.
// source, target and pad are binarrays of length len.
void hitag2crack_xor(uint8_t *target, const uint8_t *source, const uint8_t *pad, unsigned int len) {
for (int i = 0; i < len; i++) {
target[i] = source[i] ^ pad[i];
}
}
// hitag2crack_read_page uses the supplied key stream and nrar pair to read the
// given page, returning the response as a hexstring.
// responsestr is the returned hexstring;
// pagenum is the page number to read;
// nrar is the 64 bit binarray of the nR aR pair;
// keybits is the binarray of the key stream.
bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, uint8_t *keybits) {
uint8_t cmd[10];
uint8_t e_cmd[10];
uint8_t e_responsestr[9];
if (pagenum > 7) {
UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n");
return false;
}
// create cmd
binstringtobinarray(cmd, READP0CMD);
if (pagenum & 0x1) {
cmd[9] = !cmd[9];
cmd[4] = !cmd[4];
}
if (pagenum & 0x2) {
cmd[8] = !cmd[8];
cmd[3] = !cmd[3];
}
if (pagenum & 0x4) {
cmd[7] = !cmd[7];
cmd[2] = !cmd[2];
}
// encrypt command
hitag2crack_xor(e_cmd, cmd, keybits, 10);
// send encrypted command
if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10)) {
// check if it is valid
if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) {
uint8_t e_response[32];
uint8_t response[32];
// convert to binarray
hextobinarray(e_response, e_responsestr);
// decrypt response
hitag2crack_xor(response, e_response, keybits + 10, 32);
// convert to hexstring
binarray_2_hex(responsestr, response, 32);
return true;
} else {
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
}
} else {
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n");
}
return false;
}
// hitag2crack_send_e_cmd replays the auth and sends the given encrypted
// command.
// responsestr is the hexstring of the response to the command;
// nrar is the 64 bit binarray of the nR aR pair;
// cmd is the binarray of the encrypted command to send;
// len is the length of the encrypted command.
bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len) {
// uint8_t tmp[37];
uint8_t uid[9];
uint8_t e_page3str[9];
// get the UID
if (!hitag2_get_uid(uid)) {
UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n");
return false;
}
// START_AUTH kills active crypto session
CryptoActive = false;
// get the UID again
if (!hitag2_get_uid(uid)) {
UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID (2nd time)\r\n");
return false;
}
// send nrar and receive (useless) encrypted page 3 value
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) {
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx nrar failed\r\n");
return false;
}
// send encrypted command
if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false)) {
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n");
#endif
return false;
}
return true;
}
// hitag2crack_tx_rx transmits a message and receives a response.
// responsestr is the hexstring of the response;
// msg is the binarray of the message to send;
// state is the RWD state;
// reset indicates whether to reset RWD state after.
bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, bool reset) {
uint8_t tmp[37];
int ret = 0;
// START_AUTH kills active crypto session
CryptoActive = false;
if (!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) {
UserMessage("hitag2crack_tx_rx: rwd_send failed\r\n");
return false;
}
// skip 1/2 bit to synchronise manchester
HW_Skip_Bits = 1;
ret = read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp, 37, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY);
// check if response was a valid length (5 sync bits + 32 bits response)
if (ret == 37) {
// check sync bits
if (memcmp(tmp, Hitag2Sync, 5) != 0) {
UserMessage("hitag2crack_tx_rx: no sync\r\n");
return false;
}
// convert response to hexstring
binarray_2_hex(responsestr, tmp + 5, 32);
return true;
} else {
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_tx_rx: wrong rx len\r\n");
#endif
return false;
}
return false;
}
bool hitag2crack_rng_init(uint8_t *response, uint8_t *input) {
uint64_t sharedkey;
uint32_t serialnum;
uint32_t initvector;
uint8_t *spaceptr;
uint8_t *dataptr;
// extract vals from input
dataptr = input;
spaceptr = strchr(dataptr, ' ');
if (!spaceptr) {
UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n");
return false;
}
*spaceptr = 0x00;
if (strlen(dataptr) != 12) {
UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n");
return false;
}
sharedkey = rev64(hexreversetoulonglong(dataptr));
dataptr = spaceptr + 1;
spaceptr = strchr(dataptr, ' ');
if (!spaceptr) {
UserMessage("/r/nno UID\r\n");
return false;
}
*spaceptr = 0x00;
if (strlen(dataptr) != 8) {
UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n");
return false;
}
serialnum = rev32(hexreversetoulong(dataptr));
dataptr = spaceptr + 1;
if (strlen(dataptr) != 8) {
UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n");
return false;
}
initvector = rev32(hexreversetoulong(dataptr));
// start up crypto engine
hitag2_init(&Hitag_Crypto_State, sharedkey, serialnum, initvector);
strcpy(response, "Success\r\n");
return true;
}
bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) {
uint8_t bin[32];
uint8_t binhex[9];
uint8_t binstr[33];
uint32_t binulong;
if (strlen(hex) != 8) {
UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n");
return false;
}
binulong = hextoulong(hex);
ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32);
binarray_2_binstr(binstr, bin, 32);
binarray_2_hex(binhex, bin, 32);
// UserMessage("ar = %s\r\n", binstr);
// UserMessage("arhex = %s\r\n", binhex);
strcpy(response, binhex);
return true;
}
bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) {
uint8_t bin[32];
uint8_t e_bin[32];
uint8_t binstr[33];
uint32_t binulong;
int len;
len = strlen(e_binstr);
if (len > 32) {
UserMessage("\r\nbinary string must be <= 32 bits\r\n");
return false;
}
binstringtobinarray(e_bin, e_binstr);
binulong = binarraytoulong(e_bin, len);
ulongtobinarray(bin, hitag2_crypt(binulong, len), len);
binarray_2_binstr(binstr, bin, len);
strcpy(response, binstr);
return true;
}
bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex) {
// XOR pad so encrypt == decrypt :)
return hitag2crack_decrypt_hex(response, hex);
}
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr) {
return hitag2crack_decrypt_bin(response, e_binstr);
}
// hitag2_keystream uses the first crack algorithm described in the paper,
// Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits
// of keystream.
// response is a multi-line text response containing the hex of the keystream;
// nrarhex is a string containing hex representations of the 32 bit nR and aR
// values (separated by a space) snooped using SNIFF-PWM.
bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
uint8_t uidhex[9];
uint8_t uid[32];
uint8_t nrar[64];
uint8_t e_firstcmd[10];
// uint8_t e_page0cmd[10];
// uint8_t keybits[2080];
uint8_t *keybits = DataBuff;
uint8_t keybitshex[67];
int kslen;
int ksoffset;
// uint8_t pagehex[9];
// uint8_t temp[20];
int i;
uint8_t *spaceptr = NULL;
/*
keybits = calloc(2080, sizeof(uint8_t));
if (!keybits) {
UserMessage("cannot malloc keybits\r\n");
return false;
}
*/
// get uid as hexstring
if (!hitag2_get_uid(uidhex)) {
UserMessage("Cannot get UID\r\n");
return false;
}
// convert uid hexstring to binarray
hextobinarray(uid, uidhex);
// convert nR and aR hexstrings to binarray
spaceptr = strchr(nrarhex, ' ');
if (!spaceptr) {
UserMessage("Please supply a valid nR aR pair\r\n");
return false;
}
*spaceptr = 0x00;
if (hextobinarray(nrar, nrarhex) != 32) {
UserMessage("nR is not 32 bits long\r\n");
return false;
}
if (hextobinarray(nrar + 32, spaceptr + 1) != 32) {
UserMessage("aR is not 32 bits long\r\n");
return false;
}
// find a valid encrypted command
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) {
UserMessage("Cannot find a valid encrypted command\r\n");
return false;
}
// find the 'read page 0' command and recover key stream
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) {
UserMessage("Cannot find encrypted 'read page0' command\r\n");
return false;
}
// using the 40 bits of keystream in keybits, sending commands with ever
// increasing lengths to acquire 2048 bits of key stream.
kslen = 40;
while (kslen < 2048) {
ksoffset = 0;
if (!hitag2crack_send_auth(nrar)) {
UserMessage("hitag2crack_send_auth failed\r\n");
return false;
}
// while we have at least 52 bits of keystream, consume it with
// extended read page 0 commands. 52 = 10 (min command len) +
// 32 (response) + 10 (min command len we'll send)
while ((kslen - ksoffset) >= 52) {
// consume the keystream, updating ksoffset as we go
if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar)) {
UserMessage("hitag2crack_consume_keystream failed\r\n");
return false;
}
}
// send an extended command to retrieve more keystream, updating kslen
// as we go
if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid)) {
UserMessage("hitag2crack_extend_keystream failed\r\n");
return false;
}
UserMessage("Recovered %d bits of keystream\r\n", kslen);
}
for (i = 0; i < 2048; i += 256) {
binarray_2_hex(keybitshex, keybits + i, 256);
UserMessage("%s\r\n", keybitshex);
}
response[0] = 0x00;
return true;
}
// hitag2crack_send_auth replays the auth and returns.
// nrar is the 64 bit binarray of the nR aR pair;
bool hitag2crack_send_auth(uint8_t *nrar) {
uint8_t uid[9];
uint8_t e_page3str[9];
// get the UID
if (!hitag2_get_uid(uid)) {
UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n");
return false;
}
// START_AUTH kills active crypto session
CryptoActive = false;
// get the UID again
if (!hitag2_get_uid(uid)) {
UserMessage("hitag2crack_send_auth:\r\n cannot get UID (2nd time)\r\n");
return false;
}
// send nrar and receive (useless) encrypted page 3 value
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) {
UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n");
return false;
}
return true;
}
// hitag2crack_consume_keystream sends an extended command (up to 510 bits in
// length) to consume keystream.
// keybits is the binarray of keystream bits;
// kslen is the length of keystream;
// ksoffset is a pointer to the current keystream offset (updated by this fn);
// nrar is the 64 bit binarray of the nR aR pair.
bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, uint8_t *nrar) {
int conlen;
int numcmds;
int i;
uint8_t ext_cmd[510];
uint8_t e_ext_cmd[510];
uint8_t responsestr[9];
// calculate the length of keybits to consume with the extended command.
// 42 = 32 bit response + 10 bit command reserved for next command. conlen
// cannot be longer than 510 bits to fit into the small RWD buffer.
conlen = kslen - *ksoffset - 42;
if (conlen < 10) {
UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n");
return false;
}
// sanitise conlen
if (conlen > 510) {
conlen = 510;
}
// calculate how many repeated commands to send in this extended command.
numcmds = conlen / 10;
// build extended command
for (i = 0; i < numcmds; i++) {
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
}
// xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + *ksoffset, numcmds * 10);
// send encrypted command
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false)) {
UserMessage("hitag2crack_consume_keystream:\r\n tx/rx cmd failed\r\n");
return false;
}
// test response
if (strcmp(responsestr, ERROR_RESPONSE) == 0) {
UserMessage("hitag2crack_consume_keystream:\r\n got error response from card\r\n");
return false;
}
// don't bother decrypting the response - we already know the keybits
// update ksoffset with command length and response
*ksoffset += (numcmds * 10) + 32;
return true;
}
// hitag2crack_extend_keystream sends an extended command to retrieve more keybits.
// keybits is the binarray of the keystream bits;
// kslen is a pointer to the current keybits length;
// ksoffset is the offset into the keybits array;
// nrar is the 64 bit binarray of the nR aR pair;
// uid is the 32 bit binarray of the UID.
bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, uint8_t *nrar, uint8_t *uid) {
int cmdlen;
int numcmds;
uint8_t ext_cmd[510];
uint8_t e_ext_cmd[510];
uint8_t responsestr[9];
uint8_t e_response[32];
int i;
// calc number of command iterations to send
cmdlen = *kslen - ksoffset;
if (cmdlen < 10) {
UserMessage("hitag2crack_extend_keystream:\r\n cmdlen < 10\r\n");
return false;
}
numcmds = cmdlen / 10;
// build extended command
for (i = 0; i < numcmds; i++) {
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
}
// xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + ksoffset, numcmds * 10);
// send extended encrypted cmd
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false)) {
UserMessage("hitag2crack_extend_keystream:\r\n tx/rx cmd failed\r\n");
return false;
}
// test response
if (strcmp(responsestr, ERROR_RESPONSE) == 0) {
UserMessage("hitag2crack_extend_keystream:\r\n got error response from card\r\n");
return false;
}
// convert response to binarray
hextobinarray(e_response, responsestr);
// recover keystream from encrypted response
hitag2crack_xor(keybits + ksoffset + (numcmds * 10), e_response, uid, 32);
// update kslen
*kslen = ksoffset + (numcmds * 10) + 32;
return true;
}
bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive) {
uint8_t tmp[9];
response[0] = '\0';
// auth to tag
if (hitag2_crypto_auth(tmp, key)) {
// read tag, one page at a time
for (int i = 0; i <= 7; ++i) {
if (!read_tag(tmp, i, i)) {
// if read fails, it could be because of auth,
// so try to reauth
if (!hitag2_crypto_auth(tmp, key)) {
// if we can't reauth, it's a real failure
return false;
}
// temp failure (probably due to page protections)
strcpy(tmp, "XXXXXXXX");
}
// page contents are in tmp
strcat(response, tmp);
}
if (interactive) {
tmp[8] = '\0';
for (i = 0; i <= 7 ; ++i) {
UserMessageNum("%d: ", i);
memcpy(tmp, response + (i * 8), 8);
UserMessage("%s\r\n", tmp);
}
UserMessage("%s", "\r\n");
} else {
hitag2_nvm_store_tag(response);
}
return true;
} else {
return false;
}
}

View file

@ -1,42 +0,0 @@
//-----------------------------------------------------------------------------
// Borrowed initially from https://github.com/factoritbv/hitag2hell
// and https://github.com/AdamLaurie/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/hitag2crack.c
// Copyright (C) Kevin Sheldrake <kev@headhacking.com>, Aug 2018
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// Definitions hitag2 attack functions
//-----------------------------------------------------------------------------
bool hitag2_crack(uint8_t *response, uint8_t *nrarhex);
bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]);
bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8_t nrar[], uint8_t uid[]);
bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid);
void hitag2crack_xor(uint8_t *target, const uint8_t *source, const uint8_t *pad, unsigned int len);
bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, uint8_t *keybits);
bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len);
bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, bool reset);
bool hitag2crack_rng_init(uint8_t *response, uint8_t *input);
bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex);
bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr);
bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex);
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr);
bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex);
bool hitag2crack_send_auth(uint8_t *nrar);
bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, uint8_t *nrar);
bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, uint8_t *nrar, uint8_t *uid);
bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive);

View file

@ -2890,21 +2890,14 @@ void SetTag15693Uid(const uint8_t *uid) {
uint8_t cmd[4][9] = { uint8_t cmd[4][9] = {
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x8F}, {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x8F},
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00, 0x8A, 0xBB}, {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00, 0x8A, 0xBB},
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x38},
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39}
};
// Command 3 : 02 21 38 u8u7u6u5 (where uX = uid byte X) // Command 3 : 02 21 38 u8u7u6u5 (where uX = uid byte X)
cmd[2][3] = uid[7]; {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x38, uid[7], uid[6], uid[5], uid[4]},
cmd[2][4] = uid[6];
cmd[2][5] = uid[5];
cmd[2][6] = uid[4];
// Command 4 : 02 21 39 u4u3u2u1 (where uX = uid byte X) // Command 4 : 02 21 39 u4u3u2u1 (where uX = uid byte X)
cmd[3][3] = uid[3]; {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39, uid[3], uid[2], uid[1], uid[0]}
cmd[3][4] = uid[2]; };
cmd[3][5] = uid[1];
cmd[3][6] = uid[0];
AddCrc15(cmd[2], 7); AddCrc15(cmd[2], 7);
AddCrc15(cmd[3], 7); AddCrc15(cmd[3], 7);
@ -2938,6 +2931,54 @@ void SetTag15693Uid(const uint8_t *uid) {
switch_off(); switch_off();
} }
// Set the UID on Magic ISO15693 tag ( Gen2 ?)
// E0 00 09 - seem to be command
// 0x41, 0x40 - seem to be block referens
void SetTag15693Uid_v2(const uint8_t *uid) {
LED_A_ON();
uint8_t cmd[2][11] = {
// hf 15 raw -wac -d 02e00941 + uid first four bytes
{ISO15_REQ_DATARATE_HIGH, ISO15693_MAGIC_WRITE, 0x00, 0x09, 0x41, uid[7], uid[6], uid[5], uid[4], 0x00, 0x00},
// hf 15 raw -wac -d 02e00940 + uid last four bytes
{ISO15_REQ_DATARATE_HIGH, ISO15693_MAGIC_WRITE, 0x00, 0x09, 0x40, uid[3], uid[2], uid[1], uid[0], 0x00, 0x00}
};
AddCrc15(cmd[0], 9);
AddCrc15(cmd[1], 9);
uint8_t buf[ISO15693_MAX_RESPONSE_LENGTH] = {0x00};
uint32_t start_time = 0;
uint32_t eof_time = 0;
uint16_t recvlen = 0;
int res = PM3_SUCCESS;
for (int i = 0; i < 2; i++) {
res = SendDataTag(
cmd[i],
sizeof(cmd[i]),
(i == 0) ? true : false,
true,
buf,
sizeof(buf),
start_time,
ISO15693_READER_TIMEOUT_WRITE,
&eof_time,
&recvlen
);
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
}
reply_ng(CMD_HF_ISO15693_CSETUID_V2, res, NULL, 0);
switch_off();
}
static void init_password_15693_Slix(uint8_t *buffer, const uint8_t *pwd, const uint8_t *rnd) { static void init_password_15693_Slix(uint8_t *buffer, const uint8_t *pwd, const uint8_t *rnd) {
memcpy(buffer, pwd, 4); memcpy(buffer, pwd, 4);
if (rnd) { if (rnd) {

View file

@ -59,6 +59,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len); int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len);
void SetTag15693Uid(const uint8_t *uid); void SetTag15693Uid(const uint8_t *uid);
void SetTag15693Uid_v2(const uint8_t *uid);
void WritePasswordSlixIso15693(const uint8_t *old_password, const uint8_t *new_password, uint8_t pwd_id); void WritePasswordSlixIso15693(const uint8_t *old_password, const uint8_t *new_password, uint8_t pwd_id);
void DisablePrivacySlixIso15693(const uint8_t *password); void DisablePrivacySlixIso15693(const uint8_t *password);

View file

@ -118,7 +118,9 @@ static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR; volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
if (g_logging) logSampleSimple(adc_val); if (g_logging) {
logSampleSimple(adc_val);
}
// Only test field changes if state of adc values matter // Only test field changes if state of adc values matter
if (wait == false) { if (wait == false) {
@ -157,7 +159,10 @@ static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
} }
} }
if (g_logging) logSampleSimple(0xFF); if (g_logging) {
logSampleSimple(0xFF);
}
return 0; return 0;
} }
@ -210,16 +215,18 @@ void lf_init(bool reader, bool simulate, bool ledcontrol) {
sc->averaging = 0; sc->averaging = 0;
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
if (reader) { if (reader) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
} else { } else {
if (simulate)
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
else
// Sniff
//FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
if (simulate) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
} else {
// Sniff
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
// FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
}
} }
// Connect the A/D to the peak-detected low-frequency path. // Connect the A/D to the peak-detected low-frequency path.
@ -261,7 +268,9 @@ void lf_init(bool reader, bool simulate, bool ledcontrol) {
uint32_t bufsize = 10000; uint32_t bufsize = 10000;
// use malloc // use malloc
if (g_logging) initSampleBufferEx(&bufsize, true); if (g_logging) {
initSampleBufferEx(&bufsize, true);
}
lf_sample_mean(); lf_sample_mean();
} }

View file

@ -246,12 +246,13 @@ void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool
**/ **/
void LFSetupFPGAForADC(int divisor, bool reader_field) { void LFSetupFPGAForADC(int divisor, bool reader_field) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ((divisor == 1) || (divisor < 0) || (divisor > 255)) if ((divisor == 1) || (divisor < 0) || (divisor > 255)) {
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_134); //~134kHz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_134); //~134kHz
else if (divisor == 0) } else if (divisor == 0) {
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
else } else {
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | (reader_field ? FPGA_LF_ADC_READER_FIELD : 0)); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | (reader_field ? FPGA_LF_ADC_READER_FIELD : 0));
@ -623,15 +624,17 @@ void doT55x7Acquisition(size_t sample_size, bool ledcontrol) {
// skip until first high samples begin to change // skip until first high samples begin to change
if (startFound || sample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) { if (startFound || sample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) {
// if just found start - recover last sample // if just found start - recover last sample
if (!startFound) { if (startFound == false) {
dest[i++] = lastSample; dest[i++] = lastSample;
startFound = true; startFound = true;
} }
// collect samples // collect samples
if (i < bufsize) {
dest[i++] = sample; dest[i++] = sample;
} }
} }
} }
}
} }
/** /**
* acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384 * acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384
@ -698,13 +701,15 @@ void doCotagAcquisition(void) {
firstlow = true; firstlow = true;
} }
++i;
if (sample > COTAG_ONE_THRESHOLD) { if (sample > COTAG_ONE_THRESHOLD) {
dest[i] = 255; dest[i] = 255;
++i;
} else if (sample < COTAG_ZERO_THRESHOLD) { } else if (sample < COTAG_ZERO_THRESHOLD) {
dest[i] = 0; dest[i] = 0;
++i;
} else { } else {
dest[i] = dest[i - 1]; dest[i] = dest[i - 1];
++i;
} }
} }
} }

View file

@ -31,67 +31,110 @@ size_t nbytes(size_t nbits) {
} }
//convert hex digit to integer //convert hex digit to integer
uint8_t hex2int(char hexchar) { uint8_t hex2int(char x) {
switch (hexchar) { switch (x) {
case '0': case '0':
return 0; return 0;
break;
case '1': case '1':
return 1; return 1;
break;
case '2': case '2':
return 2; return 2;
break;
case '3': case '3':
return 3; return 3;
break;
case '4': case '4':
return 4; return 4;
break;
case '5': case '5':
return 5; return 5;
break;
case '6': case '6':
return 6; return 6;
break;
case '7': case '7':
return 7; return 7;
break;
case '8': case '8':
return 8; return 8;
break;
case '9': case '9':
return 9; return 9;
break;
case 'a': case 'a':
case 'A': case 'A':
return 10; return 10;
break;
case 'b': case 'b':
case 'B': case 'B':
return 11; return 11;
break;
case 'c': case 'c':
case 'C': case 'C':
return 12; return 12;
break;
case 'd': case 'd':
case 'D': case 'D':
return 13; return 13;
break;
case 'e': case 'e':
case 'E': case 'E':
return 14; return 14;
break;
case 'f': case 'f':
case 'F': case 'F':
return 15; return 15;
break;
default: default:
return 0; return 0;
} }
} }
/*
The following methods comes from Rfidler sourcecode.
https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/
*/
// convert hex to sequence of 0/1 bit values
// returns number of bits converted
int hex2binarray(char *target, char *source) {
return hex2binarray_n(target, source, strlen(source));
}
int hex2binarray_n(char *target, char *source, int sourcelen) {
int count = 0;
// process 4 bits (1 hex digit) at a time
while (sourcelen--) {
char x = *(source++);
*(target++) = (x >> 7) & 1;
*(target++) = (x >> 6) & 1;
*(target++) = (x >> 5) & 1;
*(target++) = (x >> 4) & 1;
*(target++) = (x >> 3) & 1;
*(target++) = (x >> 2) & 1;
*(target++) = (x >> 1) & 1;
*(target++) = (x & 1);
count += 8;
}
return count;
}
int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex) {
int count = 0;
int byte_index = 0;
// Clear output buffer
memset(hex, 0, bs_len >> 3);
for (int i = 0; i < bs_len; i++) {
// Set the appropriate bit in hex
if (bs[i] == 1) {
hex[byte_index] |= (1 << (7 - (count % 8)));
}
count++;
// Move to the next byte if 8 bits have been filled
if (count % 8 == 0) {
byte_index++;
}
}
return count;
}
void LEDsoff(void) { void LEDsoff(void) {
LED_A_OFF(); LED_A_OFF();
LED_B_OFF(); LED_B_OFF();

View file

@ -82,9 +82,12 @@
#endif #endif
size_t nbytes(size_t nbits); size_t nbytes(size_t nbits);
uint8_t hex2int(char hexchar); uint8_t hex2int(char hexchar);
int hex2binarray(char *target, char *source);
int hex2binarray_n(char *target, char *source, int sourcelen);
int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex);
void LED(int led, int ms); void LED(int led, int ms);
void LEDsoff(void); void LEDsoff(void);
void SpinOff(uint32_t pause); void SpinOff(uint32_t pause);

View file

@ -40,11 +40,7 @@ static bool TestKVV(void) {
bool res = memcmp(KeyKvv, kvv, CIPURSE_KVV_LENGTH) == 0; bool res = memcmp(KeyKvv, kvv, CIPURSE_KVV_LENGTH) == 0;
if (res) PrintAndLogEx(SUCCESS, "kvv.............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "kvv.............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "kvv.............. " _RED_("fail"));
return res; return res;
} }
@ -58,11 +54,7 @@ static bool TestISO9797M2(void) {
res = res && (FindISO9797M2PaddingDataLen(data, ddatalen) == 4); res = res && (FindISO9797M2PaddingDataLen(data, ddatalen) == 4);
if (res) PrintAndLogEx(SUCCESS, "ISO9797M2........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "ISO9797M2........ " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "ISO9797M2........ " _RED_("fail"));
return res; return res;
} }
@ -92,11 +84,7 @@ static bool TestSMI(void) {
res = res && (CipurseCGetSMI(&ctx, false) == 0x88); res = res && (CipurseCGetSMI(&ctx, false) == 0x88);
res = res && (CipurseCGetSMI(&ctx, true) == 0x89); res = res && (CipurseCGetSMI(&ctx, true) == 0x89);
if (res) PrintAndLogEx(SUCCESS, "SMI.............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "SMI.............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "SMI.............. " _RED_("fail"));
return res; return res;
} }
@ -115,15 +103,10 @@ static bool TestMIC(void) {
res = res && (CipurseCCheckMIC(TestData, 6, mic)); res = res && (CipurseCCheckMIC(TestData, 6, mic));
if (res) PrintAndLogEx(SUCCESS, "MIC.............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "MIC.............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "MIC.............. " _RED_("fail"));
return res; return res;
} }
static bool TestAuth(void) { static bool TestAuth(void) {
CipurseContext_t ctx = {0}; CipurseContext_t ctx = {0};
CipurseCClearContext(&ctx); CipurseCClearContext(&ctx);
@ -159,11 +142,7 @@ static bool TestAuth(void) {
uint8_t framekey[] = {0xCF, 0x6F, 0x3A, 0x47, 0xFC, 0xAC, 0x8D, 0x38, 0x25, 0x75, 0x8B, 0xFC, 0x8B, 0x61, 0x68, 0xF3}; uint8_t framekey[] = {0xCF, 0x6F, 0x3A, 0x47, 0xFC, 0xAC, 0x8D, 0x38, 0x25, 0x75, 0x8B, 0xFC, 0x8B, 0x61, 0x68, 0xF3};
res = res && (memcmp(ctx.frameKey, framekey, sizeof(framekey)) == 0); res = res && (memcmp(ctx.frameKey, framekey, sizeof(framekey)) == 0);
if (res) PrintAndLogEx(SUCCESS, "Auth............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "Auth............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "Auth............. " _RED_("fail"));
return res; return res;
} }
@ -211,11 +190,7 @@ static bool TestMAC(void) {
uint8_t framekey4[] = {0xA0, 0x65, 0x1A, 0x62, 0x56, 0x5D, 0xD7, 0xC9, 0x32, 0xAE, 0x1D, 0xE0, 0xCF, 0x8D, 0xC1, 0xB9}; uint8_t framekey4[] = {0xA0, 0x65, 0x1A, 0x62, 0x56, 0x5D, 0xD7, 0xC9, 0x32, 0xAE, 0x1D, 0xE0, 0xCF, 0x8D, 0xC1, 0xB9};
res = res && (memcmp(ctx.frameKey, framekey4, sizeof(framekey4)) == 0); res = res && (memcmp(ctx.frameKey, framekey4, sizeof(framekey4)) == 0);
if (res) PrintAndLogEx(SUCCESS, "channel MAC...... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "channel MAC...... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "channel MAC...... " _RED_("fail"));
return res; return res;
} }
@ -259,11 +234,7 @@ static bool TestEncDec(void) {
res = res && (dstdatalen == 16); res = res && (dstdatalen == 16);
res = res && (memcmp(dstdata, TestData, 16) == 0); res = res && (memcmp(dstdata, TestData, 16) == 0);
if (res) PrintAndLogEx(SUCCESS, "channel EncDec... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "channel EncDec... " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "channel EncDec... " _RED_("fail"));
return res; return res;
} }
@ -351,11 +322,7 @@ static bool TestAPDU(void) {
res = res && (memcmp(test6, dstdata, dstdatalen) == 0); res = res && (memcmp(test6, dstdata, dstdatalen) == 0);
res = res && (sw == 0xccdd); res = res && (sw == 0xccdd);
if (res) PrintAndLogEx(SUCCESS, "apdu............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "apdu............. " _GREEN_("passed"));
else
PrintAndLogEx(ERR, "apdu............. " _RED_("fail"));
return res; return res;
} }
@ -374,11 +341,7 @@ bool CIPURSETest(bool verbose) {
res = res && TestAPDU(); res = res && TestAPDU();
PrintAndLogEx(INFO, "---------------------------"); PrintAndLogEx(INFO, "---------------------------");
if (res) PrintAndLogEx(SUCCESS, "Tests ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(SUCCESS, " Tests [ %s ]", _GREEN_("ok"));
else
PrintAndLogEx(FAILED, " Tests [ %s ]", _RED_("fail"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return res; return res;
} }

View file

@ -2769,7 +2769,7 @@ static int CmdAsn1Decoder(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("d", NULL, "<hex>", "ASN1 encoded byte array"), arg_str0("d", NULL, "<hex>", "ASN1 encoded byte array"),
arg_lit0("t", "test", "perform selftest"), arg_lit0("t", "test", "perform self test"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2798,17 +2798,14 @@ static int CmdDiff(const char *Cmd) {
"data diff -w 4 -a hf-mfu-01020304.bin -b hf-mfu-04030201.bin\n" "data diff -w 4 -a hf-mfu-01020304.bin -b hf-mfu-04030201.bin\n"
"data diff -a fileA -b fileB\n" "data diff -a fileA -b fileB\n"
"data diff -a fileA --eb\n" "data diff -a fileA --eb\n"
// "data diff -a fileA --cb\n"
"data diff --fa fileA -b fileB\n" "data diff --fa fileA -b fileB\n"
"data diff --fa fileA --fb fileB\n" "data diff --fa fileA --fb fileB\n"
// "data diff --ea --cb\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("a", NULL, "<fn>", "input file name A"), arg_str0("a", NULL, "<fn>", "input file name A"),
arg_str0("b", NULL, "<fn>", "input file name B"), arg_str0("b", NULL, "<fn>", "input file name B"),
// arg_lit0(NULL, "cb", "magic gen1 <hf mf csave>"),
arg_lit0(NULL, "eb", "emulator memory <hf mf esave>"), arg_lit0(NULL, "eb", "emulator memory <hf mf esave>"),
arg_str0(NULL, "fa", "<fn>", "input spiffs file A"), arg_str0(NULL, "fa", "<fn>", "input spiffs file A"),
arg_str0(NULL, "fb", "<fn>", "input spiffs file B"), arg_str0(NULL, "fb", "<fn>", "input spiffs file B"),
@ -2825,7 +2822,6 @@ static int CmdDiff(const char *Cmd) {
char filenameB[FILE_PATH_SIZE] = {0}; char filenameB[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filenameB, FILE_PATH_SIZE, &fnlenB); CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filenameB, FILE_PATH_SIZE, &fnlenB);
// bool use_c = arg_get_lit(ctx, 3);
bool use_e = arg_get_lit(ctx, 3); bool use_e = arg_get_lit(ctx, 3);
// SPIFFS filename A // SPIFFS filename A
@ -2930,14 +2926,6 @@ static int CmdDiff(const char *Cmd) {
} }
} }
// dump magic card memory
/*
if (use_c) {
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
return PM3_ENOTIMPL;
}
*/
size_t biggest = (datalenA > datalenB) ? datalenA : datalenB; size_t biggest = (datalenA > datalenB) ? datalenA : datalenB;
PrintAndLogEx(DEBUG, "data len: %zu A %zu B %zu", biggest, datalenA, datalenB); PrintAndLogEx(DEBUG, "data len: %zu A %zu B %zu", biggest, datalenA, datalenB);
@ -2949,7 +2937,6 @@ static int CmdDiff(const char *Cmd) {
PrintAndLogEx(INFO, "inB null"); PrintAndLogEx(INFO, "inB null");
} }
char hdr0[400] = {0}; char hdr0[400] = {0};
int hdr_sln = (width * 4) + 2; int hdr_sln = (width * 4) + 2;
@ -3395,7 +3382,7 @@ static int CmdAtrLookup(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("d", NULL, "<hex>", "ASN1 encoded byte array"), arg_str0("d", NULL, "<hex>", "ASN1 encoded byte array"),
// arg_lit0("t", "test", "perform selftest"), // arg_lit0("t", "test", "perform self test"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -2735,11 +2735,14 @@ static int CmdHF15CSetUID(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 15 csetuid", CLIParserInit(&ctx, "hf 15 csetuid",
"Set UID for magic Chinese card (only works with such cards)\n", "Set UID for magic Chinese card (only works with such cards)\n",
"hf 15 csetuid -u E011223344556677"); "hf 15 csetuid -u E011223344556677 -> use gen1 command\n"
"hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command"
);
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("u", "uid", "<hex>", "UID, 8 hex bytes"), arg_str1("u", "uid", "<hex>", "UID, 8 hex bytes"),
arg_lit0("2", "v2", "Use gen2 magic command"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -2750,6 +2753,7 @@ static int CmdHF15CSetUID(const char *Cmd) {
int uidlen = 0; int uidlen = 0;
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
bool use_v2 = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
if (uidlen != HF15_UID_LENGTH) { if (uidlen != HF15_UID_LENGTH) {
@ -2775,8 +2779,14 @@ static int CmdHF15CSetUID(const char *Cmd) {
PrintAndLogEx(INFO, "Writing..."); PrintAndLogEx(INFO, "Writing...");
PacketResponseNG resp; PacketResponseNG resp;
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload));
if (WaitForResponseTimeout(CMD_HF_ISO15693_CSETUID, &resp, 2000) == false) { uint16_t cmd = CMD_HF_ISO15693_CSETUID;
if (use_v2) {
cmd = CMD_HF_ISO15693_CSETUID_V2;
}
SendCommandNG(cmd, (uint8_t *)&payload, sizeof(payload));
if (WaitForResponseTimeout(cmd, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply"); PrintAndLogEx(WARNING, "timeout while waiting for reply");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;

View file

@ -93,6 +93,8 @@ static int CmdHFCryptoRFSniff(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0); SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0);
PacketResponseNG resp;
WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp);
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf cryptorf list") "` to view captured tracelog"); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf cryptorf list") "` to view captured tracelog");
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_cryptorf_mytrace") "` to save tracelog for later analysing"); PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_cryptorf_mytrace") "` to save tracelog for later analysing");

View file

@ -2147,8 +2147,9 @@ static int CmdHFiClassDump(const char *Cmd) {
write_dump: write_dump:
if (have_credit_key && pagemap != 0x01 && aa2_success == false) if (have_credit_key && pagemap != 0x01 && aa2_success == false) {
PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file"); PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file");
}
// print the dump // print the dump
printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got, dense_output); printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got, dense_output);
@ -2852,8 +2853,8 @@ static int CmdHFiClass_loclass(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename with nr/mac data from `hf iclass sim -t 2` "), arg_str0("f", "file", "<fn>", "filename with nr/mac data from `hf iclass sim -t 2` "),
arg_lit0(NULL, "test", "Perform self-test"), arg_lit0(NULL, "test", "Perform self test"),
arg_lit0(NULL, "long", "Perform self-test, including long ones"), arg_lit0(NULL, "long", "Perform self test, including long ones"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -3776,9 +3777,10 @@ out:
static int CmdHFiClassLookUp(const char *Cmd) { static int CmdHFiClassLookUp(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass lookup", CLIParserInit(&ctx, "hf iclass lookup",
"Lookup keys takes some sniffed trace data and tries to verify what key was used against a dictionary file", "This command take sniffed trace data and try to recovery a iCLASS Standard or iCLASS Elite key.",
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic\n" "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic\n"
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite"); "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite"
);
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
@ -4628,9 +4630,9 @@ static int CmdHFiClassSAM(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHFiClassList, AlwaysAvailable, "List iclass history"}, {"list", CmdHFiClassList, AlwaysAvailable, "List iclass history"},
// {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
{"-----------", CmdHelp, IfPm3Iclass, "------------------- " _CYAN_("Operations") " -------------------"}, {"-----------", CmdHelp, IfPm3Iclass, "------------------- " _CYAN_("Operations") " -------------------"},
// {"clone", CmdHFiClassClone, IfPm3Iclass, "Create a HID credential to Picopass / iCLASS tag"}, // {"clone", CmdHFiClassClone, IfPm3Iclass, "Create a HID credential to Picopass / iCLASS tag"},
{"dump", CmdHFiClassDump, IfPm3Iclass, "Dump Picopass / iCLASS tag to file"}, {"dump", CmdHFiClassDump, IfPm3Iclass, "Dump Picopass / iCLASS tag to file"},

View file

@ -238,7 +238,7 @@ static void jooki_print(uint8_t *b64, uint8_t *result, bool verbose) {
static int jooki_selftest(void) { static int jooki_selftest(void) {
PrintAndLogEx(INFO, "======== " _CYAN_("selftest") " ==========================================="); PrintAndLogEx(INFO, "======== " _CYAN_("self test") " ===========================================");
for (int i = 0; i < ARRAYLEN(jooks); i++) { for (int i = 0; i < ARRAYLEN(jooks); i++) {
if (strlen(jooks[i].b64) == 0) if (strlen(jooks[i].b64) == 0)
continue; continue;
@ -296,7 +296,7 @@ static int CmdHF14AJookiEncode(const char *Cmd) {
arg_param_begin, arg_param_begin,
arg_str0("u", "uid", "<hex>", "uid bytes"), arg_str0("u", "uid", "<hex>", "uid bytes"),
arg_lit0("r", NULL, "read uid from tag instead"), arg_lit0("r", NULL, "read uid from tag instead"),
arg_lit0("t", NULL, "selftest"), arg_lit0("t", NULL, "self test"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_lit0(NULL, "dragon", "figurine type"), arg_lit0(NULL, "dragon", "figurine type"),
arg_lit0(NULL, "fox", "figurine type"), arg_lit0(NULL, "fox", "figurine type"),

View file

@ -704,6 +704,9 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
case ISO15693_READ_SIGNATURE: case ISO15693_READ_SIGNATURE:
snprintf(exp, size, "READ_SIGNATURE"); snprintf(exp, size, "READ_SIGNATURE");
return; return;
case ISO15693_MAGIC_WRITE:
snprintf(exp, size, "MAGIC_WRITEBLOCK");
return;
default: default:
break; break;
} }
@ -2223,7 +2226,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
char sat[5] = {0, 0, 0, 0, 0}; char sat[5] = {0, 0, 0, 0, 0};
mf_get_paritybinstr(sat, AuthData.at_enc, AuthData.at_enc_par); mf_get_paritybinstr(sat, AuthData.at_enc, AuthData.at_enc_par);
PrintAndLogEx(NORMAL, "Nested authentication detected. "); PrintAndLogEx(NORMAL, "Nested authentication detected!");
PrintAndLogEx(NORMAL, "tools/mf_nonce_brute/mf_nonce_brute %x %x %s %x %x %s %x %s %s\n" PrintAndLogEx(NORMAL, "tools/mf_nonce_brute/mf_nonce_brute %x %x %s %x %x %s %x %s %s\n"
, AuthData.uid , AuthData.uid
, AuthData.nt_enc , AuthData.nt_enc

View file

@ -41,15 +41,17 @@ static int sendPing(void) {
SendCommandNG(CMD_PING, NULL, 0); SendCommandNG(CMD_PING, NULL, 0);
clearCommandBuffer(); clearCommandBuffer();
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_PING, &resp, 1000)) if (WaitForResponseTimeout(CMD_PING, &resp, 1000) == false) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, size_t bs_len, bool verbose) { static int sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, size_t bs_len, bool verbose) {
if (verbose) if (verbose) {
PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fc, cn); PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fc, cn);
}
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) { if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
@ -205,6 +207,11 @@ int demodAWID(bool verbose) {
free(bits); free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
char binstr[68] = {0};
binarray_2_binstr(binstr, (char *)bits, size);
PrintAndLogEx(DEBUG, "no parity... %s", binstr);
// ok valid card found! // ok valid card found!
// Index map // Index map
@ -230,35 +237,47 @@ int demodAWID(bool verbose) {
uint8_t fmtLen = bytebits_to_byte(bits, 8); uint8_t fmtLen = bytebits_to_byte(bits, 8);
switch (fmtLen) { switch (fmtLen) {
case 26: case 26: {
fc = bytebits_to_byte(bits + 9, 8); fc = bytebits_to_byte(bits + 9, 8);
cardnum = bytebits_to_byte(bits + 17, 16); cardnum = bytebits_to_byte(bits + 17, 16);
code1 = bytebits_to_byte(bits + 8, fmtLen); code1 = bytebits_to_byte(bits + 8, fmtLen);
PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo); PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo);
break; break;
case 34: }
case 34: {
fc = bytebits_to_byte(bits + 9, 8); fc = bytebits_to_byte(bits + 9, 8);
cardnum = bytebits_to_byte(bits + 17, 24); cardnum = bytebits_to_byte(bits + 17, 24);
code1 = bytebits_to_byte(bits + 8, (fmtLen - 32)); code1 = bytebits_to_byte(bits + 8, (fmtLen - 32));
code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32); code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32);
PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
break; break;
case 37: }
case 36: {
fc = bytebits_to_byte(bits + 14, 11);
cardnum = bytebits_to_byte(bits + 25, 18);
code1 = bytebits_to_byte(bits + 8, (fmtLen - 32));
code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32);
PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
break;
}
case 37: {
fc = bytebits_to_byte(bits + 9, 13); fc = bytebits_to_byte(bits + 9, 13);
cardnum = bytebits_to_byte(bits + 22, 18); cardnum = bytebits_to_byte(bits + 22, 18);
code1 = bytebits_to_byte(bits + 8, (fmtLen - 32)); code1 = bytebits_to_byte(bits + 8, (fmtLen - 32));
code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32); code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32);
PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d")" FC: " _GREEN_("%d")" Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d")" FC: " _GREEN_("%d")" Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
break; break;
}
// case 40: // case 40:
// break; // break;
case 50: case 50: {
fc = bytebits_to_byte(bits + 9, 16); fc = bytebits_to_byte(bits + 9, 16);
cardnum = bytebits_to_byte(bits + 25, 32); cardnum = bytebits_to_byte(bits + 25, 32);
code1 = bytebits_to_byte(bits + 8, (fmtLen - 32)); code1 = bytebits_to_byte(bits + 8, (fmtLen - 32));
code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32); code2 = bytebits_to_byte(bits + 8 + (fmtLen - 32), 32);
PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo); PrintAndLogEx(SUCCESS, "AWID - len: " _GREEN_("%d") " FC: " _GREEN_("%d") " Card: " _GREEN_("%u") " - Wiegand: " _GREEN_("%x%08x") ", Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, code2, rawHi2, rawHi, rawLo);
break; break;
}
default: default:
if (fmtLen > 32) { if (fmtLen > 32) {
cardnum = bytebits_to_byte(bits + 8 + (fmtLen - 17), 16); cardnum = bytebits_to_byte(bits + 8 + (fmtLen - 17), 16);
@ -288,7 +307,9 @@ static int CmdAWIDDemod(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid demod", CLIParserInit(&ctx, "lf awid demod",
"Try to find AWID Prox preamble, if found decode / descramble data", "Try to find AWID Prox preamble, if found decode / descramble data",
"lf awid demod" "lf awid demod\n"
"lf awid demod --raw "
); );
void *argtable[] = { void *argtable[] = {
@ -566,9 +587,10 @@ static int CmdAWIDBrute(const char *Cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"}, {"help", CmdHelp, AlwaysAvailable, "this help"},
{"brute", CmdAWIDBrute, IfPm3Lf, "bruteforce card number against reader"},
{"clone", CmdAWIDClone, IfPm3Lf, "clone AWID tag to T55x7, Q5/T5555 or EM4305/4469"},
{"demod", CmdAWIDDemod, AlwaysAvailable, "demodulate an AWID FSK tag from the GraphBuffer"}, {"demod", CmdAWIDDemod, AlwaysAvailable, "demodulate an AWID FSK tag from the GraphBuffer"},
{"reader", CmdAWIDReader, IfPm3Lf, "attempt to read and extract tag data"}, {"reader", CmdAWIDReader, IfPm3Lf, "attempt to read and extract tag data"},
{"clone", CmdAWIDClone, IfPm3Lf, "clone AWID tag to T55x7, Q5/T5555 or EM4305/4469"},
{"sim", CmdAWIDSim, IfPm3Lf, "simulate AWID tag"}, {"sim", CmdAWIDSim, IfPm3Lf, "simulate AWID tag"},
{"brute", CmdAWIDBrute, IfPm3Lf, "bruteforce card number against reader"}, {"brute", CmdAWIDBrute, IfPm3Lf, "bruteforce card number against reader"},
{"watch", CmdAWIDWatch, IfPm3Lf, "continuously watch for cards. Reader mode"}, {"watch", CmdAWIDWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},

View file

@ -1750,9 +1750,9 @@ int CmdEM4x05Chk(const char *Cmd) {
res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount); res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) { if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) {
PrintAndLogEx(WARNING, "no keys found in file"); PrintAndLogEx(WARNING, "no keys found in file");
if (keyBlock != NULL) if (keyBlock != NULL) {
free(keyBlock); free(keyBlock);
}
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -2634,7 +2634,7 @@ static command_t CommandTable[] = {
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"}, {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"},
{"clonehelp", CmdEM4x05CloneHelp, IfPm3Lf, "Shows the available clone commands"}, {"clonehelp", CmdEM4x05CloneHelp, IfPm3Lf, "Shows the available clone commands"},
{"brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"}, {"brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"},
{"chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"}, {"chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords"},
{"config", CmdEM4x05Config, AlwaysAvailable, "Create common configuration words"}, {"config", CmdEM4x05Config, AlwaysAvailable, "Create common configuration words"},
{"demod", CmdEM4x05Demod, AlwaysAvailable, "Demodulate a EM4x05/EM4x69 tag from the GraphBuffer"}, {"demod", CmdEM4x05Demod, AlwaysAvailable, "Demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
{"dump", CmdEM4x05Dump, IfPm3Lf, "Dump EM4x05/EM4x69 tag"}, {"dump", CmdEM4x05Dump, IfPm3Lf, "Dump EM4x05/EM4x69 tag"},

View file

@ -63,10 +63,10 @@ static void em4x50_print_result(const em4x50_word_t *words, int fwr, int lwr) {
s = _YELLOW_("control cfg ( locked )"); s = _YELLOW_("control cfg ( locked )");
break; break;
case EM4X50_DEVICE_SERIAL: case EM4X50_DEVICE_SERIAL:
s = _YELLOW_("device serial number ( RO )"); s = _YELLOW_("serial number ( RO )");
break; break;
case EM4X50_DEVICE_ID: case EM4X50_DEVICE_ID:
s = _YELLOW_("device identification ( RO )"); s = _YELLOW_("device id ( RO )");
break; break;
default: default:
s = "user data"; s = "user data";
@ -602,8 +602,11 @@ int read_em4x50_uid(void) {
}; };
em4x50_word_t words[EM4X50_NO_WORDS]; em4x50_word_t words[EM4X50_NO_WORDS];
int res = em4x50_read(&etd, words); int res = em4x50_read(&etd, words);
if (res == PM3_SUCCESS) if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, " Serial: " _GREEN_("%s"), sprint_hex(words[EM4X50_DEVICE_SERIAL].byte, 4)); PrintAndLogEx(INFO, " Serial: " _GREEN_("%s"), sprint_hex(words[EM4X50_DEVICE_SERIAL].byte, 4));
} else {
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
}
return res; return res;
} }
@ -612,7 +615,10 @@ int read_em4x50_uid(void) {
// read protected) -> selective read mode // read protected) -> selective read mode
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) {
em4x50_data_t edata = { .pwd_given = false, .addr_given = false }; em4x50_data_t edata = {
.pwd_given = false,
.addr_given = false,
};
if (etd != NULL) { if (etd != NULL) {
edata = *etd; edata = *etd;
@ -630,9 +636,10 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) {
return PM3_ESOFT; return PM3_ESOFT;
} }
uint8_t *data = resp.data.asBytes; em4x50_read_data_response_t *o = (em4x50_read_data_response_t *)resp.data.asBytes;
em4x50_word_t words[EM4X50_NO_WORDS] = {0}; em4x50_word_t words[EM4X50_NO_WORDS] = {0};
em4x50_prepare_result(data, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); em4x50_prepare_result((uint8_t *)o->words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words);
if (out != NULL) { if (out != NULL) {
memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS); memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS);
@ -1331,7 +1338,7 @@ static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
{"brute", CmdEM4x50Brute, IfPm3EM4x50, "Bruteforce attack to find password"}, {"brute", CmdEM4x50Brute, IfPm3EM4x50, "Bruteforce attack to find password"},
{"chk", CmdEM4x50Chk, IfPm3EM4x50, "Check passwords from dictionary"}, {"chk", CmdEM4x50Chk, IfPm3EM4x50, "Check passwords"},
{"dump", CmdEM4x50Dump, IfPm3EM4x50, "Dump EM4x50 tag"}, {"dump", CmdEM4x50Dump, IfPm3EM4x50, "Dump EM4x50 tag"},
{"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"}, {"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"},
{"login", CmdEM4x50Login, IfPm3EM4x50, "Login into EM4x50 tag"}, {"login", CmdEM4x50Login, IfPm3EM4x50, "Login into EM4x50 tag"},

View file

@ -66,6 +66,265 @@ static t55xx_conf_block_t config = {
}; };
static t55xx_memory_item_t cardmem[T55x7_BLOCK_COUNT] = {{0}}; static t55xx_memory_item_t cardmem[T55x7_BLOCK_COUNT] = {{0}};
/*
#define DC(x) ((x) + 128)
static bool t55xx_is_valid_block0(uint32_t block, uint8_t rfclk, uint8_t pskcf) {
if (block == 0x00) {
return false;
}
// Master key = 6 or 9
if ((((block >> 28)& 0xF) != 0x0) &&
(((block >> 28)& 0xF) != 0x6) &&
(((block >> 28)& 0xF) != 0x9)) {
return false;
}
// X Mode
if ( ((block >> 17) & 1) && ((((block >> 28) & 0xf) == 0x6) || (((block >> 28) & 0xf) == 0x9)) ) {
// X mode fixed 0 bits
if ((block & 0x0F000000) != 0x00) {
return false;
}
} else {
// / Basic Mode fixed 0 bits
if ((block & 0x0FE00106) != 0x00) {
return false;
}
}
// Modulation
if ( (((block >> 12) & 0x1F) != 0x00) && // Direct
(((block >> 12) & 0x1F) != 0x01) && // PSK1
(((block >> 12) & 0x1F) != 0x02) && // PSK2
(((block >> 12) & 0x1F) != 0x03) && // PSK3
(((block >> 12) & 0x1F) != 0x04) && // FSK1
(((block >> 12) & 0x1F) != 0x05) && // FSK2
(((block >> 12) & 0x1F) != 0x06) && // FSK1a
(((block >> 12) & 0x1F) != 0x07) && // FSK2a
(((block >> 12) & 0x1F) != 0x08) && // Manchester
(((block >> 12) & 0x1F) != 0x10) && // Bi-phase
(((block >> 12) & 0x1F) != 0x18) ) { // Reserved
return false;
}
PrintAndLogEx(DEBUG, "suggested block... %08x", block);
// check pskcf
if ((pskcf <= 3) && (((block >> 10) & 0x3) != pskcf)) {
PrintAndLogEx(DEBUG, "fail 6 - %u %u", pskcf, (block >> 10) & 0x3);
return false;
}
uint8_t testSpeed;
// check rfclk
if ((((block >> 17) & 1) == 1) && ((((block >> 28) & 0xf) == 0x6) || (((block >> 28) & 0xf) == 0x9)) ){ // X mode speedBits
testSpeed = (((block >> 18) & 0x3F) * 2) + 2;
} else {
uint8_t basicSpeeds[] = {8,16,32,40,50,64,100,128};
testSpeed = basicSpeeds[(block >> 18) & 0x7];
}
if (testSpeed != rfclk) {
PrintAndLogEx(DEBUG, "fail 7 - %u %u ", testSpeed , rfclk);
return false;
}
return true;
}
static void t55xx_psk1_demod (int *data, uint8_t rfclk, uint8_t pskcf, uint32_t *block) {
if ((rfclk < 8) || (rfclk > 128)) {
return;
}
switch (pskcf) {
case 0: {
pskcf = 2;
break;
}
case 1: {
pskcf = 4;
break;
}
case 2: {
pskcf = 8;
break;
}
default: {
break;
}
}
int startOffset = 1; // where to start reading data samples
int sampleCount = 0; // Counter for 1 bit of samples
int samples0, samples1; // Number of High even and odd bits in a sample.
int startBitOffset = 1; // which bit to start at e.g. for rf/32 1 33 65 ...
int bitCount = 0;
uint32_t myblock = 0;
int offset;
uint8_t drift = 0;
uint8_t tuneOffset = 0;
drift = (rfclk % pskcf); // 50 2 = 1 50 4 = 2
// locate first "0" - high transisiton for correct start offset
while (DC(data[startOffset]) <= (DC(data[startOffset - 1]) + 5)) {
// sampleToggle ^= 1;
startOffset++;
}
// Start sample may be 1 off due to sample alignment with chip modulation
// so seach for the first lower value, and adjust as needed
if (pskcf == 2) {
tuneOffset = startOffset + 1;
while (DC(data[tuneOffset]) >= (DC(data[tuneOffset - 1]) + 5)) {
tuneOffset++;
}
if ((tuneOffset - startOffset - 1) % 2) {
startOffset++;
}
}
uint8_t pskcfidx = 0;
// Get the offset to the first sample of the data block
offset = (rfclk * startBitOffset) + startOffset;
pskcfidx = (drift / 2);
pskcfidx = pskcfidx % pskcf;
// while data my be in the settle period of sampling
// First 18 - 24 bits not usable for reference only
while (offset < 20) {
offset += (32 * rfclk);
}
// Read 1 block of data
for (bitCount = 0; bitCount < 32; bitCount++) {
samples0 = 0;
samples1 = 0;
// Get 1 bit of data
for (sampleCount = 0; sampleCount < rfclk; sampleCount++){
// Count number of even and odd high bits at center to edge
switch (pskcf) {
case 2: {
// if current sample is high
if (DC(data[offset]) > DC(data[offset + 1])) {
if (pskcfidx == 0) {
samples0++;
} else {
samples1++;
}
}
break;
}
case 4: {
// only check pskcf 2nd bit x 1 x x
if (pskcfidx == 1) {
// if current sample is high
if (DC(data[offset]) > DC(data[offset + 2])) {
samples0++;
} else {
samples1++;
}
}
break;
}
case 8: {
if (pskcfidx == 3) { // x x x 1 x x x x // 00041840 : FFFBE7BF
// if current sample is high
if (DC(data[offset]) > DC(data[offset + 4])) {
samples0++;
} else {
samples1++;
}
}
break;
}
default: {
break;
}
}
// If at bit boundary (after first bit) then adjust phase check for drift
if ((sampleCount > 0) && (sampleCount % rfclk) == 0) {
pskcfidx -= drift;
}
offset++;
pskcfidx++;
pskcfidx = pskcfidx % pskcf;
}
myblock <<= 1;
if (samples1 > samples0) {
myblock++;
}
}
*block = myblock;
}
static void t55xx_psk2_demod (int *data, uint8_t rfclk, uint8_t pskcf, uint32_t *block) {
// decode PSK
t55xx_psk1_demod (data, rfclk, pskcf, block);
uint32_t new_block = 0;
uint8_t prev_phase = 1;
// Convert to PSK2
for (int8_t bit = 31; bit >= 0; bit--) {
new_block <<= 1;
if (((*block >> bit) & 1) != prev_phase) {
new_block++;
}
prev_phase = ((*block >> bit) & 1);
}
*block = new_block;
}
static void t55xx_search_config_psk(int *d, int pskV) {
for (uint8_t pskcf = 0; pskcf < 3; pskcf++) {
for (uint8_t speedBits = 0; speedBits < 64; speedBits++) {
uint8_t rfclk = rfclk = (2 * speedBits) + 2;
uint32_t block = 0;
if (pskV == 1) {
t55xx_psk1_demod (d, rfclk, pskcf, &block);
}
if (pskV == 2) {
t55xx_psk2_demod (d, rfclk, pskcf, &block);
}
if (t55xx_is_valid_block0(block, rfclk, pskcf)) {
PrintAndLogEx(SUCCESS, "Valid config block [%08X] - rfclk [%d] - pskcf [%d]", block, rfclk, pskcf);
}
}
}
}
*/
t55xx_conf_block_t Get_t55xx_Config(void) { t55xx_conf_block_t Get_t55xx_Config(void) {
return config; return config;
@ -1203,6 +1462,8 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32
//undo trim samples //undo trim samples
restore_bufferS32(saveState, g_GraphBuffer); restore_bufferS32(saveState, g_GraphBuffer);
g_GridOffset = saveState.offset; g_GridOffset = saveState.offset;
// t55xx_search_config_psk(g_GraphBuffer, 1);
// t55xx_search_config_psk(g_GraphBuffer, 2);
} }
} }
if (hits == 1) { if (hits == 1) {
@ -1452,10 +1713,17 @@ static bool testBitRate(uint8_t readRate, uint8_t clk) {
bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5) { bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5) {
if (g_DemodBufferLen < 64) return false; if (g_DemodBufferLen < 64) {
return false;
}
for (uint8_t idx = 28; idx < 64; idx++) { for (uint8_t idx = 28; idx < 64; idx++) {
uint8_t si = idx; uint8_t si = idx;
if (PackBits(si, 28, g_DemodBuffer) == 0x00) continue;
if (PackBits(si, 28, g_DemodBuffer) == 0x00) {
continue;
}
uint8_t safer = PackBits(si, 4, g_DemodBuffer); uint8_t safer = PackBits(si, 4, g_DemodBuffer);
si += 4; //master key si += 4; //master key
@ -1463,7 +1731,10 @@ bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5)
si += 4; //was 7 & +=7+3 //should be only 4 bits if extended mode si += 4; //was 7 & +=7+3 //should be only 4 bits if extended mode
// 2nibble must be zeroed. // 2nibble must be zeroed.
// moved test to here, since this gets most faults first. // moved test to here, since this gets most faults first.
if (resv > 0x00) continue;
if (resv > 0x00) {
continue;
}
int bitRate = PackBits(si, 6, g_DemodBuffer); int bitRate = PackBits(si, 6, g_DemodBuffer);
si += 6; //bit rate (includes extended mode part of rate) si += 6; //bit rate (includes extended mode part of rate)
@ -1478,20 +1749,33 @@ bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5)
//if extended mode //if extended mode
bool extMode = ((safer == 0x6 || safer == 0x9) && extend) ? true : false; bool extMode = ((safer == 0x6 || safer == 0x9) && extend) ? true : false;
if (!extMode) { if (extMode == false) {
if (bitRate > 7) continue;
if (!testBitRate(bitRate, clk)) continue;
} else { //extended mode bitrate = same function to calc bitrate as em4x05
if (EM4x05_GET_BITRATE(bitRate) != clk) continue;
if (bitRate > 7) {
continue;
} }
if (testBitRate(bitRate, clk) == false) {
continue;
}
} else { //extended mode bitrate = same function to calc bitrate as em4x05
if (EM4x05_GET_BITRATE(bitRate) != clk) {
continue;
}
}
//test modulation //test modulation
if (!testModulation(mode, modread)) continue; if (testModulation(mode, modread) == false) {
continue;
}
*fndBitRate = bitRate; *fndBitRate = bitRate;
*offset = idx; *offset = idx;
*Q5 = false; *Q5 = false;
return true; return true;
} }
if (testQ5(mode, offset, fndBitRate, clk)) { if (testQ5(mode, offset, fndBitRate, clk)) {
*Q5 = true; *Q5 = true;
return true; return true;
@ -4409,7 +4693,7 @@ static command_t CommandTable[] = {
{"write", CmdT55xxWriteBlock, IfPm3Lf, "Write T55xx block data"}, {"write", CmdT55xxWriteBlock, IfPm3Lf, "Write T55xx block data"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"},
{"bruteforce", CmdT55xxBruteForce, IfPm3Lf, "Simple bruteforce attack to find password"}, {"bruteforce", CmdT55xxBruteForce, IfPm3Lf, "Simple bruteforce attack to find password"},
{"chk", CmdT55xxChkPwds, IfPm3Lf, "Check passwords from dictionary/flash"}, {"chk", CmdT55xxChkPwds, IfPm3Lf, "Check passwords"},
{"protect", CmdT55xxProtect, IfPm3Lf, "Password protect tag"}, {"protect", CmdT55xxProtect, IfPm3Lf, "Password protect tag"},
{"recoverpw", CmdT55xxRecoverPW, IfPm3Lf, "Try to recover from bad password write from a cloner"}, {"recoverpw", CmdT55xxRecoverPW, IfPm3Lf, "Try to recover from bad password write from a cloner"},
{"sniff", CmdT55xxSniff, AlwaysAvailable, "Attempt to recover T55xx commands from sample buffer"}, {"sniff", CmdT55xxSniff, AlwaysAvailable, "Attempt to recover T55xx commands from sample buffer"},
@ -4428,3 +4712,22 @@ int CmdLFT55XX(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
/*
one of
// Leading 0
lf t55 write -b 3 --pg1 -d 90000800
// 1 of 4
lf t55 write -b 3 --pg1 -d 90000C00
T55xx clone card lock: block 3 page 1 0x00000020 00000000 00000000 00000000 00100000
(this bit in any combo seems to lock the card)
You can have other data in the block write, but if that single bit is set "1" the entire card locks in its current state; no know way to unlock
*/

View file

@ -153,10 +153,10 @@ int roca_self_test(void) {
int ret = 0; int ret = 0;
if (emv_rocacheck(keyp, 64, false)) { if (emv_rocacheck(keyp, 64, false)) {
PrintAndLogEx(SUCCESS, "Weak modulus [ %s ]", _GREEN_("PASS")); PrintAndLogEx(SUCCESS, "Weak modulus ( %s )", _GREEN_("ok"));
} else { } else {
ret++; ret++;
PrintAndLogEx(FAILED, "Weak modulus [ %s ]", _RED_("Fail")); PrintAndLogEx(FAILED, "Weak modulus ( %s )", _RED_("fail"));
} }
// negative // negative
@ -167,9 +167,9 @@ int roca_self_test(void) {
if (emv_rocacheck(keyn, 64, false)) { if (emv_rocacheck(keyn, 64, false)) {
ret++; ret++;
PrintAndLogEx(FAILED, "Strong modulus [ %s ]", _RED_("Fail")); PrintAndLogEx(FAILED, "Strong modulus ( %s )", _RED_("fail"));
} else { } else {
PrintAndLogEx(SUCCESS, "Strong modulus [ %s ]", _GREEN_("PASS")); PrintAndLogEx(SUCCESS, "Strong modulus ( %s )", _GREEN_("ok"));
} }
return ret; return ret;
} }

View file

@ -427,16 +427,16 @@ static int cda_test_pk(bool verbose) {
int exec_cda_test(bool verbose) { int exec_cda_test(bool verbose) {
int ret = cda_test_raw(verbose); int ret = cda_test_raw(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "CDA raw test: (%s)", _RED_("failed")); PrintAndLogEx(WARNING, "CDA raw test ( %s )", _RED_("fail"));
return ret; return ret;
} }
PrintAndLogEx(INFO, "CDA raw test: (%s)", _GREEN_("passed")); PrintAndLogEx(INFO, "CDA raw test ( %s )", _GREEN_("ok"));
ret = cda_test_pk(verbose); ret = cda_test_pk(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "CDA test pk: (%s)", _RED_("failed")); PrintAndLogEx(WARNING, "CDA test pk ( %s )", _RED_("fail"));
return ret; return ret;
} }
PrintAndLogEx(INFO, "CDA test pk: (%s)", _GREEN_("passed")); PrintAndLogEx(INFO, "CDA test pk ( %s )", _GREEN_("ok"));
return 0; return 0;
} }

View file

@ -310,16 +310,16 @@ int exec_crypto_test(bool verbose, bool include_slow_tests) {
unsigned int extra_keylengths[] = {1152, 1408, 1984, 3072, 4096}; unsigned int extra_keylengths[] = {1152, 1408, 1984, 3072, 4096};
int ret = test_pk(verbose); int ret = test_pk(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "Crypto raw test: (%s)", _RED_("failed")); PrintAndLogEx(WARNING, "Crypto raw test ( %s )", _RED_("fail"));
return ret; return ret;
} }
PrintAndLogEx(SUCCESS, "Crypto raw test (%s)", _GREEN_("passed")); PrintAndLogEx(SUCCESS, "Crypto raw test ( %s )", _GREEN_("ok"));
for (int i = 0; i < ARRAYLEN(keylengths); i++) { for (int i = 0; i < ARRAYLEN(keylengths); i++) {
unsigned int kl = keylengths[i]; unsigned int kl = keylengths[i];
ret = test_genkey(kl, message, kl / 8, verbose); ret = test_genkey(kl, message, kl / 8, verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "Crypto generate key[%u] test: (%s)", kl, _RED_("failed")); PrintAndLogEx(WARNING, "Crypto generate key[ %u ] test ( %s )", kl, _RED_("fail"));
return ret; return ret;
} }
} }
@ -328,7 +328,7 @@ int exec_crypto_test(bool verbose, bool include_slow_tests) {
unsigned int kl = extra_keylengths[i]; unsigned int kl = extra_keylengths[i];
ret = test_genkey(kl, message, kl / 8, verbose); ret = test_genkey(kl, message, kl / 8, verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "Crypto generate key[%u] test: (%s)", kl, _RED_("failed")); PrintAndLogEx(WARNING, "Crypto generate key[ %u ] test ( %s )", kl, _RED_("fail"));
return ret; return ret;
} }
} }

View file

@ -111,9 +111,9 @@ int ExecuteCryptoTests(bool verbose, bool ignore_time, bool include_slow_tests)
PrintAndLogEx(INFO, "--------------------------"); PrintAndLogEx(INFO, "--------------------------");
if (TestFail) if (TestFail)
PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_("fail")); PrintAndLogEx(FAILED, "Tests ( %s )", _RED_("fail"));
else else
PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_("ok")); PrintAndLogEx(SUCCESS, "Tests ( %s )", _GREEN_("ok"));
return TestFail; return TestFail;
} }

View file

@ -373,16 +373,16 @@ static int dda_test_pk(bool verbose) {
int exec_dda_test(bool verbose) { int exec_dda_test(bool verbose) {
int ret = dda_test_raw(verbose); int ret = dda_test_raw(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "DDA raw test: %s", _RED_("failed")); PrintAndLogEx(WARNING, "DDA raw test ( %s )", _RED_("fail"));
return ret; return ret;
} }
PrintAndLogEx(SUCCESS, "DDA raw test: %s", _GREEN_("passed")); PrintAndLogEx(SUCCESS, "DDA raw test ( %s )", _GREEN_("ok"));
ret = dda_test_pk(verbose); ret = dda_test_pk(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "DDA test pk: %s", _RED_("failed")); PrintAndLogEx(WARNING, "DDA test pk ( %s )", _RED_("fail"));
return ret; return ret;
} }
PrintAndLogEx(SUCCESS, "DDA test pk: %s", _GREEN_("passed")); PrintAndLogEx(SUCCESS, "DDA test pk ( %s )", _GREEN_("ok"));
return 0; return 0;
} }

View file

@ -262,16 +262,16 @@ static int sda_test_pk(bool verbose) {
int exec_sda_test(bool verbose) { int exec_sda_test(bool verbose) {
int ret = sda_test_raw(verbose); int ret = sda_test_raw(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "SDA raw test: %s", _RED_("failed")); PrintAndLogEx(WARNING, "SDA raw test ( %s )", _RED_("fa1l"));
return ret; return ret;
} }
PrintAndLogEx(SUCCESS, "SDA raw test: %s", _GREEN_("passed")); PrintAndLogEx(SUCCESS, "SDA raw test ( %s )", _GREEN_("ok"));
ret = sda_test_pk(verbose); ret = sda_test_pk(verbose);
if (ret) { if (ret) {
PrintAndLogEx(WARNING, "SDA test pk: %s", _RED_("failed")); PrintAndLogEx(WARNING, "SDA test pk ( %s )", _RED_("fail"));
return ret; return ret;
} }
PrintAndLogEx(SUCCESS, "SDA test pk: %s", _GREEN_("passed")); PrintAndLogEx(SUCCESS, "SDA test pk ( %s )", _GREEN_("ok"));
return 0; return 0;
} }

View file

@ -674,7 +674,7 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
} }
if (respcode) { if (respcode) {
*respcode = 0xff; *respcode = 0xFF;
} }
uint16_t sw = 0; uint16_t sw = 0;
@ -698,10 +698,11 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
// tx chaining // tx chaining
size_t sentdatalen = 0; size_t sentdatalen = 0;
while (datalen >= sentdatalen) { while (datalen >= sentdatalen) {
if (datalen - sentdatalen > DESFIRE_TX_FRAME_MAX_LEN) if (datalen - sentdatalen > DESFIRE_TX_FRAME_MAX_LEN) {
apdu.Lc = DESFIRE_TX_FRAME_MAX_LEN; apdu.Lc = DESFIRE_TX_FRAME_MAX_LEN;
else } else {
apdu.Lc = datalen - sentdatalen; apdu.Lc = datalen - sentdatalen;
}
apdu.data = &data[sentdatalen]; apdu.data = &data[sentdatalen];
@ -725,8 +726,8 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
} }
} }
if (respcode != NULL && ((sw & 0xff00) == 0x9100)) { if (respcode != NULL && ((sw & 0xFF00) == 0x9100)) {
*respcode = sw & 0xff; *respcode = sw & 0xFF;
} }
if (resp) { if (resp) {
@ -759,6 +760,8 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
apdu.P2 = 0; apdu.P2 = 0;
apdu.data = NULL; apdu.data = NULL;
buflen = 0;
res = DESFIRESendApdu(false, apdu, buf, DESFIRE_BUFFER_SIZE, &buflen, &sw); res = DESFIRESendApdu(false, apdu, buf, DESFIRE_BUFFER_SIZE, &buflen, &sw);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw)); PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw));
@ -766,8 +769,8 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
return res; return res;
} }
if (respcode != NULL && ((sw & 0xff00) == 0x9100)) { if (respcode != NULL && ((sw & 0xFF00) == 0x9100)) {
*respcode = sw & 0xff; *respcode = sw & 0xFF;
} }
if (resp != NULL) { if (resp != NULL) {
@ -776,9 +779,10 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
memcpy(&resp[i * splitbysize + 1], buf, buflen); memcpy(&resp[i * splitbysize + 1], buf, buflen);
i += 1; i += 1;
} else { } else {
memcpy(&resp[pos], buf, buflen); memcpy(resp + (pos), buf, buflen);
} }
} }
pos += buflen; pos += buflen;
if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) { if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
@ -786,6 +790,7 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
} }
} }
if (resplen) { if (resplen) {
*resplen = (splitbysize) ? i : pos; *resplen = (splitbysize) ? i : pos;
} }
@ -866,13 +871,14 @@ int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, u
case DCCNativeISO: case DCCNativeISO:
DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen); DesfireSecureChannelEncode(ctx, cmd, data, datalen, databuf, &databuflen);
if (ctx->cmdSet == DCCNative) if (ctx->cmdSet == DCCNative) {
res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); res = DesfireExchangeNative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
else } else {
res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize); res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
}
if (splitbysize) { if (splitbysize) {
uint8_t sdata[250 * 5] = {0}; uint8_t sdata[DESFIRE_BUFFER_SIZE] = {0};
size_t sdatalen = 0; size_t sdatalen = 0;
DesfireJoinBlockToBytes(databuf, databuflen, splitbysize, sdata, &sdatalen); DesfireJoinBlockToBytes(databuf, databuflen, splitbysize, sdata, &sdatalen);
@ -1924,13 +1930,16 @@ void DesfirePrintAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS
} }
static int DesfireCommandEx(DesfireContext_t *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) { static int DesfireCommandEx(DesfireContext_t *dctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen, int checklength, size_t splitbysize) {
if (resplen) if (resplen) {
*resplen = 0; *resplen = 0;
}
uint8_t respcode = 0xFF;
uint8_t respcode = 0xff;
uint8_t *xresp = calloc(DESFIRE_BUFFER_SIZE, 1); uint8_t *xresp = calloc(DESFIRE_BUFFER_SIZE, 1);
if (xresp == NULL) if (xresp == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
}
size_t xresplen = 0; size_t xresplen = 0;
int res = DesfireExchangeEx(false, dctx, cmd, data, datalen, &respcode, xresp, &xresplen, true, splitbysize); int res = DesfireExchangeEx(false, dctx, cmd, data, datalen, &respcode, xresp, &xresplen, true, splitbysize);
@ -1938,19 +1947,24 @@ static int DesfireCommandEx(DesfireContext_t *dctx, uint8_t cmd, uint8_t *data,
free(xresp); free(xresp);
return res; return res;
} }
if (respcode != MFDES_S_OPERATION_OK) { if (respcode != MFDES_S_OPERATION_OK) {
free(xresp); free(xresp);
return PM3_EAPDU_FAIL; return PM3_EAPDU_FAIL;
} }
if (checklength >= 0 && xresplen != checklength) { if (checklength >= 0 && xresplen != checklength) {
free(xresp); free(xresp);
return PM3_EAPDU_FAIL; return PM3_EAPDU_FAIL;
} }
if (resplen) if (resplen) {
*resplen = xresplen; *resplen = xresplen;
if (resp) }
if (resp) {
memcpy(resp, xresp, (splitbysize == 0) ? xresplen : xresplen * splitbysize); memcpy(resp, xresp, (splitbysize == 0) ? xresplen : xresplen * splitbysize);
}
free(xresp); free(xresp);
return PM3_SUCCESS; return PM3_SUCCESS;
@ -1996,13 +2010,16 @@ int DesfireReadSignature(DesfireContext_t *dctx, uint8_t sid, uint8_t *resp, siz
uint8_t respcode = 0xff; uint8_t respcode = 0xff;
int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen); int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen);
if (res != PM3_SUCCESS) if (res != PM3_SUCCESS) {
return res; return res;
}
if (respcode != 0x90) if (respcode != 0x90) {
return PM3_EAPDU_FAIL; return PM3_EAPDU_FAIL;
}
memcpy(resp, xresp, xresplen); memcpy(resp, xresp, xresplen);
*resplen = xresplen; *resplen = xresplen;
return PM3_SUCCESS; return PM3_SUCCESS;
@ -2172,7 +2189,6 @@ int DesfireReadFile(DesfireContext_t *dctx, uint8_t fnum, uint32_t offset, uint3
data[0] = fnum; data[0] = fnum;
Uint3byteToMemLe(&data[1], offset); Uint3byteToMemLe(&data[1], offset);
Uint3byteToMemLe(&data[4], len); Uint3byteToMemLe(&data[4], len);
return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_DATA2 : MFDES_READ_DATA, data, 7, resp, resplen, -1); return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_DATA2 : MFDES_READ_DATA, data, 7, resp, resplen, -1);
} }

View file

@ -29,6 +29,7 @@
#include "crc16.h" // crc16 ccitt #include "crc16.h" // crc16 ccitt
#include "crc32.h" #include "crc32.h"
#include "commonutil.h" #include "commonutil.h"
#include "desfirecore.h" // DESFIRE_BUFFER_SIZE
void DesfireClearContext(DesfireContext_t *ctx) { void DesfireClearContext(DesfireContext_t *ctx) {
ctx->keyNum = 0; ctx->keyNum = 0;
@ -148,22 +149,29 @@ size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint
return 0; return 0;
} }
uint8_t crcdata[1024] = {0}; uint8_t crcdata[DESFIRE_BUFFER_SIZE] = {0};
size_t crcposfound = 0; size_t crcposfound = 0;
// crc may be 00..00 and at the end of file may be padding 0x80. so we search from last zero to crclen + 2 (one for crc=0 and one for padding 0x80) // crc may be 00..00 and at the end of file may be padding 0x80. so we search from last zero to crclen + 2 (one for crc=0 and one for padding 0x80)
for (int i = 0; i < crclen + 2; i++) { for (int i = 0; i < crclen + 2; i++) {
if (crcpos - i == 0)
if (crcpos - i == 0) {
break; break;
if (crcpos - i + crclen > datalen) }
if (crcpos - i + crclen > datalen) {
continue; continue;
}
memcpy(crcdata, data, crcpos - i); memcpy(crcdata, data, crcpos - i);
crcdata[crcpos - i] = respcode; crcdata[crcpos - i] = respcode;
bool res; bool res;
if (crclen == 4) if (crclen == 4) {
res = desfire_crc32_check(crcdata, crcpos - i + 1, &data[crcpos - i]); res = desfire_crc32_check(crcdata, crcpos - i + 1, &data[crcpos - i]);
else } else {
res = iso14443a_crc_check(data, crcpos - i, &data[crcpos - i]); res = iso14443a_crc_check(data, crcpos - i, &data[crcpos - i]);
}
if (res) { if (res) {
crcposfound = crcpos - i; crcposfound = crcpos - i;
} }
@ -252,7 +260,8 @@ static void DesfireCryptoEncDecSingleBlock(uint8_t *key, DesfireCryptoAlgorithm
} }
void DesfireCryptoEncDecEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) { void DesfireCryptoEncDecEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool dir_to_send, bool encode, uint8_t *iv) {
uint8_t data[1024] = {0};
uint8_t data[DESFIRE_BUFFER_SIZE] = {0};
uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
if (ctx->secureChannel == DACd40) { if (ctx->secureChannel == DACd40) {
@ -287,15 +296,17 @@ void DesfireCryptoEncDecEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_typ
else else
memcpy(iv, xiv, block_size); memcpy(iv, xiv, block_size);
if (dstdata) if (dstdata) {
memcpy(dstdata, data, srcdatalen); memcpy(dstdata, data, srcdatalen);
}
} }
void DesfireCryptoEncDec(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) { void DesfireCryptoEncDec(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, bool encode) {
bool dir_to_send = encode; bool dir_to_send = encode;
bool xencode = encode; bool xencode = encode;
if (ctx->secureChannel == DACd40) if (ctx->secureChannel == DACd40) {
xencode = false; xencode = false;
}
DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL); DesfireCryptoEncDecEx(ctx, key_type, srcdata, srcdatalen, dstdata, dir_to_send, xencode, NULL);
} }
@ -333,8 +344,9 @@ void DesfireCMACGenerateSubkeys(DesfireContext_t *ctx, DesfireCryptoOpKeyType ke
void DesfireCryptoCMACEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac) { void DesfireCryptoCMACEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, uint8_t *data, size_t len, size_t minlen, uint8_t *cmac) {
int kbs = desfire_get_key_block_length(ctx->keyType); int kbs = desfire_get_key_block_length(ctx->keyType);
if (kbs == 0) if (kbs == 0) {
return; return;
}
uint8_t buffer[padded_data_length(MAX(minlen, len) + 1, kbs)]; uint8_t buffer[padded_data_length(MAX(minlen, len) + 1, kbs)];
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
@ -357,8 +369,9 @@ void DesfireCryptoCMACEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type,
DesfireCryptoEncDec(ctx, key_type, buffer, len, NULL, true); DesfireCryptoEncDec(ctx, key_type, buffer, len, NULL, true);
if (cmac != NULL) if (cmac != NULL) {
memcpy(cmac, ctx->IV, kbs); memcpy(cmac, ctx->IV, kbs);
}
} }
void DesfireCryptoCMAC(DesfireContext_t *ctx, uint8_t *data, size_t len, uint8_t *cmac) { void DesfireCryptoCMAC(DesfireContext_t *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
@ -371,16 +384,18 @@ void MifareKdfAn10922(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, co
return; return;
int kbs = desfire_get_key_block_length(ctx->keyType); // 8 or 16 int kbs = desfire_get_key_block_length(ctx->keyType); // 8 or 16
if (kbs == 0) if (kbs == 0) {
return; return;
}
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0}; uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
uint8_t buffer[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0}; uint8_t buffer[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
if (ctx->keyType == T_AES) { if (ctx->keyType == T_AES) {
// AES uses 16 byte IV // AES uses 16 byte IV
if (kbs < CRYPTO_AES_BLOCK_SIZE) if (kbs < CRYPTO_AES_BLOCK_SIZE) {
kbs = CRYPTO_AES_BLOCK_SIZE; kbs = CRYPTO_AES_BLOCK_SIZE;
}
buffer[0] = 0x01; buffer[0] = 0x01;
memcpy(&buffer[1], data, len); memcpy(&buffer[1], data, len);
@ -429,8 +444,9 @@ void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorithm keytype, uint8
return; return;
// clear version // clear version
for (int n = 0; n < desfire_get_key_length(keytype); n++) for (int n = 0; n < desfire_get_key_length(keytype); n++) {
key[n] &= 0xFE; key[n] &= 0xFE;
}
// set version // set version
for (int n = 0; n < 8; n++) { for (int n = 0; n < 8; n++) {
@ -451,8 +467,9 @@ void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorithm keytype, uint8
uint8_t DesfireDESKeyGetVersion(const uint8_t *key) { uint8_t DesfireDESKeyGetVersion(const uint8_t *key) {
uint8_t version = 0; uint8_t version = 0;
for (int n = 0; n < 8; n++) for (int n = 0; n < 8; n++) {
version |= ((key[n] & 1) << (7 - n)); version |= ((key[n] & 1) << (7 - n));
}
return version; return version;
} }
@ -644,14 +661,16 @@ void DesfireEV2FillIV(DesfireContext_t *ctx, bool ivforcommand, uint8_t *iv) {
} }
int DesfireEV2CalcCMAC(DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) { int DesfireEV2CalcCMAC(DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) {
uint8_t mdata[1050] = {0}; uint8_t mdata[DESFIRE_BUFFER_SIZE] = {0};
size_t mdatalen = 0; size_t mdatalen = 0;
mdata[0] = cmd; mdata[0] = cmd;
Uint2byteToMemLe(&mdata[1], ctx->cmdCntr); Uint2byteToMemLe(&mdata[1], ctx->cmdCntr);
memcpy(&mdata[3], ctx->TI, 4); memcpy(&mdata[3], ctx->TI, 4);
if (data != NULL && datalen > 0) if (data != NULL && datalen > 0) {
memcpy(&mdata[7], data, datalen); memcpy(&mdata[7], data, datalen);
}
mdatalen = 1 + 2 + 4 + datalen; mdatalen = 1 + 2 + 4 + datalen;
return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen); return aes_cmac8(NULL, ctx->sessionKeyMAC, mdata, mac, mdatalen);
@ -717,14 +736,18 @@ void DesfireDecodePrevReaderID(DesfireContext_t *ctx, uint8_t *key, uint32_t trC
} }
int DesfireLRPCalcCMAC(DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) { int DesfireLRPCalcCMAC(DesfireContext_t *ctx, uint8_t cmd, uint8_t *data, size_t datalen, uint8_t *mac) {
uint8_t mdata[1050] = {0}; uint8_t mdata[DESFIRE_BUFFER_SIZE] = {0};
size_t mdatalen = 0; size_t mdatalen = 0;
mdata[0] = cmd; mdata[0] = cmd;
Uint2byteToMemLe(&mdata[1], ctx->cmdCntr); Uint2byteToMemLe(&mdata[1], ctx->cmdCntr);
memcpy(&mdata[3], ctx->TI, 4); memcpy(&mdata[3], ctx->TI, 4);
if (data != NULL && datalen > 0)
if (data != NULL && datalen > 0) {
memcpy(&mdata[7], data, datalen); memcpy(&mdata[7], data, datalen);
}
mdatalen = 1 + 2 + 4 + datalen; mdatalen = 1 + 2 + 4 + datalen;
LRPContext_t lctx = {0}; LRPContext_t lctx = {0};

View file

@ -49,9 +49,11 @@ static const uint8_t CommandsCanUseAnyChannel[] = {
}; };
static bool CommandCanUseAnyChannel(uint8_t cmd) { static bool CommandCanUseAnyChannel(uint8_t cmd) {
for (int i = 0; i < ARRAYLEN(CommandsCanUseAnyChannel); i++) for (int i = 0; i < ARRAYLEN(CommandsCanUseAnyChannel); i++) {
if (CommandsCanUseAnyChannel[i] == cmd) if (CommandsCanUseAnyChannel[i] == cmd) {
return true; return true;
}
}
return false; return false;
} }
@ -207,10 +209,11 @@ static const CmdHeaderLengths_t CmdHeaderLengths[] = {
}; };
static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) { static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) {
for (int i = 0; i < ARRAYLEN(CmdHeaderLengths); i++) for (int i = 0; i < ARRAYLEN(CmdHeaderLengths); i++) {
if (CmdHeaderLengths[i].cmd == cmd) if (CmdHeaderLengths[i].cmd == cmd) {
return CmdHeaderLengths[i].len; return CmdHeaderLengths[i].len;
}
}
return 0; return 0;
} }
@ -228,12 +231,15 @@ static const uint8_t EV1D40TransmitMAC[] = {
}; };
static bool DesfireEV1D40TransmitMAC(DesfireContext_t *ctx, uint8_t cmd) { static bool DesfireEV1D40TransmitMAC(DesfireContext_t *ctx, uint8_t cmd) {
if (ctx->secureChannel != DACd40 && ctx->secureChannel != DACEV1) if (ctx->secureChannel != DACd40 && ctx->secureChannel != DACEV1) {
return true; return true;
}
for (int i = 0; i < ARRAYLEN(EV1D40TransmitMAC); i++) for (int i = 0; i < ARRAYLEN(EV1D40TransmitMAC); i++) {
if (EV1D40TransmitMAC[i] == cmd) if (EV1D40TransmitMAC[i] == cmd) {
return true; return true;
}
}
return false; return false;
} }
@ -247,12 +253,15 @@ static const uint8_t D40ReceiveMAC[] = {
}; };
static bool DesfireEV1D40ReceiveMAC(DesfireContext_t *ctx, uint8_t cmd) { static bool DesfireEV1D40ReceiveMAC(DesfireContext_t *ctx, uint8_t cmd) {
if (ctx->secureChannel != DACd40) if (ctx->secureChannel != DACd40) {
return true; return true;
}
for (int i = 0; i < ARRAYLEN(D40ReceiveMAC); i++) for (int i = 0; i < ARRAYLEN(D40ReceiveMAC); i++) {
if (D40ReceiveMAC[i] == cmd) if (D40ReceiveMAC[i] == cmd) {
return true; return true;
}
}
return false; return false;
} }
@ -269,10 +278,11 @@ static const uint8_t ISOChannelValidCmd[] = {
}; };
static bool DesfireISOChannelValidCmd(uint8_t cmd) { static bool DesfireISOChannelValidCmd(uint8_t cmd) {
for (int i = 0; i < ARRAYLEN(ISOChannelValidCmd); i++) for (int i = 0; i < ARRAYLEN(ISOChannelValidCmd); i++) {
if (ISOChannelValidCmd[i] == cmd) if (ISOChannelValidCmd[i] == cmd) {
return true; return true;
}
}
return false; return false;
} }
@ -349,15 +359,17 @@ static void DesfireSecureChannelEncodeD40(DesfireContext_t *ctx, uint8_t cmd, ui
static void DesfireSecureChannelEncodeEV1(DesfireContext_t *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) { static void DesfireSecureChannelEncodeEV1(DesfireContext_t *ctx, uint8_t cmd, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen) {
uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t)); uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL) if (data == NULL) {
return; return;
}
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd); uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
if (srcdatalen < hdrlen) if (srcdatalen < hdrlen) {
hdrlen = srcdatalen; hdrlen = srcdatalen;
}
size_t rlen; size_t rlen;
@ -582,12 +594,14 @@ static void DesfireSecureChannelDecodeD40(DesfireContext_t *ctx, uint8_t *srcdat
static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) { static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t respcode, uint8_t *dstdata, size_t *dstdatalen) {
uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t)); uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
if (data == NULL) if (data == NULL) {
return; return;
}
// if comm mode = plain --> response with MAC // if comm mode = plain --> response with MAC
// if request is not zero length --> response MAC // if request is not zero length --> response MAC
if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) { if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) {
if (srcdatalen < DesfireGetMACLength(ctx)) { if (srcdatalen < DesfireGetMACLength(ctx)) {
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
@ -596,6 +610,7 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdat
} }
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx)); memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx); *dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
memcpy(data, srcdata, *dstdatalen); memcpy(data, srcdata, *dstdatalen);
@ -603,15 +618,22 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdat
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0}; uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac); DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) { if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
PrintAndLogEx(WARNING, "Received MAC is not match with calculated"); PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx))); PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx)));
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx))); PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx)));
} else { } else {
if (GetAPDULogging())
if (GetAPDULogging()) {
PrintAndLogEx(INFO, "Received MAC OK"); PrintAndLogEx(INFO, "Received MAC OK");
} }
}
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) { } else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) { if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
memcpy(dstdata, srcdata, srcdatalen); memcpy(dstdata, srcdata, srcdatalen);
*dstdatalen = srcdatalen; *dstdatalen = srcdatalen;
@ -620,7 +642,7 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdat
} }
DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false); DesfireCryptoEncDec(ctx, DCOSessionKeyEnc, srcdata, srcdatalen, dstdata, false);
//PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen)); // PrintAndLogEx(INFO, "decoded[%d]: %s", srcdatalen, sprint_hex(dstdata, srcdatalen));
size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4); size_t puredatalen = DesfireSearchCRCPos(dstdata, srcdatalen, respcode, 4);
if (puredatalen != 0) { if (puredatalen != 0) {

View file

@ -53,11 +53,7 @@ static bool TestCRC16(void) {
len = DesfireSearchCRCPos(data, 1, 0x00, 2); len = DesfireSearchCRCPos(data, 1, 0x00, 2);
res = res && (len == 0); res = res && (len == 0);
if (res) PrintAndLogEx(INFO, "CRC16............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "CRC16............. " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "CRC16............. " _RED_("fail"));
return res; return res;
} }
@ -80,11 +76,7 @@ static bool TestCRC32(void) {
len = DesfireSearchCRCPos(data, 2, 0x00, 4); len = DesfireSearchCRCPos(data, 2, 0x00, 4);
res = res && (len == 0); res = res && (len == 0);
if (res) PrintAndLogEx(INFO, "CRC32............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "CRC32............. " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "CRC32............. " _RED_("fail"));
return res; return res;
} }
@ -131,11 +123,7 @@ static bool TestCMACSubkeys(void) {
res = res && (memcmp(sk1, sk1_3tdea, sizeof(sk1_3tdea)) == 0); res = res && (memcmp(sk1, sk1_3tdea, sizeof(sk1_3tdea)) == 0);
res = res && (memcmp(sk2, sk2_3tdea, sizeof(sk2_3tdea)) == 0); res = res && (memcmp(sk2, sk2_3tdea, sizeof(sk2_3tdea)) == 0);
if (res) PrintAndLogEx(INFO, "CMAC subkeys...... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "CMAC subkeys...... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "CMAC subkeys...... " _RED_("fail"));
return res; return res;
} }
@ -155,11 +143,7 @@ static bool TestAn10922KDFAES(void) {
uint8_t dkey[] = {0xA8, 0xDD, 0x63, 0xA3, 0xB8, 0x9D, 0x54, 0xB3, 0x7C, 0xA8, 0x02, 0x47, 0x3F, 0xDA, 0x91, 0x75}; uint8_t dkey[] = {0xA8, 0xDD, 0x63, 0xA3, 0xB8, 0x9D, 0x54, 0xB3, 0x7C, 0xA8, 0x02, 0x47, 0x3F, 0xDA, 0x91, 0x75};
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0); res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
if (res) PrintAndLogEx(INFO, "An10922 AES....... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "An10922 AES....... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "An10922 AES....... " _RED_("fail"));
return res; return res;
} }
@ -177,11 +161,7 @@ static bool TestAn10922KDF2TDEA(void) {
uint8_t dkey[] = {0x16, 0xF8, 0x59, 0x7C, 0x9E, 0x89, 0x10, 0xC8, 0x6B, 0x96, 0x48, 0xD0, 0x06, 0x10, 0x7D, 0xD7}; uint8_t dkey[] = {0x16, 0xF8, 0x59, 0x7C, 0x9E, 0x89, 0x10, 0xC8, 0x6B, 0x96, 0x48, 0xD0, 0x06, 0x10, 0x7D, 0xD7};
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0); res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
if (res) PrintAndLogEx(INFO, "An10922 2TDEA..... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "An10922 2TDEA..... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "An10922 2TDEA..... " _RED_("fail"));
return res; return res;
} }
@ -201,11 +181,7 @@ static bool TestAn10922KDF3TDEA(void) {
}; };
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0); res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
if (res) PrintAndLogEx(INFO, "An10922 3TDEA..... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "An10922 3TDEA..... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "An10922 3TDEA..... " _RED_("fail"));
return res; return res;
} }
@ -245,11 +221,7 @@ static bool TestCMAC3TDEA(void) {
DesfireCryptoCMAC(&dctx, CMACData, 32, cmac); DesfireCryptoCMAC(&dctx, CMACData, 32, cmac);
res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0); res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0);
if (res) PrintAndLogEx(INFO, "CMAC 3TDEA........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "CMAC 3TDEA........ " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "CMAC 3TDEA........ " _RED_("fail"));
return res; return res;
} }
@ -289,11 +261,7 @@ static bool TestCMAC2TDEA(void) {
DesfireCryptoCMAC(&dctx, CMACData, 32, cmac); DesfireCryptoCMAC(&dctx, CMACData, 32, cmac);
res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0); res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0);
if (res) PrintAndLogEx(INFO, "CMAC 2TDEA........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "CMAC 2TDEA........ " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "CMAC 2TDEA........ " _RED_("fail"));
return res; return res;
} }
@ -329,11 +297,7 @@ static bool TestCMACDES(void) {
DesfireCryptoCMAC(&dctx, CMACData, 32, cmac); DesfireCryptoCMAC(&dctx, CMACData, 32, cmac);
res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0); res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0);
if (res) PrintAndLogEx(INFO, "CMAC DES.......... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "CMAC DES.......... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "CMAC DES.......... " _RED_("fail"));
return res; return res;
} }
@ -356,11 +320,7 @@ static bool TestEV2SessionKeys(void) {
DesfireGenSessionKeyEV2(key, rnda, rndb, false, sessionkey); DesfireGenSessionKeyEV2(key, rnda, rndb, false, sessionkey);
res = res && (memcmp(sessionkey, sessionkeymac, sizeof(sessionkeymac)) == 0); res = res && (memcmp(sessionkey, sessionkeymac, sizeof(sessionkeymac)) == 0);
if (res) PrintAndLogEx(INFO, "EV2 session keys.. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "EV2 session keys.. " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "EV2 session keys.. " _RED_("fail"));
return res; return res;
} }
@ -392,11 +352,7 @@ static bool TestEV2IVEncode(void) {
DesfireEV2FillIV(&ctx, true, iv); DesfireEV2FillIV(&ctx, true, iv);
res = res && (memcmp(iv, ivres2, sizeof(ivres2)) == 0); res = res && (memcmp(iv, ivres2, sizeof(ivres2)) == 0);
if (res) PrintAndLogEx(INFO, "EV2 IV calc....... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "EV2 IV calc....... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "EV2 IV calc....... " _RED_("fail"));
return res; return res;
} }
@ -452,17 +408,12 @@ static bool TestEV2MAC(void) {
DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac); DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac);
res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0); res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0);
if (res) PrintAndLogEx(INFO, "EV2 MAC calc...... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "EV2 MAC calc...... " _RED_("fail"));
return res; return res;
} }
static bool TestTransSessionKeys(void) { static bool TestTransSessionKeys(void) {
bool res = true; bool res = true;
uint8_t key[] = {0x66, 0xA8, 0xCB, 0x93, 0x26, 0x9D, 0xC9, 0xBC, 0x28, 0x85, 0xB7, 0xA9, 0x1B, 0x9C, 0x69, 0x7B}; uint8_t key[] = {0x66, 0xA8, 0xCB, 0x93, 0x26, 0x9D, 0xC9, 0xBC, 0x28, 0x85, 0xB7, 0xA9, 0x1B, 0x9C, 0x69, 0x7B};
uint8_t uid[] = {0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; uint8_t uid[] = {0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
uint32_t trCntr = 8; uint32_t trCntr = 8;
@ -476,11 +427,7 @@ static bool TestTransSessionKeys(void) {
uint8_t keyenc[] = {0x11, 0x9B, 0x90, 0x2A, 0x07, 0xB1, 0x8A, 0x86, 0x5B, 0x8E, 0x1B, 0x00, 0x60, 0x59, 0x47, 0x84}; uint8_t keyenc[] = {0x11, 0x9B, 0x90, 0x2A, 0x07, 0xB1, 0x8A, 0x86, 0x5B, 0x8E, 0x1B, 0x00, 0x60, 0x59, 0x47, 0x84};
res = res && (memcmp(sessionkey, keyenc, sizeof(keyenc)) == 0); res = res && (memcmp(sessionkey, keyenc, sizeof(keyenc)) == 0);
if (res) PrintAndLogEx(INFO, "Trans session key. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "Trans session key. " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "Trans session key. " _RED_("fail"));
return res; return res;
} }
@ -505,11 +452,7 @@ static bool TestLRPPlaintexts(void) {
uint8_t pt15[] = {0x71, 0xB4, 0x44, 0xAF, 0x25, 0x7A, 0x93, 0x21, 0x53, 0x11, 0xD7, 0x58, 0xDD, 0x33, 0x32, 0x47}; uint8_t pt15[] = {0x71, 0xB4, 0x44, 0xAF, 0x25, 0x7A, 0x93, 0x21, 0x53, 0x11, 0xD7, 0x58, 0xDD, 0x33, 0x32, 0x47};
res = res && (memcmp(ctx.plaintexts[15], pt15, sizeof(pt15)) == 0); res = res && (memcmp(ctx.plaintexts[15], pt15, sizeof(pt15)) == 0);
if (res) PrintAndLogEx(INFO, "LRP plaintexts.... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP plaintexts.... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP plaintexts.... " _RED_("fail"));
return res; return res;
} }
@ -531,11 +474,7 @@ static bool TestLRPUpdatedKeys(void) {
uint8_t key2[] = {0xFE, 0x30, 0xAB, 0x50, 0x46, 0x7E, 0x61, 0x78, 0x3B, 0xFE, 0x6B, 0x5E, 0x05, 0x60, 0x16, 0x0E}; uint8_t key2[] = {0xFE, 0x30, 0xAB, 0x50, 0x46, 0x7E, 0x61, 0x78, 0x3B, 0xFE, 0x6B, 0x5E, 0x05, 0x60, 0x16, 0x0E};
res = res && (memcmp(ctx.updatedKeys[2], key2, sizeof(key2)) == 0); res = res && (memcmp(ctx.updatedKeys[2], key2, sizeof(key2)) == 0);
if (res) PrintAndLogEx(INFO, "LRP updated keys.. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP updated keys.. " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP updated keys.. " _RED_("fail"));
return res; return res;
} }
@ -587,11 +526,7 @@ static bool TestLRPEval(void) {
uint8_t y5[] = {0xCF, 0x99, 0x13, 0x92, 0xF0, 0x36, 0x93, 0x50, 0xA7, 0xE2, 0x1B, 0xE5, 0x2F, 0x74, 0x88, 0x21}; uint8_t y5[] = {0xCF, 0x99, 0x13, 0x92, 0xF0, 0x36, 0x93, 0x50, 0xA7, 0xE2, 0x1B, 0xE5, 0x2F, 0x74, 0x88, 0x21};
res = res && (memcmp(y, y5, sizeof(y5)) == 0); res = res && (memcmp(y, y5, sizeof(y5)) == 0);
if (res) PrintAndLogEx(INFO, "LRP eval.......... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP eval.......... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP eval.......... " _RED_("fail"));
return res; return res;
} }
@ -618,11 +553,7 @@ static bool TestLRPIncCounter(void) {
uint8_t ctrr4[] = {0x00}; uint8_t ctrr4[] = {0x00};
res = res && (memcmp(ctr4, ctrr4, sizeof(ctrr4)) == 0); res = res && (memcmp(ctr4, ctrr4, sizeof(ctrr4)) == 0);
if (res) PrintAndLogEx(INFO, "LRP inc counter... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP inc counter... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP inc counter... " _RED_("fail"));
return res; return res;
} }
@ -686,11 +617,7 @@ static bool TestLRPEncode(void) {
res = res && (resplen == sizeof(res5)); res = res && (resplen == sizeof(res5));
res = res && (memcmp(resp, res5, sizeof(res5)) == 0); res = res && (memcmp(resp, res5, sizeof(res5)) == 0);
if (res) PrintAndLogEx(INFO, "LRP encode........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP encode........ " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP encode........ " _RED_("fail"));
return res; return res;
} }
@ -753,11 +680,7 @@ static bool TestLRPDecode(void) {
res = res && (resplen == sizeof(res5)); res = res && (resplen == sizeof(res5));
res = res && (memcmp(resp, res5, sizeof(res5)) == 0); res = res && (memcmp(resp, res5, sizeof(res5)) == 0);
if (res) PrintAndLogEx(INFO, "LRP decode........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP decode........ " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP decode........ " _RED_("fail"));
return res; return res;
} }
@ -793,11 +716,7 @@ static bool TestLRPSubkeys(void) {
res = res && (memcmp(sk1, sk1r3, sizeof(sk1r3)) == 0); res = res && (memcmp(sk1, sk1r3, sizeof(sk1r3)) == 0);
res = res && (memcmp(sk2, sk2r3, sizeof(sk2r3)) == 0); res = res && (memcmp(sk2, sk2r3, sizeof(sk2r3)) == 0);
if (res) PrintAndLogEx(INFO, "LRP subkeys....... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP subkeys....... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP subkeys....... " _RED_("fail"));
return res; return res;
} }
@ -855,11 +774,7 @@ static bool TestLRPCMAC(void) {
uint8_t cmacres6[] = {0x05, 0xF1, 0xCE, 0x30, 0x45, 0x1A, 0x03, 0xA6, 0xE4, 0x68, 0xB3, 0xA5, 0x90, 0x33, 0xA5, 0x54}; uint8_t cmacres6[] = {0x05, 0xF1, 0xCE, 0x30, 0x45, 0x1A, 0x03, 0xA6, 0xE4, 0x68, 0xB3, 0xA5, 0x90, 0x33, 0xA5, 0x54};
res = res && (memcmp(cmac, cmacres6, sizeof(cmacres6)) == 0); res = res && (memcmp(cmac, cmacres6, sizeof(cmacres6)) == 0);
if (res) PrintAndLogEx(INFO, "LRP CMAC.......... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP CMAC.......... " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP CMAC.......... " _RED_("fail"));
return res; return res;
} }
@ -877,11 +792,7 @@ static bool TestLRPSessionKeys(void) {
DesfireGenSessionKeyLRP(key, rnda, rndb, true, sessionkey); DesfireGenSessionKeyLRP(key, rnda, rndb, true, sessionkey);
res = res && (memcmp(sessionkey, sessionkeyres, sizeof(sessionkeyres)) == 0); res = res && (memcmp(sessionkey, sessionkeyres, sizeof(sessionkeyres)) == 0);
if (res) PrintAndLogEx(INFO, "LRP session keys.. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "LRP session keys.. " _GREEN_("ok"));
else
PrintAndLogEx(ERR, "LRP session keys.. " _RED_("fail"));
return res; return res;
} }
@ -914,11 +825,7 @@ bool DesfireTest(bool verbose) {
res = res && TestLRPSessionKeys(); res = res && TestLRPSessionKeys();
PrintAndLogEx(INFO, "---------------------------"); PrintAndLogEx(INFO, "---------------------------");
if (res) PrintAndLogEx(SUCCESS, "Tests ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(SUCCESS, " Tests [ %s ]", _GREEN_("ok"));
else
PrintAndLogEx(FAILED, " Tests [ %s ]", _RED_("fail"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return res; return res;
} }

View file

@ -144,6 +144,16 @@ uint32_t reflect32(uint32_t b) {
return v; return v;
} }
uint64_t reflect64(uint64_t b) {
// https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
uint64_t v = b; // 32-bit word to reverse bit order
// swap 2-byte long pairs
uint64_t v1 = reflect32(v >> 32);
uint64_t v2 = reflect32(v);
v = (v1 << 32) | (v2 & 0xFFFFFFFF);
return v;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t *dest) { void num_to_bytes(uint64_t n, size_t len, uint8_t *dest) {
while (len--) { while (len--) {
dest[len] = (uint8_t) n; dest[len] = (uint8_t) n;

View file

@ -74,6 +74,7 @@ uint32_t reflect(uint32_t v, int b); // used in crc.c ...
uint8_t reflect8(uint8_t b); // dedicated 8bit reversal uint8_t reflect8(uint8_t b); // dedicated 8bit reversal
uint16_t reflect16(uint16_t b); // dedicated 16bit reversal uint16_t reflect16(uint16_t b); // dedicated 16bit reversal
uint32_t reflect32(uint32_t b); // dedicated 32bit reversal uint32_t reflect32(uint32_t b); // dedicated 32bit reversal
uint64_t reflect64(uint64_t b); // dedicated 64bit reversal
void num_to_bytes(uint64_t n, size_t len, uint8_t *dest); void num_to_bytes(uint64_t n, size_t len, uint8_t *dest);
uint64_t bytes_to_num(const uint8_t *src, size_t len); uint64_t bytes_to_num(const uint8_t *src, size_t len);

View file

@ -968,8 +968,9 @@ int mbedtls_x509_self_test(int verbose) {
mbedtls_x509_crt cacert; mbedtls_x509_crt cacert;
mbedtls_x509_crt clicert; mbedtls_x509_crt clicert;
if (verbose != 0) if (verbose != 0) {
mbedtls_printf(" X.509 certificate load: "); mbedtls_printf(" X.509 certificate load ");
}
mbedtls_x509_crt_init(&cacert); mbedtls_x509_crt_init(&cacert);
mbedtls_x509_crt_init(&clicert); mbedtls_x509_crt_init(&clicert);
@ -977,8 +978,9 @@ int mbedtls_x509_self_test(int verbose) {
ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *) mbedtls_test_cli_crt, ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *) mbedtls_test_cli_crt,
mbedtls_test_cli_crt_len); mbedtls_test_cli_crt_len);
if (ret != 0) { if (ret != 0) {
if (verbose != 0) if (verbose != 0) {
mbedtls_printf("failed\n"); mbedtls_printf("( fail )\n");
}
goto cleanup; goto cleanup;
} }
@ -986,25 +988,28 @@ int mbedtls_x509_self_test(int verbose) {
ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_ca_crt, ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_ca_crt,
mbedtls_test_ca_crt_len); mbedtls_test_ca_crt_len);
if (ret != 0) { if (ret != 0) {
if (verbose != 0) if (verbose != 0) {
mbedtls_printf("failed\n"); mbedtls_printf("( fail )\n");
}
goto cleanup; goto cleanup;
} }
if (verbose != 0) if (verbose != 0) {
mbedtls_printf("passed\n X.509 signature verify: "); mbedtls_printf("( ok )\n X.509 signature verify ");
}
ret = mbedtls_x509_crt_verify(&clicert, &cacert, NULL, NULL, &flags, NULL, NULL); ret = mbedtls_x509_crt_verify(&clicert, &cacert, NULL, NULL, &flags, NULL, NULL);
if (ret != 0) { if (ret != 0) {
if (verbose != 0) if (verbose != 0) {
mbedtls_printf("failed\n"); mbedtls_printf("( fail )\n");
}
goto cleanup; goto cleanup;
} }
if (verbose != 0) if (verbose != 0) {
mbedtls_printf("passed\n\n"); mbedtls_printf("( ok )\n\n");
}
cleanup: cleanup:
mbedtls_x509_crt_free(&cacert); mbedtls_x509_crt_free(&cacert);

View file

@ -18,7 +18,7 @@
// ensure availability even with -std=c99; must be included before // ensure availability even with -std=c99; must be included before
#if !defined(_WIN32) #if !defined(_WIN32)
//#define _POSIX_C_SOURCE 199309L // need nanosleep()
#define _POSIX_C_SOURCE 200112L // need localtime_r() #define _POSIX_C_SOURCE 200112L // need localtime_r()
#else #else
#include <windows.h> #include <windows.h>
@ -116,7 +116,6 @@ int _civet_safe_clock_gettime(int clk_id, struct timespec *t) {
#endif #endif
// a milliseconds timer for performance measurement // a milliseconds timer for performance measurement
uint64_t msclock(void) { uint64_t msclock(void) {
#if defined(_WIN32) #if defined(_WIN32)
@ -143,3 +142,30 @@ uint64_t msclock(void) {
#endif #endif
} }
// a micro seconds timer for performance measurement
uint64_t usclock(void) {
#if defined(_WIN32)
#include <sys/types.h>
// WORKAROUND FOR MinGW (some versions - use if normal code does not compile)
// It has no _ftime_s and needs explicit inclusion of timeb.h
#include <sys/timeb.h>
struct _timeb t;
_ftime(&t);
return 1000 * (uint64_t)t.time + t.millitm;
// NORMAL CODE (use _ftime_s)
//struct _timeb t;
//if (_ftime_s(&t)) {
// return 0;
//} else {
// return 1000 * t.time + t.millitm;
//}
#else
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
//return (1000 * (uint64_t)t.tv_sec + t.tv_nsec / 1000);
return (1000 * (uint64_t)t.tv_sec + (t.tv_nsec / 1000));
#endif
}

View file

@ -30,5 +30,5 @@ void msleep(uint32_t n); // sleep n milliseconds
#endif // _WIN32 #endif // _WIN32
uint64_t msclock(void); // a milliseconds clock uint64_t msclock(void); // a milliseconds clock
uint64_t usclock(void); // a microseconds clock
#endif #endif

View file

@ -23,6 +23,7 @@
#include "bruteforce.h" #include "bruteforce.h"
#define EM4X50_NO_WORDS 34 #define EM4X50_NO_WORDS 34
#define EM4X50_SIZE_WORD 4
// special words // special words
#define EM4X50_DEVICE_PASSWORD 0 #define EM4X50_DEVICE_PASSWORD 0
@ -71,6 +72,12 @@ typedef struct {
uint8_t byte[4]; uint8_t byte[4];
} PACKED em4x50_word_t; } PACKED em4x50_word_t;
typedef struct {
uint8_t count;
uint32_t *words;
} PACKED em4x50_read_data_response_t;
// Global variables...
extern bool g_Login; extern bool g_Login;
extern bool g_WritePasswordProcess; extern bool g_WritePasswordProcess;
extern uint32_t g_Password; extern uint32_t g_Password;

View file

@ -564,7 +564,6 @@ typedef struct {
#define CMD_HF_ISO15693_SNIFF 0x0312 #define CMD_HF_ISO15693_SNIFF 0x0312
#define CMD_HF_ISO15693_COMMAND 0x0313 #define CMD_HF_ISO15693_COMMAND 0x0313
#define CMD_HF_ISO15693_FINDAFI 0x0315 #define CMD_HF_ISO15693_FINDAFI 0x0315
#define CMD_HF_ISO15693_CSETUID 0x0316
#define CMD_HF_ISO15693_SLIX_ENABLE_PRIVACY 0x0867 #define CMD_HF_ISO15693_SLIX_ENABLE_PRIVACY 0x0867
#define CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY 0x0317 #define CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY 0x0317
#define CMD_HF_ISO15693_SLIX_DISABLE_EAS 0x0318 #define CMD_HF_ISO15693_SLIX_DISABLE_EAS 0x0318
@ -578,12 +577,17 @@ typedef struct {
#define CMD_HF_ISO15693_EML_SETMEM 0x0331 #define CMD_HF_ISO15693_EML_SETMEM 0x0331
#define CMD_HF_ISO15693_EML_GETMEM 0x0332 #define CMD_HF_ISO15693_EML_GETMEM 0x0332
#define CMD_HF_ISO15693_CSETUID 0x0316
#define CMD_HF_ISO15693_CSETUID_V2 0x0333
#define CMD_LF_SNIFF_RAW_ADC 0x0360 #define CMD_LF_SNIFF_RAW_ADC 0x0360
// For Hitag2 transponders // For Hitag2 transponders
#define CMD_LF_HITAG_SNIFF 0x0370 #define CMD_LF_HITAG_SNIFF 0x0370
#define CMD_LF_HITAG_SIMULATE 0x0371 #define CMD_LF_HITAG_SIMULATE 0x0371
#define CMD_LF_HITAG_READER 0x0372 #define CMD_LF_HITAG_READER 0x0372
#define CMD_LF_HITAG2_WRITE 0x0377
#define CMD_LF_HITAG2_CRACK 0x0378
// For HitagS // For HitagS
#define CMD_LF_HITAGS_TEST_TRACES 0x0367 #define CMD_LF_HITAGS_TEST_TRACES 0x0367

View file

@ -369,10 +369,10 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define CRYPTORF_ERR_MEMORY_ACCESS 0xEE #define CRYPTORF_ERR_MEMORY_ACCESS 0xEE
#define CRYPTORF_ERR_MEMORY_ACCESS_SEC 0xF9 #define CRYPTORF_ERR_MEMORY_ACCESS_SEC 0xF9
//First byte is 26 // First byte is 26
#define ISO15693_INVENTORY 0x01 #define ISO15693_INVENTORY 0x01
#define ISO15693_STAYQUIET 0x02 #define ISO15693_STAYQUIET 0x02
//First byte is 02 // First byte is 02
#define ISO15693_READBLOCK 0x20 #define ISO15693_READBLOCK 0x20
#define ISO15693_WRITEBLOCK 0x21 #define ISO15693_WRITEBLOCK 0x21
#define ISO15693_LOCKBLOCK 0x22 #define ISO15693_LOCKBLOCK 0x22
@ -412,6 +412,9 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define ISO15693_STAYQUIET_PERSISTENT 0xBC #define ISO15693_STAYQUIET_PERSISTENT 0xBC
#define ISO15693_READ_SIGNATURE 0xBD #define ISO15693_READ_SIGNATURE 0xBD
//
#define ISO15693_MAGIC_WRITE 0xE0
// Topaz command set: // Topaz command set:
#define TOPAZ_REQA 0x26 // Request #define TOPAZ_REQA 0x26 // Request
#define TOPAZ_WUPA 0x52 // WakeUp #define TOPAZ_WUPA 0x52 // WakeUp

View file

@ -68,8 +68,8 @@ typedef cl_int CL_API_CALL
clGetLayerInfo_t( clGetLayerInfo_t(
cl_layer_info param_name, cl_layer_info param_name,
size_t param_value_size, size_t param_value_size,
void* param_value, void *param_value,
size_t* param_value_size_ret); size_t *param_value_size_ret);
typedef clGetLayerInfo_t * typedef clGetLayerInfo_t *
clGetLayerInfo_fn ; clGetLayerInfo_fn ;
@ -77,9 +77,9 @@ clGetLayerInfo_fn ;
typedef cl_int CL_API_CALL typedef cl_int CL_API_CALL
clInitLayer_t( clInitLayer_t(
cl_uint num_entries, cl_uint num_entries,
const cl_icd_dispatch* target_dispatch, const cl_icd_dispatch *target_dispatch,
cl_uint* num_entries_ret, cl_uint *num_entries_ret,
const cl_icd_dispatch** layer_dispatch_ret); const cl_icd_dispatch **layer_dispatch_ret);
typedef clInitLayer_t * typedef clInitLayer_t *
clInitLayer_fn ; clInitLayer_fn ;
@ -103,15 +103,15 @@ extern CL_API_ENTRY cl_int CL_API_CALL
clGetLayerInfo( clGetLayerInfo(
cl_layer_info param_name, cl_layer_info param_name,
size_t param_value_size, size_t param_value_size,
void* param_value, void *param_value,
size_t* param_value_size_ret) ; size_t *param_value_size_ret) ;
extern CL_API_ENTRY cl_int CL_API_CALL extern CL_API_ENTRY cl_int CL_API_CALL
clInitLayer( clInitLayer(
cl_uint num_entries, cl_uint num_entries,
const cl_icd_dispatch* target_dispatch, const cl_icd_dispatch *target_dispatch,
cl_uint* num_entries_ret, cl_uint *num_entries_ret,
const cl_icd_dispatch** layer_dispatch_ret) ; const cl_icd_dispatch **layer_dispatch_ret) ;
#endif /* !defined(CL_NO_NON_ICD_DISPATCH_EXTENSION_PROTOTYPES) */ #endif /* !defined(CL_NO_NON_ICD_DISPATCH_EXTENSION_PROTOTYPES) */

View file

@ -86,7 +86,7 @@ unsigned char hex2bin(unsigned char c) {
// return a single bit from a value // return a single bit from a value
int bitn(uint64_t x, int bit) { int bitn(uint64_t x, int bit) {
uint64_t bitmask = 1; uint64_t bitmask = 1;
bitmask = bitmask << bit; bitmask <<= bit;
if (x & bitmask) { if (x & bitmask) {
return 1; return 1;

View file

@ -135,12 +135,16 @@ void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, ui
int i; int i;
for (i = 0; i < 16; i++) cur_state = (cur_state >> 1) ^ (uint64_t) hitag2_crypt(cur_state) << 46; for (i = 0; i < 16; i++) {
cur_state = (cur_state >> 1) ^ (uint64_t) hitag2_crypt(cur_state) << 46;
}
// highest 16 bits of IV XOR Shared Key // highest 16 bits of IV XOR Shared Key
cur_state |= (uint64_t) initvector << 47; cur_state |= (uint64_t) initvector << 47;
for (i = 0; i < 15; i++) cur_state = (cur_state >> 1) ^ (uint64_t) hitag2_crypt(cur_state) << 46; for (i = 0; i < 15; i++) {
cur_state = (cur_state >> 1) ^ (uint64_t) hitag2_crypt(cur_state) << 46;
}
cur_state ^= (uint64_t) hitag2_crypt(cur_state) << 47; cur_state ^= (uint64_t) hitag2_crypt(cur_state) << 47;

View file

@ -309,17 +309,20 @@ static uint hitag2_nstep2 (ulong state, ulong lfsr)
return result; return result;
} }
inline static int bitn(ulong x, int bit) inline static int bitn(ulong x, int bit) {
{
const ulong bitmask = 1UL << bit; const ulong bitmask = 1UL << bit;
return (x & bitmask) ? 1 : 0; return (x & bitmask) ? 1 : 0;
} }
static int fnR (ulong x) static int fnR (ulong x) {
{ return (
return (bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^ bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^
bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^ bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 15) ^
bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47)); bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^
bitn(x, 29) ^ bitn(x, 40) ^ bitn(x, 41) ^
bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^
bitn(x, 47)
);
} }
inline static int fa(unsigned int i) { inline static int fa(unsigned int i) {
@ -330,8 +333,7 @@ inline static int fb(unsigned int i) {
return bitn(0x6671, i); return bitn(0x6671, i);
} }
static int fnf (ulong s) static int fnf (ulong s) {
{
const uint x1 = (bitn(s, 2) << 0) | lut3_0x96( (bitn(s, 3) << 1), (bitn(s, 5) << 2), (bitn(s, 6) << 3)); const uint x1 = (bitn(s, 2) << 0) | lut3_0x96( (bitn(s, 3) << 1), (bitn(s, 5) << 2), (bitn(s, 6) << 3));
const uint x2 = (bitn(s, 8) << 0) | lut3_0x96( (bitn(s, 12) << 1), (bitn(s, 14) << 2), (bitn(s, 15) << 3)); const uint x2 = (bitn(s, 8) << 0) | lut3_0x96( (bitn(s, 12) << 1), (bitn(s, 14) << 2), (bitn(s, 15) << 3));
const uint x3 = (bitn(s, 17) << 0) | lut3_0x96( (bitn(s, 21) << 1), (bitn(s, 23) << 2), (bitn(s, 26) << 3)); const uint x3 = (bitn(s, 17) << 0) | lut3_0x96( (bitn(s, 21) << 1), (bitn(s, 23) << 2), (bitn(s, 26) << 3));
@ -362,16 +364,21 @@ void find_state(const uint candidate_index_base,
{ {
const size_t gid[2] = { get_global_id(0), get_global_id(1) }; const size_t gid[2] = { get_global_id(0), get_global_id(1) };
// if (gid[0] == 0) printf("work-item 1,%u\n", gid[1]);
#ifdef HAVE_LOCAL_MEMORY #ifdef HAVE_LOCAL_MEMORY
const size_t lid = get_local_id(0); const size_t lid = get_local_id(0);
const size_t lsize = get_local_size(0); const size_t lsize = get_local_size(0);
#endif // HAVE_LOCAL_MEMORY #endif // HAVE_LOCAL_MEMORY
const uint index = 3 * (candidate_index_base + gid[0]); // dimension 0 should at least keep the execution units saturated - 8k is fine // dimension 0 should at least keep the execution units saturated - 8k is fine
const uint index = 3 * (candidate_index_base + gid[0]);
const ulong3 c = { candidates[index], candidates[index + 1], candidates[index + 2] }; const ulong3 c = {
candidates[index],
candidates[index + 1],
candidates[index + 2]
};
const ulong candidate = ( c.x << 32 | c.y << 16 | c.z ); const ulong candidate = ( c.x << 32 | c.y << 16 | c.z );
@ -379,13 +386,17 @@ void find_state(const uint candidate_index_base,
// store keystream in local memory // store keystream in local memory
__local bitslice_t keystream[32]; __local bitslice_t keystream[32];
for (size_t i = lid; i < 32; i+= lsize) keystream[i] = _keystream[i]; for (size_t i = lid; i < 32; i+= lsize) {
keystream[i] = _keystream[i];
}
#ifdef WITH_HITAG2_FULL #ifdef WITH_HITAG2_FULL
// store uid, aR2, nR1, nR2 in local memory // store uid, aR2, nR1, nR2 in local memory
__local uint checks[4]; __local uint checks[4];
for (uint i = lid; i < 4; i+= lsize) checks[i] = _checks[i]; for (uint i = lid; i < 4; i+= lsize) {
checks[i] = _checks[i];
}
#endif #endif
// threads synchronization // threads synchronization
@ -437,6 +448,7 @@ void find_state(const uint candidate_index_base,
const bitslice_t filter1 = f_c_bs(filter1_0, filter1_1, filter1_2, filter1_3, filter1_4); const bitslice_t filter1 = f_c_bs(filter1_0, filter1_1, filter1_2, filter1_3, filter1_4);
const bitslice_t results1 = filter1 ^ keystream[1]; const bitslice_t results1 = filter1 ^ keystream[1];
if (!results1) return; if (!results1) return;
const bitslice_t filter2_0 = f_a_bs(state[-2 + 4], state[-2 + 5], state[-2 + 7], state[-2 + 8]); const bitslice_t filter2_0 = f_a_bs(state[-2 + 4], state[-2 + 5], state[-2 + 7], state[-2 + 8]);

View file

@ -528,13 +528,13 @@ while true; do
if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "content from tag dump file"; then break; fi if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "content from tag dump file"; then break; fi
if ! CheckExecute slow retry ignore "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested -t --tk 000000000000'" "found:"; then break; fi if ! CheckExecute slow retry ignore "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested -t --tk 000000000000'" "found:"; then break; fi
if ! CheckExecute slow "hf iclass loclass long test" "$CLIENTBIN -c 'hf iclass loclass --long'" "verified \( ok \)"; then break; fi if ! CheckExecute slow "hf iclass loclass long test" "$CLIENTBIN -c 'hf iclass loclass --long'" "verified \( ok \)"; then break; fi
if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Test\(s\) \[ ok"; then break; fi if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf iclass lookup test" "$CLIENTBIN -c 'hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f $DICPATH/iclass_default_keys.dic'" \ if ! CheckExecute "hf iclass lookup test" "$CLIENTBIN -c 'hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f $DICPATH/iclass_default_keys.dic'" \
"valid key AE A6 84 A6 DA B2 32 78"; then break; fi "valid key AE A6 84 A6 DA B2 32 78"; then break; fi
if ! CheckExecute "hf iclass loclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification \( ok \)"; then break; fi if ! CheckExecute "hf iclass loclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification \( ok \)"; then break; fi
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Test\(s\) \[ ok"; then break; fi if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \[ ok"; then break; fi if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \[ ok"; then break; fi if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf waveshare load" "$CLIENTBIN -c 'hf waveshare load -m 6 -f tools/lena.bmp -s dither.bmp' && echo '34ff55fe7257876acf30dae00eb0e439 dither.bmp' | md5sum -c" "dither.bmp: OK"; then break; fi if ! CheckExecute "hf waveshare load" "$CLIENTBIN -c 'hf waveshare load -m 6 -f tools/lena.bmp -s dither.bmp' && echo '34ff55fe7257876acf30dae00eb0e439 dither.bmp' | md5sum -c" "dither.bmp: OK"; then break; fi
fi fi
echo -e "\n------------------------------------------------------------" echo -e "\n------------------------------------------------------------"