Merge pull request #3204 from Antiklesys/master

Huge hf iclass legbrute performance improvements (4x)
This commit is contained in:
Iceman
2026-04-03 11:31:34 +07:00
committed by GitHub
6 changed files with 149 additions and 180 deletions
+1
View File
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Optimized `hf iclass legbrute` throughput: replaced recursive `suc()`/`output()` cipher functions with iterative loops, added 256-entry LUT for the `select()` function eliminating redundant bit arithmetic and halving key lookups per state step, switched successor state to in-place pointer update removing per-call struct copies, added `doMAC_brute()` with byte-wise LSB-first processing and direct output bit packing eliminating all bitstream struct overhead and output reversal calls per key candidate, and replaced per-iteration 64-bit modulo progress check with a countdown counter (@antiklesys)
- Improved `hf iclass legbrute`: fixed multithreaded key-range partitioning so threads cover non-overlapping slices of the 40-bit keyspace, added ETA display, keyboard abort with resume hint, `_Atomic` correctness for shared state, `pthread_create` error handling, and thread count capped at available CPUs (@antiklesys)
- Added wildcard support to `hf secc sim` payloads (@antiklesys)
- Added `hf secc` to build a base for simulating basic function of iclass SE config cards (@antiklesys)
+3 -2
View File
@@ -3187,12 +3187,13 @@ fast_restore:
Dbhexdump(8, fast_restore_key, false);
Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries);
}
if (recovered) {
if (recovered && reverted) {
goto restore;
} else {
} else if (revert_retries >= 7) {
goto out;
}
}
goto out;
restore:
;// empty statement for compilation
+24 -24
View File
@@ -4338,7 +4338,7 @@ static int CmdHFiClass_BlackTears(const char *Cmd) {
arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
arg_int0("s", NULL, "<dec>", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us"),
arg_int0("i", NULL, "<dec>", "tearoff delay increment (in us) - default 10"),
arg_int0("i", NULL, "<dec>", "tearoff delay increment (in us) - default 5"),
arg_int0("e", NULL, "<dec>", "tearoff delay end (in us) must be a higher value than the start delay"),
arg_str0("o", "otp", "<hex>", "Custom OTP value as 2 hex bytes"),
arg_lit0(NULL, "dns", "Do not stabilize the bits, and return the raw dump of the block after tearoff"),
@@ -4510,27 +4510,16 @@ static int CmdHFiClass_BlackTears(const char *Cmd) {
uint8_t data_read_orig[8] = {0};
uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
bool first_read = false;
bool reread = false;
bool erase_phase = false;
read_auth = false;
int blockno = 1;
int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read_orig, false, false);
while (reread) {
if (res_orig == PM3_SUCCESS && !reread) {
if (memcmp(data_read_orig, zeros, 8) == 0) {
reread = true;
} else {
reread = false;
}
} else if (res_orig == PM3_SUCCESS && reread) {
reread = false;
if (blockno == 2 && memcmp(data_read_orig, zeros, 8) == 0) {
reread = true;
}
}
if (res_orig == PM3_SUCCESS && memcmp(data_read_orig, zeros, 8) == 0) {
// zeros may be a transient read artifact - read once more to confirm
res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read_orig, false, false);
}
uint8_t data[8] = { 0 }; // tearoff payload
@@ -4604,7 +4593,7 @@ static int CmdHFiClass_BlackTears(const char *Cmd) {
// read the data back
uint8_t data_read[8] = {0};
first_read = false;
reread = false;
bool reread = false;
bool decrease = false;
int readcount = 0;
while (first_read == false) {
@@ -4631,6 +4620,9 @@ static int CmdHFiClass_BlackTears(const char *Cmd) {
reread = false;
} else if (res != PM3_SUCCESS) {
decrease = true;
if (readcount == 100) {
PrintAndLogEx(WARNING, "\nCard not responding after %d attempts, press " _GREEN_("<Enter>") " to abort", readcount);
}
}
readcount++;
@@ -4688,7 +4680,7 @@ static int CmdHFiClass_BlackTears(const char *Cmd) {
bool goto_out = false;
// App limit became SMALLER :(
if (data_read[0] > data_read_orig[0]) {
if (data_read[0] < data_read_orig[0]) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Application limit changed, from "_YELLOW_("%u")" to "_YELLOW_("%u"), data_read_orig[0], data_read[0]);
@@ -4772,7 +4764,7 @@ static int CmdHFiClass_BlackTears(const char *Cmd) {
msleep(tearoff_sleep);
}
}
out:
@@ -6111,13 +6103,14 @@ static void *brute_thread(void *args_void) {
return NULL;
}
uint32_t progress_countdown = 1000000;
while (index < args->index_end && !*(args->found) && !*(args->aborted)) {
generate_key_block_inverted(args->startingKey, index, div_key);
doMAC(args->CCNR1, div_key, mac);
doMAC_brute(args->CCNR1, div_key, mac);
if (memcmp(mac, args->MAC_TAG1, 4) == 0) {
doMAC(args->CCNR2, div_key, verification_mac);
doMAC_brute(args->CCNR2, div_key, verification_mac);
if (memcmp(verification_mac, args->MAC_TAG2, 4) == 0) {
pthread_mutex_lock(args->log_lock);
if (!*(args->found)) {
@@ -6134,7 +6127,8 @@ static void *brute_thread(void *args_void) {
}
uint64_t thread_progress = index - args->index_start;
if (thread_progress % 1000000 == 0 && !*(args->found)) {
if (--progress_countdown == 0 && !*(args->found)) {
progress_countdown = 1000000;
if (args->thread_id == 0) {
uint64_t keyspace = (uint64_t)1 << 40;
@@ -6481,7 +6475,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass legrec",
"Attempts to recover the diversified key of a specific iCLASS card. This may take several days.\n"
"The card must remain be on the PM3 antenna during the whole process.\n"
"The card must remain on the PM3 antenna during the whole process.\n"
_RED_(" ! Warning ! ") _WHITE_(" This process may brick the card! ") _RED_(" ! Warning ! "),
"hf iclass legrec --macs 0000000089cb984b\n"
"hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest"
@@ -6489,7 +6483,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1(NULL, "macs", "<hex>", "AA1 Authentication MACs"),
arg_str0(NULL, "macs", "<hex>", "AA1 Authentication MACs"),
arg_int0(NULL, "index", "<dec>", "Where to start from to retrieve the key (def: 0)"),
arg_int0(NULL, "loop", "<dec>", "The number of key retrieval cycles to perform, max 10000 (def 100)"),
arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1"),
@@ -6523,6 +6517,12 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
return PM3_SUCCESS;
}
if (macs_len == 0) {
PrintAndLogEx(ERR, "Missing required argument: --macs");
CLIParserFree(ctx);
return PM3_EINVARG;
}
if (no_test) {
test = false;
}
+94 -135
View File
@@ -59,132 +59,57 @@ typedef struct {
uint16_t t;
} State_t;
/**
* Definition 2. The feedback function for the top register T : F 16/2 F 2
* is defined as
* T (x 0 x 1 . . . . . . x 15 ) = x 0 x 1 x 5 x 7 x 10 x 11 x 14 x 15 .
**/
static bool T(State_t state) {
/*
bool x0 = state.t & 0x8000;
bool x1 = state.t & 0x4000;
bool x5 = state.t & 0x0400;
bool x7 = state.t & 0x0100;
bool x10 = state.t & 0x0020;
bool x11 = state.t & 0x0010;
bool x14 = state.t & 0x0002;
bool x15 = state.t & 0x0001;
return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
*/
#define _x0 ((state.t & 0x8000) >> 15 )
#define _x1 ((state.t & 0x4000) >> 14 )
#define _x5 ((state.t & 0x0400) >> 10 )
#define _x7 ((state.t & 0x0100) >> 8 )
#define _x10 ((state.t & 0x0020) >> 5 )
#define _x11 ((state.t & 0x0010) >> 4 )
#define _x14 ((state.t & 0x0002) >> 1 )
#define _x15 (state.t & 0x0001)
return (_x0) ^ (_x1) ^ (_x5) ^ (_x7) ^ (_x10) ^ (_x11) ^ (_x14) ^ (_x15);
}
/**
* Similarly, the feedback function for the bottom register B : F 8/2 F 2 is defined as
* B(x 0 x 1 . . . x 7 ) = x 1 x 2 x 3 x 7 .
**/
/*static bool B(State_t state) {
bool x1 = state.b & 0x40;
bool x2 = state.b & 0x20;
bool x3 = state.b & 0x10;
bool x7 = state.b & 0x01;
return x1 ^ x2 ^ x3 ^ x7;
}
*/
#define B(x) (((x.b & 0x40) >> 6) ^ ((x.b & 0x20) >> 5) ^ ((x.b & 0x10) >> 4) ^ (x.b & 0x01))
// 12 3456
// 0100 0000
// Precomputed lookup table for the r-dependent part of select(x, y, r).
// z0 (bit2) depends only on r. z1 (bit1) = LUT_bit1 ^ x ^ y. z2 (bit0) = LUT_bit0 ^ x.
// Generated from the _select formula; x and y are folded in at call time.
static const uint8_t opt_select_LUT[256] = {
00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04,
01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04,
06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06,
07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06,
06, 05, 04, 07, 04, 05, 06, 07, 02, 01, 01, 02, 00, 01, 03, 02,
03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06,
00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00,
05, 06, 07, 04, 06, 07, 04, 05, 05, 06, 06, 05, 06, 07, 05, 04,
02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06,
03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06,
02, 01, 00, 03, 00, 01, 02, 03, 02, 01, 01, 02, 00, 01, 03, 02,
03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02,
04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00,
01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04,
04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04,
01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00,
};
/**
* Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
* F 8/2 F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
* z 0 = (r 0 r 2 ) (r 1 r 3 ) (r 2 r 4 )
* z 1 = (r 0 r 2 ) (r 5 r 7 ) r 1 r 6 x y
* z 2 = (r 3 r 5 ) (r 4 r 6 ) r 7 x
* Definition 4 (Successor state). Optimized in-place version.
* T(t) computed via parallel XOR reduction on the masked t register.
* B(b) computed via parallel XOR reduction on the b register.
* select(x,y,r) resolved via opt_select_LUT with a single key lookup.
**/
static uint8_t _select(bool x, bool y, uint8_t r) {
#define _r0 ((r >> 7) & 0x01)
#define _r1 ((r >> 6) & 0x01)
#define _r2 ((r >> 5) & 0x01)
#define _r3 ((r >> 4) & 0x01)
#define _r4 ((r >> 3) & 0x01)
#define _r5 ((r >> 2) & 0x01)
#define _r6 ((r >> 1) & 0x01)
#define _r7 (r & 0x01)
static void successor(const uint8_t *k, State_t *s, uint8_t y) {
// T(t) = x0^x1^x5^x7^x10^x11^x14^x15, mask selects those bits
uint16_t Tt = s->t & 0xc533;
Tt ^= Tt >> 1;
Tt ^= Tt >> 4;
Tt ^= Tt >> 10;
Tt ^= Tt >> 8;
// bit0 of Tt is now T(t)
#define _z0 ( (_r0 & _r2) ^ ( _r1 & (!_r3)) ^ (_r2 | _r4) )
#define _z1 ( (_r0 | _r2) ^ ( _r5 | _r7) ^_r1 ^ _r6 ^ (x) ^ (y) )
#define _z2 ( (_r3 & (!_r5)) ^ (_r4 & _r6) ^ _r7 ^ (x) )
s->t = (s->t >> 1) | ((Tt ^ (s->r >> 7) ^ (s->r >> 3)) << 15);
/*
uint8_t r0 = r >> 7 & 0x1;
uint8_t r1 = r >> 6 & 0x1;
uint8_t r2 = r >> 5 & 0x1;
uint8_t r3 = r >> 4 & 0x1;
uint8_t r4 = r >> 3 & 0x1;
uint8_t r5 = r >> 2 & 0x1;
uint8_t r6 = r >> 1 & 0x1;
uint8_t r7 = r & 0x1;
// B(b) = b1^b2^b3^b7; bit0 of opt_B = B(b) after the XOR reduction
uint8_t opt_B = s->b ^ (s->b >> 6) ^ (s->b >> 5) ^ (s->b >> 4);
s->b = (s->b >> 1) | ((opt_B ^ s->r) << 7);
bool z0 = (r0 & r2) ^ (r1 & (!r3)) ^ (r2 | r4);
bool z1 = (r0 | r2) ^ (r5 | r7) ^ r1 ^ r6 ^ x ^ y;
bool z2 = (r3 & (!r5)) ^ (r4 & r6) ^ r7 ^ x;
// select via LUT: z0 from LUT directly, z1/z2 fold in Tt and y
uint8_t sel = opt_select_LUT[s->r] & 0x04;
sel |= (opt_select_LUT[s->r] ^ ((Tt ^ y) << 1)) & 0x02;
sel |= (opt_select_LUT[s->r] ^ Tt) & 0x01;
// The three bitz z0.. z1 are packed into a uint8_t:
// 00000ZZZ
//Return value is a uint8_t
return ((z0 << 2) & 4) | ((z1 << 1) & 2) | (z2 & 1);
*/
return ((_z0 << 2) & 4) | ((_z1 << 1) & 2) | (_z2 & 1);
/*
uint8_t retval = 0;
retval |= (z0 << 2) & 4;
retval |= (z1 << 1) & 2;
retval |= (z2) & 1;
// Return value 0 <= retval <= 7
return retval;
*/
}
/**
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k (F 82 ) 8
* be a key and y F 2 be the input bit. Then, the successor cipher state s =
* l , r , t , b is defined as
* t := (T (t) r 0 r 4 )t 0 . . . t 14 l := (k [select(T (t),y,r)] b ) l r
* b := (B(b) r 7 )b 0 . . . b 6 r := (k [select(T (t),y,r)] b ) l
*
* @param s - state
* @param k - array containing 8 bytes
**/
static State_t successor(const uint8_t *k, State_t s, bool y) {
bool r0 = s.r >> 7 & 0x1;
bool r4 = s.r >> 3 & 0x1;
bool r7 = s.r & 0x1;
State_t successor = {0, 0, 0, 0};
successor.t = s.t >> 1;
successor.t |= ((T(s)) ^ (r0) ^ (r4)) << 15;
successor.b = s.b >> 1;
successor.b |= ((B(s)) ^ (r7)) << 7;
bool Tt = T(s);
successor.l = ((k[_select(Tt, y, s.r)] ^ successor.b) + s.l + s.r) & 0xFF;
successor.r = ((k[_select(Tt, y, s.r)] ^ successor.b) + s.l) & 0xFF;
return successor;
uint8_t r = s->r;
s->r = (k[sel] ^ s->b) + s->l;
s->l = s->r + r;
}
/**
* We define the successor function suc which takes a key k (F 82 ) 8 , a state s and
@@ -193,11 +118,9 @@ static State_t successor(const uint8_t *k, State_t s, bool y) {
* @param k - array containing 8 bytes
**/
static State_t suc(uint8_t *k, State_t s, BitstreamIn_t *bitstream) {
if (bitsLeft(bitstream) == 0) {
return s;
}
bool lastbit = tailBit(bitstream);
return successor(k, suc(k, s, bitstream), lastbit);
while (bitsLeft(bitstream) > 0)
successor(k, &s, headBit(bitstream));
return s;
}
/**
@@ -208,15 +131,11 @@ static State_t suc(uint8_t *k, State_t s, BitstreamIn_t *bitstream) {
* output(k, s, x 0 . . . x n ) = output(s) · output(k, s , x 1 . . . x n )
* where s = suc(k, s, x 0 ).
**/
static void output(uint8_t *k, State_t s, BitstreamIn_t *in, BitstreamOut_t *out) {
if (bitsLeft(in) == 0) {
return;
static void output(uint8_t *k, State_t s, BitstreamIn_t *in, BitstreamOut_t *out) {
while (bitsLeft(in) > 0) {
pushBit(out, (s.r >> 2) & 1);
successor(k, &s, headBit(in));
}
pushBit(out, (s.r >> 2) & 1);
//Remove first bit
uint8_t x0 = headBit(in);
State_t ss = successor(k, s, x0);
output(k, ss, in, out);
}
/**
@@ -243,21 +162,61 @@ static void MAC(uint8_t *k, BitstreamIn_t input, BitstreamOut_t out) {
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) {
uint8_t cc_nr[13] = { 0 };
uint8_t div_key[8];
memcpy(cc_nr, cc_nr_p, 12);
memcpy(div_key, div_key_p, 8);
reverse_arraybytes(cc_nr, 12);
BitstreamIn_t bitstream = {cc_nr, 12 * 8, 0};
uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0};
BitstreamOut_t out = { dest, sizeof(dest) * 8, 0 };
MAC(div_key, bitstream, out);
MAC(div_key_p, bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac, dest, 4);
}
// Feeds `length` raw bytes into cipher state s, one bit at a time LSB-first.
// Equivalent to reflect8-then-MSB-first used by doMAC, with no intermediate buffer.
static void suc_bytes(const uint8_t *k, State_t *s, const uint8_t *in, int length) {
for (int i = 0; i < length; i++) {
uint8_t b = in[i];
successor(k, s, b); b >>= 1;
successor(k, s, b); b >>= 1;
successor(k, s, b); b >>= 1;
successor(k, s, b); b >>= 1;
successor(k, s, b); b >>= 1;
successor(k, s, b); b >>= 1;
successor(k, s, b); b >>= 1;
successor(k, s, b);
}
}
// Collects nbytes of cipher output into `out`, packing bits LSB-first per byte.
// Equivalent to output()+reflect8 used by doMAC, with no intermediate buffer or reversal.
static void output_bytes(const uint8_t *k, State_t *s, uint8_t *out, int nbytes) {
for (int i = 0; i < nbytes; i++) {
uint8_t bout = 0;
bout |= (s->r & 0x4) >> 2; successor(k, s, 0);
bout |= (s->r & 0x4) >> 1; successor(k, s, 0);
bout |= (s->r & 0x4); successor(k, s, 0);
bout |= (s->r & 0x4) << 1; successor(k, s, 0);
bout |= (s->r & 0x4) << 2; successor(k, s, 0);
bout |= (s->r & 0x4) << 3; successor(k, s, 0);
bout |= (s->r & 0x4) << 4; successor(k, s, 0);
bout |= (s->r & 0x4) << 5; successor(k, s, 0);
out[i] = bout;
}
}
// doMAC variant for the brute-force hot loop: takes raw (non-reflected) cc_nr and
// produces the same MAC as doMAC with no intermediate buffers, no reversal calls,
// and no bitstream overhead.
void doMAC_brute(const uint8_t *cc_nr, const uint8_t *div_key, uint8_t mac[4]) {
State_t s = init(div_key);
suc_bytes(div_key, &s, cc_nr, 12);
output_bytes(div_key, &s, mac, 4);
}
void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]) {
uint8_t *address_data;
uint8_t div_key[8];
+1
View File
@@ -38,6 +38,7 @@
#include "pm3_cmd.h"
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
void doMAC_brute(const uint8_t *cc_nr, const uint8_t *div_key, uint8_t mac[4]);
void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]);
#ifndef ON_DEVICE
+26 -19
View File
@@ -327,6 +327,24 @@ static void *bf_thread(void *thread_arg) {
memcpy(bytes_to_recover, targ->bytes_to_recover, sizeof(bytes_to_recover));
memcpy(keytable, targ->keytable, sizeof(keytable));
// Precompute which key_sel positions are fixed (already-cracked) vs. brute-forced.
// sel_brute_idx[i] == 0xFF: key_sel[i] is constant for this entire brute-force run.
// sel_brute_idx[i] == j: key_sel[i] = (brute >> (j*8)) & 0xFF each iteration.
uint8_t sel_brute_idx[8];
uint8_t key_sel[8];
for (uint8_t i = 0; i < 8; i++) {
sel_brute_idx[i] = 0xFF;
for (uint8_t j = 0; j < numbytes_to_recover; j++) {
if (key_index[i] == bytes_to_recover[j]) {
sel_brute_idx[i] = j;
break;
}
}
if (sel_brute_idx[i] == 0xFF) {
key_sel[i] = keytable[key_index[i]] & 0xFF;
}
}
while (!(brute & endmask)) {
int found = __atomic_load_n(&loclass_found, __ATOMIC_SEQ_CST);
@@ -335,24 +353,13 @@ static void *bf_thread(void *thread_arg) {
return NULL;
}
//Update the keytable with the brute-values
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
keytable[bytes_to_recover[i]] &= 0xFF00;
keytable[bytes_to_recover[i]] |= (brute >> (i * 8) & 0xFF);
// Update only the bruted positions of key_sel directly from brute
for (uint8_t i = 0; i < 8; i++) {
if (sel_brute_idx[i] != 0xFF) {
key_sel[i] = (brute >> (sel_brute_idx[i] * 8)) & 0xFF;
}
}
uint8_t key_sel[8] = {0};
// Piece together the key
key_sel[0] = keytable[key_index[0]] & 0xFF;
key_sel[1] = keytable[key_index[1]] & 0xFF;
key_sel[2] = keytable[key_index[2]] & 0xFF;
key_sel[3] = keytable[key_index[3]] & 0xFF;
key_sel[4] = keytable[key_index[4]] & 0xFF;
key_sel[5] = keytable[key_index[5]] & 0xFF;
key_sel[6] = keytable[key_index[6]] & 0xFF;
key_sel[7] = keytable[key_index[7]] & 0xFF;
// Permute from iclass format to standard format
uint8_t key_sel_p[8] = {0};
@@ -364,7 +371,7 @@ static void *bf_thread(void *thread_arg) {
// Calc mac
uint8_t calculated_MAC[4] = {0};
doMAC(cc_nr, div_key, calculated_MAC);
doMAC_brute(cc_nr, div_key, calculated_MAC);
// success
if (memcmp(calculated_MAC, mac, 4) == 0) {
@@ -375,8 +382,8 @@ static void *bf_thread(void *thread_arg) {
pthread_exit(NULL);
}
for (uint8_t i = 0 ; i < numbytes_to_recover; i++) {
r->values[i] = keytable[bytes_to_recover[i]] & 0xFF;
for (uint8_t i = 0 ; i < numbytes_to_recover && i < sizeof(r->values); i++) {
r->values[i] = (brute >> (i * 8)) & 0xFF;
}
__atomic_store_n(&loclass_found, targ->thread_idx, __ATOMIC_SEQ_CST);
pthread_exit((void *)r);