Convert all remaining dos files to unix format.

This commit is contained in:
romuald@libnfc.org 2012-09-23 10:29:36 +00:00
parent 4ddf2de7b2
commit 1b6d022668
6 changed files with 1079 additions and 1079 deletions

View File

@ -1,487 +1,487 @@
/* crapto1.c /* crapto1.c
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (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, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, US$ Boston, MA 02110-1301, US$
Copyright (C) 2008-2008 bla <blapost@gmail.com> Copyright (C) 2008-2008 bla <blapost@gmail.com>
*/ */
#include "crapto1.h" #include "crapto1.h"
#include <stdlib.h> #include <stdlib.h>
#if !defined LOWMEM && defined __GNUC__ #if !defined LOWMEM && defined __GNUC__
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* static inline uint32_t*
binsearch(uint32_t *start, uint32_t *stop) 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
* helper, calculates the partial linear feedback contributions and puts in MSB * helper, calculates the partial linear feedback contributions and puts in MSB
*/ */
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
* 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 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 static inline void
extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) 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++) {
extend_table(o_head, &o_tail, (oks >>= 1) & 1, extend_table(o_head, &o_tail, (oks >>= 1) & 1,
LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); LF_POLY_EVEN << 1 | 1, 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) & 1, extend_table(e_head, &e_tail, (eks >>= 1) & 1,
LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, (in >>= 2) & 3); LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, (in >>= 2) & 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)
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] = BIT(ks2, i ^ 24); oks[i >> 1] = BIT(ks2, i ^ 24);
oks[16 + (i >> 1)] = BIT(ks3, i ^ 24); oks[16 + (i >> 1)] = BIT(ks3, i ^ 24);
} }
for(i = 31; i >= 0; i -= 2) { for(i = 31; i >= 0; i -= 2) {
eks[i >> 1] = BIT(ks2, i ^ 24); eks[i >> 1] = BIT(ks2, i ^ 24);
eks[16 + (i >> 1)] = BIT(ks3, i ^ 24); eks[16 + (i >> 1)] = BIT(ks3, i ^ 24);
} }
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
* Rollback the shift register in order to get previous states * Rollback the shift register in order to get previous states
*/ */
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; int i;
uint8_t ret = 0; uint8_t 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
* x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y
*/ */
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
* Described in the "dark side" paper. It returns an -1 terminated array * Described in the "dark side" paper. It returns an -1 terminated array
* of possible partial(21 bit) secret state. * of possible partial(21 bit) secret state.
* The required keystream(ks) needs to contain the keystream that was used to * The required keystream(ks) needs to contain the keystream that was used to
* encrypt the NACK which is observed when varying only the 4 last bits of Nr * encrypt the NACK which is observed when varying only the 4 last bits of Nr
* only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3
*/ */
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 << 21); uint32_t c, entry, *candidates = malloc(4 << 21);
int i, size = (1 << 21) - 1; int i, size = (1 << 21) - 1;
if(!candidates) if(!candidates)
return 0; return 0;
for(i = 0; i <= size; ++i) for(i = 0; i <= size; ++i)
candidates[i] = i; candidates[i] = i;
for(c = 0; c < 8; ++c) for(c = 0; c < 8; ++c)
for(i = 0;i <= size; ++i) { for(i = 0;i <= size; ++i) {
entry = candidates[i] ^ fastfwd[isodd][c]; entry = candidates[i] ^ fastfwd[isodd][c];
if(filter(entry >> 1) != BIT(ks[c], isodd) || if(filter(entry >> 1) != BIT(ks[c], isodd) ||
filter(entry) != BIT(ks[c], isodd + 2)) filter(entry) != BIT(ks[c], isodd + 2))
candidates[i--] = candidates[size--]; candidates[i--] = candidates[size--];
} }
candidates[size + 1] = -1; candidates[size + 1] = -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.
* Requires the 29 bit constant prefix used as reader nonce (pfx) * Requires the 29 bit constant prefix used as reader nonce (pfx)
* The reader response used (rr) * The reader response used (rr)
* The keystream used to encrypt the observed NACK's (ks) * The keystream used to encrypt the observed NACK's (ks)
* The parity bits (par) * The parity bits (par)
* It returns a zero terminated list of possible cipher states after the * It returns a zero terminated list of possible cipher states after the
* tag nonce was fed in * tag nonce was fed in
*/ */
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(odd); free(odd);
free(even); free(even);
free(statelist); free(statelist);
return 0; return 0;
} }
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;
free(odd); free(odd);
free(even); free(even);
return statelist; return statelist;
} }

View File

@ -1,120 +1,120 @@
/* /*
Package: Package:
MiFare Classic Universal toolKit (MFCUK) MiFare Classic Universal toolKit (MFCUK)
Filename: Filename:
mfcuk_keyrecovery_darkside.h mfcuk_keyrecovery_darkside.h
Description: Description:
MFCUK DarkSide Key Recovery specific typedefs and defines MFCUK DarkSide Key Recovery specific typedefs and defines
Contact, bug-reports: Contact, bug-reports:
http://andreicostin.com/ http://andreicostin.com/
mailto:zveriu@gmail.com mailto:zveriu@gmail.com
License: License:
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
*/ */
/* /*
VERSION HISTORY VERSION HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
| Number : 0.1 | Number : 0.1
| dd/mm/yyyy : 23/11/2009 | dd/mm/yyyy : 23/11/2009
| Author : zveriu@gmail.com, http://andreicostin.com | Author : zveriu@gmail.com, http://andreicostin.com
| Description: Moved bulk of defines and things from "mfcuk_keyrecovery_darkside.c" | Description: Moved bulk of defines and things from "mfcuk_keyrecovery_darkside.c"
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
*/ */
/* /*
LICENSE LICENSE
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by 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_
#define _MFCUK_KEYRECOVERY_DARKSIDE_H_ #define _MFCUK_KEYRECOVERY_DARKSIDE_H_
// Define package and executable related info // Define package and executable related info
#define BUILD_NAME "Mifare Classic DarkSide Key Recovery Tool" #define BUILD_NAME "Mifare Classic DarkSide Key Recovery Tool"
#define BUILD_VERSION "0.3" #define BUILD_VERSION "0.3"
#define BUILD_AUTHOR "Andrei Costin, zveriu@gmail.com, http://andreicostin.com" #define BUILD_AUTHOR "Andrei Costin, zveriu@gmail.com, http://andreicostin.com"
// Define return statuses // Define return statuses
#define MFCUK_SUCCESS 0x0 #define MFCUK_SUCCESS 0x0
#define MFCUK_OK_KEY_RECOVERED (MFCUK_SUCCESS+1) #define MFCUK_OK_KEY_RECOVERED (MFCUK_SUCCESS+1)
#define MFCUK_FAIL_AUTH (MFCUK_OK_KEY_RECOVERED+1) #define MFCUK_FAIL_AUTH (MFCUK_OK_KEY_RECOVERED+1)
#define MFCUK_FAIL_CRAPTO (MFCUK_FAIL_AUTH+1) #define MFCUK_FAIL_CRAPTO (MFCUK_FAIL_AUTH+1)
#define MFCUK_FAIL_TAGTYPE_INVALID (MFCUK_FAIL_CRAPTO+1) #define MFCUK_FAIL_TAGTYPE_INVALID (MFCUK_FAIL_CRAPTO+1)
#define MFCUK_FAIL_KEYTYPE_INVALID (MFCUK_FAIL_TAGTYPE_INVALID+1) #define MFCUK_FAIL_KEYTYPE_INVALID (MFCUK_FAIL_TAGTYPE_INVALID+1)
#define MFCUK_FAIL_BLOCK_INVALID (MFCUK_FAIL_KEYTYPE_INVALID+1) #define MFCUK_FAIL_BLOCK_INVALID (MFCUK_FAIL_KEYTYPE_INVALID+1)
#define MFCUK_FAIL_SECTOR_INVALID (MFCUK_FAIL_BLOCK_INVALID+1) #define MFCUK_FAIL_SECTOR_INVALID (MFCUK_FAIL_BLOCK_INVALID+1)
#define MFCUK_FAIL_COMM (MFCUK_FAIL_SECTOR_INVALID+1) #define MFCUK_FAIL_COMM (MFCUK_FAIL_SECTOR_INVALID+1)
#define MFCUK_FAIL_MEMORY (MFCUK_FAIL_COMM+1) #define MFCUK_FAIL_MEMORY (MFCUK_FAIL_COMM+1)
// There are 4 bytes in ACBITS, use each byte as below // There are 4 bytes in ACBITS, use each byte as below
#define ACTIONS_KEY_A 0 // Specifies the byte index where actions for key A are stored #define ACTIONS_KEY_A 0 // Specifies the byte index where actions for key A are stored
#define RESULTS_KEY_A 1 // Specifies the byte index where results for key A are stored #define RESULTS_KEY_A 1 // Specifies the byte index where results for key A are stored
#define ACTIONS_KEY_B 2 // Specifies the byte index where actions for key B are stored #define ACTIONS_KEY_B 2 // Specifies the byte index where actions for key B are stored
#define RESULTS_KEY_B 3 // Specifies the byte index where results for key B are stored #define RESULTS_KEY_B 3 // Specifies the byte index where results for key B are stored
// The action/result byte can contain any combination of these // The action/result byte can contain any combination of these
#define ACTIONS_VERIFY 0x1 // Specifies whether the key should be first verified #define ACTIONS_VERIFY 0x1 // Specifies whether the key should be first verified
#define ACTIONS_RECOVER 0x2 // Specifies whether the key should be recovered. If a key has verify action and the key was verified, RESULTS_ byte will indicate that and recovery will not take place #define ACTIONS_RECOVER 0x2 // Specifies whether the key should be recovered. If a key has verify action and the key was verified, RESULTS_ byte will indicate that and recovery will not take place
#define ACTIONS_KEYSET 0x4 // Specifies whether the key was set from command line rather that should be loaded from the eventual -i/-I dump #define ACTIONS_KEYSET 0x4 // Specifies whether the key was set from command line rather that should be loaded from the eventual -i/-I dump
// Implementation specific, since we are not 100% sure we can fix the tag nonce // Implementation specific, since we are not 100% sure we can fix the tag nonce
// Suppose from 2^32, only MAX 2^16 tag nonces will appear given current SLEEP_ values // Suppose from 2^32, only MAX 2^16 tag nonces will appear given current SLEEP_ values
#define MAX_TAG_NONCES 65536 #define MAX_TAG_NONCES 65536
// Maximum possible states allocated and returned by lsfr_common_prefix(). Used this value in the looping // Maximum possible states allocated and returned by lsfr_common_prefix(). Used this value in the looping
#define MAX_COMMON_PREFIX_STATES (1<<20) #define MAX_COMMON_PREFIX_STATES (1<<20)
// 10 ms, though {WPMCC09} claims 30 us is enough // 10 ms, though {WPMCC09} claims 30 us is enough
#define SLEEP_AT_FIELD_OFF 10 #define SLEEP_AT_FIELD_OFF 10
// 50 ms, seems pretty good constant, though if you don't like it - make it even 3.1415..., we don't care // 50 ms, seems pretty good constant, though if you don't like it - make it even 3.1415..., we don't care
#define SLEEP_AFTER_FIELD_ON 50 #define SLEEP_AFTER_FIELD_ON 50
// Since the 29 bits of {Nr} are constant, darkside varies only "last" (0xFFFFFF1F) 3 bits, thus we have 8 possible parity bits arrays // Since the 29 bits of {Nr} are constant, darkside varies only "last" (0xFFFFFF1F) 3 bits, thus we have 8 possible parity bits arrays
#define MFCUK_DARKSIDE_MAX_LEVELS 8 #define MFCUK_DARKSIDE_MAX_LEVELS 8
#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
byte_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 byte_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

@ -1,145 +1,145 @@
/* /*
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
Description: Description:
MFCUK defines and function prototypes header file extending MFCUK defines and function prototypes header file extending
mainly libnfc's "mifare.h" interface/functionality. mainly libnfc's "mifare.h" interface/functionality.
Contact, bug-reports: Contact, bug-reports:
http://andreicostin.com/ http://andreicostin.com/
mailto:zveriu@gmail.com mailto:zveriu@gmail.com
License: License:
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
*/ */
/* /*
VERSION HISTORY VERSION HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
| Number : 0.1 | Number : 0.1
| dd/mm/yyyy : 23/11/2009 | dd/mm/yyyy : 23/11/2009
| Author : zveriu@gmail.com, http://andreicostin.com | Author : zveriu@gmail.com, http://andreicostin.com
| Description: Moved bulk of defines and functions from "mfcuk_keyrecovery_darkside.c" | Description: Moved bulk of defines and functions from "mfcuk_keyrecovery_darkside.c"
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
*/ */
/* /*
LICENSE LICENSE
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by 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_
#define _MFCUK_MIFARE_H_ #define _MFCUK_MIFARE_H_
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include "mifare.h" #include "mifare.h"
#define MIFARE_CLASSIC_UID_BYTELENGTH 4 // Length of a Mifare Classic UID in bytes #define MIFARE_CLASSIC_UID_BYTELENGTH 4 // Length of a Mifare Classic UID in bytes
#define MIFARE_CLASSIC_KEY_BYTELENGTH 6 // Length of a Mifare Classic key in bytes #define MIFARE_CLASSIC_KEY_BYTELENGTH 6 // Length of a Mifare Classic key in bytes
#define MIFARE_CLASSIC_1K_NAME "MC1K" #define MIFARE_CLASSIC_1K_NAME "MC1K"
#define MIFARE_CLASSIC_4K_NAME "MC4K" #define MIFARE_CLASSIC_4K_NAME "MC4K"
#define MIFARE_CLASSIC_UNKN_NAME "UNKN" #define MIFARE_CLASSIC_UNKN_NAME "UNKN"
#define MIFARE_CLASSIC_1K 0x08 // MF1ICS50 Functional Specifications - 0x08 #define MIFARE_CLASSIC_1K 0x08 // MF1ICS50 Functional Specifications - 0x08
#define MIFARE_CLASSIC_4K 0x18 // MF1ICS70 Functional Specifications - 0x18 #define MIFARE_CLASSIC_4K 0x18 // MF1ICS70 Functional Specifications - 0x18
#define MIFARE_DESFIRE 0x20 // XXXXXXXX Functional Specifications - 0x20 #define MIFARE_DESFIRE 0x20 // XXXXXXXX Functional Specifications - 0x20
#define MIFARE_CLASSIC_1K_RATB 0x88 // Infineon Licensed Mifare 1K = 0x88 (thanks JPS) #define MIFARE_CLASSIC_1K_RATB 0x88 // Infineon Licensed Mifare 1K = 0x88 (thanks JPS)
#define MIFARE_CLASSIC_4K_SKGT 0x98 // Infineon Licensed Mifare 4K = 0x98??? #define MIFARE_CLASSIC_4K_SKGT 0x98 // Infineon Licensed Mifare 4K = 0x98???
#define IS_MIFARE_CLASSIC_1K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_1K) || ((ats_sak) == MIFARE_CLASSIC_1K_RATB) ) #define IS_MIFARE_CLASSIC_1K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_1K) || ((ats_sak) == MIFARE_CLASSIC_1K_RATB) )
#define IS_MIFARE_CLASSIC_4K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_4K) || ((ats_sak) == MIFARE_CLASSIC_4K_SKGT) ) #define IS_MIFARE_CLASSIC_4K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_4K) || ((ats_sak) == MIFARE_CLASSIC_4K_SKGT) )
#define IS_MIFARE_DESFIRE(ats_sak) ( ((ats_sak) == MIFARE_DESFIRE) ) #define IS_MIFARE_DESFIRE(ats_sak) ( ((ats_sak) == MIFARE_DESFIRE) )
#define IS_MIFARE_CLASSIC_1K_TAG(tag) IS_MIFARE_CLASSIC_1K(tag->amb[0].mbm.btUnknown) #define IS_MIFARE_CLASSIC_1K_TAG(tag) IS_MIFARE_CLASSIC_1K(tag->amb[0].mbm.btUnknown)
#define IS_MIFARE_CLASSIC_4K_TAG(tag) IS_MIFARE_CLASSIC_4K(tag->amb[0].mbm.btUnknown) #define IS_MIFARE_CLASSIC_4K_TAG(tag) IS_MIFARE_CLASSIC_4K(tag->amb[0].mbm.btUnknown)
#define IS_MIFARE_DESFIRE_TAG(tag) IS_MIFARE_DESFIRE(tag->amb[0].mbm.btUnknown) #define IS_MIFARE_DESFIRE_TAG(tag) IS_MIFARE_DESFIRE(tag->amb[0].mbm.btUnknown)
#define MIFARE_CLASSIC_BYTES_PER_BLOCK 16 // Common for Mifare Classic 1K and Mifare Classic 4K #define MIFARE_CLASSIC_BYTES_PER_BLOCK 16 // Common for Mifare Classic 1K and Mifare Classic 4K
#define MIFARE_CLASSIC_INVALID_BLOCK 0xFFFFFFFF #define MIFARE_CLASSIC_INVALID_BLOCK 0xFFFFFFFF
#define MIFARE_CLASSIC_1K_MAX_SECTORS 16 #define MIFARE_CLASSIC_1K_MAX_SECTORS 16
#define MIFARE_CLASSIC_1K_BLOCKS_PER_SECTOR 4 #define MIFARE_CLASSIC_1K_BLOCKS_PER_SECTOR 4
#define MIFARE_CLASSIC_1K_MAX_BLOCKS ( (MIFARE_CLASSIC_1K_MAX_SECTORS) * (MIFARE_CLASSIC_1K_BLOCKS_PER_SECTOR) ) #define MIFARE_CLASSIC_1K_MAX_BLOCKS ( (MIFARE_CLASSIC_1K_MAX_SECTORS) * (MIFARE_CLASSIC_1K_BLOCKS_PER_SECTOR) )
#define MIFARE_CLASSIC_4K_MAX_SECTORS1 32 #define MIFARE_CLASSIC_4K_MAX_SECTORS1 32
#define MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 MIFARE_CLASSIC_1K_BLOCKS_PER_SECTOR // Possibly NXP made it for Mifare 1K backward compatibility #define MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 MIFARE_CLASSIC_1K_BLOCKS_PER_SECTOR // Possibly NXP made it for Mifare 1K backward compatibility
#define MIFARE_CLASSIC_4K_MAX_BLOCKS1 ( (MIFARE_CLASSIC_4K_MAX_SECTORS1) * (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) ) #define MIFARE_CLASSIC_4K_MAX_BLOCKS1 ( (MIFARE_CLASSIC_4K_MAX_SECTORS1) * (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) )
#define MIFARE_CLASSIC_4K_MAX_SECTORS2 8 #define MIFARE_CLASSIC_4K_MAX_SECTORS2 8
#define MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 16 #define MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 16
#define MIFARE_CLASSIC_4K_MAX_BLOCKS2 ( (MIFARE_CLASSIC_4K_MAX_SECTORS2) * (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) ) #define MIFARE_CLASSIC_4K_MAX_BLOCKS2 ( (MIFARE_CLASSIC_4K_MAX_SECTORS2) * (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) )
#define MIFARE_CLASSIC_4K_MAX_SECTORS ( (MIFARE_CLASSIC_4K_MAX_SECTORS1) + (MIFARE_CLASSIC_4K_MAX_SECTORS2) ) #define MIFARE_CLASSIC_4K_MAX_SECTORS ( (MIFARE_CLASSIC_4K_MAX_SECTORS1) + (MIFARE_CLASSIC_4K_MAX_SECTORS2) )
#define MIFARE_CLASSIC_4K_MAX_BLOCKS ( (MIFARE_CLASSIC_4K_MAX_BLOCKS1) + (MIFARE_CLASSIC_4K_MAX_BLOCKS2) ) #define MIFARE_CLASSIC_4K_MAX_BLOCKS ( (MIFARE_CLASSIC_4K_MAX_BLOCKS1) + (MIFARE_CLASSIC_4K_MAX_BLOCKS2) )
#define MFCUK_EXTENDED_DESCRIPTION_LENGTH 128 #define MFCUK_EXTENDED_DESCRIPTION_LENGTH 128
// 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]
byte_t type; // ATS/SAK from ti.tia.btSak, example 0x08h for Mifare 1K, 0x18h for Mifare 4K byte_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!
extern byte_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH]; extern byte_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH];
extern int mfcuk_default_keys_num; extern int mfcuk_default_keys_num;
bool is_valid_block(byte_t bTagType, uint32_t uiBlock); bool is_valid_block(byte_t bTagType, uint32_t uiBlock);
bool is_valid_sector(byte_t bTagType, uint32_t uiSector); bool is_valid_sector(byte_t bTagType, uint32_t uiSector);
bool is_first_block(byte_t bTagType, uint32_t uiBlock); bool is_first_block(byte_t bTagType, uint32_t uiBlock);
bool is_trailer_block(byte_t bTagType, uint32_t uiBlock); bool is_trailer_block(byte_t bTagType, uint32_t uiBlock);
uint32_t get_first_block(byte_t bTagType, uint32_t uiBlock); uint32_t get_first_block(byte_t bTagType, uint32_t uiBlock);
uint32_t get_trailer_block(byte_t bTagType, uint32_t uiBlock); uint32_t get_trailer_block(byte_t bTagType, uint32_t uiBlock);
bool is_big_sector(byte_t bTagType, uint32_t uiSector); bool is_big_sector(byte_t bTagType, uint32_t uiSector);
uint32_t get_first_block_for_sector(byte_t bTagType, uint32_t uiSector); uint32_t get_first_block_for_sector(byte_t bTagType, uint32_t uiSector);
uint32_t get_trailer_block_for_sector(byte_t bTagType, uint32_t uiSector); uint32_t get_trailer_block_for_sector(byte_t bTagType, uint32_t uiSector);
uint32_t get_sector_for_block(byte_t bTagType, uint32_t uiBlock); uint32_t get_sector_for_block(byte_t bTagType, uint32_t uiBlock);
bool is_first_sector(byte_t bTagType, uint32_t uiSector); bool is_first_sector(byte_t bTagType, uint32_t uiSector);
bool is_first_big_sector(byte_t bTagType, uint32_t uiSector); bool is_first_big_sector(byte_t bTagType, uint32_t uiSector);
bool is_first_small_sector(byte_t bTagType, uint32_t uiSector); bool is_first_small_sector(byte_t bTagType, uint32_t uiSector);
bool is_last_sector(byte_t bTagType, uint32_t uiSector); bool is_last_sector(byte_t bTagType, uint32_t uiSector);
bool is_last_big_sector(byte_t bTagType, uint32_t uiSector); bool is_last_big_sector(byte_t bTagType, uint32_t uiSector);
bool is_last_small_sector(byte_t bTagType, uint32_t uiSector); bool is_last_small_sector(byte_t bTagType, uint32_t uiSector);
void test_mifare_classic_blocks_sectors_functions(byte_t bTagType); void test_mifare_classic_blocks_sectors_functions(byte_t bTagType);
bool mfcuk_save_tag_dump(char *filename, mifare_classic_tag *tag); bool mfcuk_save_tag_dump(char *filename, mifare_classic_tag *tag);
bool mfcuk_save_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext); bool mfcuk_save_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext);
bool mfcuk_load_tag_dump(char *filename, mifare_classic_tag *tag); bool mfcuk_load_tag_dump(char *filename, mifare_classic_tag *tag);
bool mfcuk_load_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext); bool mfcuk_load_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext);
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);
bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, byte_t *arr6Key); bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, byte_t *arr6Key);
bool mfcuk_key_arr_to_uint64(const byte_t *arr6Key, uint64_t *ui64Key); bool mfcuk_key_arr_to_uint64(const byte_t *arr6Key, uint64_t *ui64Key);
#endif // _MFCUK_MIFARE_H_ #endif // _MFCUK_MIFARE_H_

View File

@ -1,81 +1,81 @@
/* /*
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
Description: Description:
MFCUK common utility functions implementation. MFCUK common utility functions implementation.
License: License:
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
*/ */
/* /*
VERSION HISTORY VERSION HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
| Number : 0.1 | Number : 0.1
| dd/mm/yyyy : 23/11/2009 | dd/mm/yyyy : 23/11/2009
| Author : zveriu@gmail.com, http://andreicostin.com | Author : zveriu@gmail.com, http://andreicostin.com
| Description: Moved bulk of defines and prototypes from "mfcuk_keyrecovery_darkside.c" | Description: Moved bulk of defines and prototypes from "mfcuk_keyrecovery_darkside.c"
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
*/ */
/* /*
LICENSE LICENSE
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by 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
/* /*
http://www.velocityreviews.com/forums/t451319-advice-required-on-my-ascii-to-hex-conversion-c.html http://www.velocityreviews.com/forums/t451319-advice-required-on-my-ascii-to-hex-conversion-c.html
Basically, converting a hex digit into a hex nibble (4 binary digits) algorithm looks like; Basically, converting a hex digit into a hex nibble (4 binary digits) algorithm looks like;
char xdigit; // hex digit to convert [0-9A-Fa-f] char xdigit; // hex digit to convert [0-9A-Fa-f]
xdigit = tolower(xdigit); // make it lowercase [0-9a-f] xdigit = tolower(xdigit); // make it lowercase [0-9a-f]
xdigit -= '0'; // if it was a [0-9] digit, it's the value now xdigit -= '0'; // if it was a [0-9] digit, it's the value now
if(xdigit > 9) // if it was a [a-f] digit, compensate for that if(xdigit > 9) // if it was a [a-f] digit, compensate for that
xdigit = xdigit + '0' - 'a'; xdigit = xdigit + '0' - 'a';
The below code is just an optimization of the algorithm. Maxim Yegorushkin 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,223 +1,223 @@
// 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 // X G e t o p t . c p p
// //
// //
// NAME // NAME
// getopt -- parse command line options // getopt -- parse command line options
// //
// SYNOPSIS // SYNOPSIS
// int getopt(int argc, char *argv[], char *optstring) // int getopt(int argc, char *argv[], char *optstring)
// //
// extern char *optarg; // extern char *optarg;
// extern int optind; // extern int optind;
// //
// DESCRIPTION // DESCRIPTION
// The getopt() function parses the command line arguments. Its // The getopt() function parses the command line arguments. Its
// arguments argc and argv are the argument count and array as // arguments argc and argv are the argument count and array as
// passed into the application on program invocation. In the case // passed into the application on program invocation. In the case
// of Visual C++ programs, argc and argv are available via the // of Visual C++ programs, argc and argv are available via the
// variables __argc and __argv (double underscores), respectively. // variables __argc and __argv (double underscores), respectively.
// getopt returns the next option letter in argv that matches a // getopt returns the next option letter in argv that matches a
// letter in optstring. (Note: Unicode programs should use // letter in optstring. (Note: Unicode programs should use
// __targv instead of __argv. Also, all character and string // __targv instead of __argv. Also, all character and string
// literals should be enclosed in _T( ) ). // literals should be enclosed in _T( ) ).
// //
// optstring is a string of recognized option letters; if a letter // optstring is a string of recognized option letters; if a letter
// is followed by a colon, the option is expected to have an argument // 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 // 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 // is set to point to the start of the option argument on return from
// getopt. // getopt.
// //
// Option letters may be combined, e.g., "-ab" is equivalent to // Option letters may be combined, e.g., "-ab" is equivalent to
// "-a -b". Option letters are case sensitive. // "-a -b". Option letters are case sensitive.
// //
// getopt places in the external variable optind the argv index // getopt places in the external variable optind the argv index
// of the next argument to be processed. optind is initialized // of the next argument to be processed. optind is initialized
// to 0 before the first call to getopt. // to 0 before the first call to getopt.
// //
// When all options have been processed (i.e., up to the first // When all options have been processed (i.e., up to the first
// non-option argument), getopt returns EOF, optarg will point // non-option argument), getopt returns EOF, optarg will point
// to the argument, and optind will be set to the argv index of // to the argument, and optind will be set to the argv index of
// the argument. If there are no non-option arguments, optarg // the argument. If there are no non-option arguments, optarg
// will be set to NULL. // will be set to NULL.
// //
// The special option "--" may be used to delimit the end of the // The special option "--" may be used to delimit the end of the
// options; EOF will be returned, and "--" (and everything after it) // options; EOF will be returned, and "--" (and everything after it)
// will be skipped. // will be skipped.
// //
// RETURN VALUE // RETURN VALUE
// For option letters contained in the string optstring, getopt // For option letters contained in the string optstring, getopt
// will return the option letter. getopt returns a question mark (?) // will return the option letter. getopt returns a question mark (?)
// when it encounters an option letter not included in optstring. // when it encounters an option letter not included in optstring.
// EOF is returned when processing is finished. // EOF is returned when processing is finished.
// //
// BUGS // BUGS
// 1) Long options are not supported. // 1) Long options are not supported.
// 2) The GNU double-colon extension is not supported. // 2) The GNU double-colon extension is not supported.
// 3) The environment variable POSIXLY_CORRECT is not supported. // 3) The environment variable POSIXLY_CORRECT is not supported.
// 4) The + syntax is not supported. // 4) The + syntax is not supported.
// 5) The automatic permutation of arguments is not supported. // 5) The automatic permutation of arguments is not supported.
// 6) This implementation of getopt() returns EOF if an error is // 6) This implementation of getopt() returns EOF if an error is
// encountered, instead of -1 as the latest standard requires. // encountered, instead of -1 as the latest standard requires.
// //
// EXAMPLE // EXAMPLE
// BOOL CMyApp::ProcessCommandLine(int argc, char *argv[]) // BOOL CMyApp::ProcessCommandLine(int argc, char *argv[])
// { // {
// int c; // int c;
// //
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF) // while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
// { // {
// switch (c) // switch (c)
// { // {
// case _T('a'): // case _T('a'):
// TRACE(_T("option a\n")); // TRACE(_T("option a\n"));
// // // //
// // set some flag here // // set some flag here
// // // //
// break; // break;
// //
// case _T('B'): // case _T('B'):
// TRACE( _T("option B\n")); // TRACE( _T("option B\n"));
// // // //
// // set some other flag here // // set some other flag here
// // // //
// break; // break;
// //
// case _T('n'): // case _T('n'):
// TRACE(_T("option n: value=%d\n"), atoi(optarg)); // TRACE(_T("option n: value=%d\n"), atoi(optarg));
// // // //
// // do something with value here // // do something with value here
// // // //
// break; // break;
// //
// case _T('?'): // case _T('?'):
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); // TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
// return FALSE; // return FALSE;
// break; // break;
// //
// default: // default:
// TRACE(_T("WARNING: no handler for option %c\n"), c); // TRACE(_T("WARNING: no handler for option %c\n"), c);
// return FALSE; // return FALSE;
// break; // break;
// } // }
// } // }
// // // //
// // check for non-option args here // // check for non-option args here
// // // //
// return TRUE; // return TRUE;
// } // }
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
char *optarg; // global argument pointer char *optarg; // global argument pointer
int optind = 0; // global argv index int optind = 0; // global argv index
int getopt(int argc, char *argv[], char *optstring) int getopt(int argc, char *argv[], char *optstring)
{ {
char c = 0; char c = 0;
char *cp = NULL; char *cp = NULL;
static char *next = NULL; static char *next = NULL;
if (optind == 0) if (optind == 0)
next = NULL; next = NULL;
optarg = NULL; optarg = NULL;
if (next == NULL || *next == '\0') if (next == NULL || *next == '\0')
{ {
if (optind == 0) if (optind == 0)
optind++; optind++;
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
{ {
optarg = NULL; optarg = NULL;
if (optind < argc) if (optind < argc)
optarg = argv[optind]; optarg = argv[optind];
return EOF; return EOF;
} }
if (strcmp(argv[optind], "--") == 0) if (strcmp(argv[optind], "--") == 0)
{ {
optind++; optind++;
optarg = NULL; optarg = NULL;
if (optind < argc) if (optind < argc)
optarg = argv[optind]; optarg = argv[optind];
return EOF; return EOF;
} }
next = argv[optind]; next = argv[optind];
next++; // skip past - next++; // skip past -
optind++; optind++;
} }
c = *next++; c = *next++;
cp = strchr(optstring, c); cp = strchr(optstring, c);
if (cp == NULL || c == ':') if (cp == NULL || c == ':')
return '?'; return '?';
cp++; cp++;
if (*cp == ':') if (*cp == ':')
{ {
if (*next != '\0') if (*next != '\0')
{ {
optarg = next; optarg = next;
next = NULL; next = NULL;
} }
else if (optind < argc) else if (optind < argc)
{ {
optarg = argv[optind]; optarg = argv[optind];
optind++; optind++;
} }
else else
{ {
return '?'; return '?';
} }
} }
return c; 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