Applies make style

This commit is contained in:
romuald@libnfc.org 2013-01-30 14:54:27 +00:00
parent 22fa583429
commit 776b0d3f79
13 changed files with 2458 additions and 2741 deletions

View File

@ -24,49 +24,49 @@
static uint8_t filterlut[1 << 20]; static uint8_t filterlut[1 << 20];
static void __attribute__((constructor)) fill_lut() static void __attribute__((constructor)) fill_lut()
{ {
uint32_t i; uint32_t i;
for(i = 0; i < 1 << 20; ++i) for (i = 0; i < 1 << 20; ++i)
filterlut[i] = filter(i); filterlut[i] = filter(i);
} }
#define filter(x) (filterlut[(x) & 0xfffff]) #define filter(x) (filterlut[(x) & 0xfffff])
#endif #endif
static void quicksort(uint32_t* const start, uint32_t* const stop) static void quicksort(uint32_t *const start, uint32_t *const stop)
{ {
uint32_t *it = start + 1, *rit = stop; uint32_t *it = start + 1, *rit = stop;
if(it > rit) if (it > rit)
return; return;
while(it < rit) while (it < rit)
if(*it <= *start) if (*it <= *start)
++it; ++it;
else if(*rit > *start) else if (*rit > *start)
--rit; --rit;
else else
*it ^= (*it ^= *rit, *rit ^= *it); *it ^= (*it ^= *rit, *rit ^= *it);
if(*rit >= *start) if (*rit >= *start)
--rit; --rit;
if(rit != start) if (rit != start)
*rit ^= (*rit ^= *start, *start ^= *rit); *rit ^= (*rit ^= *start, *start ^= *rit);
quicksort(start, rit - 1); quicksort(start, rit - 1);
quicksort(rit + 1, stop); quicksort(rit + 1, stop);
} }
/** binsearch /** binsearch
* Binary search for the first occurence of *stop's MSB in sorted [start,stop] * Binary search for the first occurence of *stop's MSB in sorted [start,stop]
*/ */
static inline uint32_t* binsearch(uint32_t *start, uint32_t *stop) static inline uint32_t *binsearch(uint32_t *start, uint32_t *stop)
{ {
uint32_t mid, val = *stop & 0xff000000; uint32_t mid, val = *stop & 0xff000000;
while(start != stop) while (start != stop)
if(start[mid = (stop - start) >> 1] > val) if (start[mid = (stop - start) >> 1] > val)
stop = &start[mid]; stop = &start[mid];
else else
start += mid + 1; start += mid + 1;
return start; return start;
} }
/** update_contribution /** update_contribution
@ -75,11 +75,11 @@ static inline uint32_t* binsearch(uint32_t *start, uint32_t *stop)
static inline void static inline void
update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
{ {
uint32_t p = *item >> 25; uint32_t p = *item >> 25;
p = p << 1 | parity(*item & mask1); p = p << 1 | parity(*item & mask1);
p = p << 1 | parity(*item & mask2); p = p << 1 | parity(*item & mask2);
*item = p << 24 | (*item & 0xffffff); *item = p << 24 | (*item & 0xffffff);
} }
/** extend_table /** extend_table
@ -88,228 +88,229 @@ update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
static inline void static inline void
extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in)
{ {
in <<= 24; in <<= 24;
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
if(filter(*tbl) ^ filter(*tbl | 1)) { if (filter(*tbl) ^ filter(*tbl | 1)) {
*tbl |= filter(*tbl) ^ bit; *tbl |= filter(*tbl) ^ bit;
update_contribution(tbl, m1, m2); update_contribution(tbl, m1, m2);
*tbl ^= in; *tbl ^= in;
} else if(filter(*tbl) == bit) { } else if (filter(*tbl) == bit) {
*++*end = tbl[1]; *++*end = tbl[1];
tbl[1] = tbl[0] | 1; tbl[1] = tbl[0] | 1;
update_contribution(tbl, m1, m2); update_contribution(tbl, m1, m2);
*tbl++ ^= in; *tbl++ ^= in;
update_contribution(tbl, m1, m2); update_contribution(tbl, m1, m2);
*tbl ^= in; *tbl ^= in;
} else } else
*tbl-- = *(*end)--; *tbl-- = *(*end)--;
} }
/** extend_table_simple /** extend_table_simple
* using a bit of the keystream extend the table of possible lfsr states * using a bit of the keystream extend the table of possible lfsr states
*/ */
static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit)
{ {
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
if(filter(*tbl) ^ filter(*tbl | 1)) { if (filter(*tbl) ^ filter(*tbl | 1)) {
*tbl |= filter(*tbl) ^ bit; *tbl |= filter(*tbl) ^ bit;
} else if(filter(*tbl) == bit) { } else if (filter(*tbl) == bit) {
*++*end = *++tbl; *++*end = *++tbl;
*tbl = tbl[-1] | 1; *tbl = tbl[-1] | 1;
} else } else
*tbl-- = *(*end)--; *tbl-- = *(*end)--;
} }
/** recover /** recover
* recursively narrow down the search space, 4 bits of keystream at a time * recursively narrow down the search space, 4 bits of keystream at a time
*/ */
static struct Crypto1State* static struct Crypto1State *
recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem,
struct Crypto1State *sl, uint32_t in) struct Crypto1State *sl, uint32_t in) {
{ uint32_t *o, *e, i;
uint32_t *o, *e, i;
if(rem == -1) { if (rem == -1) {
for(e = e_head; e <= e_tail; ++e) { for (e = e_head; e <= e_tail; ++e) {
*e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4); *e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4);
for(o = o_head; o <= o_tail; ++o, ++sl) { for (o = o_head; o <= o_tail; ++o, ++sl) {
sl->even = *o; sl->even = *o;
sl->odd = *e ^ parity(*o & LF_POLY_ODD); sl->odd = *e ^ parity(*o & LF_POLY_ODD);
sl[1].odd = sl[1].even = 0; sl[1].odd = sl[1].even = 0;
} }
} }
return sl; return sl;
} }
for(i = 0; i < 4 && rem--; i++) { for (i = 0; i < 4 && rem--; i++) {
oks >>= 1; oks >>= 1;
eks >>= 1; eks >>= 1;
in >>= 2; in >>= 2;
extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1,
LF_POLY_ODD << 1, 0); LF_POLY_ODD << 1, 0);
if(o_head > o_tail) if (o_head > o_tail)
return sl; return sl;
extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD, extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD,
LF_POLY_EVEN << 1 | 1, in & 3); LF_POLY_EVEN << 1 | 1, in & 3);
if(e_head > e_tail) if (e_head > e_tail)
return sl; return sl;
} }
quicksort(o_head, o_tail); quicksort(o_head, o_tail);
quicksort(e_head, e_tail); quicksort(e_head, e_tail);
while(o_tail >= o_head && e_tail >= e_head) while (o_tail >= o_head && e_tail >= e_head)
if(((*o_tail ^ *e_tail) >> 24) == 0) { if (((*o_tail ^ *e_tail) >> 24) == 0) {
o_tail = binsearch(o_head, o = o_tail); o_tail = binsearch(o_head, o = o_tail);
e_tail = binsearch(e_head, e = e_tail); e_tail = binsearch(e_head, e = e_tail);
sl = recover(o_tail--, o, oks, sl = recover(o_tail--, o, oks,
e_tail--, e, eks, rem, sl, in); e_tail--, e, eks, rem, sl, in);
} } else if (*o_tail > *e_tail)
else if(*o_tail > *e_tail) o_tail = binsearch(o_head, o_tail) - 1;
o_tail = binsearch(o_head, o_tail) - 1; else
else e_tail = binsearch(e_head, e_tail) - 1;
e_tail = binsearch(e_head, e_tail) - 1;
return sl; return sl;
} }
/** lfsr_recovery /** lfsr_recovery
* recover the state of the lfsr given 32 bits of the keystream * recover the state of the lfsr given 32 bits of the keystream
* additionally you can use the in parameter to specify the value * additionally you can use the in parameter to specify the value
* that was fed into the lfsr at the time the keystream was generated * that was fed into the lfsr at the time the keystream was generated
*/ */
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in) struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in) {
{ struct Crypto1State *statelist;
struct Crypto1State *statelist; uint32_t *odd_head = 0, *odd_tail = 0, oks = 0;
uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; uint32_t *even_head = 0, *even_tail = 0, eks = 0;
uint32_t *even_head = 0, *even_tail = 0, eks = 0; int i;
int i;
for(i = 31; i >= 0; i -= 2) for (i = 31; i >= 0; i -= 2)
oks = oks << 1 | BEBIT(ks2, i); oks = oks << 1 | BEBIT(ks2, i);
for(i = 30; i >= 0; i -= 2) for (i = 30; i >= 0; i -= 2)
eks = eks << 1 | BEBIT(ks2, i); eks = eks << 1 | BEBIT(ks2, i);
odd_head = odd_tail = malloc(sizeof(uint32_t) << 21); odd_head = odd_tail = malloc(sizeof(uint32_t) << 21);
even_head = even_tail = malloc(sizeof(uint32_t) << 21); even_head = even_tail = malloc(sizeof(uint32_t) << 21);
statelist = malloc(sizeof(struct Crypto1State) << 18); statelist = malloc(sizeof(struct Crypto1State) << 18);
if(!odd_tail-- || !even_tail-- || !statelist) { if (!odd_tail-- || !even_tail-- || !statelist) {
free(statelist); free(statelist);
statelist = 0; statelist = 0;
goto out; goto out;
} }
statelist->odd = statelist->even = 0; statelist->odd = statelist->even = 0;
for(i = 1 << 20; i >= 0; --i) { for (i = 1 << 20; i >= 0; --i) {
if(filter(i) == (oks & 1)) if (filter(i) == (oks & 1))
*++odd_tail = i; *++odd_tail = i;
if(filter(i) == (eks & 1)) if (filter(i) == (eks & 1))
*++even_tail = i; *++even_tail = i;
} }
for(i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1);
extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1);
} }
in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00);
recover(odd_head, odd_tail, oks, recover(odd_head, odd_tail, oks,
even_head, even_tail, eks, 11, statelist, in << 1); even_head, even_tail, eks, 11, statelist, in << 1);
out: out:
free(odd_head); free(odd_head);
free(even_head); free(even_head);
return statelist; return statelist;
} }
static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214,
0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83,
0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA}; 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA
};
static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60,
0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8,
0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20,
0x7EC7EE90, 0x7F63F748, 0x79117020}; 0x7EC7EE90, 0x7F63F748, 0x79117020
};
static const uint32_t T1[] = { static const uint32_t T1[] = {
0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66,
0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B,
0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615,
0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C}; 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C
};
static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0,
0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268,
0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0,
0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0,
0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950,
0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0}; 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0
};
static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD};
static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0};
/** Reverse 64 bits of keystream into possible cipher states /** Reverse 64 bits of keystream into possible cipher states
* Variation mentioned in the paper. Somewhat optimized version * Variation mentioned in the paper. Somewhat optimized version
*/ */
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3) struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3) {
{ struct Crypto1State *statelist, *sl;
struct Crypto1State *statelist, *sl; uint8_t oks[32], eks[32], hi[32];
uint8_t oks[32], eks[32], hi[32]; uint32_t low = 0, win = 0;
uint32_t low = 0, win = 0; uint32_t *tail, table[1 << 16];
uint32_t *tail, table[1 << 16]; int i, j;
int i, j;
sl = statelist = malloc(sizeof(struct Crypto1State) << 4); sl = statelist = malloc(sizeof(struct Crypto1State) << 4);
if(!sl) if (!sl)
return 0; return 0;
sl->odd = sl->even = 0; sl->odd = sl->even = 0;
for(i = 30; i >= 0; i -= 2) { for (i = 30; i >= 0; i -= 2) {
oks[i >> 1] = BEBIT(ks2, i); oks[i >> 1] = BEBIT(ks2, i);
oks[16 + (i >> 1)] = BEBIT(ks3, i); oks[16 + (i >> 1)] = BEBIT(ks3, i);
} }
for(i = 31; i >= 0; i -= 2) { for (i = 31; i >= 0; i -= 2) {
eks[i >> 1] = BEBIT(ks2, i); eks[i >> 1] = BEBIT(ks2, i);
eks[16 + (i >> 1)] = BEBIT(ks3, i); eks[16 + (i >> 1)] = BEBIT(ks3, i);
} }
for(i = 0xfffff; i >= 0; --i) { for (i = 0xfffff; i >= 0; --i) {
if (filter(i) != oks[0]) if (filter(i) != oks[0])
continue; continue;
*(tail = table) = i; *(tail = table) = i;
for(j = 1; tail >= table && j < 29; ++j) for (j = 1; tail >= table && j < 29; ++j)
extend_table_simple(table, &tail, oks[j]); extend_table_simple(table, &tail, oks[j]);
if(tail < table) if (tail < table)
continue; continue;
for(j = 0; j < 19; ++j) for (j = 0; j < 19; ++j)
low = low << 1 | parity(i & S1[j]); low = low << 1 | parity(i & S1[j]);
for(j = 0; j < 32; ++j) for (j = 0; j < 32; ++j)
hi[j] = parity(i & T1[j]); hi[j] = parity(i & T1[j]);
for(; tail >= table; --tail) { for (; tail >= table; --tail) {
for(j = 0; j < 3; ++j) { for (j = 0; j < 3; ++j) {
*tail = *tail << 1; *tail = *tail << 1;
*tail |= parity((i & C1[j]) ^ (*tail & C2[j])); *tail |= parity((i & C1[j]) ^(*tail & C2[j]));
if(filter(*tail) != oks[29 + j]) if (filter(*tail) != oks[29 + j])
goto continue2; goto continue2;
} }
for(j = 0; j < 19; ++j) for (j = 0; j < 19; ++j)
win = win << 1 | parity(*tail & S2[j]); win = win << 1 | parity(*tail & S2[j]);
win ^= low; win ^= low;
for(j = 0; j < 32; ++j) { for (j = 0; j < 32; ++j) {
win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]); win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]);
if(filter(win) != eks[j]) if (filter(win) != eks[j])
goto continue2; goto continue2;
} }
*tail = *tail << 1 | parity(LF_POLY_EVEN & *tail); *tail = *tail << 1 | parity(LF_POLY_EVEN & *tail);
sl->odd = *tail ^ parity(LF_POLY_ODD & win); sl->odd = *tail ^ parity(LF_POLY_ODD & win);
sl->even = win; sl->even = win;
++sl; ++sl;
sl->odd = sl->even = 0; sl->odd = sl->even = 0;
continue2:; continue2:
} ;
} }
return statelist; }
return statelist;
} }
/** lfsr_rollback_bit /** lfsr_rollback_bit
@ -317,41 +318,41 @@ struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3)
*/ */
uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
{ {
int out; int out;
uint8_t ret; uint8_t ret;
s->odd &= 0xffffff; s->odd &= 0xffffff;
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
out = s->even & 1; out = s->even & 1;
out ^= LF_POLY_EVEN & (s->even >>= 1); out ^= LF_POLY_EVEN & (s->even >>= 1);
out ^= LF_POLY_ODD & s->odd; out ^= LF_POLY_ODD & s->odd;
out ^= !!in; out ^= !!in;
out ^= (ret = filter(s->odd)) & !!fb; out ^= (ret = filter(s->odd)) & !!fb;
s->even |= parity(out) << 23; s->even |= parity(out) << 23;
return ret; return ret;
} }
/** lfsr_rollback_byte /** lfsr_rollback_byte
* Rollback the shift register in order to get previous states * Rollback the shift register in order to get previous states
*/ */
uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb)
{ {
int i, ret = 0; int i, ret = 0;
for (i = 7; i >= 0; --i) for (i = 7; i >= 0; --i)
ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i; ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i;
return ret; return ret;
} }
/** lfsr_rollback_word /** lfsr_rollback_word
* Rollback the shift register in order to get previous states * Rollback the shift register in order to get previous states
*/ */
uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb)
{ {
int i; int i;
uint32_t ret = 0; uint32_t ret = 0;
for (i = 31; i >= 0; --i) for (i = 31; i >= 0; --i)
ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24);
return ret; return ret;
} }
/** nonce_distance /** nonce_distance
@ -360,25 +361,26 @@ uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb)
static uint16_t *dist = 0; static uint16_t *dist = 0;
int nonce_distance(uint32_t from, uint32_t to) int nonce_distance(uint32_t from, uint32_t to)
{ {
uint16_t x, i; uint16_t x, i;
if(!dist) { if (!dist) {
dist = malloc(2 << 16); dist = malloc(2 << 16);
if(!dist) if (!dist)
return -1; return -1;
for (x = i = 1; i; ++i) { for (x = i = 1; i; ++i) {
dist[(x & 0xff) << 8 | x >> 8] = i; dist[(x & 0xff) << 8 | x >> 8] = i;
x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
} }
} }
return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535;
} }
static uint32_t fastfwd[2][8] = { static uint32_t fastfwd[2][8] = {
{ 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB},
{ 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}}; { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}
};
/** lfsr_prefix_ks /** lfsr_prefix_ks
* *
* Is an exported helper function from the common prefix attack * Is an exported helper function from the common prefix attack
@ -390,91 +392,89 @@ static uint32_t fastfwd[2][8] = {
*/ */
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd)
{ {
uint32_t c, entry, *candidates = malloc(4 << 10); uint32_t c, entry, *candidates = malloc(4 << 10);
int i, size = 0, good; int i, size = 0, good;
if(!candidates) if (!candidates)
return 0; return 0;
for(i = 0; i < 1 << 21; ++i) { for (i = 0; i < 1 << 21; ++i) {
for(c = 0, good = 1; good && c < 8; ++c) { for (c = 0, good = 1; good && c < 8; ++c) {
entry = i ^ fastfwd[isodd][c]; entry = i ^ fastfwd[isodd][c];
good &= (BIT(ks[c], isodd) == filter(entry >> 1)); good &= (BIT(ks[c], isodd) == filter(entry >> 1));
good &= (BIT(ks[c], isodd + 2) == filter(entry)); good &= (BIT(ks[c], isodd + 2) == filter(entry));
} }
if(good) if (good)
candidates[size++] = i; candidates[size++] = i;
} }
candidates[size] = -1; candidates[size] = -1;
return candidates; return candidates;
} }
/** check_pfx_parity /** check_pfx_parity
* helper function which eliminates possible secret states using parity bits * helper function which eliminates possible secret states using parity bits
*/ */
static struct Crypto1State* static struct Crypto1State *
check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
uint32_t odd, uint32_t even, struct Crypto1State* sl) uint32_t odd, uint32_t even, struct Crypto1State *sl) {
{ uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;
uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;
for(c = 0; good && c < 8; ++c) { for (c = 0; good && c < 8; ++c) {
sl->odd = odd ^ fastfwd[1][c]; sl->odd = odd ^ fastfwd[1][c];
sl->even = even ^ fastfwd[0][c]; sl->even = even ^ fastfwd[0][c];
lfsr_rollback_bit(sl, 0, 0); lfsr_rollback_bit(sl, 0, 0);
lfsr_rollback_bit(sl, 0, 0); lfsr_rollback_bit(sl, 0, 0);
ks3 = lfsr_rollback_bit(sl, 0, 0); ks3 = lfsr_rollback_bit(sl, 0, 0);
ks2 = lfsr_rollback_word(sl, 0, 0); ks2 = lfsr_rollback_word(sl, 0, 0);
ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1);
nr = ks1 ^ (prefix | c << 5); nr = ks1 ^(prefix | c << 5);
rr = ks2 ^ rresp; rr = ks2 ^ rresp;
good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24);
good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16);
good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8);
good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0);
good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3; good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3;
} }
return sl + good; return sl + good;
} }
/** lfsr_common_prefix /** lfsr_common_prefix
* Implentation of the common prefix attack. * Implentation of the common prefix attack.
*/ */
struct Crypto1State* struct Crypto1State *
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) {
{ struct Crypto1State *statelist, *s;
struct Crypto1State *statelist, *s; uint32_t *odd, *even, *o, *e, top;
uint32_t *odd, *even, *o, *e, top;
odd = lfsr_prefix_ks(ks, 1); odd = lfsr_prefix_ks(ks, 1);
even = lfsr_prefix_ks(ks, 0); even = lfsr_prefix_ks(ks, 0);
s = statelist = malloc((sizeof *statelist) << 20); s = statelist = malloc((sizeof *statelist) << 20);
if(!s || !odd || !even) { if (!s || !odd || !even) {
free(statelist); free(statelist);
statelist = 0; statelist = 0;
goto out; goto out;
} }
for(o = odd; *o + 1; ++o) for (o = odd; *o + 1; ++o)
for(e = even; *e + 1; ++e) for (e = even; *e + 1; ++e)
for(top = 0; top < 64; ++top) { for (top = 0; top < 64; ++top) {
*o += 1 << 21; *o += 1 << 21;
*e += (!(top & 7) + 1) << 21; *e += (!(top & 7) + 1) << 21;
s = check_pfx_parity(pfx, rr, par, *o, *e, s); s = check_pfx_parity(pfx, rr, par, *o, *e, s);
} }
s->odd = s->even = 0; s->odd = s->even = 0;
out: out:
free(odd); free(odd);
free(even); free(even);
return statelist; return statelist;
} }

View File

@ -24,69 +24,69 @@
extern "C" { extern "C" {
#endif #endif
struct Crypto1State {uint32_t odd, even;}; struct Crypto1State {uint32_t odd, even;};
struct Crypto1State* crypto1_create(uint64_t); struct Crypto1State *crypto1_create(uint64_t);
void crypto1_destroy(struct Crypto1State*); void crypto1_destroy(struct Crypto1State *);
void crypto1_get_lfsr(struct Crypto1State*, uint64_t*); void crypto1_get_lfsr(struct Crypto1State *, uint64_t *);
uint8_t crypto1_bit(struct Crypto1State*, uint8_t, int); uint8_t crypto1_bit(struct Crypto1State *, uint8_t, int);
uint8_t crypto1_byte(struct Crypto1State*, uint8_t, int); uint8_t crypto1_byte(struct Crypto1State *, uint8_t, int);
uint32_t crypto1_word(struct Crypto1State*, uint32_t, int); uint32_t crypto1_word(struct Crypto1State *, uint32_t, int);
uint32_t prng_successor(uint32_t x, uint32_t n); uint32_t prng_successor(uint32_t x, uint32_t n);
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in); struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in);
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3); struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3);
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd); uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
struct Crypto1State* struct Crypto1State *
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]); lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb); uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb);
uint8_t lfsr_rollback_byte(struct Crypto1State* s, uint32_t in, int fb); uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb);
uint32_t lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb); uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb);
int nonce_distance(uint32_t from, uint32_t to); int nonce_distance(uint32_t from, uint32_t to);
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\ #define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
uint32_t __n = 0,__M = 0, N = 0;\ uint32_t __n = 0,__M = 0, N = 0;\
int __i;\ int __i;\
for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\
for(__i = FSIZE - 1; __i >= 0; __i--)\ for(__i = FSIZE - 1; __i >= 0; __i--)\
if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\ if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\
break;\ break;\
else if(__i)\ else if(__i)\
__M = prng_successor(__M, (__i == 7) ? 48 : 8);\ __M = prng_successor(__M, (__i == 7) ? 48 : 8);\
else else
#define LF_POLY_ODD (0x29CE5C) #define LF_POLY_ODD (0x29CE5C)
#define LF_POLY_EVEN (0x870804) #define LF_POLY_EVEN (0x870804)
#define BIT(x, n) ((x) >> (n) & 1) #define BIT(x, n) ((x) >> (n) & 1)
#define BEBIT(x, n) BIT(x, (n) ^ 24) #define BEBIT(x, n) BIT(x, (n) ^ 24)
static inline int parity(uint32_t x) static inline int parity(uint32_t x)
{ {
#if !defined __i386__ || !defined __GNUC__ #if !defined __i386__ || !defined __GNUC__
x ^= x >> 16; x ^= x >> 16;
x ^= x >> 8; x ^= x >> 8;
x ^= x >> 4; x ^= x >> 4;
return BIT(0x6996, x & 0xf); return BIT(0x6996, x & 0xf);
#else #else
asm( "movl %1, %%eax\n" asm("movl %1, %%eax\n"
"mov %%ax, %%cx\n" "mov %%ax, %%cx\n"
"shrl $0x10, %%eax\n" "shrl $0x10, %%eax\n"
"xor %%ax, %%cx\n" "xor %%ax, %%cx\n"
"xor %%ch, %%cl\n" "xor %%ch, %%cl\n"
"setpo %%al\n" "setpo %%al\n"
"movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx"); "movzx %%al, %0\n": "=r"(x) : "r"(x): "eax", "ecx");
return x; return x;
#endif #endif
} }
static inline int filter(uint32_t const x) static inline int filter(uint32_t const x)
{ {
uint32_t f; uint32_t f;
f = 0xf22c0 >> (x & 0xf) & 16; f = 0xf22c0 >> (x & 0xf) & 16;
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
f |= 0x1e458 >> (x >> 12 & 0xf) & 2; f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
f |= 0x0d938 >> (x >> 16 & 0xf) & 1; f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
return BIT(0xEC57E80A, f); return BIT(0xEC57E80A, f);
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -21,63 +21,62 @@
#include <stdlib.h> #include <stdlib.h>
#define SWAPENDIAN(x)\ #define SWAPENDIAN(x)\
(x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16)
struct Crypto1State * crypto1_create(uint64_t key) struct Crypto1State *crypto1_create(uint64_t key) {
{ struct Crypto1State *s = malloc(sizeof(*s));
struct Crypto1State *s = malloc(sizeof(*s)); int i;
int i;
for(i = 47;s && i > 0; i -= 2) { for (i = 47; s && i > 0; i -= 2) {
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7); s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
s->even = s->even << 1 | BIT(key, i ^ 7); s->even = s->even << 1 | BIT(key, i ^ 7);
} }
return s; return s;
} }
void crypto1_destroy(struct Crypto1State *state) void crypto1_destroy(struct Crypto1State *state)
{ {
free(state); free(state);
} }
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
{ {
int i; int i;
for(*lfsr = 0, i = 23; i >= 0; --i) { for (*lfsr = 0, i = 23; i >= 0; --i) {
*lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
*lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
} }
} }
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
{ {
uint32_t feedin; uint32_t feedin;
uint8_t ret = filter(s->odd); uint8_t ret = filter(s->odd);
feedin = ret & !!is_encrypted; feedin = ret & !!is_encrypted;
feedin ^= !!in; feedin ^= !!in;
feedin ^= LF_POLY_ODD & s->odd; feedin ^= LF_POLY_ODD & s->odd;
feedin ^= LF_POLY_EVEN & s->even; feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | parity(feedin); s->even = s->even << 1 | parity(feedin);
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
return ret; return ret;
} }
uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted)
{ {
uint8_t i, ret = 0; uint8_t i, ret = 0;
for (i = 0; i < 8; ++i) for (i = 0; i < 8; ++i)
ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i; ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i;
return ret; return ret;
} }
uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
{ {
uint32_t i, ret = 0; uint32_t i, ret = 0;
for (i = 0; i < 32; ++i) for (i = 0; i < 32; ++i)
ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24); ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24);
return ret; return ret;
} }
/* prng_successor /* prng_successor
@ -85,9 +84,9 @@ uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
*/ */
uint32_t prng_successor(uint32_t x, uint32_t n) uint32_t prng_successor(uint32_t x, uint32_t n)
{ {
SWAPENDIAN(x); SWAPENDIAN(x);
while(n--) while (n--)
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
return SWAPENDIAN(x); return SWAPENDIAN(x);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Filename: Filename:
mfcuk_keyrecovery_darkside.h mfcuk_keyrecovery_darkside.h
@ -16,7 +16,7 @@
GPL2 (see below), Copyright (C) 2009, Andrei Costin GPL2 (see below), Copyright (C) 2009, Andrei Costin
* @file mfcuk_keyrecovery_darkside.h * @file mfcuk_keyrecovery_darkside.h
* @brief * @brief
*/ */
/* /*
@ -36,14 +36,14 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _MFCUK_KEYRECOVERY_DARKSIDE_H_ #ifndef _MFCUK_KEYRECOVERY_DARKSIDE_H_
@ -92,29 +92,28 @@
#define MFCUK_DARKSIDE_START_NR 0xDEADBEEF #define MFCUK_DARKSIDE_START_NR 0xDEADBEEF
#define MFCUK_DARKSIDE_START_AR 0xFACECAFE #define MFCUK_DARKSIDE_START_AR 0xFACECAFE
typedef struct tag_nonce_entry typedef struct tag_nonce_entry {
{ uint32_t tagNonce; // Tag nonce we target for fixation
uint32_t tagNonce; // Tag nonce we target for fixation uint8_t spoofFlag; // No spoofing until we have a successful auth with this tagNonce. Once we have, we want to spoof to get the encrypted 0x5 value
uint8_t spoofFlag; // No spoofing until we have a successful auth with this tagNonce. Once we have, we want to spoof to get the encrypted 0x5 value uint32_t num_of_appearances; // For statistics, how many times this tag nonce appeared for the given SLEEP_ values
uint32_t num_of_appearances; // For statistics, how many times this tag nonce appeared for the given SLEEP_ values
// STAGE1 data for "dark side" and lsfr_common_prefix() // STAGE1 data for "dark side" and lsfr_common_prefix()
uint32_t spoofNrPfx; // PARAM: used as pfx, calculated from (spoofNrEnc & 0xFFFFFF1F). BUG: weird way to denote "first 29 prefix bits" in "dark side" paper. Perhaps I see the world different uint32_t spoofNrPfx; // PARAM: used as pfx, calculated from (spoofNrEnc & 0xFFFFFF1F). BUG: weird way to denote "first 29 prefix bits" in "dark side" paper. Perhaps I see the world different
uint32_t spoofNrEnc; // {Nr} value which we will be using to make the tag respond with 4 bits uint32_t spoofNrEnc; // {Nr} value which we will be using to make the tag respond with 4 bits
uint32_t spoofArEnc; // PARAM: used as rr uint32_t spoofArEnc; // PARAM: used as rr
uint8_t spoofParBitsEnc; // parity bits we are trying to guess for the first time uint8_t spoofParBitsEnc; // parity bits we are trying to guess for the first time
uint8_t spoofNackEnc; // store here the encrypted NACK returned first time we match the parity bits uint8_t spoofNackEnc; // store here the encrypted NACK returned first time we match the parity bits
uint8_t spoofKs; // store here the keystream ks used for encryptying spoofNackEnc, specifically spoofKs = spoofNackEnc ^ 0x5 uint8_t spoofKs; // store here the keystream ks used for encryptying spoofNackEnc, specifically spoofKs = spoofNackEnc ^ 0x5
// STAGE2 data for "dark side" and lsfr_common_prefix() // STAGE2 data for "dark side" and lsfr_common_prefix()
int current_out_of_8; // starting from -1 until we find parity for chosen spoofNrEnc,spoofArEnc int current_out_of_8; // starting from -1 until we find parity for chosen spoofNrEnc,spoofArEnc
uint8_t parBitsCrntCombination[MFCUK_DARKSIDE_MAX_LEVELS]; // Loops over 32 combinations of the last 5 parity bits which generated the 4 bit NACK in STAGE1 uint8_t parBitsCrntCombination[MFCUK_DARKSIDE_MAX_LEVELS]; // Loops over 32 combinations of the last 5 parity bits which generated the 4 bit NACK in STAGE1
uint32_t nrEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the 29 bits constant prefix, varying only 3 bits, thus 8 possible values uint32_t nrEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the 29 bits constant prefix, varying only 3 bits, thus 8 possible values
uint32_t arEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the same reader response as spoofArEnc; redundant but... :) uint32_t arEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the same reader response as spoofArEnc; redundant but... :)
uint8_t ks[MFCUK_DARKSIDE_MAX_LEVELS]; // PARAM: used as ks, obtained as (ks[i] = nackEnc[i] ^ 0x5) uint8_t ks[MFCUK_DARKSIDE_MAX_LEVELS]; // PARAM: used as ks, obtained as (ks[i] = nackEnc[i] ^ 0x5)
uint8_t nackEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the encrypted 4 bits values which tag responded uint8_t nackEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the encrypted 4 bits values which tag responded
uint8_t parBits[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the values based on spoofParBitsEnc, varying only last 5 bits uint8_t parBits[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the values based on spoofParBitsEnc, varying only last 5 bits
uint8_t parBitsArr[MFCUK_DARKSIDE_MAX_LEVELS][8]; // PARAM: used as par, contains value of parBits byte-bit values just splitted out one bit per byte thus second pair of braces [8] uint8_t parBitsArr[MFCUK_DARKSIDE_MAX_LEVELS][8]; // PARAM: used as par, contains value of parBits byte-bit values just splitted out one bit per byte thus second pair of braces [8]
} tag_nonce_entry_t; } tag_nonce_entry_t;
#endif // _MFCUK_KEYRECOVERY_DARKSIDE_H_ #endif // _MFCUK_KEYRECOVERY_DARKSIDE_H_

View File

@ -5,23 +5,23 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Package version: Package version:
0.1 0.1
Filename: Filename:
mfcuk_finger.c mfcuk_finger.c
@ -38,174 +38,150 @@
#include "mfcuk_finger.h" #include "mfcuk_finger.h"
mfcuk_finger_tmpl_entry mfcuk_finger_db[] = mfcuk_finger_tmpl_entry mfcuk_finger_db[] = {
{ { "./data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd", "Sofia SKGT", mfcuk_finger_default_comparator, mfcuk_finger_skgt_decoder, NULL },
{ "./data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd", "Sofia SKGT", mfcuk_finger_default_comparator, mfcuk_finger_skgt_decoder, NULL }, { "./data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd", "Bucharest RATB", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
{ "./data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd", "Bucharest RATB", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL }, { "./data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd", "London OYSTER", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
{ "./data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd", "London OYSTER", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
}; };
int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db)/sizeof(mfcuk_finger_db[0]); int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db) / sizeof(mfcuk_finger_db[0]);
int mfcuk_finger_default_decoder(mifare_classic_tag *dump) int mfcuk_finger_default_decoder(mifare_classic_tag *dump)
{ {
if (!dump) if (!dump) {
{ fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n"); return 0;
return 0; }
}
printf("UID:\t%02x%02x%02x%02x\n", dump->amb[0].mbm.abtUID[0], dump->amb[0].mbm.abtUID[1], dump->amb[0].mbm.abtUID[2], dump->amb[0].mbm.abtUID[3]);
printf("UID:\t%02x%02x%02x%02x\n", dump->amb[0].mbm.abtUID[0], dump->amb[0].mbm.abtUID[1], dump->amb[0].mbm.abtUID[2], dump->amb[0].mbm.abtUID[3]); printf("TYPE:\t%02x\n", dump->amb[0].mbm.btUnknown);
printf("TYPE:\t%02x\n", dump->amb[0].mbm.btUnknown);
return 1;
return 1;
} }
// Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++? // Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++?
int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump) int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump)
{ {
if (!dump) if (!dump) {
{ fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n"); return 0;
return 0; }
}
printf("Bulgaria/Sofia/SKGT public transport card information decoder (info credits to Andy)\n");
printf("Bulgaria/Sofia/SKGT public transport card information decoder (info credits to Andy)\n"); mfcuk_finger_default_decoder(dump);
mfcuk_finger_default_decoder(dump);
printf("LAST TRAVEL DATA\n");
printf("LAST TRAVEL DATA\n");
// TODO: get proper information
// TODO: get proper information
return 1;
return 1;
} }
int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score) int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score)
{ {
int max_bytes = 0; int max_bytes = 0;
int i; int i;
int num_bytes_tomatch = 0; int num_bytes_tomatch = 0;
int num_bytes_matched = 0; int num_bytes_matched = 0;
if ( (!dump) || (!tmpl) || (!score) ) if ((!dump) || (!tmpl) || (!score)) {
{ return 0;
return 0; }
if (IS_MIFARE_CLASSIC_1K_TAG(dump)) {
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_1K_MAX_BLOCKS;
} else if (IS_MIFARE_CLASSIC_4K_TAG(dump)) {
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_4K_MAX_BLOCKS;
} else {
return 0;
}
for (i = 0; i < max_bytes; i++) {
if (((char *)(&tmpl->mask))[i] == 0x0) {
continue;
} }
if (IS_MIFARE_CLASSIC_1K_TAG(dump)) num_bytes_tomatch++;
{
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_1K_MAX_BLOCKS; if (((char *)(&tmpl->values))[i] == ((char *)dump)[i]) {
num_bytes_matched++;
} }
else if (IS_MIFARE_CLASSIC_4K_TAG(dump)) }
{
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_4K_MAX_BLOCKS; if (num_bytes_tomatch == 0) {
} return 0;
else } else {
{ *score = (float)(num_bytes_matched) / num_bytes_tomatch;
return 0; }
}
return 1;
for (i=0; i<max_bytes; i++)
{
if ( ((char *)(&tmpl->mask))[i] == 0x0 )
{
continue;
}
num_bytes_tomatch++;
if ( ((char *)(&tmpl->values))[i] == ((char *)dump)[i] )
{
num_bytes_matched++;
}
}
if (num_bytes_tomatch == 0)
{
return 0;
}
else
{
*score = (float)(num_bytes_matched)/num_bytes_tomatch;
}
return 1;
} }
int mfcuk_finger_load(void) int mfcuk_finger_load(void)
{ {
int i; int i;
mifare_classic_tag mask; mifare_classic_tag mask;
mifare_classic_tag values; mifare_classic_tag values;
FILE *fp = NULL; FILE *fp = NULL;
size_t result = 0; size_t result = 0;
mfcuk_finger_template *tmpl_new = NULL; mfcuk_finger_template *tmpl_new = NULL;
int template_loaded_count = 0; int template_loaded_count = 0;
for (i = 0; i<mfcuk_finger_db_entries; i++) for (i = 0; i < mfcuk_finger_db_entries; i++) {
{ fp = fopen(mfcuk_finger_db[i].tmpl_filename, "rb");
fp = fopen(mfcuk_finger_db[i].tmpl_filename, "rb");
if (!fp) {
if (!fp) fprintf(stderr, "WARN: cannot open template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
{ continue;
fprintf(stderr, "WARN: cannot open template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
continue;
}
// If not read exactly 1 record, something is wrong
if ( (result = fread((void *)(&mask), sizeof(mask), 1, fp)) != 1)
{
fprintf(stderr, "WARN: cannot read MASK from template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
// If not read exactly 1 record, something is wrong
if ( (result = fread((void *)(&values), sizeof(values), 1, fp)) != 1)
{
fprintf(stderr, "WARN: cannot read VALUES template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
if (mfcuk_finger_db[i].tmpl_data == NULL)
{
if ( (tmpl_new = (mfcuk_finger_template *) malloc(sizeof(mfcuk_finger_template))) == NULL)
{
fprintf(stderr, "WARN: cannot allocate memory to template record %d\n", i);
fclose(fp);
continue;
}
memcpy( &(tmpl_new->mask), &(mask), sizeof(mask));
memcpy( &(tmpl_new->values), &(values), sizeof(values));
mfcuk_finger_db[i].tmpl_data = tmpl_new;
template_loaded_count++;
}
if (fp)
{
fclose(fp);
fp = NULL;
}
} }
return template_loaded_count; // If not read exactly 1 record, something is wrong
if ((result = fread((void *)(&mask), sizeof(mask), 1, fp)) != 1) {
fprintf(stderr, "WARN: cannot read MASK from template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
// If not read exactly 1 record, something is wrong
if ((result = fread((void *)(&values), sizeof(values), 1, fp)) != 1) {
fprintf(stderr, "WARN: cannot read VALUES template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
if (mfcuk_finger_db[i].tmpl_data == NULL) {
if ((tmpl_new = (mfcuk_finger_template *) malloc(sizeof(mfcuk_finger_template))) == NULL) {
fprintf(stderr, "WARN: cannot allocate memory to template record %d\n", i);
fclose(fp);
continue;
}
memcpy(&(tmpl_new->mask), &(mask), sizeof(mask));
memcpy(&(tmpl_new->values), &(values), sizeof(values));
mfcuk_finger_db[i].tmpl_data = tmpl_new;
template_loaded_count++;
}
if (fp) {
fclose(fp);
fp = NULL;
}
}
return template_loaded_count;
} }
int mfcuk_finger_unload(void) int mfcuk_finger_unload(void)
{ {
int i; int i;
for (i = 0; i<mfcuk_finger_db_entries; i++) for (i = 0; i < mfcuk_finger_db_entries; i++) {
{ if (mfcuk_finger_db[i].tmpl_data != NULL) {
if (mfcuk_finger_db[i].tmpl_data != NULL) free(mfcuk_finger_db[i].tmpl_data);
{ mfcuk_finger_db[i].tmpl_data = NULL;
free(mfcuk_finger_db[i].tmpl_data);
mfcuk_finger_db[i].tmpl_data = NULL;
}
} }
}
return 1;
return 1;
} }

View File

@ -5,23 +5,23 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Package version: Package version:
0.1 0.1
Filename: Filename:
mfcuk_finger.h mfcuk_finger.h
@ -45,24 +45,22 @@
#include "mfcuk_mifare.h" #include "mfcuk_mifare.h"
// Wrapping an ugly template into an externally pleasant name. To implement proper template later. // Wrapping an ugly template into an externally pleasant name. To implement proper template later.
typedef struct _mfcuk_finger_template_ typedef struct _mfcuk_finger_template_ {
{ mifare_classic_tag mask;
mifare_classic_tag mask; mifare_classic_tag values;
mifare_classic_tag values;
} mfcuk_finger_template; } mfcuk_finger_template;
// Function type definition, to be used for custom decoders/comparators // Function type definition, to be used for custom decoders/comparators
typedef int (*mfcuk_finger_comparator) (mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score); typedef int (*mfcuk_finger_comparator)(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score);
typedef int (*mfcuk_finger_decoder) (mifare_classic_tag *dump); typedef int (*mfcuk_finger_decoder)(mifare_classic_tag *dump);
// Naive implementation of a self-contained fingerprint database entry // Naive implementation of a self-contained fingerprint database entry
typedef struct _mfcuk_finger_tmpl_entry_ typedef struct _mfcuk_finger_tmpl_entry_ {
{ const char *tmpl_filename;
const char *tmpl_filename; const char *tmpl_name;
const char *tmpl_name; mfcuk_finger_comparator tmpl_comparison_func;
mfcuk_finger_comparator tmpl_comparison_func; mfcuk_finger_decoder tmpl_decoder_func;
mfcuk_finger_decoder tmpl_decoder_func; mfcuk_finger_template *tmpl_data;
mfcuk_finger_template *tmpl_data;
} mfcuk_finger_tmpl_entry; } mfcuk_finger_tmpl_entry;
int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score); int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score);

View File

@ -1,10 +1,10 @@
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Package version: Package version:
0.1 0.1
Filename: Filename:
mfcuk_mifare.c mfcuk_mifare.c
@ -20,7 +20,7 @@
GPL2 (see below), Copyright (C) 2009, Andrei Costin GPL2 (see below), Copyright (C) 2009, Andrei Costin
* @file mfcuk_mifare.c * @file mfcuk_mifare.c
* @brief * @brief
*/ */
/* /*
@ -40,485 +40,424 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mfcuk_mifare.h" #include "mfcuk_mifare.h"
// Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention! // Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention!
uint8_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH] = uint8_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH] = {
{ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Place-holder for current key to verify
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Place-holder for current key to verify {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5},
{0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5},
{0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd},
{0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a},
{0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7},
{0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
}; };
int mfcuk_default_keys_num = sizeof(mfcuk_default_keys)/sizeof(mfcuk_default_keys[0]); int mfcuk_default_keys_num = sizeof(mfcuk_default_keys) / sizeof(mfcuk_default_keys[0]);
bool is_valid_block(uint8_t bTagType, uint32_t uiBlock) bool is_valid_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( IS_MIFARE_CLASSIC_1K(bTagType) && (uiBlock < MIFARE_CLASSIC_1K_MAX_BLOCKS) ) if (IS_MIFARE_CLASSIC_1K(bTagType) && (uiBlock < MIFARE_CLASSIC_1K_MAX_BLOCKS)) {
{ return true;
return true; }
}
if ( IS_MIFARE_CLASSIC_4K(bTagType) && (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS) ) if (IS_MIFARE_CLASSIC_4K(bTagType) && (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS)) {
{ return true;
return true; }
}
return false; return false;
} }
bool is_valid_sector(uint8_t bTagType, uint32_t uiSector) bool is_valid_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( IS_MIFARE_CLASSIC_1K(bTagType) && (uiSector < MIFARE_CLASSIC_1K_MAX_SECTORS) ) if (IS_MIFARE_CLASSIC_1K(bTagType) && (uiSector < MIFARE_CLASSIC_1K_MAX_SECTORS)) {
{ return true;
return true; }
}
if ( IS_MIFARE_CLASSIC_4K(bTagType) && (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS) ) if (IS_MIFARE_CLASSIC_4K(bTagType) && (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS)) {
{ return true;
return true; }
}
return false; return false;
} }
bool is_first_block(uint8_t bTagType, uint32_t uiBlock) bool is_first_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// For Mifare Classic 1K, it will enter always here
return ( (uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0 );
}
else
{
// This branch will enter only for Mifare Classic 4K big sectors
return ( (uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0 );
}
// Should not reach here, but... never know
return false; return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// For Mifare Classic 1K, it will enter always here
return ((uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0);
} else {
// This branch will enter only for Mifare Classic 4K big sectors
return ((uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0);
}
// Should not reach here, but... never know
return false;
} }
bool is_trailer_block(uint8_t bTagType, uint32_t uiBlock) bool is_trailer_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// For Mifare Classic 1K, it will enter always here
return ( (uiBlock+1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0 );
}
else
{
// This branch will enter only for Mifare Classic 4K big sectors
return ( (uiBlock+1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0 );
}
// Should not reach here, but... never know
return false; return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// For Mifare Classic 1K, it will enter always here
return ((uiBlock + 1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0);
} else {
// This branch will enter only for Mifare Classic 4K big sectors
return ((uiBlock + 1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0);
}
// Should not reach here, but... never know
return false;
} }
uint32_t get_first_block(uint8_t bTagType, uint32_t uiBlock) uint32_t get_first_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// Integer divide, then integer multiply
return (uiBlock/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1;
}
else
{
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2;
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// Integer divide, then integer multiply
return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1;
} else {
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2;
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
uint32_t get_trailer_block(uint8_t bTagType, uint32_t uiBlock) uint32_t get_trailer_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// Integer divide, then integer multiply
return (uiBlock/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1-1);
}
else
{
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2-1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// Integer divide, then integer multiply
return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 - 1);
} else {
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 - 1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
bool is_big_sector(uint8_t bTagType, uint32_t uiSector) bool is_big_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( !is_valid_sector(bTagType, uiSector) ) if (!is_valid_sector(bTagType, uiSector)) {
{
return false;
}
if (uiSector >= MIFARE_CLASSIC_4K_MAX_SECTORS1)
{
return true;
}
return false; return false;
}
if (uiSector >= MIFARE_CLASSIC_4K_MAX_SECTORS1) {
return true;
}
return false;
} }
uint32_t get_first_block_for_sector(uint8_t bTagType, uint32_t uiSector) uint32_t get_first_block_for_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( !is_valid_sector(bTagType, uiSector) ) if (!is_valid_sector(bTagType, uiSector)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1)
{
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
}
else
{
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1) {
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
} else {
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
uint32_t get_trailer_block_for_sector(uint8_t bTagType, uint32_t uiSector) uint32_t get_trailer_block_for_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( !is_valid_sector(bTagType, uiSector) ) if (!is_valid_sector(bTagType, uiSector)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1)
{
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1-1);
}
else
{
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2-1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1) {
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 - 1);
} else {
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 - 1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
uint32_t get_sector_for_block(uint8_t bTagType, uint32_t uiBlock) uint32_t get_sector_for_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// For Mifare Classic 1K, it will enter always here
return (uiBlock/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
}
else
{
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_SECTORS1 + (tmp/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// For Mifare Classic 1K, it will enter always here
return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
} else {
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_SECTORS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
// Test case function for checking correct functionality of the block/sector is_ ang get_ functions // Test case function for checking correct functionality of the block/sector is_ ang get_ functions
void test_mifare_classic_blocks_sectors_functions(uint8_t bTagType) void test_mifare_classic_blocks_sectors_functions(uint8_t bTagType)
{ {
uint32_t i; uint32_t i;
uint32_t max_blocks, max_sectors; uint32_t max_blocks, max_sectors;
if ( IS_MIFARE_CLASSIC_1K(bTagType) ) if (IS_MIFARE_CLASSIC_1K(bTagType)) {
{ printf("\nMIFARE CLASSIC 1K\n");
printf("\nMIFARE CLASSIC 1K\n"); max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS; max_sectors = MIFARE_CLASSIC_1K_MAX_SECTORS;
max_sectors = MIFARE_CLASSIC_1K_MAX_SECTORS; } else if (IS_MIFARE_CLASSIC_4K(bTagType)) {
} printf("\nMIFARE CLASSIC 4K\n");
else if ( IS_MIFARE_CLASSIC_4K(bTagType) ) max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
{ max_sectors = MIFARE_CLASSIC_4K_MAX_SECTORS;
printf("\nMIFARE CLASSIC 4K\n"); } else {
max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS; return;
max_sectors = MIFARE_CLASSIC_4K_MAX_SECTORS; }
}
else
{
return;
}
// Include one invalid block, that is why we add +1 // Include one invalid block, that is why we add +1
for (i = 0; i<max_blocks+1; i++) for (i = 0; i < max_blocks + 1; i++) {
{ printf("BLOCK %d\n", i);
printf("BLOCK %d\n", i); printf("\t is_valid_block: %c\n", (is_valid_block(bTagType, i) ? 'Y' : 'N'));
printf("\t is_valid_block: %c\n", (is_valid_block(bTagType, i)?'Y':'N') ); printf("\t is_first_block: %c\n", (is_first_block(bTagType, i) ? 'Y' : 'N'));
printf("\t is_first_block: %c\n", (is_first_block(bTagType, i)?'Y':'N') ); printf("\t is_trailer_block: %c\n", (is_trailer_block(bTagType, i) ? 'Y' : 'N'));
printf("\t is_trailer_block: %c\n", (is_trailer_block(bTagType, i)?'Y':'N') ); printf("\t get_first_block: %d\n", get_first_block(bTagType, i));
printf("\t get_first_block: %d\n", get_first_block(bTagType, i)); printf("\t get_trailer_block: %d\n", get_trailer_block(bTagType, i));
printf("\t get_trailer_block: %d\n", get_trailer_block(bTagType, i)); printf("\t get_sector_for_block: %d\n", get_sector_for_block(bTagType, i));
printf("\t get_sector_for_block: %d\n", get_sector_for_block(bTagType, i)); }
}
// Include one invalid sector, that is why we add +1 // Include one invalid sector, that is why we add +1
for (i = 0; i<max_sectors+1; i++) for (i = 0; i < max_sectors + 1; i++) {
{ printf("SECTOR %d\n", i);
printf("SECTOR %d\n", i); printf("\t is_valid_sector: %c\n", (is_valid_sector(bTagType, i) ? 'Y' : 'N'));
printf("\t is_valid_sector: %c\n", (is_valid_sector(bTagType, i)?'Y':'N') ); printf("\t is_big_sector: %c\n", (is_big_sector(bTagType, i) ? 'Y' : 'N'));
printf("\t is_big_sector: %c\n", (is_big_sector(bTagType, i)?'Y':'N') ); printf("\t get_first_block_for_sector: %d\n", get_first_block_for_sector(bTagType, i));
printf("\t get_first_block_for_sector: %d\n", get_first_block_for_sector(bTagType, i) ); printf("\t get_trailer_block_for_sector: %d\n", get_trailer_block_for_sector(bTagType, i));
printf("\t get_trailer_block_for_sector: %d\n", get_trailer_block_for_sector(bTagType, i) ); }
}
} }
bool mfcuk_save_tag_dump(const char *filename, mifare_classic_tag *tag) bool mfcuk_save_tag_dump(const char *filename, mifare_classic_tag *tag)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "wb"); fp = fopen(filename, "wb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to write 1 record // Expect to write 1 record
result = fwrite((void *) tag, sizeof(*tag), 1, fp); result = fwrite((void *) tag, sizeof(*tag), 1, fp);
// If not written exactly 1 record, something is wrong
if (result != 1)
{
fclose(fp);
return false;
}
// If not written exactly 1 record, something is wrong
if (result != 1) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
bool mfcuk_save_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext) bool mfcuk_save_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "wb"); fp = fopen(filename, "wb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to write 1 record // Expect to write 1 record
result = fwrite((void *) tag_ext, sizeof(*tag_ext), 1, fp); result = fwrite((void *) tag_ext, sizeof(*tag_ext), 1, fp);
// If not written exactly 1 record, something is wrong
if (result != 1)
{
fclose(fp);
return false;
}
// If not written exactly 1 record, something is wrong
if (result != 1) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
bool mfcuk_load_tag_dump(const char *filename, mifare_classic_tag *tag) bool mfcuk_load_tag_dump(const char *filename, mifare_classic_tag *tag)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "rb"); fp = fopen(filename, "rb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to read 1 record // Expect to read 1 record
result = fread((void *) tag, sizeof(*tag), 1, fp); result = fread((void *) tag, sizeof(*tag), 1, fp);
// If not read exactly 1 record, something is wrong
if (result != 1)
{
fclose(fp);
return false;
}
// If not read exactly 1 record, something is wrong
if (result != 1) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
bool mfcuk_load_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext) bool mfcuk_load_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "rb"); fp = fopen(filename, "rb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to read 1 record // Expect to read 1 record
result = fread((void *) tag_ext, sizeof(*tag_ext), 1, fp); result = fread((void *) tag_ext, sizeof(*tag_ext), 1, fp);
// If not read exactly 1 record, something is wrong
if (result != sizeof(*tag_ext))
{
fclose(fp);
return false;
}
// If not read exactly 1 record, something is wrong
if (result != sizeof(*tag_ext)) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag) void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag)
{ {
uint32_t i, max_blocks, trailer_block; uint32_t i, max_blocks, trailer_block;
uint8_t bTagType; uint8_t bTagType;
mifare_classic_block_trailer *ptr_trailer = NULL; mifare_classic_block_trailer *ptr_trailer = NULL;
if (!tag)
{
return;
}
bTagType = tag->amb->mbm.btUnknown;
if ( !IS_MIFARE_CLASSIC_1K(bTagType) && !IS_MIFARE_CLASSIC_4K(bTagType) )
{
return;
}
printf("%s - UID %02x %02x %02x %02x - TYPE 0x%02x (%s)\n",
title, tag->amb->mbm.abtUID[0], tag->amb->mbm.abtUID[1], tag->amb->mbm.abtUID[2], tag->amb->mbm.abtUID[3], bTagType,
(IS_MIFARE_CLASSIC_1K(bTagType)?(MIFARE_CLASSIC_1K_NAME):(IS_MIFARE_CLASSIC_4K(bTagType)?(MIFARE_CLASSIC_4K_NAME):(MIFARE_CLASSIC_UNKN_NAME)))
);
printf("-------------------------------------------------------\n");
printf("Sector\t| Key A\t| AC bits\t| Key B\n");
printf("-------------------------------------------------------\n");
if ( IS_MIFARE_CLASSIC_1K(tag->amb->mbm.btUnknown) )
{
max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
}
else
{
max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
}
for (i=0; i<max_blocks; i++)
{
trailer_block = get_trailer_block(bTagType, i);
if ( !is_valid_block(bTagType, trailer_block) )
{
break;
}
ptr_trailer = (mifare_classic_block_trailer *) ((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %02x%02x%02x%02x\t| %02x%02x%02x%02x%02x%02x\n",
get_sector_for_block(bTagType, trailer_block),
ptr_trailer->abtKeyA[0], ptr_trailer->abtKeyA[1], ptr_trailer->abtKeyA[2],
ptr_trailer->abtKeyA[3], ptr_trailer->abtKeyA[4], ptr_trailer->abtKeyA[5],
ptr_trailer->abtAccessBits[0], ptr_trailer->abtAccessBits[1], ptr_trailer->abtAccessBits[2], ptr_trailer->abtAccessBits[3],
ptr_trailer->abtKeyB[0], ptr_trailer->abtKeyB[1], ptr_trailer->abtKeyB[2],
ptr_trailer->abtKeyB[3], ptr_trailer->abtKeyB[4], ptr_trailer->abtKeyB[5]
);
// Go beyond current trailer block, i.e. go to next sector
i = trailer_block;
}
printf("\n");
if (!tag) {
return; return;
}
bTagType = tag->amb->mbm.btUnknown;
if (!IS_MIFARE_CLASSIC_1K(bTagType) && !IS_MIFARE_CLASSIC_4K(bTagType)) {
return;
}
printf("%s - UID %02x %02x %02x %02x - TYPE 0x%02x (%s)\n",
title, tag->amb->mbm.abtUID[0], tag->amb->mbm.abtUID[1], tag->amb->mbm.abtUID[2], tag->amb->mbm.abtUID[3], bTagType,
(IS_MIFARE_CLASSIC_1K(bTagType) ? (MIFARE_CLASSIC_1K_NAME) : (IS_MIFARE_CLASSIC_4K(bTagType) ? (MIFARE_CLASSIC_4K_NAME) : (MIFARE_CLASSIC_UNKN_NAME)))
);
printf("-------------------------------------------------------\n");
printf("Sector\t| Key A\t| AC bits\t| Key B\n");
printf("-------------------------------------------------------\n");
if (IS_MIFARE_CLASSIC_1K(tag->amb->mbm.btUnknown)) {
max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
} else {
max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
}
for (i = 0; i < max_blocks; i++) {
trailer_block = get_trailer_block(bTagType, i);
if (!is_valid_block(bTagType, trailer_block)) {
break;
}
ptr_trailer = (mifare_classic_block_trailer *)((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK));
printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %02x%02x%02x%02x\t| %02x%02x%02x%02x%02x%02x\n",
get_sector_for_block(bTagType, trailer_block),
ptr_trailer->abtKeyA[0], ptr_trailer->abtKeyA[1], ptr_trailer->abtKeyA[2],
ptr_trailer->abtKeyA[3], ptr_trailer->abtKeyA[4], ptr_trailer->abtKeyA[5],
ptr_trailer->abtAccessBits[0], ptr_trailer->abtAccessBits[1], ptr_trailer->abtAccessBits[2], ptr_trailer->abtAccessBits[3],
ptr_trailer->abtKeyB[0], ptr_trailer->abtKeyB[1], ptr_trailer->abtKeyB[2],
ptr_trailer->abtKeyB[3], ptr_trailer->abtKeyB[4], ptr_trailer->abtKeyB[5]
);
// Go beyond current trailer block, i.e. go to next sector
i = trailer_block;
}
printf("\n");
return;
} }
bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, uint8_t *arr6Key) bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, uint8_t *arr6Key)
{ {
int i; int i;
if ( !ui64Key || !arr6Key ) if (!ui64Key || !arr6Key) {
{ return false;
return false; }
}
for (i = 0; i<MIFARE_CLASSIC_KEY_BYTELENGTH; i++) for (i = 0; i < MIFARE_CLASSIC_KEY_BYTELENGTH; i++) {
{ arr6Key[i] = (uint8_t)(((*ui64Key) >> 8 * (MIFARE_CLASSIC_KEY_BYTELENGTH - i - 1)) & 0xFF);
arr6Key[i] = (uint8_t) (((*ui64Key) >> 8*(MIFARE_CLASSIC_KEY_BYTELENGTH - i - 1)) & 0xFF); }
}
return true; return true;
} }
bool mfcuk_key_arr_to_uint64(const uint8_t *arr6Key, uint64_t *ui64Key) bool mfcuk_key_arr_to_uint64(const uint8_t *arr6Key, uint64_t *ui64Key)
{ {
uint64_t key = 0; uint64_t key = 0;
int i; int i;
if ( !ui64Key || !arr6Key ) if (!ui64Key || !arr6Key) {
{ return false;
return false; }
}
for (i = 0; i<MIFARE_CLASSIC_KEY_BYTELENGTH; i++, key <<= 8) for (i = 0; i < MIFARE_CLASSIC_KEY_BYTELENGTH; i++, key <<= 8) {
{ key |= arr6Key[i];
key |= arr6Key[i]; }
} key >>= 8;
key >>= 8;
*ui64Key = key; *ui64Key = key;
return true; return true;
} }

View File

@ -1,10 +1,10 @@
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Package version: Package version:
0.1 0.1
Filename: Filename:
mfcuk_mifare.h mfcuk_mifare.h
@ -20,7 +20,7 @@
GPL2 (see below), Copyright (C) 2009, Andrei Costin GPL2 (see below), Copyright (C) 2009, Andrei Costin
* @file mfcuk_mifare.h * @file mfcuk_mifare.h
* @brief * @brief
*/ */
/* /*
@ -40,14 +40,14 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _MFCUK_MIFARE_H_ #ifndef _MFCUK_MIFARE_H_
@ -100,17 +100,17 @@
// Define an extended type of dump, basically a wrapper dump around basic tag dump // Define an extended type of dump, basically a wrapper dump around basic tag dump
typedef struct { typedef struct {
uint32_t uid; // looks redundant, but it is easier to use dmp.uid instead of dmp.amb.mbm.abtUID[0]...[3] uint32_t uid; // looks redundant, but it is easier to use dmp.uid instead of dmp.amb.mbm.abtUID[0]...[3]
uint8_t type; // ATS/SAK from ti.tia.btSak, example 0x08h for Mifare 1K, 0x18h for Mifare 4K uint8_t type; // ATS/SAK from ti.tia.btSak, example 0x08h for Mifare 1K, 0x18h for Mifare 4K
char datetime[14]; // non-zero-terminated date-time of dump in format YYYYMMDDH24MISS, example 20091114231541 - 14 Nov 2009, 11:15:41 PM char datetime[14]; // non-zero-terminated date-time of dump in format YYYYMMDDH24MISS, example 20091114231541 - 14 Nov 2009, 11:15:41 PM
char description[MFCUK_EXTENDED_DESCRIPTION_LENGTH]; // a description of the tag dump, example "RATB_DUMP_BEFORE_PAY" char description[MFCUK_EXTENDED_DESCRIPTION_LENGTH]; // a description of the tag dump, example "RATB_DUMP_BEFORE_PAY"
mifare_classic_tag tag_basic; mifare_classic_tag tag_basic;
} mifare_classic_tag_ext; } mifare_classic_tag_ext;
// Define type of keys (A or B) in NXP notation // Define type of keys (A or B) in NXP notation
typedef enum { typedef enum {
keyA = 0x60, keyA = 0x60,
keyB = 0x61, keyB = 0x61,
} mifare_key_type; } mifare_key_type;
// Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention! // Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention!

View File

@ -1,10 +1,10 @@
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Package version: Package version:
0.1 0.1
Filename: Filename:
mfcuk_utils.c mfcuk_utils.c
@ -15,7 +15,7 @@
GPL2 (see below), Copyright (C) 2009, Andrei Costin GPL2 (see below), Copyright (C) 2009, Andrei Costin
* @file mfcuk_utils.c * @file mfcuk_utils.c
* @brief * @brief
*/ */
/* /*
@ -35,20 +35,20 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mfcuk_utils.h" #include "mfcuk_utils.h"
#ifdef __STDC__ #ifdef __STDC__
struct timeval global_timeout; struct timeval global_timeout;
#endif #endif
/* /*
@ -65,17 +65,17 @@ The below code is just an optimization of the algorithm. Maxim Yegorushkin
/*inline*/ /*inline*/
int is_hex(char c) int is_hex(char c)
{ {
return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
} }
/*inline*/ /*inline*/
unsigned char hex2bin(unsigned char h, unsigned char l) unsigned char hex2bin(unsigned char h, unsigned char l)
{ {
h |= 0x20; // to lower h |= 0x20; // to lower
h -= 0x30; h -= 0x30;
h -= -(h > 9) & 0x27; h -= -(h > 9) & 0x27;
l |= 0x20; l |= 0x20;
l -= 0x30; l -= 0x30;
l -= -(l > 9) & 0x27; l -= -(l > 9) & 0x27;
return h << 4 | l; return h << 4 | l;
} }

View File

@ -1,10 +1,10 @@
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Package version: Package version:
0.1 0.1
Filename: Filename:
mfcuk_utils.h mfcuk_utils.h
@ -15,7 +15,7 @@
GPL2 (see below), Copyright (C) 2009, Andrei Costin GPL2 (see below), Copyright (C) 2009, Andrei Costin
* @file mfcuk_utils.h/ * @file mfcuk_utils.h/
* @brief * @brief
*/ */
/* /*
@ -35,14 +35,14 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _MFCUK_UTILS_H_ #ifndef _MFCUK_UTILS_H_
@ -53,28 +53,28 @@
#include <string.h> #include <string.h>
#ifdef WIN32 #ifdef WIN32
#define NOMINMAX #define NOMINMAX
#include "windows.h" #include "windows.h"
#include "xgetopt.h" #include "xgetopt.h"
#elif __STDC__ #elif __STDC__
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#endif #endif
// "Portable" sleep(miliseconds) // "Portable" sleep(miliseconds)
#ifdef WIN32 #ifdef WIN32
#define sleep(x) Sleep(x) #define sleep(x) Sleep(x)
#elif __STDC__ #elif __STDC__
extern struct timeval global_timeout; extern struct timeval global_timeout;
#define sleep(x) { global_timeout.tv_usec = 1000 * (x); select(0,NULL,NULL,NULL,&global_timeout); } #define sleep(x) { global_timeout.tv_usec = 1000 * (x); select(0,NULL,NULL,NULL,&global_timeout); }
#endif #endif
// "Portable" clear_screen() - NOTE: system performance penalty introduced // "Portable" clear_screen() - NOTE: system performance penalty introduced
#ifdef WIN32 #ifdef WIN32
#define clear_screen() system("cls") #define clear_screen() system("cls")
#elif __STDC__ #elif __STDC__
#define clear_screen() system("sh -c clear") #define clear_screen() system("sh -c clear")
#endif #endif
/** /**

View File

@ -1,223 +1,214 @@
// XGetopt.cpp Version 1.2 // XGetopt.cpp Version 1.2
// //
// Author: Hans Dietrich // Author: Hans Dietrich
// hdietrich2@hotmail.com // hdietrich2@hotmail.com
// //
// Description: // Description:
// XGetopt.cpp implements getopt(), a function to parse command lines. // XGetopt.cpp implements getopt(), a function to parse command lines.
// //
// History // History
// Version 1.2 - 2003 May 17 // Version 1.2 - 2003 May 17
// - Added Unicode support // - Added Unicode support
// //
// Version 1.1 - 2002 March 10 // Version 1.1 - 2002 March 10
// - Added example to XGetopt.cpp module header // - Added example to XGetopt.cpp module header
// //
// This software is released into the public domain. // This software is released into the public domain.
// You are free to use it in any way you like. // You are free to use it in any way you like.
// //
// This software is provided "as is" with no expressed // This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any // or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause. // damage or loss of business that this software may cause.
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// if you are using precompiled headers then include this line: // if you are using precompiled headers then include this line:
//#include "stdafx.h" //#include "stdafx.h"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// if you are not using precompiled headers then include these lines: // if you are not using precompiled headers then include these lines:
//#include //#include
//#include //#include
//#include //#include
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "xgetopt.h" #include "xgetopt.h"
///////////////////////////////////////////////////////////////////////////////
//
// X G e t o p t . c p p
//
//
// NAME
// getopt -- parse command line options
//
// SYNOPSIS
// int getopt(int argc, char *argv[], char *optstring)
//
// extern char *optarg;
// extern int optind;
//
// DESCRIPTION
// The getopt() function parses the command line arguments. Its
// arguments argc and argv are the argument count and array as
// passed into the application on program invocation. In the case
// of Visual C++ programs, argc and argv are available via the
// variables __argc and __argv (double underscores), respectively.
// getopt returns the next option letter in argv that matches a
// letter in optstring. (Note: Unicode programs should use
// __targv instead of __argv. Also, all character and string
// literals should be enclosed in _T( ) ).
//
// optstring is a string of recognized option letters; if a letter
// is followed by a colon, the option is expected to have an argument
// that may or may not be separated from it by white space. optarg
// is set to point to the start of the option argument on return from
// getopt.
//
// Option letters may be combined, e.g., "-ab" is equivalent to
// "-a -b". Option letters are case sensitive.
//
// getopt places in the external variable optind the argv index
// of the next argument to be processed. optind is initialized
// to 0 before the first call to getopt.
//
// When all options have been processed (i.e., up to the first
// non-option argument), getopt returns EOF, optarg will point
// to the argument, and optind will be set to the argv index of
// the argument. If there are no non-option arguments, optarg
// will be set to NULL.
//
// The special option "--" may be used to delimit the end of the
// options; EOF will be returned, and "--" (and everything after it)
// will be skipped.
//
// RETURN VALUE
// For option letters contained in the string optstring, getopt
// will return the option letter. getopt returns a question mark (?)
// when it encounters an option letter not included in optstring.
// EOF is returned when processing is finished.
//
// BUGS
// 1) Long options are not supported.
// 2) The GNU double-colon extension is not supported.
// 3) The environment variable POSIXLY_CORRECT is not supported.
// 4) The + syntax is not supported.
// 5) The automatic permutation of arguments is not supported.
// 6) This implementation of getopt() returns EOF if an error is
// encountered, instead of -1 as the latest standard requires.
//
// EXAMPLE
// BOOL CMyApp::ProcessCommandLine(int argc, char *argv[])
// {
// int c;
//
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
// {
// switch (c)
// {
// case _T('a'):
// TRACE(_T("option a\n"));
// //
// // set some flag here
// //
// break;
//
// case _T('B'):
// TRACE( _T("option B\n"));
// //
// // set some other flag here
// //
// break;
//
// case _T('n'):
// TRACE(_T("option n: value=%d\n"), atoi(optarg));
// //
// // do something with value here
// //
// break;
//
// case _T('?'):
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
// return FALSE;
// break;
//
// default:
// TRACE(_T("WARNING: no handler for option %c\n"), c);
// return FALSE;
// break;
// }
// }
// //
// // check for non-option args here
// //
// return TRUE;
// }
//
///////////////////////////////////////////////////////////////////////////////
char *optarg; // global argument pointer
int optind = 0; // global argv index
int getopt(int argc, char *argv[], char *optstring)
{
char c = 0;
char *cp = NULL;
static char *next = NULL; ///////////////////////////////////////////////////////////////////////////////
if (optind == 0) //
next = NULL; // X G e t o p t . c p p
//
optarg = NULL; //
// NAME
if (next == NULL || *next == '\0') // getopt -- parse command line options
{ //
if (optind == 0) // SYNOPSIS
optind++; // int getopt(int argc, char *argv[], char *optstring)
//
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') // extern char *optarg;
{ // extern int optind;
optarg = NULL; //
if (optind < argc) // DESCRIPTION
optarg = argv[optind]; // The getopt() function parses the command line arguments. Its
return EOF; // arguments argc and argv are the argument count and array as
} // passed into the application on program invocation. In the case
// of Visual C++ programs, argc and argv are available via the
if (strcmp(argv[optind], "--") == 0) // variables __argc and __argv (double underscores), respectively.
{ // getopt returns the next option letter in argv that matches a
optind++; // letter in optstring. (Note: Unicode programs should use
optarg = NULL; // __targv instead of __argv. Also, all character and string
if (optind < argc) // literals should be enclosed in _T( ) ).
optarg = argv[optind]; //
return EOF; // optstring is a string of recognized option letters; if a letter
} // is followed by a colon, the option is expected to have an argument
// that may or may not be separated from it by white space. optarg
next = argv[optind]; // is set to point to the start of the option argument on return from
next++; // skip past - // getopt.
optind++; //
} // Option letters may be combined, e.g., "-ab" is equivalent to
// "-a -b". Option letters are case sensitive.
c = *next++; //
cp = strchr(optstring, c); // getopt places in the external variable optind the argv index
// of the next argument to be processed. optind is initialized
if (cp == NULL || c == ':') // to 0 before the first call to getopt.
return '?'; //
// When all options have been processed (i.e., up to the first
cp++; // non-option argument), getopt returns EOF, optarg will point
if (*cp == ':') // to the argument, and optind will be set to the argv index of
{ // the argument. If there are no non-option arguments, optarg
if (*next != '\0') // will be set to NULL.
{ //
optarg = next; // The special option "--" may be used to delimit the end of the
next = NULL; // options; EOF will be returned, and "--" (and everything after it)
} // will be skipped.
else if (optind < argc) //
{ // RETURN VALUE
optarg = argv[optind]; // For option letters contained in the string optstring, getopt
optind++; // will return the option letter. getopt returns a question mark (?)
} // when it encounters an option letter not included in optstring.
else // EOF is returned when processing is finished.
{ //
return '?'; // BUGS
} // 1) Long options are not supported.
} // 2) The GNU double-colon extension is not supported.
// 3) The environment variable POSIXLY_CORRECT is not supported.
return c; // 4) The + syntax is not supported.
} // 5) The automatic permutation of arguments is not supported.
// 6) This implementation of getopt() returns EOF if an error is
// encountered, instead of -1 as the latest standard requires.
//
// EXAMPLE
// BOOL CMyApp::ProcessCommandLine(int argc, char *argv[])
// {
// int c;
//
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
// {
// switch (c)
// {
// case _T('a'):
// TRACE(_T("option a\n"));
// //
// // set some flag here
// //
// break;
//
// case _T('B'):
// TRACE( _T("option B\n"));
// //
// // set some other flag here
// //
// break;
//
// case _T('n'):
// TRACE(_T("option n: value=%d\n"), atoi(optarg));
// //
// // do something with value here
// //
// break;
//
// case _T('?'):
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
// return FALSE;
// break;
//
// default:
// TRACE(_T("WARNING: no handler for option %c\n"), c);
// return FALSE;
// break;
// }
// }
// //
// // check for non-option args here
// //
// return TRUE;
// }
//
///////////////////////////////////////////////////////////////////////////////
char *optarg; // global argument pointer
int optind = 0; // global argv index
int getopt(int argc, char *argv[], char *optstring)
{
char c = 0;
char *cp = NULL;
static char *next = NULL;
if (optind == 0)
next = NULL;
optarg = NULL;
if (next == NULL || *next == '\0') {
if (optind == 0)
optind++;
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') {
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
if (strcmp(argv[optind], "--") == 0) {
optind++;
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
next = argv[optind];
next++; // skip past -
optind++;
}
c = *next++;
cp = strchr(optstring, c);
if (cp == NULL || c == ':')
return '?';
cp++;
if (*cp == ':') {
if (*next != '\0') {
optarg = next;
next = NULL;
} else if (optind < argc) {
optarg = argv[optind];
optind++;
} else {
return '?';
}
}
return c;
}

View File

@ -1,23 +1,23 @@
// XGetopt.h Version 1.2 // XGetopt.h Version 1.2
// //
// Author: Hans Dietrich // Author: Hans Dietrich
// hdietrich2@hotmail.com // hdietrich2@hotmail.com
// //
// This software is released into the public domain. // This software is released into the public domain.
// You are free to use it in any way you like. // You are free to use it in any way you like.
// //
// This software is provided "as is" with no expressed // This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any // or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause. // damage or loss of business that this software may cause.
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#ifndef XGETOPT_H #ifndef XGETOPT_H
#define XGETOPT_H #define XGETOPT_H
extern int optind, opterr; extern int optind, opterr;
extern char *optarg; extern char *optarg;
int getopt(int argc, char *argv[], char *optstring); int getopt(int argc, char *argv[], char *optstring);
#endif //XGETOPT_H #endif //XGETOPT_H