mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge branch 'master' into purring-basilisk
Signed-off-by: JLitewski <hackhalotwo@gmail.com>
This commit is contained in:
commit
6097c531c8
50 changed files with 1544 additions and 1560 deletions
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
|
@ -98,7 +98,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: WSL setup
|
||||
uses: Vampire/setup-wsl@v2
|
||||
uses: Vampire/setup-wsl@v3
|
||||
with:
|
||||
distribution: Ubuntu-22.04
|
||||
update: "true"
|
||||
|
|
|
@ -5,7 +5,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
## [unreleased][unreleased]
|
||||
- Removed `save_restoreDB` - 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 to SWIG 4.2.1 (@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)
|
||||
- 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)
|
||||
- Fixed buffer overflow in mfu ndef decode (@mwalker)
|
||||
- Changed spiffs write/append to send in 8192 chunks to ensure its eraised (@mwalker)
|
||||
- Fixed spiffs dump to ensure to fails correctly if no big_buff was allocated (@mwalker)
|
||||
- Fixed buffer overflow in mfu ndef decode (@mwalker33)
|
||||
- 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 (@mwalker33)
|
||||
- Change Client Makefile to respect global flags (@blshkv)
|
||||
- Change Makefile, honors global CC values (@blshkv)
|
||||
- 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)
|
||||
- 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 `--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)
|
||||
- Moved / renamed `fido2.json` -> `client/resource/fido2_defparams.json` (@iceman1001)
|
||||
- Added openocd shikra support based on @ninjastyle82 patch to deprecated iceman fork (@iceman1001)
|
||||
|
|
|
@ -1364,6 +1364,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
SetTag15693Uid(payload->uid);
|
||||
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: {
|
||||
struct p {
|
||||
uint8_t pwd[4];
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
// FeliCa timings
|
||||
// minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56MHz) cycles
|
||||
#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
|
||||
// FRAME DELAY TIME 2672 carrier cycles
|
||||
#ifndef FELICA_FRAME_DELAY_TIME
|
||||
|
@ -64,6 +65,11 @@ static uint32_t iso18092_get_timeout(void) {
|
|||
#define FELICA_MAX_FRAME_SIZE 260
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//structure to hold outgoing NFC frame
|
||||
static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE + 4];
|
||||
|
||||
|
@ -122,7 +128,9 @@ static void shiftInByte(uint8_t bt) {
|
|||
}
|
||||
|
||||
static void Process18092Byte(uint8_t bt) {
|
||||
|
||||
switch (FelicaFrame.state) {
|
||||
|
||||
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
|
||||
if (bt > 0) {
|
||||
|
@ -131,12 +139,15 @@ static void Process18092Byte(uint8_t bt) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_TRYING_SYNC: {
|
||||
|
||||
if (bt == 0) {
|
||||
// desync
|
||||
FelicaFrame.shiftReg = bt;
|
||||
FelicaFrame.state = STATE_UNSYNCD;
|
||||
} else {
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
|
||||
if (FelicaFrame.shiftReg == SYNC_16BIT) {
|
||||
|
@ -145,6 +156,7 @@ static void Process18092Byte(uint8_t bt) {
|
|||
FelicaFrame.framebytes[0] = 0xb2;
|
||||
FelicaFrame.framebytes[1] = 0x4d;
|
||||
FelicaFrame.byte_offset = i;
|
||||
|
||||
// shift in remaining byte, slowly...
|
||||
for (uint8_t j = i; j < 8; j++) {
|
||||
FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1);
|
||||
|
@ -152,9 +164,10 @@ static void Process18092Byte(uint8_t bt) {
|
|||
}
|
||||
|
||||
FelicaFrame.posCnt = 2;
|
||||
if (i == 0)
|
||||
if (i == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 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) {
|
||||
|
||||
if (NYI_timing_NYI != NULL) {
|
||||
Dbprintf("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
|
||||
if (power)
|
||||
|
||||
if (power) {
|
||||
flags |= FPGA_HF_ISO18092_FLAG_READER;
|
||||
if (highspeed)
|
||||
}
|
||||
|
||||
if (highspeed) {
|
||||
flags |= FPGA_HF_ISO18092_FLAG_424K;
|
||||
}
|
||||
|
||||
FpgaWriteConfWord(flags);
|
||||
|
||||
|
@ -419,9 +437,13 @@ static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const
|
|||
// stop when button is pressed
|
||||
// or return TRUE when command is captured
|
||||
bool WaitForFelicaReply(uint16_t maxbytes) {
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("WaitForFelicaReply Start");
|
||||
}
|
||||
|
||||
uint32_t c = 0;
|
||||
|
||||
// power, no modulation
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
FelicaFrameReset();
|
||||
|
@ -433,12 +455,19 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
uint32_t timeout = iso18092_get_timeout();
|
||||
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
|
||||
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
|
||||
Process18092Byte(b);
|
||||
|
||||
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);
|
||||
|
||||
LogTrace(
|
||||
|
@ -449,10 +478,15 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
NULL,
|
||||
false
|
||||
);
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("All bytes received! STATE_FULL");
|
||||
|
||||
return true;
|
||||
|
||||
} else if (c++ > timeout && (FelicaFrame.state == STATE_UNSYNCD || FelicaFrame.state == STATE_TRYING_SYNC)) {
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -478,8 +512,9 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
|
|||
// DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
||||
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
|
||||
|
||||
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER;
|
||||
iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card
|
||||
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; // 418
|
||||
// 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);
|
||||
|
||||
|
|
356
armsrc/hitag2_crack.c
Normal file
356
armsrc/hitag2_crack.c
Normal 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
27
armsrc/hitag2_crack.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -2890,21 +2890,14 @@ void SetTag15693Uid(const uint8_t *uid) {
|
|||
uint8_t cmd[4][9] = {
|
||||
{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, 0x38},
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39}
|
||||
};
|
||||
|
||||
// Command 3 : 02 21 38 u8u7u6u5 (where uX = uid byte X)
|
||||
cmd[2][3] = uid[7];
|
||||
cmd[2][4] = uid[6];
|
||||
cmd[2][5] = uid[5];
|
||||
cmd[2][6] = uid[4];
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x38, uid[7], uid[6], uid[5], uid[4]},
|
||||
|
||||
// Command 4 : 02 21 39 u4u3u2u1 (where uX = uid byte X)
|
||||
cmd[3][3] = uid[3];
|
||||
cmd[3][4] = uid[2];
|
||||
cmd[3][5] = uid[1];
|
||||
cmd[3][6] = uid[0];
|
||||
{ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39, uid[3], uid[2], uid[1], uid[0]}
|
||||
};
|
||||
|
||||
|
||||
AddCrc15(cmd[2], 7);
|
||||
AddCrc15(cmd[3], 7);
|
||||
|
@ -2938,6 +2931,54 @@ void SetTag15693Uid(const uint8_t *uid) {
|
|||
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) {
|
||||
memcpy(buffer, pwd, 4);
|
||||
if (rnd) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
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 DisablePrivacySlixIso15693(const uint8_t *password);
|
||||
|
|
|
@ -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;
|
||||
|
||||
if (g_logging) logSampleSimple(adc_val);
|
||||
if (g_logging) {
|
||||
logSampleSimple(adc_val);
|
||||
}
|
||||
|
||||
// Only test field changes if state of adc values matter
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -210,16 +215,18 @@ void lf_init(bool reader, bool simulate, bool ledcontrol) {
|
|||
sc->averaging = 0;
|
||||
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
|
||||
|
||||
if (reader) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
} 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.
|
||||
|
@ -261,7 +268,9 @@ void lf_init(bool reader, bool simulate, bool ledcontrol) {
|
|||
uint32_t bufsize = 10000;
|
||||
|
||||
// use malloc
|
||||
if (g_logging) initSampleBufferEx(&bufsize, true);
|
||||
if (g_logging) {
|
||||
initSampleBufferEx(&bufsize, true);
|
||||
}
|
||||
|
||||
lf_sample_mean();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
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
|
||||
else if (divisor == 0)
|
||||
} else if (divisor == 0) {
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
|
||||
else
|
||||
} else {
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
|
||||
}
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | (reader_field ? FPGA_LF_ADC_READER_FIELD : 0));
|
||||
|
||||
|
@ -623,16 +624,18 @@ void doT55x7Acquisition(size_t sample_size, bool ledcontrol) {
|
|||
// skip until first high samples begin to change
|
||||
if (startFound || sample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) {
|
||||
// if just found start - recover last sample
|
||||
if (!startFound) {
|
||||
if (startFound == false) {
|
||||
dest[i++] = lastSample;
|
||||
startFound = true;
|
||||
}
|
||||
// collect samples
|
||||
if (i < bufsize) {
|
||||
dest[i++] = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384
|
||||
* and is Manchester?, we directly gather the manchester data into bigbuff
|
||||
|
@ -698,13 +701,15 @@ void doCotagAcquisition(void) {
|
|||
firstlow = true;
|
||||
}
|
||||
|
||||
++i;
|
||||
if (sample > COTAG_ONE_THRESHOLD) {
|
||||
dest[i] = 255;
|
||||
++i;
|
||||
} else if (sample < COTAG_ZERO_THRESHOLD) {
|
||||
dest[i] = 0;
|
||||
++i;
|
||||
} else {
|
||||
dest[i] = dest[i - 1];
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,67 +31,110 @@ size_t nbytes(size_t nbits) {
|
|||
}
|
||||
|
||||
//convert hex digit to integer
|
||||
uint8_t hex2int(char hexchar) {
|
||||
switch (hexchar) {
|
||||
uint8_t hex2int(char x) {
|
||||
switch (x) {
|
||||
case '0':
|
||||
return 0;
|
||||
break;
|
||||
case '1':
|
||||
return 1;
|
||||
break;
|
||||
case '2':
|
||||
return 2;
|
||||
break;
|
||||
case '3':
|
||||
return 3;
|
||||
break;
|
||||
case '4':
|
||||
return 4;
|
||||
break;
|
||||
case '5':
|
||||
return 5;
|
||||
break;
|
||||
case '6':
|
||||
return 6;
|
||||
break;
|
||||
case '7':
|
||||
return 7;
|
||||
break;
|
||||
case '8':
|
||||
return 8;
|
||||
break;
|
||||
case '9':
|
||||
return 9;
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
return 10;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
return 11;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
return 12;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
return 13;
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
return 14;
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
return 15;
|
||||
break;
|
||||
default:
|
||||
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) {
|
||||
LED_A_OFF();
|
||||
LED_B_OFF();
|
||||
|
|
|
@ -82,9 +82,12 @@
|
|||
#endif
|
||||
|
||||
size_t nbytes(size_t nbits);
|
||||
|
||||
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 LEDsoff(void);
|
||||
void SpinOff(uint32_t pause);
|
||||
|
|
|
@ -40,11 +40,7 @@ static bool TestKVV(void) {
|
|||
|
||||
bool res = memcmp(KeyKvv, kvv, CIPURSE_KVV_LENGTH) == 0;
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "kvv.............. " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "kvv.............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "kvv.............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -58,11 +54,7 @@ static bool TestISO9797M2(void) {
|
|||
|
||||
res = res && (FindISO9797M2PaddingDataLen(data, ddatalen) == 4);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "ISO9797M2........ " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "ISO9797M2........ " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "ISO9797M2........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -92,11 +84,7 @@ static bool TestSMI(void) {
|
|||
res = res && (CipurseCGetSMI(&ctx, false) == 0x88);
|
||||
res = res && (CipurseCGetSMI(&ctx, true) == 0x89);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "SMI.............. " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "SMI.............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "SMI.............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -115,15 +103,10 @@ static bool TestMIC(void) {
|
|||
|
||||
res = res && (CipurseCCheckMIC(TestData, 6, mic));
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "MIC.............. " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "MIC.............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "MIC.............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static bool TestAuth(void) {
|
||||
CipurseContext_t ctx = {0};
|
||||
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};
|
||||
res = res && (memcmp(ctx.frameKey, framekey, sizeof(framekey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "Auth............. " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "Auth............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Auth............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(ctx.frameKey, framekey4, sizeof(framekey4)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "channel MAC...... " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "channel MAC...... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "channel MAC...... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -259,11 +234,7 @@ static bool TestEncDec(void) {
|
|||
res = res && (dstdatalen == 16);
|
||||
res = res && (memcmp(dstdata, TestData, 16) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "channel EncDec... " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "channel EncDec... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "channel EncDec... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -351,11 +322,7 @@ static bool TestAPDU(void) {
|
|||
res = res && (memcmp(test6, dstdata, dstdatalen) == 0);
|
||||
res = res && (sw == 0xccdd);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "apdu............. " _GREEN_("passed"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "apdu............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "apdu............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -374,11 +341,7 @@ bool CIPURSETest(bool verbose) {
|
|||
res = res && TestAPDU();
|
||||
|
||||
PrintAndLogEx(INFO, "---------------------------");
|
||||
if (res)
|
||||
PrintAndLogEx(SUCCESS, " Tests [ %s ]", _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(FAILED, " Tests [ %s ]", _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Tests ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -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 -a fileA -b fileB\n"
|
||||
"data diff -a fileA --eb\n"
|
||||
// "data diff -a fileA --cb\n"
|
||||
"data diff --fa fileA -b fileB\n"
|
||||
"data diff --fa fileA --fb fileB\n"
|
||||
// "data diff --ea --cb\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("a", NULL, "<fn>", "input file name A"),
|
||||
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_str0(NULL, "fa", "<fn>", "input spiffs file A"),
|
||||
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};
|
||||
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);
|
||||
|
||||
// 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;
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
char hdr0[400] = {0};
|
||||
|
||||
int hdr_sln = (width * 4) + 2;
|
||||
|
|
|
@ -2735,11 +2735,14 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 csetuid",
|
||||
"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[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "<hex>", "UID, 8 hex bytes"),
|
||||
arg_lit0("2", "v2", "Use gen2 magic command"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -2750,6 +2753,7 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
|||
|
||||
int uidlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
|
||||
bool use_v2 = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (uidlen != HF15_UID_LENGTH) {
|
||||
|
@ -2775,8 +2779,14 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Writing...");
|
||||
PacketResponseNG resp;
|
||||
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");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
|
|
|
@ -93,6 +93,8 @@ static int CmdHFCryptoRFSniff(const char *Cmd) {
|
|||
|
||||
clearCommandBuffer();
|
||||
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_("trace save -f hf_cryptorf_mytrace") "` to save tracelog for later analysing");
|
||||
|
|
|
@ -2147,8 +2147,9 @@ static int CmdHFiClassDump(const char *Cmd) {
|
|||
|
||||
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");
|
||||
}
|
||||
|
||||
// print the dump
|
||||
printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got, dense_output);
|
||||
|
@ -2852,8 +2853,8 @@ static int CmdHFiClass_loclass(const char *Cmd) {
|
|||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
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, "long", "Perform self-test, including long ones"),
|
||||
arg_lit0(NULL, "test", "Perform self test"),
|
||||
arg_lit0(NULL, "long", "Perform self test, including long ones"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -3776,9 +3777,10 @@ out:
|
|||
static int CmdHFiClassLookUp(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
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 --elite");
|
||||
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -4628,9 +4630,9 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHFiClassList, AlwaysAvailable, "List iclass history"},
|
||||
// {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
||||
{"-----------", CmdHelp, IfPm3Iclass, "------------------- " _CYAN_("Operations") " -------------------"},
|
||||
// {"clone", CmdHFiClassClone, IfPm3Iclass, "Create a HID credential to Picopass / iCLASS tag"},
|
||||
{"dump", CmdHFiClassDump, IfPm3Iclass, "Dump Picopass / iCLASS tag to file"},
|
||||
|
|
|
@ -704,6 +704,9 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
case ISO15693_READ_SIGNATURE:
|
||||
snprintf(exp, size, "READ_SIGNATURE");
|
||||
return;
|
||||
case ISO15693_MAGIC_WRITE:
|
||||
snprintf(exp, size, "MAGIC_WRITEBLOCK");
|
||||
return;
|
||||
default:
|
||||
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};
|
||||
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"
|
||||
, AuthData.uid
|
||||
, AuthData.nt_enc
|
||||
|
|
|
@ -41,15 +41,17 @@ static int sendPing(void) {
|
|||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_PING, &resp, 1000))
|
||||
if (WaitForResponseTimeout(CMD_PING, &resp, 1000) == false) {
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
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) {
|
||||
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fc, cn);
|
||||
}
|
||||
|
||||
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
|
@ -205,6 +207,11 @@ int demodAWID(bool verbose) {
|
|||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
char binstr[68] = {0};
|
||||
binarray_2_binstr(binstr, (char *)bits, size);
|
||||
PrintAndLogEx(DEBUG, "no parity... %s", binstr);
|
||||
|
||||
// ok valid card found!
|
||||
|
||||
// Index map
|
||||
|
@ -230,35 +237,47 @@ int demodAWID(bool verbose) {
|
|||
uint8_t fmtLen = bytebits_to_byte(bits, 8);
|
||||
|
||||
switch (fmtLen) {
|
||||
case 26:
|
||||
case 26: {
|
||||
fc = bytebits_to_byte(bits + 9, 8);
|
||||
cardnum = bytebits_to_byte(bits + 17, 16);
|
||||
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);
|
||||
break;
|
||||
case 34:
|
||||
}
|
||||
case 34: {
|
||||
fc = bytebits_to_byte(bits + 9, 8);
|
||||
cardnum = bytebits_to_byte(bits + 17, 24);
|
||||
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:
|
||||
}
|
||||
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);
|
||||
cardnum = bytebits_to_byte(bits + 22, 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 40:
|
||||
// break;
|
||||
case 50:
|
||||
case 50: {
|
||||
fc = bytebits_to_byte(bits + 9, 16);
|
||||
cardnum = bytebits_to_byte(bits + 25, 32);
|
||||
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;
|
||||
}
|
||||
default:
|
||||
if (fmtLen > 32) {
|
||||
cardnum = bytebits_to_byte(bits + 8 + (fmtLen - 17), 16);
|
||||
|
@ -288,7 +307,9 @@ static int CmdAWIDDemod(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid demod",
|
||||
"Try to find AWID Prox preamble, if found decode / descramble data",
|
||||
"lf awid demod"
|
||||
"lf awid demod\n"
|
||||
"lf awid demod --raw "
|
||||
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -566,9 +587,10 @@ static int CmdAWIDBrute(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"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"},
|
||||
{"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"},
|
||||
{"brute", CmdAWIDBrute, IfPm3Lf, "bruteforce card number against reader"},
|
||||
{"watch", CmdAWIDWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},
|
||||
|
|
|
@ -1750,9 +1750,9 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) {
|
||||
PrintAndLogEx(WARNING, "no keys found in file");
|
||||
if (keyBlock != NULL)
|
||||
if (keyBlock != NULL) {
|
||||
free(keyBlock);
|
||||
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -2634,7 +2634,7 @@ static command_t CommandTable[] = {
|
|||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"},
|
||||
{"clonehelp", CmdEM4x05CloneHelp, IfPm3Lf, "Shows the available clone commands"},
|
||||
{"brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"},
|
||||
{"chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"},
|
||||
{"chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords"},
|
||||
{"config", CmdEM4x05Config, AlwaysAvailable, "Create common configuration words"},
|
||||
{"demod", CmdEM4x05Demod, AlwaysAvailable, "Demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
|
||||
{"dump", CmdEM4x05Dump, IfPm3Lf, "Dump EM4x05/EM4x69 tag"},
|
||||
|
|
|
@ -63,10 +63,10 @@ static void em4x50_print_result(const em4x50_word_t *words, int fwr, int lwr) {
|
|||
s = _YELLOW_("control cfg ( locked )");
|
||||
break;
|
||||
case EM4X50_DEVICE_SERIAL:
|
||||
s = _YELLOW_("device serial number ( RO )");
|
||||
s = _YELLOW_("serial number ( RO )");
|
||||
break;
|
||||
case EM4X50_DEVICE_ID:
|
||||
s = _YELLOW_("device identification ( RO )");
|
||||
s = _YELLOW_("device id ( RO )");
|
||||
break;
|
||||
default:
|
||||
s = "user data";
|
||||
|
@ -602,8 +602,11 @@ int read_em4x50_uid(void) {
|
|||
};
|
||||
em4x50_word_t words[EM4X50_NO_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));
|
||||
} else {
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -612,7 +615,10 @@ int read_em4x50_uid(void) {
|
|||
// read protected) -> selective read mode
|
||||
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) {
|
||||
edata = *etd;
|
||||
|
@ -630,9 +636,10 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) {
|
|||
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_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) {
|
||||
memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS);
|
||||
|
@ -1331,7 +1338,7 @@ static command_t CommandTable[] = {
|
|||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
|
||||
{"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"},
|
||||
{"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"},
|
||||
{"login", CmdEM4x50Login, IfPm3EM4x50, "Login into EM4x50 tag"},
|
||||
|
|
|
@ -66,6 +66,265 @@ static t55xx_conf_block_t config = {
|
|||
};
|
||||
|
||||
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) {
|
||||
return config;
|
||||
|
@ -1203,6 +1462,8 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32
|
|||
//undo trim samples
|
||||
restore_bufferS32(saveState, g_GraphBuffer);
|
||||
g_GridOffset = saveState.offset;
|
||||
// t55xx_search_config_psk(g_GraphBuffer, 1);
|
||||
// t55xx_search_config_psk(g_GraphBuffer, 2);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
||||
if (g_DemodBufferLen < 64) return false;
|
||||
if (g_DemodBufferLen < 64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t idx = 28; idx < 64; 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);
|
||||
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
|
||||
// 2nibble must be zeroed.
|
||||
// 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);
|
||||
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
|
||||
bool extMode = ((safer == 0x6 || safer == 0x9) && extend) ? true : false;
|
||||
|
||||
if (!extMode) {
|
||||
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 (extMode == false) {
|
||||
|
||||
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
|
||||
if (!testModulation(mode, modread)) continue;
|
||||
if (testModulation(mode, modread) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*fndBitRate = bitRate;
|
||||
*offset = idx;
|
||||
*Q5 = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (testQ5(mode, offset, fndBitRate, clk)) {
|
||||
*Q5 = true;
|
||||
return true;
|
||||
|
@ -4409,7 +4693,7 @@ static command_t CommandTable[] = {
|
|||
{"write", CmdT55xxWriteBlock, IfPm3Lf, "Write T55xx block data"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"},
|
||||
{"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"},
|
||||
{"recoverpw", CmdT55xxRecoverPW, IfPm3Lf, "Try to recover from bad password write from a cloner"},
|
||||
{"sniff", CmdT55xxSniff, AlwaysAvailable, "Attempt to recover T55xx commands from sample buffer"},
|
||||
|
@ -4428,3 +4712,22 @@ int CmdLFT55XX(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
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
|
||||
|
||||
*/
|
||||
|
|
|
@ -153,10 +153,10 @@ int roca_self_test(void) {
|
|||
|
||||
int ret = 0;
|
||||
if (emv_rocacheck(keyp, 64, false)) {
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s ]", _GREEN_("PASS"));
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus ( %s )", _GREEN_("ok"));
|
||||
} else {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s ]", _RED_("Fail"));
|
||||
PrintAndLogEx(FAILED, "Weak modulus ( %s )", _RED_("fail"));
|
||||
}
|
||||
|
||||
// negative
|
||||
|
@ -167,9 +167,9 @@ int roca_self_test(void) {
|
|||
|
||||
if (emv_rocacheck(keyn, 64, false)) {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Strong modulus [ %s ]", _RED_("Fail"));
|
||||
PrintAndLogEx(FAILED, "Strong modulus ( %s )", _RED_("fail"));
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Strong modulus [ %s ]", _GREEN_("PASS"));
|
||||
PrintAndLogEx(SUCCESS, "Strong modulus ( %s )", _GREEN_("ok"));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -427,16 +427,16 @@ static int cda_test_pk(bool verbose) {
|
|||
int exec_cda_test(bool verbose) {
|
||||
int ret = cda_test_raw(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "CDA raw test: (%s)", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "CDA raw test ( %s )", _RED_("fail"));
|
||||
return ret;
|
||||
}
|
||||
PrintAndLogEx(INFO, "CDA raw test: (%s)", _GREEN_("passed"));
|
||||
PrintAndLogEx(INFO, "CDA raw test ( %s )", _GREEN_("ok"));
|
||||
|
||||
ret = cda_test_pk(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "CDA test pk: (%s)", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "CDA test pk ( %s )", _RED_("fail"));
|
||||
return ret;
|
||||
}
|
||||
PrintAndLogEx(INFO, "CDA test pk: (%s)", _GREEN_("passed"));
|
||||
PrintAndLogEx(INFO, "CDA test pk ( %s )", _GREEN_("ok"));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -310,16 +310,16 @@ int exec_crypto_test(bool verbose, bool include_slow_tests) {
|
|||
unsigned int extra_keylengths[] = {1152, 1408, 1984, 3072, 4096};
|
||||
int ret = test_pk(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "Crypto raw test: (%s)", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "Crypto raw test ( %s )", _RED_("fail"));
|
||||
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++) {
|
||||
unsigned int kl = keylengths[i];
|
||||
ret = test_genkey(kl, message, kl / 8, verbose);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ int exec_crypto_test(bool verbose, bool include_slow_tests) {
|
|||
unsigned int kl = extra_keylengths[i];
|
||||
ret = test_genkey(kl, message, kl / 8, verbose);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,9 +111,9 @@ int ExecuteCryptoTests(bool verbose, bool ignore_time, bool include_slow_tests)
|
|||
PrintAndLogEx(INFO, "--------------------------");
|
||||
|
||||
if (TestFail)
|
||||
PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_("fail"));
|
||||
PrintAndLogEx(FAILED, "Tests ( %s )", _RED_("fail"));
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_("ok"));
|
||||
PrintAndLogEx(SUCCESS, "Tests ( %s )", _GREEN_("ok"));
|
||||
|
||||
return TestFail;
|
||||
}
|
||||
|
|
|
@ -373,16 +373,16 @@ static int dda_test_pk(bool verbose) {
|
|||
int exec_dda_test(bool verbose) {
|
||||
int ret = dda_test_raw(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "DDA raw test: %s", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "DDA raw test ( %s )", _RED_("fail"));
|
||||
return ret;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "DDA raw test: %s", _GREEN_("passed"));
|
||||
PrintAndLogEx(SUCCESS, "DDA raw test ( %s )", _GREEN_("ok"));
|
||||
|
||||
ret = dda_test_pk(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "DDA test pk: %s", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "DDA test pk ( %s )", _RED_("fail"));
|
||||
return ret;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "DDA test pk: %s", _GREEN_("passed"));
|
||||
PrintAndLogEx(SUCCESS, "DDA test pk ( %s )", _GREEN_("ok"));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -262,16 +262,16 @@ static int sda_test_pk(bool verbose) {
|
|||
int exec_sda_test(bool verbose) {
|
||||
int ret = sda_test_raw(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "SDA raw test: %s", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "SDA raw test ( %s )", _RED_("fa1l"));
|
||||
return ret;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "SDA raw test: %s", _GREEN_("passed"));
|
||||
PrintAndLogEx(SUCCESS, "SDA raw test ( %s )", _GREEN_("ok"));
|
||||
|
||||
ret = sda_test_pk(verbose);
|
||||
if (ret) {
|
||||
PrintAndLogEx(WARNING, "SDA test pk: %s", _RED_("failed"));
|
||||
PrintAndLogEx(WARNING, "SDA test pk ( %s )", _RED_("fail"));
|
||||
return ret;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "SDA test pk: %s", _GREEN_("passed"));
|
||||
PrintAndLogEx(SUCCESS, "SDA test pk ( %s )", _GREEN_("ok"));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -674,7 +674,7 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
}
|
||||
|
||||
if (respcode) {
|
||||
*respcode = 0xff;
|
||||
*respcode = 0xFF;
|
||||
}
|
||||
|
||||
uint16_t sw = 0;
|
||||
|
@ -698,10 +698,11 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
// tx chaining
|
||||
size_t sentdatalen = 0;
|
||||
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;
|
||||
else
|
||||
} else {
|
||||
apdu.Lc = datalen - sentdatalen;
|
||||
}
|
||||
|
||||
apdu.data = &data[sentdatalen];
|
||||
|
||||
|
@ -725,8 +726,8 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
}
|
||||
}
|
||||
|
||||
if (respcode != NULL && ((sw & 0xff00) == 0x9100)) {
|
||||
*respcode = sw & 0xff;
|
||||
if (respcode != NULL && ((sw & 0xFF00) == 0x9100)) {
|
||||
*respcode = sw & 0xFF;
|
||||
}
|
||||
|
||||
if (resp) {
|
||||
|
@ -759,6 +760,8 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
apdu.P2 = 0;
|
||||
apdu.data = NULL;
|
||||
|
||||
buflen = 0;
|
||||
|
||||
res = DESFIRESendApdu(false, apdu, buf, DESFIRE_BUFFER_SIZE, &buflen, &sw);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(DEBUG, "error DESFIRESendApdu %s", DesfireGetErrorString(res, &sw));
|
||||
|
@ -766,8 +769,8 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
return res;
|
||||
}
|
||||
|
||||
if (respcode != NULL && ((sw & 0xff00) == 0x9100)) {
|
||||
*respcode = sw & 0xff;
|
||||
if (respcode != NULL && ((sw & 0xFF00) == 0x9100)) {
|
||||
*respcode = sw & 0xFF;
|
||||
}
|
||||
|
||||
if (resp != NULL) {
|
||||
|
@ -776,9 +779,10 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
memcpy(&resp[i * splitbysize + 1], buf, buflen);
|
||||
i += 1;
|
||||
} else {
|
||||
memcpy(&resp[pos], buf, buflen);
|
||||
memcpy(resp + (pos), buf, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
pos += buflen;
|
||||
|
||||
if (sw != DESFIRE_GET_ISO_STATUS(MFDES_ADDITIONAL_FRAME)) {
|
||||
|
@ -786,6 +790,7 @@ static int DesfireExchangeISONative(bool activate_field, DesfireContext_t *ctx,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (resplen) {
|
||||
*resplen = (splitbysize) ? i : pos;
|
||||
}
|
||||
|
@ -866,13 +871,14 @@ int DesfireExchangeEx(bool activate_field, DesfireContext_t *ctx, uint8_t cmd, u
|
|||
case DCCNativeISO:
|
||||
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);
|
||||
else
|
||||
} else {
|
||||
res = DesfireExchangeISONative(activate_field, ctx, cmd, databuf, databuflen, respcode, databuf, &databuflen, enable_chaining, splitbysize);
|
||||
}
|
||||
|
||||
if (splitbysize) {
|
||||
uint8_t sdata[250 * 5] = {0};
|
||||
uint8_t sdata[DESFIRE_BUFFER_SIZE] = {0};
|
||||
size_t sdatalen = 0;
|
||||
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) {
|
||||
if (resplen)
|
||||
if (resplen) {
|
||||
*resplen = 0;
|
||||
}
|
||||
|
||||
uint8_t respcode = 0xFF;
|
||||
|
||||
uint8_t respcode = 0xff;
|
||||
uint8_t *xresp = calloc(DESFIRE_BUFFER_SIZE, 1);
|
||||
if (xresp == NULL)
|
||||
if (xresp == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
size_t xresplen = 0;
|
||||
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);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (respcode != MFDES_S_OPERATION_OK) {
|
||||
free(xresp);
|
||||
return PM3_EAPDU_FAIL;
|
||||
}
|
||||
|
||||
if (checklength >= 0 && xresplen != checklength) {
|
||||
free(xresp);
|
||||
return PM3_EAPDU_FAIL;
|
||||
}
|
||||
|
||||
if (resplen)
|
||||
if (resplen) {
|
||||
*resplen = xresplen;
|
||||
if (resp)
|
||||
}
|
||||
|
||||
if (resp) {
|
||||
memcpy(resp, xresp, (splitbysize == 0) ? xresplen : xresplen * splitbysize);
|
||||
}
|
||||
|
||||
free(xresp);
|
||||
return PM3_SUCCESS;
|
||||
|
@ -1996,13 +2010,16 @@ int DesfireReadSignature(DesfireContext_t *dctx, uint8_t sid, uint8_t *resp, siz
|
|||
uint8_t respcode = 0xff;
|
||||
|
||||
int res = DesfireExchange(dctx, MFDES_READSIG, &sid, 1, &respcode, xresp, &xresplen);
|
||||
if (res != PM3_SUCCESS)
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (respcode != 0x90)
|
||||
if (respcode != 0x90) {
|
||||
return PM3_EAPDU_FAIL;
|
||||
}
|
||||
|
||||
memcpy(resp, xresp, xresplen);
|
||||
|
||||
*resplen = xresplen;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
|
@ -2172,7 +2189,6 @@ int DesfireReadFile(DesfireContext_t *dctx, uint8_t fnum, uint32_t offset, uint3
|
|||
data[0] = fnum;
|
||||
Uint3byteToMemLe(&data[1], offset);
|
||||
Uint3byteToMemLe(&data[4], len);
|
||||
|
||||
return DesfireCommand(dctx, (dctx->isoChaining) ? MFDES_READ_DATA2 : MFDES_READ_DATA, data, 7, resp, resplen, -1);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc32.h"
|
||||
#include "commonutil.h"
|
||||
#include "desfirecore.h" // DESFIRE_BUFFER_SIZE
|
||||
|
||||
void DesfireClearContext(DesfireContext_t *ctx) {
|
||||
ctx->keyNum = 0;
|
||||
|
@ -148,22 +149,29 @@ size_t DesfireSearchCRCPos(uint8_t *data, size_t datalen, uint8_t respcode, uint
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint8_t crcdata[1024] = {0};
|
||||
uint8_t crcdata[DESFIRE_BUFFER_SIZE] = {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)
|
||||
for (int i = 0; i < crclen + 2; i++) {
|
||||
if (crcpos - i == 0)
|
||||
|
||||
if (crcpos - i == 0) {
|
||||
break;
|
||||
if (crcpos - i + crclen > datalen)
|
||||
}
|
||||
|
||||
if (crcpos - i + crclen > datalen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(crcdata, data, crcpos - i);
|
||||
crcdata[crcpos - i] = respcode;
|
||||
|
||||
bool res;
|
||||
if (crclen == 4)
|
||||
if (crclen == 4) {
|
||||
res = desfire_crc32_check(crcdata, crcpos - i + 1, &data[crcpos - i]);
|
||||
else
|
||||
} else {
|
||||
res = iso14443a_crc_check(data, crcpos - i, &data[crcpos - i]);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
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) {
|
||||
uint8_t data[1024] = {0};
|
||||
|
||||
uint8_t data[DESFIRE_BUFFER_SIZE] = {0};
|
||||
uint8_t xiv[DESFIRE_MAX_CRYPTO_BLOCK_SIZE] = {0};
|
||||
|
||||
if (ctx->secureChannel == DACd40) {
|
||||
|
@ -287,15 +296,17 @@ void DesfireCryptoEncDecEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_typ
|
|||
else
|
||||
memcpy(iv, xiv, block_size);
|
||||
|
||||
if (dstdata)
|
||||
if (dstdata) {
|
||||
memcpy(dstdata, data, srcdatalen);
|
||||
}
|
||||
}
|
||||
|
||||
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 xencode = encode;
|
||||
if (ctx->secureChannel == DACd40)
|
||||
if (ctx->secureChannel == DACd40) {
|
||||
xencode = false;
|
||||
}
|
||||
|
||||
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) {
|
||||
int kbs = desfire_get_key_block_length(ctx->keyType);
|
||||
if (kbs == 0)
|
||||
if (kbs == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t buffer[padded_data_length(MAX(minlen, len) + 1, kbs)];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
@ -357,9 +369,10 @@ void DesfireCryptoCMACEx(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type,
|
|||
|
||||
DesfireCryptoEncDec(ctx, key_type, buffer, len, NULL, true);
|
||||
|
||||
if (cmac != NULL)
|
||||
if (cmac != NULL) {
|
||||
memcpy(cmac, ctx->IV, kbs);
|
||||
}
|
||||
}
|
||||
|
||||
void DesfireCryptoCMAC(DesfireContext_t *ctx, uint8_t *data, size_t len, uint8_t *cmac) {
|
||||
DesfireCryptoCMACEx(ctx, DCOSessionKeyMac, data, len, 0, cmac);
|
||||
|
@ -371,16 +384,18 @@ void MifareKdfAn10922(DesfireContext_t *ctx, DesfireCryptoOpKeyType key_type, co
|
|||
return;
|
||||
|
||||
int kbs = desfire_get_key_block_length(ctx->keyType); // 8 or 16
|
||||
if (kbs == 0)
|
||||
if (kbs == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t cmac[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
|
||||
uint8_t buffer[DESFIRE_MAX_CRYPTO_BLOCK_SIZE * 3] = {0};
|
||||
|
||||
if (ctx->keyType == T_AES) {
|
||||
// AES uses 16 byte IV
|
||||
if (kbs < CRYPTO_AES_BLOCK_SIZE)
|
||||
if (kbs < CRYPTO_AES_BLOCK_SIZE) {
|
||||
kbs = CRYPTO_AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
buffer[0] = 0x01;
|
||||
memcpy(&buffer[1], data, len);
|
||||
|
@ -429,8 +444,9 @@ void DesfireDESKeySetVersion(uint8_t *key, DesfireCryptoAlgorithm keytype, uint8
|
|||
return;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// set version
|
||||
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 version = 0;
|
||||
for (int n = 0; n < 8; n++)
|
||||
for (int n = 0; n < 8; n++) {
|
||||
version |= ((key[n] & 1) << (7 - n));
|
||||
}
|
||||
|
||||
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) {
|
||||
uint8_t mdata[1050] = {0};
|
||||
uint8_t mdata[DESFIRE_BUFFER_SIZE] = {0};
|
||||
size_t mdatalen = 0;
|
||||
|
||||
mdata[0] = cmd;
|
||||
Uint2byteToMemLe(&mdata[1], ctx->cmdCntr);
|
||||
memcpy(&mdata[3], ctx->TI, 4);
|
||||
if (data != NULL && datalen > 0)
|
||||
if (data != NULL && datalen > 0) {
|
||||
memcpy(&mdata[7], data, datalen);
|
||||
}
|
||||
|
||||
mdatalen = 1 + 2 + 4 + datalen;
|
||||
|
||||
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) {
|
||||
uint8_t mdata[1050] = {0};
|
||||
uint8_t mdata[DESFIRE_BUFFER_SIZE] = {0};
|
||||
size_t mdatalen = 0;
|
||||
|
||||
mdata[0] = cmd;
|
||||
Uint2byteToMemLe(&mdata[1], ctx->cmdCntr);
|
||||
|
||||
memcpy(&mdata[3], ctx->TI, 4);
|
||||
if (data != NULL && datalen > 0)
|
||||
|
||||
if (data != NULL && datalen > 0) {
|
||||
memcpy(&mdata[7], data, datalen);
|
||||
}
|
||||
|
||||
mdatalen = 1 + 2 + 4 + datalen;
|
||||
|
||||
LRPContext_t lctx = {0};
|
||||
|
|
|
@ -49,9 +49,11 @@ static const uint8_t CommandsCanUseAnyChannel[] = {
|
|||
};
|
||||
|
||||
static bool CommandCanUseAnyChannel(uint8_t cmd) {
|
||||
for (int i = 0; i < ARRAYLEN(CommandsCanUseAnyChannel); i++)
|
||||
if (CommandsCanUseAnyChannel[i] == cmd)
|
||||
for (int i = 0; i < ARRAYLEN(CommandsCanUseAnyChannel); i++) {
|
||||
if (CommandsCanUseAnyChannel[i] == cmd) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -207,10 +209,11 @@ static const CmdHeaderLengths_t CmdHeaderLengths[] = {
|
|||
};
|
||||
|
||||
static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) {
|
||||
for (int i = 0; i < ARRAYLEN(CmdHeaderLengths); i++)
|
||||
if (CmdHeaderLengths[i].cmd == cmd)
|
||||
for (int i = 0; i < ARRAYLEN(CmdHeaderLengths); i++) {
|
||||
if (CmdHeaderLengths[i].cmd == cmd) {
|
||||
return CmdHeaderLengths[i].len;
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -228,12 +231,15 @@ static const uint8_t EV1D40TransmitMAC[] = {
|
|||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYLEN(EV1D40TransmitMAC); i++)
|
||||
if (EV1D40TransmitMAC[i] == cmd)
|
||||
for (int i = 0; i < ARRAYLEN(EV1D40TransmitMAC); i++) {
|
||||
if (EV1D40TransmitMAC[i] == cmd) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -247,12 +253,15 @@ static const uint8_t D40ReceiveMAC[] = {
|
|||
};
|
||||
|
||||
static bool DesfireEV1D40ReceiveMAC(DesfireContext_t *ctx, uint8_t cmd) {
|
||||
if (ctx->secureChannel != DACd40)
|
||||
if (ctx->secureChannel != DACd40) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYLEN(D40ReceiveMAC); i++)
|
||||
if (D40ReceiveMAC[i] == cmd)
|
||||
for (int i = 0; i < ARRAYLEN(D40ReceiveMAC); i++) {
|
||||
if (D40ReceiveMAC[i] == cmd) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -269,10 +278,11 @@ static const uint8_t ISOChannelValidCmd[] = {
|
|||
};
|
||||
|
||||
static bool DesfireISOChannelValidCmd(uint8_t cmd) {
|
||||
for (int i = 0; i < ARRAYLEN(ISOChannelValidCmd); i++)
|
||||
if (ISOChannelValidCmd[i] == cmd)
|
||||
for (int i = 0; i < ARRAYLEN(ISOChannelValidCmd); i++) {
|
||||
if (ISOChannelValidCmd[i] == cmd) {
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
||||
uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
|
||||
if (data == NULL)
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
|
||||
uint8_t hdrlen = DesfireGetCmdHeaderLen(cmd);
|
||||
if (srcdatalen < hdrlen)
|
||||
if (srcdatalen < hdrlen) {
|
||||
hdrlen = srcdatalen;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
uint8_t *data = calloc(DESFIRE_BUFFER_SIZE, sizeof(uint8_t));
|
||||
if (data == NULL)
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if comm mode = plain --> response with MAC
|
||||
// if request is not zero length --> response MAC
|
||||
if (ctx->commMode == DCMPlain || ctx->commMode == DCMMACed || (ctx->commMode == DCMEncrypted && !ctx->lastRequestZeroLen)) {
|
||||
|
||||
if (srcdatalen < DesfireGetMACLength(ctx)) {
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
|
@ -596,6 +610,7 @@ static void DesfireSecureChannelDecodeEV1(DesfireContext_t *ctx, uint8_t *srcdat
|
|||
}
|
||||
|
||||
memcpy(dstdata, srcdata, srcdatalen - DesfireGetMACLength(ctx));
|
||||
|
||||
*dstdatalen = srcdatalen - DesfireGetMACLength(ctx);
|
||||
|
||||
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};
|
||||
DesfireCryptoCMAC(ctx, data, *dstdatalen + 1, cmac);
|
||||
|
||||
if (memcmp(&srcdata[*dstdatalen], cmac, DesfireGetMACLength(ctx)) != 0) {
|
||||
|
||||
PrintAndLogEx(WARNING, "Received MAC is not match with calculated");
|
||||
PrintAndLogEx(INFO, " received MAC: %s", sprint_hex(&srcdata[*dstdatalen], DesfireGetMACLength(ctx)));
|
||||
PrintAndLogEx(INFO, " calculated MAC: %s", sprint_hex(cmac, DesfireGetMACLength(ctx)));
|
||||
|
||||
} else {
|
||||
if (GetAPDULogging())
|
||||
|
||||
if (GetAPDULogging()) {
|
||||
PrintAndLogEx(INFO, "Received MAC OK");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ctx->commMode == DCMEncrypted || ctx->commMode == DCMEncryptedWithPadding) {
|
||||
|
||||
if (srcdatalen < desfire_get_key_block_length(ctx->keyType)) {
|
||||
memcpy(dstdata, srcdata, srcdatalen);
|
||||
*dstdatalen = srcdatalen;
|
||||
|
|
|
@ -53,11 +53,7 @@ static bool TestCRC16(void) {
|
|||
len = DesfireSearchCRCPos(data, 1, 0x00, 2);
|
||||
res = res && (len == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CRC16............. " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CRC16............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "CRC16............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -80,11 +76,7 @@ static bool TestCRC32(void) {
|
|||
len = DesfireSearchCRCPos(data, 2, 0x00, 4);
|
||||
res = res && (len == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CRC32............. " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CRC32............. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "CRC32............. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -131,11 +123,7 @@ static bool TestCMACSubkeys(void) {
|
|||
res = res && (memcmp(sk1, sk1_3tdea, sizeof(sk1_3tdea)) == 0);
|
||||
res = res && (memcmp(sk2, sk2_3tdea, sizeof(sk2_3tdea)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CMAC subkeys...... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CMAC subkeys...... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "CMAC subkeys...... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "An10922 AES....... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "An10922 AES....... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "An10922 AES....... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "An10922 2TDEA..... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "An10922 2TDEA..... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "An10922 2TDEA..... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -201,11 +181,7 @@ static bool TestAn10922KDF3TDEA(void) {
|
|||
};
|
||||
res = res && (memcmp(dctx.key, dkey, sizeof(dkey)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "An10922 3TDEA..... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "An10922 3TDEA..... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "An10922 3TDEA..... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -245,11 +221,7 @@ static bool TestCMAC3TDEA(void) {
|
|||
DesfireCryptoCMAC(&dctx, CMACData, 32, cmac);
|
||||
res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CMAC 3TDEA........ " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CMAC 3TDEA........ " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "CMAC 3TDEA........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -289,11 +261,7 @@ static bool TestCMAC2TDEA(void) {
|
|||
DesfireCryptoCMAC(&dctx, CMACData, 32, cmac);
|
||||
res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CMAC 2TDEA........ " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CMAC 2TDEA........ " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "CMAC 2TDEA........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -329,11 +297,7 @@ static bool TestCMACDES(void) {
|
|||
DesfireCryptoCMAC(&dctx, CMACData, 32, cmac);
|
||||
res = res && (memcmp(cmac, cmac4, sizeof(cmac1)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "CMAC DES.......... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "CMAC DES.......... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "CMAC DES.......... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -356,11 +320,7 @@ static bool TestEV2SessionKeys(void) {
|
|||
DesfireGenSessionKeyEV2(key, rnda, rndb, false, sessionkey);
|
||||
res = res && (memcmp(sessionkey, sessionkeymac, sizeof(sessionkeymac)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "EV2 session keys.. " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "EV2 session keys.. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "EV2 session keys.. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -392,11 +352,7 @@ static bool TestEV2IVEncode(void) {
|
|||
DesfireEV2FillIV(&ctx, true, iv);
|
||||
res = res && (memcmp(iv, ivres2, sizeof(ivres2)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "EV2 IV calc....... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "EV2 IV calc....... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "EV2 IV calc....... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -452,17 +408,12 @@ static bool TestEV2MAC(void) {
|
|||
DesfireEV2CalcCMAC(&ctx, rc, cmddata4, sizeof(cmddata4), mac);
|
||||
res = res && (memcmp(mac, macres4, sizeof(macres4)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "EV2 MAC calc...... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "EV2 MAC calc...... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "EV2 MAC calc...... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool TestTransSessionKeys(void) {
|
||||
bool res = true;
|
||||
|
||||
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};
|
||||
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};
|
||||
res = res && (memcmp(sessionkey, keyenc, sizeof(keyenc)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "Trans session key. " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "Trans session key. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "Trans session key. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(ctx.plaintexts[15], pt15, sizeof(pt15)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP plaintexts.... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP plaintexts.... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP plaintexts.... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(ctx.updatedKeys[2], key2, sizeof(key2)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP updated keys.. " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP updated keys.. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP updated keys.. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(y, y5, sizeof(y5)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP eval.......... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP eval.......... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP eval.......... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -618,11 +553,7 @@ static bool TestLRPIncCounter(void) {
|
|||
uint8_t ctrr4[] = {0x00};
|
||||
res = res && (memcmp(ctr4, ctrr4, sizeof(ctrr4)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP inc counter... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP inc counter... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP inc counter... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -686,11 +617,7 @@ static bool TestLRPEncode(void) {
|
|||
res = res && (resplen == sizeof(res5));
|
||||
res = res && (memcmp(resp, res5, sizeof(res5)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP encode........ " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP encode........ " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP encode........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -753,11 +680,7 @@ static bool TestLRPDecode(void) {
|
|||
res = res && (resplen == sizeof(res5));
|
||||
res = res && (memcmp(resp, res5, sizeof(res5)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP decode........ " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP decode........ " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP decode........ ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -793,11 +716,7 @@ static bool TestLRPSubkeys(void) {
|
|||
res = res && (memcmp(sk1, sk1r3, sizeof(sk1r3)) == 0);
|
||||
res = res && (memcmp(sk2, sk2r3, sizeof(sk2r3)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP subkeys....... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP subkeys....... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP subkeys....... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
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};
|
||||
res = res && (memcmp(cmac, cmacres6, sizeof(cmacres6)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP CMAC.......... " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP CMAC.......... " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP CMAC.......... ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -877,11 +792,7 @@ static bool TestLRPSessionKeys(void) {
|
|||
DesfireGenSessionKeyLRP(key, rnda, rndb, true, sessionkey);
|
||||
res = res && (memcmp(sessionkey, sessionkeyres, sizeof(sessionkeyres)) == 0);
|
||||
|
||||
if (res)
|
||||
PrintAndLogEx(INFO, "LRP session keys.. " _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(ERR, "LRP session keys.. " _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "LRP session keys.. ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -914,11 +825,7 @@ bool DesfireTest(bool verbose) {
|
|||
res = res && TestLRPSessionKeys();
|
||||
|
||||
PrintAndLogEx(INFO, "---------------------------");
|
||||
if (res)
|
||||
PrintAndLogEx(SUCCESS, " Tests [ %s ]", _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(FAILED, " Tests [ %s ]", _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Tests ( %s )", (res) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -144,6 +144,16 @@ uint32_t reflect32(uint32_t b) {
|
|||
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) {
|
||||
while (len--) {
|
||||
dest[len] = (uint8_t) n;
|
||||
|
|
|
@ -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
|
||||
uint16_t reflect16(uint16_t b); // dedicated 16bit 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);
|
||||
uint64_t bytes_to_num(const uint8_t *src, size_t len);
|
||||
|
|
|
@ -968,8 +968,9 @@ int mbedtls_x509_self_test(int verbose) {
|
|||
mbedtls_x509_crt cacert;
|
||||
mbedtls_x509_crt clicert;
|
||||
|
||||
if (verbose != 0)
|
||||
mbedtls_printf(" X.509 certificate load: ");
|
||||
if (verbose != 0) {
|
||||
mbedtls_printf(" X.509 certificate load ");
|
||||
}
|
||||
|
||||
mbedtls_x509_crt_init(&cacert);
|
||||
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,
|
||||
mbedtls_test_cli_crt_len);
|
||||
if (ret != 0) {
|
||||
if (verbose != 0)
|
||||
mbedtls_printf("failed\n");
|
||||
if (verbose != 0) {
|
||||
mbedtls_printf("( fail )\n");
|
||||
}
|
||||
|
||||
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,
|
||||
mbedtls_test_ca_crt_len);
|
||||
if (ret != 0) {
|
||||
if (verbose != 0)
|
||||
mbedtls_printf("failed\n");
|
||||
if (verbose != 0) {
|
||||
mbedtls_printf("( fail )\n");
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (verbose != 0)
|
||||
mbedtls_printf("passed\n X.509 signature verify: ");
|
||||
if (verbose != 0) {
|
||||
mbedtls_printf("( ok )\n X.509 signature verify ");
|
||||
}
|
||||
|
||||
ret = mbedtls_x509_crt_verify(&clicert, &cacert, NULL, NULL, &flags, NULL, NULL);
|
||||
if (ret != 0) {
|
||||
if (verbose != 0)
|
||||
mbedtls_printf("failed\n");
|
||||
|
||||
if (verbose != 0) {
|
||||
mbedtls_printf("( fail )\n");
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (verbose != 0)
|
||||
mbedtls_printf("passed\n\n");
|
||||
if (verbose != 0) {
|
||||
mbedtls_printf("( ok )\n\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mbedtls_x509_crt_free(&cacert);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
// ensure availability even with -std=c99; must be included before
|
||||
#if !defined(_WIN32)
|
||||
//#define _POSIX_C_SOURCE 199309L // need nanosleep()
|
||||
|
||||
#define _POSIX_C_SOURCE 200112L // need localtime_r()
|
||||
#else
|
||||
#include <windows.h>
|
||||
|
@ -116,7 +116,6 @@ int _civet_safe_clock_gettime(int clk_id, struct timespec *t) {
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
// a milliseconds timer for performance measurement
|
||||
uint64_t msclock(void) {
|
||||
#if defined(_WIN32)
|
||||
|
@ -143,3 +142,30 @@ uint64_t msclock(void) {
|
|||
#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
|
||||
}
|
||||
|
||||
|
|
|
@ -30,5 +30,5 @@ void msleep(uint32_t n); // sleep n milliseconds
|
|||
#endif // _WIN32
|
||||
|
||||
uint64_t msclock(void); // a milliseconds clock
|
||||
|
||||
uint64_t usclock(void); // a microseconds clock
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "bruteforce.h"
|
||||
|
||||
#define EM4X50_NO_WORDS 34
|
||||
#define EM4X50_SIZE_WORD 4
|
||||
|
||||
// special words
|
||||
#define EM4X50_DEVICE_PASSWORD 0
|
||||
|
@ -71,6 +72,12 @@ typedef struct {
|
|||
uint8_t byte[4];
|
||||
} 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_WritePasswordProcess;
|
||||
extern uint32_t g_Password;
|
||||
|
|
|
@ -564,7 +564,6 @@ typedef struct {
|
|||
#define CMD_HF_ISO15693_SNIFF 0x0312
|
||||
#define CMD_HF_ISO15693_COMMAND 0x0313
|
||||
#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_DISABLE_PRIVACY 0x0317
|
||||
#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_GETMEM 0x0332
|
||||
|
||||
#define CMD_HF_ISO15693_CSETUID 0x0316
|
||||
#define CMD_HF_ISO15693_CSETUID_V2 0x0333
|
||||
|
||||
#define CMD_LF_SNIFF_RAW_ADC 0x0360
|
||||
|
||||
// For Hitag2 transponders
|
||||
#define CMD_LF_HITAG_SNIFF 0x0370
|
||||
#define CMD_LF_HITAG_SIMULATE 0x0371
|
||||
#define CMD_LF_HITAG_READER 0x0372
|
||||
#define CMD_LF_HITAG2_WRITE 0x0377
|
||||
#define CMD_LF_HITAG2_CRACK 0x0378
|
||||
|
||||
// For HitagS
|
||||
#define CMD_LF_HITAGS_TEST_TRACES 0x0367
|
||||
|
|
|
@ -412,6 +412,9 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define ISO15693_STAYQUIET_PERSISTENT 0xBC
|
||||
#define ISO15693_READ_SIGNATURE 0xBD
|
||||
|
||||
//
|
||||
#define ISO15693_MAGIC_WRITE 0xE0
|
||||
|
||||
// Topaz command set:
|
||||
#define TOPAZ_REQA 0x26 // Request
|
||||
#define TOPAZ_WUPA 0x52 // WakeUp
|
||||
|
|
|
@ -86,7 +86,7 @@ unsigned char hex2bin(unsigned char c) {
|
|||
// return a single bit from a value
|
||||
int bitn(uint64_t x, int bit) {
|
||||
uint64_t bitmask = 1;
|
||||
bitmask = bitmask << bit;
|
||||
bitmask <<= bit;
|
||||
|
||||
if (x & bitmask) {
|
||||
return 1;
|
||||
|
|
|
@ -135,12 +135,16 @@ void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
|
||||
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
|
||||
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;
|
||||
|
||||
|
|
|
@ -309,17 +309,20 @@ static uint hitag2_nstep2 (ulong state, ulong lfsr)
|
|||
return result;
|
||||
}
|
||||
|
||||
inline static int bitn(ulong x, int bit)
|
||||
{
|
||||
inline static int bitn(ulong x, int bit) {
|
||||
const ulong bitmask = 1UL << bit;
|
||||
return (x & bitmask) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int fnR (ulong x)
|
||||
{
|
||||
return (bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^ bitn(x, 6) ^ bitn(x, 7) ^
|
||||
bitn(x, 15) ^ 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));
|
||||
static int fnR (ulong x) {
|
||||
return (
|
||||
bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^
|
||||
bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 15) ^
|
||||
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) {
|
||||
|
@ -330,8 +333,7 @@ inline static int fb(unsigned int 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 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));
|
||||
|
@ -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) };
|
||||
|
||||
// if (gid[0] == 0) printf("work-item 1,%u\n", gid[1]);
|
||||
|
||||
#ifdef HAVE_LOCAL_MEMORY
|
||||
|
||||
const size_t lid = get_local_id(0);
|
||||
const size_t lsize = get_local_size(0);
|
||||
|
||||
#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 );
|
||||
|
||||
|
@ -379,13 +386,17 @@ void find_state(const uint candidate_index_base,
|
|||
// store keystream in local memory
|
||||
__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
|
||||
// store uid, aR2, nR1, nR2 in local memory
|
||||
__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
|
||||
|
||||
// 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 results1 = filter1 ^ keystream[1];
|
||||
|
||||
if (!results1) return;
|
||||
|
||||
const bitslice_t filter2_0 = f_a_bs(state[-2 + 4], state[-2 + 5], state[-2 + 7], state[-2 + 8]);
|
||||
|
|
|
@ -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 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 "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'" \
|
||||
"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 "emv test" "$CLIENTBIN -c 'emv test'" "Test\(s\) \[ 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 "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 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
|
||||
fi
|
||||
echo -e "\n------------------------------------------------------------"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue