This commit is contained in:
iceman1001 2024-03-14 11:26:06 +01:00
commit 94c3bdd91c
17 changed files with 355 additions and 297 deletions

View file

@ -159,7 +159,7 @@ void ModInfo(void) {
DbpString(" HF UNISNIFF - multimode HF sniffer (hazardousvoltage)");
Dbprintf(" Compile-time default protocol... %s", HF_UNISNIFF_PROTOCOL);
#ifdef WITH_FLASH
DbpString(" FLASH support................... yes");
DbpString(" FLASH support................... yes");
#endif
}
@ -169,12 +169,12 @@ void RunMod(void) {
Dbprintf(_YELLOW_("HF UNISNIFF started"));
const char *protocols[] = {"14a", "14b", "15", "iclass","user"};
const char *protocols[] = {"14a", "14b", "15", "iclass", "user"};
// some magic to allow for `hw standalone` command to trigger a particular sniff from inside the pm3 client
const char *bb = (const char*)BigBuf_get_EM_addr();
const char *bb = (const char *)BigBuf_get_EM_addr();
uint8_t sniff_protocol;
if (strlen(bb) > 0 ) {
if (strlen(bb) > 0) {
for (sniff_protocol = 0; sniff_protocol < ARRAYLEN(protocols); sniff_protocol++) {
if (strcmp(protocols[sniff_protocol], bb) == 0) {
break;
@ -217,10 +217,10 @@ void RunMod(void) {
char *d = &config_buffer[0];
rdv40_spiffs_read_as_filetype(HF_UNISNIFF_CONFIG
, (uint8_t *)d
, fsize
, RDV40_SPIFFS_SAFETY_SAFE
);
, (uint8_t *)d
, fsize
, RDV40_SPIFFS_SAFETY_SAFE
);
// This parser is terrible but I think fairly memory efficient? Maybe better to use JSON?
char *x = d;
@ -384,11 +384,11 @@ void RunMod(void) {
}
sprintf(filename, "%s_%s-%03d%s"
, HF_UNISNIFF_LOGFILE
, protocols[sniff_protocol]
, file_index
, HF_UNISNIFF_LOGEXT
);
, HF_UNISNIFF_LOGFILE
, protocols[sniff_protocol]
, file_index
, HF_UNISNIFF_LOGEXT
);
}
if (file_index > 999) {

View file

@ -1156,7 +1156,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
(cardAUTHKEY == ar_nr_resp[i + mM].keytype) &&
(ar_nr_collected[i + mM] > 0)
)
) {
) {
// if first auth for sector, or matches sector and keytype of previous auth
if (ar_nr_collected[i + mM] < 2) {
// if we haven't already collected 2 nonces for this sector
@ -1361,9 +1361,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
if (ar_nr_collected[i] == 2) {
Dbprintf("Collected two pairs of AR/NR which can be used to extract sector %d " _YELLOW_("%s")
, ar_nr_resp[i].sector
, (ar_nr_resp[i].keytype == AUTHKEYA) ? "key A" : "key B"
);
, ar_nr_resp[i].sector
, (ar_nr_resp[i].keytype == AUTHKEYA) ? "key A" : "key B"
);
Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
ar_nr_resp[i].cuid, //UID
ar_nr_resp[i].nonce, //NT
@ -1380,9 +1380,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
for (uint8_t i = ATTACK_KEY_COUNT; i < ATTACK_KEY_COUNT * 2; i++) {
if (ar_nr_collected[i] == 2) {
Dbprintf("Collected two pairs of AR/NR which can be used to extract sector %d " _YELLOW_("%s")
, ar_nr_resp[i].sector
, (ar_nr_resp[i].keytype == AUTHKEYB) ? "key A" : "key B"
);
, ar_nr_resp[i].sector
, (ar_nr_resp[i].keytype == AUTHKEYB) ? "key A" : "key B"
);
Dbprintf("../tools/mfkey/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x",
ar_nr_resp[i].cuid, //UID
ar_nr_resp[i].nonce, //NT

View file

@ -209,8 +209,8 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
if (try++ == maxtry) {
// Dbprintf_usb("Dbg USART TIMEOUT");
break;
}
break;
}
}
// highest_observed_try = MAX(highest_observed_try, try);
// Dbprintf_usb("Dbg USART max observed try %i", highest_observed_try);

View file

@ -31,13 +31,13 @@
#include <string.h>
#include <stdbool.h>
#if defined(NDEBUG)
#define ASSERT(x) ((void)0)
#define ASSERT(x) ((void)0)
#elif defined(ID48_NO_STDIO)
#define ASSERT(x) ((void)0)
#define ASSERT(x) ((void)0)
#else // neither NDEBUG nor ID48_NO_STDIO defined
#include <stdio.h>
#include <assert.h>
#define ASSERT(x) assert((x))
#include <stdio.h>
#include <assert.h>
#define ASSERT(x) assert((x))
#endif
@ -128,11 +128,11 @@ typedef struct _ID48LIB_GRN {
/// Note: In C++, each parameter would be a reference (not pointer).
/// </remarks>
void id48lib_generator(
const ID48LIB_KEY* key_96bit,
const ID48LIB_NONCE* nonce_56bit,
ID48LIB_FRN* frn28_out,
ID48LIB_GRN* grn20_out
);
const ID48LIB_KEY *key_96bit,
const ID48LIB_NONCE *nonce_56bit,
ID48LIB_FRN *frn28_out,
ID48LIB_GRN *grn20_out
);
/// <summary>
/// Initializes to allow iterative recovery
@ -165,10 +165,10 @@ void id48lib_generator(
/// Note: In C++, each parameter would be a reference (not pointer).
/// </remarks>
void id48lib_key_recovery_init(
const ID48LIB_KEY* input_partial_key,
const ID48LIB_NONCE* input_nonce,
const ID48LIB_FRN* input_frn,
const ID48LIB_GRN* input_grn
const ID48LIB_KEY *input_partial_key,
const ID48LIB_NONCE *input_nonce,
const ID48LIB_FRN *input_frn,
const ID48LIB_GRN *input_grn
);
/// <summary>
/// This can be repeated called (after calling init())
@ -195,7 +195,7 @@ void id48lib_key_recovery_init(
/// Note: In C++, each parameter would be a reference (not pointer).
/// </remarks>
bool id48lib_key_recovery_next(
ID48LIB_KEY* potential_key_output
ID48LIB_KEY *potential_key_output
);
#if defined(__cplusplus)

View file

@ -50,7 +50,7 @@ static const uint8_t small_lut_group4[4] = { // aka 32 bits
0x8f, 0x34, 0x52, 0xe9,
};
static inline bool get_bit(const uint8_t* table_start, uint32_t bit_idx) {
static inline bool get_bit(const uint8_t *table_start, uint32_t bit_idx) {
const uint32_t byte = bit_idx / 8u;
const uint8_t mask = 1u << (bit_idx % 8u);
return (table_start[byte] & mask) != 0;

View file

@ -242,34 +242,33 @@ static inline uint64_t reverse_bits_64(uint64_t n) {
// 0 // == 0 value defines as unstable state
#pragma endregion // bit definitions for the (stable) id48lib state register
#pragma region // single bit test/set/clear/flip/assign
static inline bool is_ssr_state_stable (const ID48LIBX_STATE_REGISTERS* ssr) { ASSERT(ssr != nullptr); return ((ssr->Raw & 1u) == 1u); }
static inline bool test_single_ssr_bit (const ID48LIBX_STATE_REGISTERS* ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); return ((ssr->Raw) >> bit_index) & 1; }
static inline void set_single_ssr_bit ( ID48LIBX_STATE_REGISTERS* ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); ssr->Raw |= ((uint64_t)(1ull << bit_index)); }
static inline void clear_single_ssr_bit ( ID48LIBX_STATE_REGISTERS* ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); ssr->Raw &= ~((uint64_t)(1ull << bit_index)); }
static inline void flip_single_ssr_bit ( ID48LIBX_STATE_REGISTERS* ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); ssr->Raw ^= ((uint64_t)(1ull << bit_index)); }
static inline void assign_single_ssr_bit ( ID48LIBX_STATE_REGISTERS* ssr, size_t bit_index, bool value) {
static inline bool is_ssr_state_stable(const ID48LIBX_STATE_REGISTERS *ssr) { ASSERT(ssr != nullptr); return ((ssr->Raw & 1u) == 1u); }
static inline bool test_single_ssr_bit(const ID48LIBX_STATE_REGISTERS *ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); return ((ssr->Raw) >> bit_index) & 1; }
static inline void set_single_ssr_bit(ID48LIBX_STATE_REGISTERS *ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); ssr->Raw |= ((uint64_t)(1ull << bit_index)); }
static inline void clear_single_ssr_bit(ID48LIBX_STATE_REGISTERS *ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); ssr->Raw &= ~((uint64_t)(1ull << bit_index)); }
static inline void flip_single_ssr_bit(ID48LIBX_STATE_REGISTERS *ssr, size_t bit_index) { ASSERT(ssr != nullptr); ASSERT(bit_index < (sizeof(uint64_t) * 8)); ssr->Raw ^= ((uint64_t)(1ull << bit_index)); }
static inline void assign_single_ssr_bit(ID48LIBX_STATE_REGISTERS *ssr, size_t bit_index, bool value) {
ASSERT(ssr != nullptr);
ASSERT(bit_index < (sizeof(uint64_t) * 8));
if (value) {
set_single_ssr_bit(ssr, bit_index);
}
else {
} else {
clear_single_ssr_bit(ssr, bit_index);
}
}
#pragma endregion // single bit test/set/clear/flip/assign
#pragma region // test/assign of temporaries a/b/c/i/j
static inline void test_temporary_a(ID48LIBX_STATE_REGISTERS* ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_a); }
static inline void test_temporary_b(ID48LIBX_STATE_REGISTERS* ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_b); }
static inline void test_temporary_c(ID48LIBX_STATE_REGISTERS* ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c); }
static inline void test_temporary_i(ID48LIBX_STATE_REGISTERS* ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_i); }
static inline void test_temporary_j(ID48LIBX_STATE_REGISTERS* ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_j); }
static inline void test_temporary_a(ID48LIBX_STATE_REGISTERS *ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_a); }
static inline void test_temporary_b(ID48LIBX_STATE_REGISTERS *ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_b); }
static inline void test_temporary_c(ID48LIBX_STATE_REGISTERS *ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c); }
static inline void test_temporary_i(ID48LIBX_STATE_REGISTERS *ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_i); }
static inline void test_temporary_j(ID48LIBX_STATE_REGISTERS *ssr) { ASSERT(!is_ssr_state_stable(ssr)); test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_j); }
static inline void assign_temporary_a(ID48LIBX_STATE_REGISTERS* ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_a, v); }
static inline void assign_temporary_b(ID48LIBX_STATE_REGISTERS* ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_b, v); }
static inline void assign_temporary_c(ID48LIBX_STATE_REGISTERS* ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c, v); }
static inline void assign_temporary_i(ID48LIBX_STATE_REGISTERS* ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_i, v); }
static inline void assign_temporary_j(ID48LIBX_STATE_REGISTERS* ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_j, v); }
static inline void assign_temporary_a(ID48LIBX_STATE_REGISTERS *ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_a, v); }
static inline void assign_temporary_b(ID48LIBX_STATE_REGISTERS *ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_b, v); }
static inline void assign_temporary_c(ID48LIBX_STATE_REGISTERS *ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c, v); }
static inline void assign_temporary_i(ID48LIBX_STATE_REGISTERS *ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_i, v); }
static inline void assign_temporary_j(ID48LIBX_STATE_REGISTERS *ssr, bool v) { ASSERT(!is_ssr_state_stable(ssr)); assign_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_j, v); }
#pragma endregion // test/assign of temporaries a/b/c/i/j
#pragma region // Mask & Macro to get registers (in minimal bit form)
@ -301,17 +300,17 @@ static inline void assign_temporary_j(ID48LIBX_STATE_REGISTERS* ssr, bool v) { A
#define SSR_VALUE_MASK_REG_M (0x00007Fu) // 7 bits
#define SSR_VALUE_MASK_REG_R (0x00007Fu) // 7 bits
static inline uint16_t get_register_h(const ID48LIBX_STATE_REGISTERS* ssr) { return ((uint16_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_H)) & (SSR_VALUE_MASK_REG_H); }
static inline uint32_t get_register_g(const ID48LIBX_STATE_REGISTERS* ssr) { return ((uint32_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_G)) & (SSR_VALUE_MASK_REG_G); }
static inline uint8_t get_register_l(const ID48LIBX_STATE_REGISTERS* ssr) { return ((uint8_t )(ssr->Raw >> SSR_SHIFT_COUNT_REG_L)) & (SSR_VALUE_MASK_REG_L); }
static inline uint8_t get_register_m(const ID48LIBX_STATE_REGISTERS* ssr) { return ((uint8_t )(ssr->Raw >> SSR_SHIFT_COUNT_REG_M)) & (SSR_VALUE_MASK_REG_M); }
static inline uint8_t get_register_r(const ID48LIBX_STATE_REGISTERS* ssr) { return ((uint8_t )(ssr->Raw >> SSR_SHIFT_COUNT_REG_R)) & (SSR_VALUE_MASK_REG_R); }
static inline uint16_t get_register_h(const ID48LIBX_STATE_REGISTERS *ssr) { return ((uint16_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_H)) & (SSR_VALUE_MASK_REG_H); }
static inline uint32_t get_register_g(const ID48LIBX_STATE_REGISTERS *ssr) { return ((uint32_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_G)) & (SSR_VALUE_MASK_REG_G); }
static inline uint8_t get_register_l(const ID48LIBX_STATE_REGISTERS *ssr) { return ((uint8_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_L)) & (SSR_VALUE_MASK_REG_L); }
static inline uint8_t get_register_m(const ID48LIBX_STATE_REGISTERS *ssr) { return ((uint8_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_M)) & (SSR_VALUE_MASK_REG_M); }
static inline uint8_t get_register_r(const ID48LIBX_STATE_REGISTERS *ssr) { return ((uint8_t)(ssr->Raw >> SSR_SHIFT_COUNT_REG_R)) & (SSR_VALUE_MASK_REG_R); }
static inline void set_register_h(ID48LIBX_STATE_REGISTERS* ssr, uint16_t v) { ASSERT((v & SSR_VALUE_MASK_REG_H) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_H) | (((uint64_t)(v & SSR_VALUE_MASK_REG_H)) << SSR_SHIFT_COUNT_REG_H); }
static inline void set_register_g(ID48LIBX_STATE_REGISTERS* ssr, uint32_t v) { ASSERT((v & SSR_VALUE_MASK_REG_G) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_G) | (((uint64_t)(v & SSR_VALUE_MASK_REG_G)) << SSR_SHIFT_COUNT_REG_G); }
static inline void set_register_l(ID48LIBX_STATE_REGISTERS* ssr, uint8_t v) { ASSERT((v & SSR_VALUE_MASK_REG_L) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_L) | (((uint64_t)(v & SSR_VALUE_MASK_REG_L)) << SSR_SHIFT_COUNT_REG_L); }
static inline void set_register_m(ID48LIBX_STATE_REGISTERS* ssr, uint8_t v) { ASSERT((v & SSR_VALUE_MASK_REG_M) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_M) | (((uint64_t)(v & SSR_VALUE_MASK_REG_M)) << SSR_SHIFT_COUNT_REG_M); }
static inline void set_register_r(ID48LIBX_STATE_REGISTERS* ssr, uint8_t v) { ASSERT((v & SSR_VALUE_MASK_REG_R) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_R) | (((uint64_t)(v & SSR_VALUE_MASK_REG_R)) << SSR_SHIFT_COUNT_REG_R); }
static inline void set_register_h(ID48LIBX_STATE_REGISTERS *ssr, uint16_t v) { ASSERT((v & SSR_VALUE_MASK_REG_H) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_H) | (((uint64_t)(v & SSR_VALUE_MASK_REG_H)) << SSR_SHIFT_COUNT_REG_H); }
static inline void set_register_g(ID48LIBX_STATE_REGISTERS *ssr, uint32_t v) { ASSERT((v & SSR_VALUE_MASK_REG_G) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_G) | (((uint64_t)(v & SSR_VALUE_MASK_REG_G)) << SSR_SHIFT_COUNT_REG_G); }
static inline void set_register_l(ID48LIBX_STATE_REGISTERS *ssr, uint8_t v) { ASSERT((v & SSR_VALUE_MASK_REG_L) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_L) | (((uint64_t)(v & SSR_VALUE_MASK_REG_L)) << SSR_SHIFT_COUNT_REG_L); }
static inline void set_register_m(ID48LIBX_STATE_REGISTERS *ssr, uint8_t v) { ASSERT((v & SSR_VALUE_MASK_REG_M) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_M) | (((uint64_t)(v & SSR_VALUE_MASK_REG_M)) << SSR_SHIFT_COUNT_REG_M); }
static inline void set_register_r(ID48LIBX_STATE_REGISTERS *ssr, uint8_t v) { ASSERT((v & SSR_VALUE_MASK_REG_R) == v); ssr->Raw = (ssr->Raw & SSR_BITMASK_WITHOUT_REG_R) | (((uint64_t)(v & SSR_VALUE_MASK_REG_R)) << SSR_SHIFT_COUNT_REG_R); }
#pragma endregion // Mask & Macro to get registers (in minimal bit form)
/// <summary>
@ -322,7 +321,7 @@ static inline void set_register_r(ID48LIBX_STATE_REGISTERS* ssr, uint8_t v) { A
/// <param name="k96">key in pm3 order</param>
/// <param name="n56">nonce in pm3 order</param>
/// <returns>56-bit value p₅₅..p₀₀</returns>
static inline uint64_t calculate__p55_p00(const ID48LIB_KEY* k96, const ID48LIB_NONCE* n56) {
static inline uint64_t calculate__p55_p00(const ID48LIB_KEY *k96, const ID48LIB_NONCE *n56) {
// messy ... have to reverse the bits AND shift them into position,
// perform the addition, and then reverse bits again to return to
// native bit order (subscript is same as bit position).
@ -367,7 +366,7 @@ static inline uint64_t calculate__p55_p00(const ID48LIB_KEY* k96, const ID48LIB_
/// </summary>
/// <param name="p55_p00">56 bit value: p₅₅..p₀₀</param>
/// <returns>44-bit value: q₄₃..q₀₀</returns>
static inline uint64_t calculate__q43_q00(const uint64_t* p55_p00) {
static inline uint64_t calculate__q43_q00(const uint64_t *p55_p00) {
ASSERT(p55_p00 != nullptr);
static const uint64_t C_BITMASK44 = (1ull << 44) - 1u;
uint64_t result = (*p55_p00 >> 2);
@ -382,7 +381,7 @@ static inline uint64_t calculate__q43_q00(const uint64_t* p55_p00) {
/// Relies on old g22 bit (now in L00).
/// May modify G00, G03, G04, G05, G06, G13, G16
/// </summary>
static inline void g_successor(ID48LIBX_STATE_REGISTERS* ssr) {
static inline void g_successor(ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
ASSERT(!is_ssr_state_stable(ssr));
assign_single_ssr_bit(ssr, SSR_BIT_G00, test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_j));
@ -403,21 +402,22 @@ static inline void g_successor(ID48LIBX_STATE_REGISTERS* ssr) {
}
}
static inline ID48LIBX_STATE_REGISTERS init_id48libx_state_register(const ID48LIB_KEY* k96, const ID48LIB_NONCE* n56) {
static inline ID48LIBX_STATE_REGISTERS init_id48libx_state_register(const ID48LIB_KEY *k96, const ID48LIB_NONCE *n56) {
ASSERT(k96 != nullptr);
ASSERT(n56 != nullptr);
ID48LIBX_STATE_REGISTERS result; result.Raw = 0;
ID48LIBX_STATE_REGISTERS* const ssr = &result; // the pointer is constant ... not the value it points to
ID48LIBX_STATE_REGISTERS result;
result.Raw = 0;
ID48LIBX_STATE_REGISTERS *const ssr = &result; // the pointer is constant ... not the value it points to
const uint64_t p55_p00 = calculate__p55_p00(k96, n56);
// p55_p00 is used to set initial value of register l
if (true) {
static const uint8_t C_BITMASK7 = ((1u << 7) - 1u);
const uint8_t l = (
((uint8_t)(p55_p00 >> 55)) ^ // 0 0 0 0 0 0 p55
((uint8_t)(p55_p00 >> 51)) ^ // 0 0 p55 p54 p53 p52 p51
((uint8_t)(p55_p00 >> 45)) // p51 p50 p49 p48 p47 p46 p45
) & C_BITMASK7;
((uint8_t)(p55_p00 >> 55)) ^ // 0 0 0 0 0 0 p55
((uint8_t)(p55_p00 >> 51)) ^ // 0 0 p55 p54 p53 p52 p51
((uint8_t)(p55_p00 >> 45)) // p51 p50 p49 p48 p47 p46 p45
) & C_BITMASK7;
set_register_l(ssr, l);
ASSERT(l == get_register_l(ssr));
}
@ -442,13 +442,12 @@ static inline ID48LIBX_STATE_REGISTERS init_id48libx_state_register(const ID48LI
// input bits for `j` during init are q00..q19, with q19 used first
// For ease of use, I'll generate this as q00..q19, so the loop
// can test the lsb (and then shift it right one bit)
uint32_t q00_q19 = reverse_bits_32( ((uint32_t)q43_q00) << 12 );
uint32_t q00_q19 = reverse_bits_32(((uint32_t)q43_q00) << 12);
uint32_t q_lsb_next = q00_q19;
ssr->Raw |= 1u;
// G(g,0,j) twenty times, using q19, q18, ... q00 for `j`
for (uint8_t ix = 0; ix < 20; ++ix)
{
for (uint8_t ix = 0; ix < 20; ++ix) {
ASSERT(is_ssr_state_stable(ssr));
ssr->Raw <<= 1; // starts the process ... it's now an unstable value
ASSERT(!is_ssr_state_stable(ssr));
@ -485,20 +484,20 @@ static inline ID48LIBX_STATE_REGISTERS init_id48libx_state_register(const ID48LI
/// If ssr is in unstable state, caller is responsible for ensuring
/// the values have not changed.
/// </remarks>
static inline bool calculate_feedback_h(const ID48LIBX_STATE_REGISTERS* ssr) {
static inline bool calculate_feedback_h(const ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
// ( h₀₁ && h₀₈ ) || ( h₀₉ && h₁₁ ) || (!h₁₂ )
// \____ a1 ____/ \____ a2 ____/ \____ a3 ____/
// result == xor(a1,a2,a3)
bool a1 = is_ssr_state_stable(ssr) ?
test_single_ssr_bit(ssr, SSR_BIT_H01) && test_single_ssr_bit(ssr, SSR_BIT_H08) :
test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H01) && test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H08);
test_single_ssr_bit(ssr, SSR_BIT_H01) && test_single_ssr_bit(ssr, SSR_BIT_H08) :
test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H01) && test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H08);
bool a2 = is_ssr_state_stable(ssr) ?
test_single_ssr_bit(ssr, SSR_BIT_H09) && test_single_ssr_bit(ssr, SSR_BIT_H11) :
test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H09) && test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H11);
test_single_ssr_bit(ssr, SSR_BIT_H09) && test_single_ssr_bit(ssr, SSR_BIT_H11) :
test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H09) && test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H11);
bool a3 = is_ssr_state_stable(ssr) ?
!test_single_ssr_bit(ssr, SSR_BIT_H12) :
!test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H12);
!test_single_ssr_bit(ssr, SSR_BIT_H12) :
!test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_H12);
bool result = false;
if (a1) result = !result;
if (a2) result = !result;
@ -510,7 +509,7 @@ static inline bool calculate_feedback_h(const ID48LIBX_STATE_REGISTERS* ssr) {
/// fₗ(...) matches the research paper, definition 3.4
/// hard-coded to use bits for calculation of 'a'
/// </summary>
static inline bool calculate_feedback_l(const ID48LIBX_STATE_REGISTERS* ssr) {
static inline bool calculate_feedback_l(const ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
// a = fₗ( g00 g04 g06 g13 g18 h03 ) ⊕ g22 ⊕ r02 ⊕ r06
// fₗ( x₀ x₁ x₂ x₃ x₄ x₅ )
@ -534,7 +533,7 @@ static inline bool calculate_feedback_l(const ID48LIBX_STATE_REGISTERS* ssr) {
/// fₘ(...) matches the research paper, definition 3.5
/// hard-coded to use bits for calculation of 'b'
/// </summary>
static inline bool calculate_feedback_m(const ID48LIBX_STATE_REGISTERS* ssr) {
static inline bool calculate_feedback_m(const ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
// b = fₘ( g01 g05 g10 g15 h00 h07 ) ⊕ l00 ⊕ l03 ⊕ l06
// fₘ( x₀ x₁ x₂ x₃ x₄ x₅ )
@ -558,7 +557,7 @@ static inline bool calculate_feedback_m(const ID48LIBX_STATE_REGISTERS* ssr) {
/// fᵣ(...) matches the research paper, definition 3.6
/// hard-coded to use bits for calculation of 'c'
/// </summary>
static inline bool calculate_feedback_r(const ID48LIBX_STATE_REGISTERS* ssr) {
static inline bool calculate_feedback_r(const ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
ASSERT(!is_ssr_state_stable(ssr));
// c = fᵣ( g02 g03⊕i g09 g14 g16 h01 ) ⊕ m00 ⊕ m03 ⊕ m06
@ -583,7 +582,7 @@ static inline bool calculate_feedback_r(const ID48LIBX_STATE_REGISTERS* ssr) {
/// Matches the research paper, definition 3.7
/// See also Definition 3.2, defining that parameter as `j`.
/// </summary>
static inline bool calculate_j(const ID48LIBX_STATE_REGISTERS* ssr) {
static inline bool calculate_j(const ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
// g := G(g, i, l₀₁ ⊕ m₀₆ ⊕ h₀₂ ⊕ h₀₈ ⊕ h₁₂)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^------ calculates `j`
@ -602,21 +601,21 @@ static inline bool calculate_j(const ID48LIBX_STATE_REGISTERS* ssr) {
/// Calculates a, b, c, j and new value for H₀₀.
/// These are the only bits changed by this function.
/// </summary>
static inline void calculate_temporaries(ID48LIBX_STATE_REGISTERS* ssr) {
static inline void calculate_temporaries(ID48LIBX_STATE_REGISTERS *ssr) {
ASSERT(ssr != nullptr);
#pragma region // to be removed after all is validated
#pragma region // to be removed after all is validated
static const uint64_t bits_must_remain_same_mask =
~(
(1ull << SSR_UNSTABLE_BIT_a) |
(1ull << SSR_UNSTABLE_BIT_b) |
(1ull << SSR_UNSTABLE_BIT_c) |
(1ull << SSR_UNSTABLE_BIT_j) |
(1ull << SSR_UNSTABLE_NEW_BIT_H00)
~(
(1ull << SSR_UNSTABLE_BIT_a) |
(1ull << SSR_UNSTABLE_BIT_b) |
(1ull << SSR_UNSTABLE_BIT_c) |
(1ull << SSR_UNSTABLE_BIT_j) |
(1ull << SSR_UNSTABLE_NEW_BIT_H00)
);
const uint64_t backup = ssr->Raw & bits_must_remain_same_mask;
(void)backup; // to avoid warning about unused variable
#pragma endregion // to be removed after all is validated
#pragma endregion // to be removed after all is validated
// Only bits that change value: H00, a, b, c, j
@ -643,25 +642,26 @@ static inline void calculate_temporaries(ID48LIBX_STATE_REGISTERS* ssr) {
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_M03)) flip_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c);
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_OLD_BIT_M06)) flip_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c);
#pragma region // to be removed after all is validated
#pragma region // to be removed after all is validated
const uint64_t chk = ssr->Raw & bits_must_remain_same_mask;
(void)chk; // to avoid warning about unused variable
ASSERT(chk == backup);
#pragma endregion // to be removed after all is validated
#pragma endregion // to be removed after all is validated
return;
}
static inline OUTPUT_INDEX2 calculate_output_index(const ID48LIBX_STATE_REGISTERS* ssr) {
static inline OUTPUT_INDEX2 calculate_output_index(const ID48LIBX_STATE_REGISTERS *ssr) {
// Fₒ( abc l₀l₂l₃l₄l₅l₆ m₀m₁m₃m₅ r₀r₁r₂r₃r₄r₅r₆ )
// msb 19 ---^ lsb 00 ---^^
ASSERT(ssr != nullptr);
ASSERT(!is_ssr_state_stable(ssr));
OUTPUT_INDEX2 result; result.Raw = 0;
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_a )) result.Raw |= (1u << 19);
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_b )) result.Raw |= (1u << 18);
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c )) result.Raw |= (1u << 17);
OUTPUT_INDEX2 result;
result.Raw = 0;
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_a)) result.Raw |= (1u << 19);
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_b)) result.Raw |= (1u << 18);
if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c)) result.Raw |= (1u << 17);
//bool bit17 = test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_c);
//if (test_single_ssr_bit(ssr, SSR_UNSTABLE_BIT_i) ) bit17 = !bit17;
//if (bit17 ) result.Raw |= (1u << 17);
@ -686,7 +686,7 @@ static inline OUTPUT_INDEX2 calculate_output_index(const ID48LIBX_STATE_REGISTER
}
// returns a single bit corresponding to the output bit for this transition
static inline bool calculate_successor_state(ID48LIBX_STATE_REGISTERS* ssr, bool i) {
static inline bool calculate_successor_state(ID48LIBX_STATE_REGISTERS *ssr, bool i) {
ASSERT(ssr != nullptr);
ASSERT(is_ssr_state_stable(ssr));
@ -748,14 +748,15 @@ static inline bool calculate_successor_state(ID48LIBX_STATE_REGISTERS* ssr, bool
/// by one bit each iteration (allowing least significant bit
/// to always be the input bit).
/// </summary>
static inline INPUT_BITS2 get_key_input_bits(const ID48LIB_KEY* k) {
static inline INPUT_BITS2 get_key_input_bits(const ID48LIB_KEY *k) {
ASSERT(k != nullptr);
// Per research paper, key bit 39 is used first.
// So, what should end up in result is: 0²⁴ k₀₀..K₃₉
// This allows simply shifting the lsb out each cycle....
INPUT_BITS2 result; result.Raw = 0;
INPUT_BITS2 result;
result.Raw = 0;
// k[ 0] :== K₉₅..K₈₈
// ...
@ -775,19 +776,19 @@ static inline INPUT_BITS2 get_key_input_bits(const ID48LIB_KEY* k) {
return result;
}
static inline bool shift_out_next_input_bit(INPUT_BITS2* inputs) {
static inline bool shift_out_next_input_bit(INPUT_BITS2 *inputs) {
ASSERT(inputs != nullptr);
bool result = inputs->Raw & 1ull;
inputs->Raw >>= 1;
return result;
}
static inline void shift_in_next_output_bit(OUTPUT_BITS2* outputs, bool v) {
static inline void shift_in_next_output_bit(OUTPUT_BITS2 *outputs, bool v) {
ASSERT(outputs != nullptr);
outputs->Raw <<= 1;
if (v) outputs->Raw |= 1ull;
}
static inline void extract_frn(const OUTPUT_BITS2* outputs, ID48LIB_FRN* frn28_out) {
static inline void extract_frn(const OUTPUT_BITS2 *outputs, ID48LIB_FRN *frn28_out) {
ASSERT(outputs != nullptr);
ASSERT(frn28_out != nullptr);
@ -802,7 +803,7 @@ static inline void extract_frn(const OUTPUT_BITS2* outputs, ID48LIB_FRN* frn28_o
frn28_out->frn[2] = (uint8_t)((tmp >> (8 * 1)) & 0xFFu);
frn28_out->frn[3] = (uint8_t)((tmp >> (8 * 0)) & 0xFFu);
}
static inline void extract_grn(const OUTPUT_BITS2* outputs, ID48LIB_GRN* grn20_out) {
static inline void extract_grn(const OUTPUT_BITS2 *outputs, ID48LIB_GRN *grn20_out) {
ASSERT(outputs != nullptr);
ASSERT(grn20_out != nullptr);
memset(grn20_out, 0, sizeof(ID48LIB_GRN));
@ -817,12 +818,11 @@ static inline void extract_grn(const OUTPUT_BITS2* outputs, ID48LIB_GRN* grn20_o
}
static void retro_generator_impl(
const ID48LIB_KEY* k,
const ID48LIB_NONCE* n,
ID48LIB_FRN* frn28_out,
ID48LIB_GRN* grn20_out
)
{
const ID48LIB_KEY *k,
const ID48LIB_NONCE *n,
ID48LIB_FRN *frn28_out,
ID48LIB_GRN *grn20_out
) {
ASSERT(k != nullptr);
ASSERT(n != nullptr);
ASSERT(frn28_out != nullptr);
@ -834,7 +834,8 @@ static void retro_generator_impl(
// get 55-bit successor state input
INPUT_BITS2 inputs = get_key_input_bits(k);
OUTPUT_BITS2 outputs; outputs.Raw = 0ull;
OUTPUT_BITS2 outputs;
outputs.Raw = 0ull;
for (uint8_t ix = 0; ix < 55; ix++) {
ASSERT(is_ssr_state_stable(&ssr));
@ -865,9 +866,10 @@ static void retro_generator_impl(
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// internal function
ID48LIBX_SUCCESSOR_RESULT id48libx_retro003_successor(const ID48LIBX_STATE_REGISTERS* initial_state, uint8_t input_bit) {
ID48LIBX_SUCCESSOR_RESULT id48libx_retro003_successor(const ID48LIBX_STATE_REGISTERS *initial_state, uint8_t input_bit) {
ASSERT(initial_state != nullptr);
ID48LIBX_SUCCESSOR_RESULT r; memset(&r, 0, sizeof(ID48LIBX_SUCCESSOR_RESULT));
ID48LIBX_SUCCESSOR_RESULT r;
memset(&r, 0, sizeof(ID48LIBX_SUCCESSOR_RESULT));
ID48LIBX_STATE_REGISTERS s = *initial_state;
bool output_bit = calculate_successor_state(&s, !!input_bit);
r.state.Raw = s.Raw;
@ -875,23 +877,23 @@ ID48LIBX_SUCCESSOR_RESULT id48libx_retro003_successor(const ID48LIBX_STATE_REGIS
return r;
}
// internal function
ID48LIBX_STATE_REGISTERS id48libx_retro003_init(const ID48LIB_KEY* key, const ID48LIB_NONCE* nonce) {
ID48LIBX_STATE_REGISTERS id48libx_retro003_init(const ID48LIB_KEY *key, const ID48LIB_NONCE *nonce) {
ASSERT(key != nullptr);
ASSERT(nonce != nullptr);
ID48LIBX_STATE_REGISTERS ssr = init_id48libx_state_register(key, nonce);
ID48LIBX_STATE_REGISTERS result; memset(&result, 0, sizeof(ID48LIBX_STATE_REGISTERS));
ID48LIBX_STATE_REGISTERS result;
memset(&result, 0, sizeof(ID48LIBX_STATE_REGISTERS));
result.Raw = ssr.Raw;
return result;
}
// public API
void id48lib_generator(
const ID48LIB_KEY* k,
const ID48LIB_NONCE* n,
ID48LIB_FRN* frn28_out,
ID48LIB_GRN* grn20_out
)
{
const ID48LIB_KEY *k,
const ID48LIB_NONCE *n,
ID48LIB_FRN *frn28_out,
ID48LIB_GRN *grn20_out
) {
retro_generator_impl(k, n, frn28_out, grn20_out);
}

View file

@ -45,8 +45,8 @@ typedef struct _ID48LIBX_SUCCESSOR_RESULT {
} ID48LIBX_SUCCESSOR_RESULT;
// the following are used in key recovery but implemented in id48.c
ID48LIBX_SUCCESSOR_RESULT id48libx_retro003_successor(const ID48LIBX_STATE_REGISTERS* initial_state, uint8_t input_bit);
ID48LIBX_STATE_REGISTERS id48libx_retro003_init (const ID48LIB_KEY* key, const ID48LIB_NONCE* nonce);
ID48LIBX_SUCCESSOR_RESULT id48libx_retro003_successor(const ID48LIBX_STATE_REGISTERS *initial_state, uint8_t input_bit);
ID48LIBX_STATE_REGISTERS id48libx_retro003_init(const ID48LIB_KEY *key, const ID48LIB_NONCE *nonce);
bool id48libx_output_lookup(uint32_t output_index);

View file

@ -116,8 +116,8 @@ typedef struct _RECOVERY_STATE {
} RECOVERY_STATE;
// Need equivalent of the following two function pointers:
typedef ID48LIBX_SUCCESSOR_RESULT (*ID48LIB_SUCCESSOR_FN)(const ID48LIBX_STATE_REGISTERS* initial_state, uint8_t input_bit);
typedef ID48LIBX_STATE_REGISTERS(*ID48LIB_INIT_FN )(const ID48LIB_KEY* key, const ID48LIB_NONCE* nonce);
typedef ID48LIBX_SUCCESSOR_RESULT(*ID48LIB_SUCCESSOR_FN)(const ID48LIBX_STATE_REGISTERS *initial_state, uint8_t input_bit);
typedef ID48LIBX_STATE_REGISTERS(*ID48LIB_INIT_FN)(const ID48LIB_KEY *key, const ID48LIB_NONCE *nonce);
static const ID48LIB_INIT_FN init_fn = id48libx_retro003_init;
static const ID48LIB_SUCCESSOR_FN successor_fn = id48libx_retro003_successor;
@ -129,7 +129,7 @@ static const ID48LIB_SUCCESSOR_FN successor_fn = id48libx_retro003_successor;
/// <param name="input_partial_key">Key with K₉₅..K₄₈, in PM3 compatible layout</param>
/// <param name="more_bits">0 K₃₃..K₄₇ (to support simple incrementing input)</param>
/// <returns>PM3-formatted key: K₉₅..K₃₃ 0³³</returns>
static ID48LIB_KEY create_partial_key56(const ID48LIB_KEY * input_partial_key, uint8_t k47_to_k40) {
static ID48LIB_KEY create_partial_key56(const ID48LIB_KEY *input_partial_key, uint8_t k47_to_k40) {
ID48LIB_KEY result;
result.k[ 0] = input_partial_key->k[0]; // k[ 0] :== K₉₅..K₈₈
result.k[ 1] = input_partial_key->k[1]; // k[ 1] :== K₈₇..K₈₀
@ -153,7 +153,7 @@ static ID48LIB_KEY create_partial_key56(const ID48LIB_KEY * input_partial_key, u
/// <param name="input_frn">PM3 compatible input for frn</param>
/// <param name="input_grn">PM3 compatible input for grn</param>
/// <returns></returns>
static EXPECTED_OUTPUT_BITS create_expected_output_bits(const ID48LIB_FRN* input_frn, const ID48LIB_GRN* input_grn) {
static EXPECTED_OUTPUT_BITS create_expected_output_bits(const ID48LIB_FRN *input_frn, const ID48LIB_GRN *input_grn) {
// inputs:
// frn[ 0] :== O₀₀..O₀₇
// frn[ 1] :== O₀₈..O₁₅
@ -162,15 +162,23 @@ static EXPECTED_OUTPUT_BITS create_expected_output_bits(const ID48LIB_FRN* input
// grn[ 0] :== O₂₈ .. O₃₅
// grn[ 1] :== O₃₆ .. O₄₃
// grn[ 2] :== O₄₄..O₄₇ 0000
EXPECTED_OUTPUT_BITS result; result.Raw = 0u;
result.Raw <<= 4; result.Raw |= reverse_bits_08(input_grn->grn[2] & 0xF0u); // adds grn₁₉..grn₁₆ aka O₄₇..O₄₄
result.Raw <<= 8; result.Raw |= reverse_bits_08(input_grn->grn[1] & 0xFFu); // adds grn₁₅..grn₀₈ aka O₄₃..O₃₆
result.Raw <<= 8; result.Raw |= reverse_bits_08(input_grn->grn[0] & 0xFFu); // adds grn₀₇..grn₀₀ aka O₃₅..O₂₈
EXPECTED_OUTPUT_BITS result;
result.Raw = 0u;
result.Raw <<= 4;
result.Raw |= reverse_bits_08(input_grn->grn[2] & 0xF0u); // adds grn₁₉..grn₁₆ aka O₄₇..O₄₄
result.Raw <<= 8;
result.Raw |= reverse_bits_08(input_grn->grn[1] & 0xFFu); // adds grn₁₅..grn₀₈ aka O₄₃..O₃₆
result.Raw <<= 8;
result.Raw |= reverse_bits_08(input_grn->grn[0] & 0xFFu); // adds grn₀₇..grn₀₀ aka O₃₅..O₂₈
result.Raw <<= 4; result.Raw |= reverse_bits_08(input_frn->frn[3] & 0xF0u); // adds frn₂₇..frn₂₄ aka O₂₇..O₂₄
result.Raw <<= 8; result.Raw |= reverse_bits_08(input_frn->frn[2] & 0xFFu); // adds frn₂₃..frn₁₆ aka O₂₃..O₁₆
result.Raw <<= 8; result.Raw |= reverse_bits_08(input_frn->frn[1] & 0xFFu); // adds frn₁₅..frn₀₈ aka O₁₅..O₀₈
result.Raw <<= 8; result.Raw |= reverse_bits_08(input_frn->frn[0] & 0xFFu); // adds frn₀₇..frn₀₀ aka O₀₇..O₀₀
result.Raw <<= 4;
result.Raw |= reverse_bits_08(input_frn->frn[3] & 0xF0u); // adds frn₂₇..frn₂₄ aka O₂₇..O₂₄
result.Raw <<= 8;
result.Raw |= reverse_bits_08(input_frn->frn[2] & 0xFFu); // adds frn₂₃..frn₁₆ aka O₂₃..O₁₆
result.Raw <<= 8;
result.Raw |= reverse_bits_08(input_frn->frn[1] & 0xFFu); // adds frn₁₅..frn₀₈ aka O₁₅..O₀₈
result.Raw <<= 8;
result.Raw |= reverse_bits_08(input_frn->frn[0] & 0xFFu); // adds frn₀₇..frn₀₀ aka O₀₇..O₀₀
return result;
}
/// <summary>
@ -180,7 +188,7 @@ static EXPECTED_OUTPUT_BITS create_expected_output_bits(const ID48LIB_FRN* input
/// </summary>
/// <param name="recovery_state">A value in the range [0,55]</param>
/// <returns>Zero or non-zero (boolean) corresponding to the expected output.</returns>
static bool get_expected_output_bit(const RECOVERY_STATE* recovery_state, uint8_t current_state_index) {
static bool get_expected_output_bit(const RECOVERY_STATE *recovery_state, uint8_t current_state_index) {
ASSERT(recovery_state != nullptr);
ASSERT(current_state_index >= 7);
ASSERT(current_state_index <= 55);
@ -188,7 +196,7 @@ static bool get_expected_output_bit(const RECOVERY_STATE* recovery_state, uint8_
return !!(shifted & 0x1u); // return the single bit result
}
static void restart_and_calculate_s00(RECOVERY_STATE* s, const KEY_BITS_K47_TO_K00* k_low) {
static void restart_and_calculate_s00(RECOVERY_STATE *s, const KEY_BITS_K47_TO_K00 *k_low) {
ASSERT(s != nullptr);
ASSERT(k_low != nullptr);
memset(&(s->states[0]), 0xAA, sizeof(ID48LIBX_STATE_REGISTERS) * MAXIMUM_STATE_HISTORY);
@ -197,11 +205,11 @@ static void restart_and_calculate_s00(RECOVERY_STATE* s, const KEY_BITS_K47_TO_K
s->states[0] = init_fn(&start_56b_key, &(s->known_nonce));
}
static bool validate_output_from_additional_fifteen_zero_bits(RECOVERY_STATE* s) {
static bool validate_output_from_additional_fifteen_zero_bits(RECOVERY_STATE *s) {
bool all_still_match = true;
for (uint8_t i = 0; all_still_match && i < 15; i++) {
const uint8_t src_idx = 40 + i;
const ID48LIBX_STATE_REGISTERS* state = &(s->states[src_idx]);
const ID48LIBX_STATE_REGISTERS *state = &(s->states[src_idx]);
ID48LIBX_SUCCESSOR_RESULT r = successor_fn(state, 0);
bool expected_result = get_expected_output_bit(s, src_idx);
if (expected_result != (!!r.output)) {
@ -220,12 +228,11 @@ static bool validate_output_from_additional_fifteen_zero_bits(RECOVERY_STATE* s)
RECOVERY_STATE g_S = { 0 };
static void init(
const ID48LIB_KEY * input_partial_key,
const ID48LIB_NONCE * input_nonce,
const ID48LIB_FRN * input_frn,
const ID48LIB_GRN * input_grn
)
{
const ID48LIB_KEY *input_partial_key,
const ID48LIB_NONCE *input_nonce,
const ID48LIB_FRN *input_frn,
const ID48LIB_GRN *input_grn
) {
memset(&g_S, 0, sizeof(RECOVERY_STATE));
memset(&(g_S.states[0]), 0xAA, sizeof(ID48LIBX_STATE_REGISTERS) * MAXIMUM_STATE_HISTORY);
g_S.known_k95_to_k48.k[0] = input_partial_key->k[0];
@ -240,7 +247,7 @@ static void init(
g_S.is_fresh_initialization = true;
}
static bool get_next_potential_key(
ID48LIB_KEY* potential_key_output
ID48LIB_KEY *potential_key_output
) {
memset(potential_key_output, 0, sizeof(ID48LIB_KEY));
@ -271,8 +278,7 @@ static bool get_next_potential_key(
g_S.is_fresh_initialization = false;
k_low.Raw = 0ull;
current_key_bit_shift = 47;
}
else {
} else {
// by definition, a returned potential key had all the bits defined
current_key_bit_shift = 0;
k_low = g_S.last_returned_potential_key;
@ -417,16 +423,15 @@ static bool get_next_potential_key(
void id48lib_key_recovery_init(
const ID48LIB_KEY * input_partial_key,
const ID48LIB_NONCE * input_nonce,
const ID48LIB_FRN * input_frn,
const ID48LIB_GRN * input_grn
)
{
const ID48LIB_KEY *input_partial_key,
const ID48LIB_NONCE *input_nonce,
const ID48LIB_FRN *input_frn,
const ID48LIB_GRN *input_grn
) {
init(input_partial_key, input_nonce, input_frn, input_grn);
}
bool id48lib_key_recovery_next(
ID48LIB_KEY* potential_key_output
ID48LIB_KEY *potential_key_output
) {
return get_next_potential_key(potential_key_output);
}

View file

@ -740,7 +740,7 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n
memcpy(carddata + (MFBLOCK_SIZE * (mfFirstBlockOfSector(sectorNo) + blockNo)), data, MFBLOCK_SIZE);
PrintAndLogEx(INPLACE, "Sector... " _YELLOW_("%2d") " block..." _YELLOW_("%2d") " ( " _GREEN_("ok") " )", sectorNo, blockNo);
} else {
PrintAndLogEx(FAILED, "\nSector... %2d Block... %2d ( " _RED_("fail") " )" , sectorNo, blockNo);
PrintAndLogEx(FAILED, "\nSector... %2d Block... %2d ( " _RED_("fail") " )", sectorNo, blockNo);
}
} else {
PrintAndLogEx(WARNING, "Timeout reading sector... %2d block... %2d", sectorNo, blockNo);
@ -8464,11 +8464,11 @@ static void parse_gdm_cfg(const uint8_t *d) {
PrintAndLogEx(SUCCESS, "------------------- " _CYAN_("GDM Configuration") " -----------------------------------------");
PrintAndLogEx(SUCCESS, _YELLOW_("%s"), sprint_hex_inrow(d, MFBLOCK_SIZE));
PrintAndLogEx(SUCCESS, _YELLOW_("%02X%02X") "............................ %s %s"
, d[0]
, d[1]
, (d[0] == 0x85 && d[1] == 0x00) ? "Magic wakeup disabled" : _GREEN_("Magic wakeup enabled")
, (d[0] == 0x85 && d[1] == 0x00) ? "" : ((d[0] == 0x7A && d[1] == 0xFF) ? _GREEN_("with GDM cfg block access") : _RED_(", no GDM cfg block access"))
);
, d[0]
, d[1]
, (d[0] == 0x85 && d[1] == 0x00) ? "Magic wakeup disabled" : _GREEN_("Magic wakeup enabled")
, (d[0] == 0x85 && d[1] == 0x00) ? "" : ((d[0] == 0x7A && d[1] == 0xFF) ? _GREEN_("with GDM cfg block access") : _RED_(", no GDM cfg block access"))
);
PrintAndLogEx(SUCCESS, "...." _YELLOW_("%02X") ".......................... Magic wakeup style %s", d[2], ((d[2] == 0x85) ? "GDM 20(7)/23" : "Gen1a 40(7)/43"));
PrintAndLogEx(SUCCESS, "......" _YELLOW_("%02X%02X%02X") ".................... n/a", d[3], d[4], d[5]);
PrintAndLogEx(SUCCESS, "............" _YELLOW_("%02X") ".................. %s", d[6], (d[6] == 0x5A) ? "Key B use blocked when readable by ACL" : "Key B use allowed when readable by ACL");

View file

@ -5374,10 +5374,10 @@ static int CmdHF14AMfuWipe(const char *Cmd) {
// UL / NTAG with PWD/PACK
if ((tagtype & (MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1 | MFU_TT_UL_NANO_40 |
MFU_TT_NTAG_210u | MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C |
MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216 | MFU_TT_NTAG_216_F |
MFU_TT_NTAG_I2C_1K | MFU_TT_NTAG_I2C_2K | MFU_TT_NTAG_I2C_1K_PLUS | MFU_TT_NTAG_I2C_2K_PLUS
))) {
MFU_TT_NTAG_210u | MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C |
MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216 | MFU_TT_NTAG_216_F |
MFU_TT_NTAG_I2C_1K | MFU_TT_NTAG_I2C_2K | MFU_TT_NTAG_I2C_1K_PLUS | MFU_TT_NTAG_I2C_2K_PLUS
))) {
// cfg 1

View file

@ -423,6 +423,7 @@ const static vocabulary_t vocabulary[] = {
{ 0, "hf mfu restore" },
{ 0, "hf mfu tamper" },
{ 1, "hf mfu view" },
{ 0, "hf mfu wipe" },
{ 0, "hf mfu wrbl" },
{ 0, "hf mfu eload" },
{ 0, "hf mfu esave" },
@ -512,6 +513,8 @@ const static vocabulary_t vocabulary[] = {
{ 1, "hf vas help" },
{ 0, "hf vas reader" },
{ 1, "hf vas decrypt" },
{ 1, "hf waveshare help" },
{ 1, "hf waveshare load" },
{ 1, "hf xerox help" },
{ 1, "hf xerox list" },
{ 0, "hf xerox info" },

View file

@ -3061,7 +3061,7 @@
},
"hf help": {
"command": "hf help",
"description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
"description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
"notes": [
"hf list --frame -> show frame delay times",
"hf list -1 -> use trace buffer"
@ -7084,6 +7084,20 @@
],
"usage": "hf mfu view [-hvz] -f <fn>"
},
"hf mfu wipe": {
"command": "hf mfu wipe",
"description": "Wipe card to zeros. It will ignore block0,1,2,3 you will need to call it with password in order to wipe the config and sett default pwd/pack Abort by pressing a key New password... FFFFFFFF",
"notes": [
"hf mfu wipe"
],
"offline": false,
"options": [
"-h, --help This help",
"-k, --key <hex> Key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)",
"-l Swap entered key's endianness"
],
"usage": "hf mfu wipe [-hl] [-k <hex>]"
},
"hf mfu wrbl": {
"command": "hf mfu wrbl",
"description": "Write a block. It autodetects card type.",
@ -7722,6 +7736,28 @@
],
"usage": "hf vas reader [-h@v] [--pid <str>] [-f <fn>] [--url <str>]"
},
"hf waveshare help": {
"command": "hf waveshare help",
"description": "help This help load Load image file to Waveshare NFC ePaper --------------------------------------------------------------------------------------- hf waveshare load available offline: yes Load image file to Waveshare NFC ePaper",
"notes": [
"hf waveshare load -f myfile -m 0 -> 2.13 inch e-paper ( 122, 250 )",
"hf waveshare load -f myfile -m 1 -> 2.9 inch e-paper ( 296, 128 )",
"hf waveshare load -f myfile -m 2 -> 4.2 inch e-paper ( 400, 300 )",
"hf waveshare load -f myfile -m 3 -> 7.5 inch e-paper ( 800, 480 )",
"hf waveshare load -f myfile -m 4 -> 2.7 inch e-paper ( 176, 276 )",
"hf waveshare load -f myfile -m 5 -> 2.13 inch e-paper B (with red) ( 104, 212 )",
"hf waveshare load -f myfile -m 6 -> 1.54 inch e-paper B (with red) ( 200, 200 )",
"hf waveshare load -f myfile -m 7 -> 7.5 inch e-paper HD ( 880, 528 )"
],
"offline": true,
"options": [
"-h, --help This help",
"-m <nr> model number [0 - 7] of your tag",
"-f, --file <fn> specify image to upload to tag",
"-s, --save <fn> save paletized version in file"
],
"usage": "hf waveshare load [-h] -m <nr> -f <fn> [-s <fn>]"
},
"hf xerox dump": {
"command": "hf xerox dump",
"description": "Dump all memory from a Fuji/Xerox tag ISO/IEC 14443 type B based communications",
@ -8039,9 +8075,10 @@
"offline": false,
"options": [
"-h, --help This help",
"-a, --arg <dec> argument byte"
"-a, --arg <dec> argument byte",
"-b <str> UniSniff arg: 14a, 14b, 15, iclass"
],
"usage": "hw standalone [-h] [-a <dec>]"
"usage": "hw standalone [-h] [-a <dec>] [-b <str>]"
},
"hw status": {
"command": "hw status",
@ -8889,7 +8926,7 @@
},
"lf em 4x70 help": {
"command": "lf em 4x70 help",
"description": "help This help --------------------------------------------------------------------------------------- lf em 4x70 brute available offline: no Optimized partial key-update attack of 16-bit key block 7, 8 or 9 of an EM4x70 This attack does NOT write anything to the tag. Before starting this attack, 0000 must be written to the 16-bit key block: 'lf em 4x70 write -b 9 -d 0000'. After success, the 16-bit key block have to be restored with the key found: 'lf em 4x70 write -b 9 -d c0de'",
"description": "help This help recover Recover remaining key from partial key --------------------------------------------------------------------------------------- lf em 4x70 brute available offline: no Optimized partial key-update attack of 16-bit key block 7, 8 or 9 of an EM4x70 This attack does NOT write anything to the tag. Before starting this attack, 0000 must be written to the 16-bit key block: 'lf em 4x70 write -b 9 -d 0000'. After success, the 16-bit key block have to be restored with the key found: 'lf em 4x70 write -b 9 -d c0de'",
"notes": [
"lf em 4x70 brute -b 9 --rnd 45F54ADA252AAC --frn 4866BB70 -> bruteforcing key bits k95...k80"
],
@ -8925,7 +8962,7 @@
"lf em 4x70 recover --key F32AA98CF5BE --rnd 45F54ADA252AAC --frn 4866BB70 --grn 9BD180 (pm3 test key)",
"lf em 4x70 recover --key A090A0A02080 --rnd 3FFE1FB6CC513F --frn F355F1A0 --grn 609D60 (research paper key)"
],
"offline": false,
"offline": true,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
@ -8936,6 +8973,36 @@
],
"usage": "lf em 4x70 recover [-h] [--par] -k <hex> --rnd <hex> --frn <hex> --grn <hex>"
},
"lf em 4x70 setkey": {
"command": "lf em 4x70 setkey",
"description": "Write new 96-bit key to tag",
"notes": [
"lf em 4x70 setkey -k F32AA98CF5BE4ADFA6D3480B (pm3 test key)",
"lf em 4x70 setkey -k A090A0A02080000000000000 (research paper key)"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-k, --key <hex> Key as 12 hex bytes"
],
"usage": "lf em 4x70 setkey [-h] [--par] -k <hex>"
},
"lf em 4x70 setpin": {
"command": "lf em 4x70 setpin",
"description": "Write new PIN",
"notes": [
"lf em 4x70 setpin -p 11223344 -> Write new PIN",
"lf em 4x70 setpin -p 11223344 --par -> Write new PIN using parity commands"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-p, --pin <hex> pin, 4 bytes"
],
"usage": "lf em 4x70 setpin [-h] [--par] -p <hex>"
},
"lf em 4x70 unlock": {
"command": "lf em 4x70 unlock",
"description": "Unlock EM4x70 by sending PIN Default pin may be: AAAAAAAA 00000000",
@ -8967,36 +9034,6 @@
],
"usage": "lf em 4x70 write [-h] [--par] -b <dec> -d <hex>"
},
"lf em 4x70 setkey": {
"command": "lf em 4x70 setkey",
"description": "Write new 96-bit key to tag",
"notes": [
"lf em 4x70 setkey -k F32AA98CF5BE4ADFA6D3480B (pm3 test key)",
"lf em 4x70 setkey -k A090A0A02080000000000000 (research paper key)"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-k, --key <hex> Key as 12 hex bytes"
],
"usage": "lf em 4x70 setkey [-h] [--par] -k <hex>"
},
"lf em 4x70 setpin": {
"command": "lf em 4x70 setpin",
"description": "Write PIN",
"notes": [
"lf em 4x70 setpin -p 11223344 -> Write new PIN",
"lf em 4x70 setpin -p 11223344 --par -> Write new PIN using parity commands"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-p, --pin <hex> pin, 4 bytes"
],
"usage": "lf em 4x70 setpin [-h] [--par] -p <hex>"
},
"lf em help": {
"command": "lf em help",
"description": "help This help 410x { EM 4102 commands... } 4x05 { EM 4205 / 4305 / 4369 / 4469 commands... } 4x50 { EM 4350 / 4450 commands... } 4x70 { EM 4070 / 4170 commands... } ======================================================================================= lf em 410x { EM 4102 commands... } --------------------------------------------------------------------------------------- lf em 410x help available offline: yes help This help demod demodulate a EM410x tag from the GraphBuffer --------------------------------------------------------------------------------------- lf em 410x demod available offline: yes Try to find EM 410x preamble, if found decode / descramble data",
@ -12529,8 +12566,8 @@
}
},
"metadata": {
"commands_extracted": 723,
"commands_extracted": 725,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2024-03-12T00:21:47"
"extracted_on": "2024-03-14T10:14:29"
}
}

View file

@ -610,6 +610,7 @@ Check column "offline" for their availability.
|`hf mfu restore `|N |`Restore a dump file onto a tag`
|`hf mfu tamper `|N |`NTAG 213TT - Configure the tamper feature`
|`hf mfu view `|Y |`Display content from tag dump file`
|`hf mfu wipe `|N |`Wipe card to zeros and default key`
|`hf mfu wrbl `|N |`Write block`
|`hf mfu eload `|N |`Upload file into emulator memory`
|`hf mfu esave `|N |`Save emulator memory to file`
@ -773,6 +774,16 @@ Check column "offline" for their availability.
|`hf vas decrypt `|Y |`Decrypt a previously captured VAS cryptogram`
### hf waveshare
{ Waveshare NFC ePaper... }
|command |offline |description
|------- |------- |-----------
|`hf waveshare help `|Y |`This help`
|`hf waveshare load `|Y |`Load image file to Waveshare NFC ePaper`
### hf xerox
{ Fuji/Xerox cartridge RFIDs... }
@ -960,8 +971,8 @@ Check column "offline" for their availability.
|`lf em 4x70 write `|N |`Write EM4x70`
|`lf em 4x70 unlock `|N |`Unlock EM4x70 for writing`
|`lf em 4x70 auth `|N |`Authenticate EM4x70`
|`lf em 4x70 setpin `|N |`Write new PIN`
|`lf em 4x70 setkey `|N |`Write new key`
|`lf em 4x70 setpin `|N |`Write PIN`
|`lf em 4x70 setkey `|N |`Write key`
|`lf em 4x70 recover `|Y |`Recover remaining key from partial key`
|`lf em 4x70 autorecover `|N |`Recover entire key from writable tag`