client: fix mix of spaces & tabs

This commit is contained in:
Philippe Teuwen
2019-03-09 23:35:06 +01:00
parent 112411042f
commit 0d9223a547
197 changed files with 49383 additions and 49383 deletions

View File

@@ -50,151 +50,151 @@
/**
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
* consisting of the following four components:
* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
**/
typedef struct {
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
} State;
/**
* Definition 2. The feedback function for the top register T : F 16/2 → F 2
* is defined as
* T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 .
* Definition 2. The feedback function for the top register T : F 16/2 → F 2
* is defined as
* T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 .
**/
bool T(State state)
{
bool x0 = state.t & 0x8000;
bool x1 = state.t & 0x4000;
bool x5 = state.t & 0x0400;
bool x7 = state.t & 0x0100;
bool x10 = state.t & 0x0020;
bool x11 = state.t & 0x0010;
bool x14 = state.t & 0x0002;
bool x15 = state.t & 0x0001;
return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
bool x0 = state.t & 0x8000;
bool x1 = state.t & 0x4000;
bool x5 = state.t & 0x0400;
bool x7 = state.t & 0x0100;
bool x10 = state.t & 0x0020;
bool x11 = state.t & 0x0010;
bool x14 = state.t & 0x0002;
bool x15 = state.t & 0x0001;
return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
}
/**
* Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as
* B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 .
* Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as
* B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 .
**/
bool B(State state)
{
bool x1 = state.b & 0x40;
bool x2 = state.b & 0x20;
bool x3 = state.b & 0x10;
bool x7 = state.b & 0x01;
bool x1 = state.b & 0x40;
bool x2 = state.b & 0x20;
bool x3 = state.b & 0x10;
bool x7 = state.b & 0x01;
return x1 ^ x2 ^ x3 ^ x7;
return x1 ^ x2 ^ x3 ^ x7;
}
/**
* Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
* F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
* z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 r 4 )
* z 1 = (r 0 r 2 ) ⊕ (r 5 r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y
* z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x
* Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
* F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
* z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 r 4 )
* z 1 = (r 0 r 2 ) ⊕ (r 5 r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y
* z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x
**/
uint8_t _select(bool x, bool y, uint8_t r)
{
bool r0 = r >> 7 & 0x1;
bool r1 = r >> 6 & 0x1;
bool r2 = r >> 5 & 0x1;
bool r3 = r >> 4 & 0x1;
bool r4 = r >> 3 & 0x1;
bool r5 = r >> 2 & 0x1;
bool r6 = r >> 1 & 0x1;
bool r7 = r & 0x1;
bool r0 = r >> 7 & 0x1;
bool r1 = r >> 6 & 0x1;
bool r2 = r >> 5 & 0x1;
bool r3 = r >> 4 & 0x1;
bool r4 = r >> 3 & 0x1;
bool r5 = r >> 2 & 0x1;
bool r6 = r >> 1 & 0x1;
bool r7 = r & 0x1;
bool z0 = (r0 & r2) ^ (r1 & !r3) ^ (r2 | r4);
bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
bool z2 = (r3 & !r5) ^ (r4 & r6 ) ^ r7 ^ x;
bool z0 = (r0 & r2) ^ (r1 & !r3) ^ (r2 | r4);
bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
bool z2 = (r3 & !r5) ^ (r4 & r6 ) ^ r7 ^ x;
// The three bitz z0.. z1 are packed into a uint8_t:
// 00000ZZZ
//Return value is a uint8_t
uint8_t retval = 0;
retval |= (z0 << 2) & 4;
retval |= (z1 << 1) & 2;
retval |= z2 & 1;
// The three bitz z0.. z1 are packed into a uint8_t:
// 00000ZZZ
//Return value is a uint8_t
uint8_t retval = 0;
retval |= (z0 << 2) & 4;
retval |= (z1 << 1) & 2;
retval |= z2 & 1;
// Return value 0 <= retval <= 7
return retval;
// Return value 0 <= retval <= 7
return retval;
}
/**
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8
* be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s =
* l , r , t , b is defined as
* t := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l := (k [select(T (t),y,r)] ⊕ b ) ⊞ l ⊞ r
* b := (B(b) ⊕ r 7 )b 0 . . . b 6 r := (k [select(T (t),y,r)] ⊕ b ) ⊞ l
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8
* be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s =
* l , r , t , b is defined as
* t := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l := (k [select(T (t),y,r)] ⊕ b ) ⊞ l ⊞ r
* b := (B(b) ⊕ r 7 )b 0 . . . b 6 r := (k [select(T (t),y,r)] ⊕ b ) ⊞ l
*
* @param s - state
* @param k - array containing 8 bytes
**/
State successor(uint8_t* k, State s, bool y)
{
bool r0 = s.r >> 7 & 0x1;
bool r4 = s.r >> 3 & 0x1;
bool r7 = s.r & 0x1;
bool r0 = s.r >> 7 & 0x1;
bool r4 = s.r >> 3 & 0x1;
bool r7 = s.r & 0x1;
State successor = {0,0,0,0};
State successor = {0,0,0,0};
successor.t = s.t >> 1;
successor.t |= (T(s) ^ r0 ^ r4) << 15;
successor.t = s.t >> 1;
successor.t |= (T(s) ^ r0 ^ r4) << 15;
successor.b = s.b >> 1;
successor.b |= (B(s) ^ r7) << 7;
successor.b = s.b >> 1;
successor.b |= (B(s) ^ r7) << 7;
bool Tt = T(s);
bool Tt = T(s);
successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
return successor;
return successor;
}
/**
* We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and
* an input y ∈ F 2 and outputs the successor state s . We overload the function suc
* to multiple bit input x ∈ F n 2 which we define as
* We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and
* an input y ∈ F 2 and outputs the successor state s . We overload the function suc
* to multiple bit input x ∈ F n 2 which we define as
* @param k - array containing 8 bytes
**/
State suc(uint8_t* k,State s, BitstreamIn *bitstream)
{
if(bitsLeft(bitstream) == 0)
{
return s;
}
bool lastbit = tailBit(bitstream);
return successor(k,suc(k,s,bitstream), lastbit);
if(bitsLeft(bitstream) == 0)
{
return s;
}
bool lastbit = tailBit(bitstream);
return successor(k,suc(k,s,bitstream), lastbit);
}
/**
* Definition 5 (Output). Define the function output which takes an internal
* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
* on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as
* output(k, s, ǫ) = ǫ
* output(k, s, x 0 . . . x n ) = output(s) · output(k, s , x 1 . . . x n )
* where s = suc(k, s, x 0 ).
* Definition 5 (Output). Define the function output which takes an internal
* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
* on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as
* output(k, s, ǫ) = ǫ
* output(k, s, x 0 . . . x n ) = output(s) · output(k, s , x 1 . . . x n )
* where s = suc(k, s, x 0 ).
**/
void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out)
{
if(bitsLeft(in) == 0)
{
return;
}
pushBit(out,(s.r >> 2) & 1);
//Remove first bit
uint8_t x0 = headBit(in);
State ss = successor(k,s,x0);
output(k,ss,in, out);
if(bitsLeft(in) == 0)
{
return;
}
pushBit(out,(s.r >> 2) & 1);
//Remove first bit
uint8_t x0 = headBit(in);
State ss = successor(k,s,x0);
output(k,ss,in, out);
}
/**
@@ -204,85 +204,85 @@ void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out)
State init(uint8_t* k)
{
State s = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
return s;
State s = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
return s;
}
void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
{
uint8_t zeroes_32[] = {0,0,0,0};
BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
State initState = suc(k,init(k),&input);
output(k,initState,&input_32_zeroes,&out);
uint8_t zeroes_32[] = {0,0,0,0};
BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
State initState = suc(k,init(k),&input);
output(k,initState,&input_32_zeroes,&out);
}
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
{
uint8_t cc_nr[13] = { 0 };
uint8_t cc_nr[13] = { 0 };
uint8_t div_key[8];
//cc_nr=(uint8_t*) calloc(length+1, sizeof(uint8_t));
//cc_nr=(uint8_t*) calloc(length+1, sizeof(uint8_t));
memcpy(cc_nr, cc_nr_p, 12);
memcpy(cc_nr, cc_nr_p, 12);
memcpy(div_key, div_key_p, 8);
reverse_arraybytes(cc_nr, 12);
BitstreamIn bitstream = {cc_nr, 12 * 8, 0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
MAC(div_key,bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac, dest, 4);
//free(cc_nr);
reverse_arraybytes(cc_nr, 12);
BitstreamIn bitstream = {cc_nr, 12 * 8, 0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
MAC(div_key,bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac, dest, 4);
//free(cc_nr);
return;
}
void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4])
{
uint8_t *address_data;
uint8_t div_key[8];
address_data = (uint8_t*) calloc(address_data_size, sizeof(uint8_t));
uint8_t *address_data;
uint8_t div_key[8];
address_data = (uint8_t*) calloc(address_data_size, sizeof(uint8_t));
memcpy(address_data, address_data_p, address_data_size);
memcpy(div_key, div_key_p, 8);
memcpy(address_data, address_data_p, address_data_size);
memcpy(div_key, div_key_p, 8);
reverse_arraybytes(address_data, address_data_size);
BitstreamIn bitstream = {address_data, address_data_size * 8, 0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
MAC(div_key, bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac, dest, 4);
free(address_data);
return;
reverse_arraybytes(address_data, address_data_size);
BitstreamIn bitstream = {address_data, address_data_size * 8, 0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
MAC(div_key, bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac, dest, 4);
free(address_data);
return;
}
#ifndef ON_DEVICE
int testMAC()
{
PrintAndLogDevice(SUCCESS, "Testing MAC calculation...");
PrintAndLogDevice(SUCCESS, "Testing MAC calculation...");
//From the "dismantling.IClass" paper:
uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
//From the paper
uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
//From the "dismantling.IClass" paper:
uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
//From the paper
uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
uint8_t calculated_mac[4] = {0};
doMAC(cc_nr,div_key, calculated_mac);
uint8_t calculated_mac[4] = {0};
doMAC(cc_nr,div_key, calculated_mac);
if (memcmp(calculated_mac, correct_MAC,4) == 0) {
PrintAndLogDevice(SUCCESS, "MAC calculation OK!");
} else {
PrintAndLogDevice(FAILED, "FAILED: MAC calculation failed:");
printarr(" Calculated_MAC", calculated_mac, 4);
printarr(" Correct_MAC ", correct_MAC, 4);
return 1;
}
return 0;
if (memcmp(calculated_mac, correct_MAC,4) == 0) {
PrintAndLogDevice(SUCCESS, "MAC calculation OK!");
} else {
PrintAndLogDevice(FAILED, "FAILED: MAC calculation failed:");
printarr(" Calculated_MAC", calculated_mac, 4);
printarr(" Correct_MAC ", correct_MAC, 4);
return 1;
}
return 0;
}
#endif

View File

@@ -48,9 +48,9 @@
*/
bool headBit( BitstreamIn *stream)
{
int bytepos = stream->position >> 3; // divide by 8
int bitpos = (stream->position++) & 7; // mask out 00000111
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
int bytepos = stream->position >> 3; // divide by 8
int bitpos = (stream->position++) & 7; // mask out 00000111
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
@@ -59,11 +59,11 @@ bool headBit( BitstreamIn *stream)
*/
bool tailBit( BitstreamIn *stream)
{
int bitpos = stream->numbits -1 - (stream->position++);
int bitpos = stream->numbits -1 - (stream->position++);
int bytepos= bitpos >> 3;
bitpos &= 7;
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
int bytepos= bitpos >> 3;
bitpos &= 7;
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Pushes bit onto the stream
@@ -72,11 +72,11 @@ bool tailBit( BitstreamIn *stream)
*/
void pushBit( BitstreamOut* stream, bool bit)
{
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos);
stream->position++;
stream->numbits++;
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos);
stream->position++;
stream->numbits++;
}
/**
@@ -87,12 +87,12 @@ void pushBit( BitstreamOut* stream, bool bit)
*/
void push6bits( BitstreamOut* stream, uint8_t bits)
{
pushBit(stream, bits & 0x20);
pushBit(stream, bits & 0x10);
pushBit(stream, bits & 0x08);
pushBit(stream, bits & 0x04);
pushBit(stream, bits & 0x02);
pushBit(stream, bits & 0x01);
pushBit(stream, bits & 0x20);
pushBit(stream, bits & 0x10);
pushBit(stream, bits & 0x08);
pushBit(stream, bits & 0x04);
pushBit(stream, bits & 0x02);
pushBit(stream, bits & 0x01);
}
/**
@@ -102,7 +102,7 @@ void push6bits( BitstreamOut* stream, uint8_t bits)
*/
int bitsLeft( BitstreamIn *stream)
{
return stream->numbits - stream->position;
return stream->numbits - stream->position;
}
/**
* @brief numBits
@@ -111,88 +111,88 @@ int bitsLeft( BitstreamIn *stream)
*/
int numBits(BitstreamOut *stream)
{
return stream->numbits;
return stream->numbits;
}
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
dest[len] = (uint8_t) n;
n >>= 8;
}
while (len--) {
dest[len] = (uint8_t) n;
n >>= 8;
}
}
uint64_t x_bytes_to_num(uint8_t* src, size_t len)
{
uint64_t num = 0;
while (len--)
{
num = (num << 8) | (*src);
src++;
}
return num;
uint64_t num = 0;
while (len--)
{
num = (num << 8) | (*src);
src++;
}
return num;
}
uint8_t reversebytes(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void reverse_arraybytes(uint8_t* arr, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
{
arr[i] = reversebytes(arr[i]);
}
uint8_t i;
for( i =0; i< len ; i++)
{
arr[i] = reversebytes(arr[i]);
}
}
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
{
dest[i] = reversebytes(arr[i]);
}
uint8_t i;
for( i =0; i< len ; i++)
{
dest[i] = reversebytes(arr[i]);
}
}
void printarr(char * name, uint8_t* arr, int len) {
int cx, i;
size_t outsize = 40 + strlen(name) + len*5;
char* output = calloc(outsize, sizeof(char));
cx = snprintf(output,outsize, "uint8_t %s[] = {", name);
for (i=0; i < len; i++) {
cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte
}
cx += snprintf(output+cx,outsize-cx,"};");
PrintAndLogDevice(NORMAL, output);
free(output);
int cx, i;
size_t outsize = 40 + strlen(name) + len*5;
char* output = calloc(outsize, sizeof(char));
cx = snprintf(output,outsize, "uint8_t %s[] = {", name);
for (i=0; i < len; i++) {
cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte
}
cx += snprintf(output+cx,outsize-cx,"};");
PrintAndLogDevice(NORMAL, output);
free(output);
}
void printvar(char * name, uint8_t* arr, int len) {
int cx, i;
size_t outsize = 40 + strlen(name) + len*2;
char* output = calloc(outsize, sizeof(char));
cx = snprintf(output,outsize,"%s = ", name);
for (i=0; i < len; i++) {
cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte
}
int cx, i;
size_t outsize = 40 + strlen(name) + len*2;
char* output = calloc(outsize, sizeof(char));
cx = snprintf(output,outsize,"%s = ", name);
for (i=0; i < len; i++) {
cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte
}
PrintAndLogDevice(NORMAL, output);
free(output);
PrintAndLogDevice(NORMAL, output);
free(output);
}
void printarr_human_readable(char * title, uint8_t* arr, int len) {
int cx, i;
size_t outsize = 100 + strlen(title) + len*4;
char* output = calloc(outsize, sizeof(char));
cx = snprintf(output,outsize, "\n\t%s\n", title);
for (i=0; i < len; i++) {
if (i % 16 == 0)
cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i );
cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i));
}
PrintAndLogDevice(NORMAL, output);
free(output);
int cx, i;
size_t outsize = 100 + strlen(title) + len*4;
char* output = calloc(outsize, sizeof(char));
cx = snprintf(output,outsize, "\n\t%s\n", title);
for (i=0; i < len; i++) {
if (i % 16 == 0)
cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i );
cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i));
}
PrintAndLogDevice(NORMAL, output);
free(output);
}
//-----------------------------
@@ -202,69 +202,69 @@ void printarr_human_readable(char * title, uint8_t* arr, int len) {
#ifndef ON_DEVICE
int testBitStream()
{
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out = { output, 0,0}
;
while (bitsLeft(&in) > 0) {
pushBit(&out, headBit(&in));
//printf("Bits left: %d\n", bitsLeft(&in));
//printf("Bits out: %d\n", numBits(&out));
}
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out = { output, 0,0}
;
while (bitsLeft(&in) > 0) {
pushBit(&out, headBit(&in));
//printf("Bits left: %d\n", bitsLeft(&in));
//printf("Bits out: %d\n", numBits(&out));
}
if(memcmp(input, output, sizeof(input)) == 0) {
PrintAndLogDevice(SUCCESS, " Bitstream test 1 ok");
} else {
PrintAndLogDevice(FAILED, " Bitstream test 1 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
PrintAndLogDevice(NORMAL, " IN %02x, OUT %02x", input[i], output[i]);
}
return 1;
}
return 0;
if(memcmp(input, output, sizeof(input)) == 0) {
PrintAndLogDevice(SUCCESS, " Bitstream test 1 ok");
} else {
PrintAndLogDevice(FAILED, " Bitstream test 1 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
PrintAndLogDevice(NORMAL, " IN %02x, OUT %02x", input[i], output[i]);
}
return 1;
}
return 0;
}
int testReversedBitstream()
{
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t reverse [] = {0,0,0,0,0,0,0,0};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out = { output, 0,0};
BitstreamIn reversed_in = { reverse, sizeof(input)*8,0};
BitstreamOut reversed_out = { reverse,0 ,0};
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t reverse [] = {0,0,0,0,0,0,0,0};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out = { output, 0,0};
BitstreamIn reversed_in = { reverse, sizeof(input)*8,0};
BitstreamOut reversed_out = { reverse,0 ,0};
while (bitsLeft(&in) > 0) {
pushBit(&reversed_out, tailBit(&in));
}
while (bitsLeft(&in) > 0) {
pushBit(&reversed_out, tailBit(&in));
}
while (bitsLeft(&reversed_in) > 0) {
pushBit(&out, tailBit(&reversed_in));
}
while (bitsLeft(&reversed_in) > 0) {
pushBit(&out, tailBit(&reversed_in));
}
if (memcmp(input, output, sizeof(input)) == 0) {
PrintAndLogDevice(SUCCESS, " Bitstream test 2 ok");
} else {
PrintAndLogDevice(FAILED, " Bitstream test 2 failed");
uint8_t i;
for (i = 0 ; i < sizeof(input) ; i++) {
PrintAndLogDevice(NORMAL, " IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
}
return 1;
}
return 0;
if (memcmp(input, output, sizeof(input)) == 0) {
PrintAndLogDevice(SUCCESS, " Bitstream test 2 ok");
} else {
PrintAndLogDevice(FAILED, " Bitstream test 2 failed");
uint8_t i;
for (i = 0 ; i < sizeof(input) ; i++) {
PrintAndLogDevice(NORMAL, " IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
}
return 1;
}
return 0;
}
int testCipherUtils(void)
{
PrintAndLogDevice(INFO, "Testing some internals...");
int retval = 0;
retval |= testBitStream();
retval |= testReversedBitstream();
return retval;
PrintAndLogDevice(INFO, "Testing some internals...");
int retval = 0;
retval |= testBitStream();
retval |= testReversedBitstream();
return retval;
}
#endif

View File

@@ -43,15 +43,15 @@
#include <stdlib.h>
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
} BitstreamIn;
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
} BitstreamOut;
bool headBit( BitstreamIn *stream);

View File

@@ -50,37 +50,37 @@
/**
* @brief Permutes a key from standard NIST format to Iclass specific format
* from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
* from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
*
* If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below.
* If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below.
*
* 1 0 1 1 1 1 1 1 bf
* 0 0 0 0 0 0 0 1 01
* 0 0 1 0 1 1 0 1 2d
* 0 0 1 0 1 0 1 0 2a
* 1 1 1 1 1 0 0 1 f9
* 0 1 0 0 0 1 0 0 44
* 1 0 0 0 1 1 0 1 8d
* 0 1 1 0 1 1 0 0 6c
* 1 0 1 1 1 1 1 1 bf
* 0 0 0 0 0 0 0 1 01
* 0 0 1 0 1 1 0 1 2d
* 0 0 1 0 1 0 1 0 2a
* 1 1 1 1 1 0 0 1 f9
* 0 1 0 0 0 1 0 0 44
* 1 0 0 0 1 1 0 1 8d
* 0 1 1 0 1 1 0 0 6c
*
* 8 0 b 8 b a 9 e
* a d 9 8 b 7 0 a
* 8 0 b 8 b a 9 e
* a d 9 8 b 7 0 a
*
* @param key
* @param dest
*/
void permutekey(uint8_t key[8], uint8_t dest[8]) {
int i;
for(i = 0 ; i < 8 ; i++) {
dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[0] & (0x80 >> i)) >> (7-i)) << 0);
}
int i;
for(i = 0 ; i < 8 ; i++) {
dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[0] & (0x80 >> i)) >> (7-i)) << 0);
}
}
/**
* Permutes a key from iclass specific format to NIST format
@@ -89,17 +89,17 @@ void permutekey(uint8_t key[8], uint8_t dest[8]) {
* @param dest
*/
void permutekey_rev(uint8_t key[8], uint8_t dest[8]) {
int i;
for(i = 0 ; i < 8 ; i++) {
dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[7] & (0x80 >> i)) >> (7-i)) << 0);
}
int i;
for(i = 0 ; i < 8 ; i++) {
dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[7] & (0x80 >> i)) >> (7-i)) << 0);
}
}
/**
@@ -109,7 +109,7 @@ void permutekey_rev(uint8_t key[8], uint8_t dest[8]) {
* @return
*/
inline uint8_t rr(uint8_t val) {
return val >> 1 | (( val & 1) << 7);
return val >> 1 | (( val & 1) << 7);
}
/**
@@ -129,7 +129,7 @@ inline uint8_t rl(uint8_t val) {
* @return
*/
inline uint8_t swap(uint8_t val) {
return ((val >> 4) & 0xFF) | ((val &0xFF) << 4);
return ((val >> 4) & 0xFF) | ((val &0xFF) << 4);
}
/**
@@ -139,23 +139,23 @@ inline uint8_t swap(uint8_t val) {
* @param k output
*/
void hash1(uint8_t csn[] , uint8_t k[]) {
k[0] = csn[0] ^ csn[1] ^ csn[2] ^ csn[3] ^ csn[4] ^ csn[5] ^ csn[6] ^ csn[7];
k[1] = csn[0] + csn[1] + csn[2] + csn[3] + csn[4] + csn[5] + csn[6] + csn[7];
k[2] = rr(swap( csn[2] + k[1] ));
k[3] = rl(swap( csn[3] + k[0] ));
k[4] = ~rr( csn[4] + k[2] ) + 1;
k[5] = ~rl( csn[5] + k[3] ) + 1;
k[6] = rr( csn[6] + (k[4] ^ 0x3c) );
k[7] = rl( csn[7] + (k[5] ^ 0xc3) );
k[0] = csn[0] ^ csn[1] ^ csn[2] ^ csn[3] ^ csn[4] ^ csn[5] ^ csn[6] ^ csn[7];
k[1] = csn[0] + csn[1] + csn[2] + csn[3] + csn[4] + csn[5] + csn[6] + csn[7];
k[2] = rr(swap( csn[2] + k[1] ));
k[3] = rl(swap( csn[3] + k[0] ));
k[4] = ~rr( csn[4] + k[2] ) + 1;
k[5] = ~rl( csn[5] + k[3] ) + 1;
k[6] = rr( csn[6] + (k[4] ^ 0x3c) );
k[7] = rl( csn[7] + (k[5] ^ 0xc3) );
k[7] &= 0x7F;
k[6] &= 0x7F;
k[5] &= 0x7F;
k[4] &= 0x7F;
k[3] &= 0x7F;
k[2] &= 0x7F;
k[1] &= 0x7F;
k[0] &= 0x7F;
k[7] &= 0x7F;
k[6] &= 0x7F;
k[5] &= 0x7F;
k[4] &= 0x7F;
k[3] &= 0x7F;
k[2] &= 0x7F;
k[1] &= 0x7F;
k[0] &= 0x7F;
}
/**
Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as
@@ -168,7 +168,7 @@ void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) {
while (n-- > 0) {
for (j=0; j < 8 ; j++)
outp_key[j] = rl(outp_key[j]);
}
}
return;
}
@@ -253,12 +253,12 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) {
/**
* @brief Reads data from the iclass-reader-attack dump file.
* @param dump, data from a iclass reader attack dump. The format of the dumpdata is expected to be as follows:
* <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER>
* .. N times...
* <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER>
* .. N times...
*
* So the first attack, with 3 bytes to recover would be : ... 03000145
* And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000
* And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700
* So the first attack, with 3 bytes to recover would be : ... 03000145
* And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000
* And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700
*
* @param cc_nr an array to store cc_nr into (12 bytes)
* @param csn an arracy ot store CSN into (8 bytes)
@@ -267,15 +267,15 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) {
* @return
*/
int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i) {
size_t itemsize = sizeof(dumpdata);
memcpy(item, dump+i*itemsize, itemsize);
size_t itemsize = sizeof(dumpdata);
memcpy(item, dump+i*itemsize, itemsize);
if (true) {
printvar("csn", item->csn, sizeof(item->csn));
printvar("cc_nr", item->cc_nr, sizeof(item->cc_nr));
printvar("mac", item->mac, sizeof(item->mac));
}
return 0;
if (true) {
printvar("csn", item->csn, sizeof(item->csn));
printvar("cc_nr", item->cc_nr, sizeof(item->cc_nr));
printvar("mac", item->mac, sizeof(item->mac));
}
return 0;
}
//static uint32_t startvalue = 0;
@@ -291,193 +291,193 @@ int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i) {
* @return
*/
int bruteforceItem(dumpdata item, uint16_t keytable[]) {
int errors = 0;
int found = false;
uint8_t key_sel_p[8] = {0};
uint8_t div_key[8] = {0};
uint8_t key_sel[8] = {0};
uint8_t calculated_MAC[4] = {0};
int errors = 0;
int found = false;
uint8_t key_sel_p[8] = {0};
uint8_t div_key[8] = {0};
uint8_t key_sel[8] = {0};
uint8_t calculated_MAC[4] = {0};
//Get the key index (hash1)
uint8_t key_index[8] = {0};
hash1(item.csn, key_index);
//Get the key index (hash1)
uint8_t key_index[8] = {0};
hash1(item.csn, key_index);
/*
* Determine which bytes to retrieve. A hash is typically
* 01010000454501
* We go through that hash, and in the corresponding keytable, we put markers
* on what state that particular index is:
* - CRACKED (this has already been cracked)
* - BEING_CRACKED (this is being bruteforced now)
* - CRACK_FAILED (self-explaining...)
*
* The markers are placed in the high area of the 16 bit key-table.
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
**/
uint8_t bytes_to_recover[3] = {0};
uint8_t numbytes_to_recover = 0 ;
int i;
for (i=0; i<8; i++) {
if (keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue;
/*
* Determine which bytes to retrieve. A hash is typically
* 01010000454501
* We go through that hash, and in the corresponding keytable, we put markers
* on what state that particular index is:
* - CRACKED (this has already been cracked)
* - BEING_CRACKED (this is being bruteforced now)
* - CRACK_FAILED (self-explaining...)
*
* The markers are placed in the high area of the 16 bit key-table.
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
**/
uint8_t bytes_to_recover[3] = {0};
uint8_t numbytes_to_recover = 0 ;
int i;
for (i=0; i<8; i++) {
if (keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue;
bytes_to_recover[numbytes_to_recover++] = key_index[i];
keytable[key_index[i]] |= BEING_CRACKED;
bytes_to_recover[numbytes_to_recover++] = key_index[i];
keytable[key_index[i]] |= BEING_CRACKED;
if (numbytes_to_recover > 3) {
PrintAndLogDevice(FAILED, "The CSN requires > 3 byte bruteforce, not supported");
printvar("[-] CSN", item.csn, 8);
printvar("[-] HASH1", key_index, 8);
PrintAndLogDevice(NORMAL, "");
//Before we exit, reset the 'BEING_CRACKED' to zero
keytable[bytes_to_recover[0]] &= ~BEING_CRACKED;
keytable[bytes_to_recover[1]] &= ~BEING_CRACKED;
keytable[bytes_to_recover[2]] &= ~BEING_CRACKED;
return 1;
}
}
if (numbytes_to_recover > 3) {
PrintAndLogDevice(FAILED, "The CSN requires > 3 byte bruteforce, not supported");
printvar("[-] CSN", item.csn, 8);
printvar("[-] HASH1", key_index, 8);
PrintAndLogDevice(NORMAL, "");
//Before we exit, reset the 'BEING_CRACKED' to zero
keytable[bytes_to_recover[0]] &= ~BEING_CRACKED;
keytable[bytes_to_recover[1]] &= ~BEING_CRACKED;
keytable[bytes_to_recover[2]] &= ~BEING_CRACKED;
return 1;
}
}
/*
*A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
*/
//uint32_t brute = startvalue;
uint32_t brute = 0;
/*
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
(when brute reaches 0x100). And so on...
bytes_to_recover = 1 --> endmask = 0x000000100
bytes_to_recover = 2 --> endmask = 0x000010000
bytes_to_recover = 3 --> endmask = 0x001000000
*/
/*
*A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
*/
//uint32_t brute = startvalue;
uint32_t brute = 0;
/*
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
(when brute reaches 0x100). And so on...
bytes_to_recover = 1 --> endmask = 0x000000100
bytes_to_recover = 2 --> endmask = 0x000010000
bytes_to_recover = 3 --> endmask = 0x001000000
*/
uint32_t endmask = 1 << 8*numbytes_to_recover;
PrintAndLogDevice(NORMAL, "----------------------------");
for (i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
PrintAndLogDevice(INFO, "Bruteforcing byte %d", bytes_to_recover[i]);
uint32_t endmask = 1 << 8*numbytes_to_recover;
PrintAndLogDevice(NORMAL, "----------------------------");
for (i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
PrintAndLogDevice(INFO, "Bruteforcing byte %d", bytes_to_recover[i]);
while (!found && !(brute & endmask)) {
while (!found && !(brute & endmask)) {
//Update the keytable with the brute-values
for (i=0; i < numbytes_to_recover; i++) {
keytable[bytes_to_recover[i]] &= 0xFF00;
keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF);
}
//Update the keytable with the brute-values
for (i=0; i < numbytes_to_recover; i++) {
keytable[bytes_to_recover[i]] &= 0xFF00;
keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF);
}
// Piece together the key
key_sel[0] = keytable[key_index[0]] & 0xFF;
key_sel[1] = keytable[key_index[1]] & 0xFF;
key_sel[2] = keytable[key_index[2]] & 0xFF;
key_sel[3] = keytable[key_index[3]] & 0xFF;
key_sel[4] = keytable[key_index[4]] & 0xFF;
key_sel[5] = keytable[key_index[5]] & 0xFF;
key_sel[6] = keytable[key_index[6]] & 0xFF;
key_sel[7] = keytable[key_index[7]] & 0xFF;
// Piece together the key
key_sel[0] = keytable[key_index[0]] & 0xFF;
key_sel[1] = keytable[key_index[1]] & 0xFF;
key_sel[2] = keytable[key_index[2]] & 0xFF;
key_sel[3] = keytable[key_index[3]] & 0xFF;
key_sel[4] = keytable[key_index[4]] & 0xFF;
key_sel[5] = keytable[key_index[5]] & 0xFF;
key_sel[6] = keytable[key_index[6]] & 0xFF;
key_sel[7] = keytable[key_index[7]] & 0xFF;
//Permute from iclass format to standard format
permutekey_rev(key_sel, key_sel_p);
//Diversify
diversifyKey(item.csn, key_sel_p, div_key);
//Calc mac
doMAC(item.cc_nr, div_key, calculated_MAC);
//Permute from iclass format to standard format
permutekey_rev(key_sel, key_sel_p);
//Diversify
diversifyKey(item.csn, key_sel_p, div_key);
//Calc mac
doMAC(item.cc_nr, div_key, calculated_MAC);
// success
if (memcmp(calculated_MAC, item.mac, 4) == 0) {
printf("\r\n");
for (i =0 ; i < numbytes_to_recover; i++) {
PrintAndLogDevice(INFO, "%d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]);
}
found = true;
break;
}
// success
if (memcmp(calculated_MAC, item.mac, 4) == 0) {
printf("\r\n");
for (i =0 ; i < numbytes_to_recover; i++) {
PrintAndLogDevice(INFO, "%d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]);
}
found = true;
break;
}
brute++;
if ((brute & 0xFFFF) == 0) {
printf("%3d,",(brute >> 16) & 0xFF);
if ( ((brute >> 16) % 0x10) == 0)
printf("\n");
fflush(stdout);
}
}
brute++;
if ((brute & 0xFFFF) == 0) {
printf("%3d,",(brute >> 16) & 0xFF);
if ( ((brute >> 16) % 0x10) == 0)
printf("\n");
fflush(stdout);
}
}
if (!found) {
PrintAndLogDevice(NORMAL, "\n"); PrintAndLogDevice(WARNING, "Failed to recover %d bytes using the following CSN", numbytes_to_recover);
printvar("[!] CSN", item.csn, 8);
errors++;
if (!found) {
PrintAndLogDevice(NORMAL, "\n"); PrintAndLogDevice(WARNING, "Failed to recover %d bytes using the following CSN", numbytes_to_recover);
printvar("[!] CSN", item.csn, 8);
errors++;
//Before we exit, reset the 'BEING_CRACKED' to zero
for (i=0; i < numbytes_to_recover; i++){
keytable[bytes_to_recover[i]] &= 0xFF;
keytable[bytes_to_recover[i]] |= CRACK_FAILED;
}
} else {
//PrintAndLogDevice(SUCCESS, "DES calcs: %u", brute);
for (i=0; i < numbytes_to_recover; i++){
keytable[bytes_to_recover[i]] &= 0xFF;
keytable[bytes_to_recover[i]] |= CRACKED;
}
}
return errors;
//Before we exit, reset the 'BEING_CRACKED' to zero
for (i=0; i < numbytes_to_recover; i++){
keytable[bytes_to_recover[i]] &= 0xFF;
keytable[bytes_to_recover[i]] |= CRACK_FAILED;
}
} else {
//PrintAndLogDevice(SUCCESS, "DES calcs: %u", brute);
for (i=0; i < numbytes_to_recover; i++){
keytable[bytes_to_recover[i]] &= 0xFF;
keytable[bytes_to_recover[i]] |= CRACKED;
}
}
return errors;
}
/**
* From dismantling iclass-paper:
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
*
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* @param keytable an array (128 bytes) of hash2(kcus)
* @param master_key where to put the master key
* @return 0 for ok, 1 for failz
*/
int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ){
mbedtls_des_context ctx_e;
mbedtls_des_context ctx_e;
uint8_t z_0[8] = {0};
uint8_t y_0[8] = {0};
uint8_t z_0_rev[8] = {0};
uint8_t key64[8] = {0};
uint8_t key64_negated[8] = {0};
uint8_t result[8] = {0};
uint8_t z_0[8] = {0};
uint8_t y_0[8] = {0};
uint8_t z_0_rev[8] = {0};
uint8_t key64[8] = {0};
uint8_t key64_negated[8] = {0};
uint8_t result[8] = {0};
// y_0 and z_0 are the first 16 bytes of the keytable
memcpy(y_0, first16bytes,8);
memcpy(z_0, first16bytes+8,8);
// y_0 and z_0 are the first 16 bytes of the keytable
memcpy(y_0, first16bytes,8);
memcpy(z_0, first16bytes+8,8);
// Our DES-implementation uses the standard NIST
// format for keys, thus must translate from iclass
// format to NIST-format
permutekey_rev(z_0, z_0_rev);
// Our DES-implementation uses the standard NIST
// format for keys, thus must translate from iclass
// format to NIST-format
permutekey_rev(z_0, z_0_rev);
// ~K_cus = DESenc(z[0], y[0])
mbedtls_des_setkey_enc( &ctx_e, z_0_rev );
mbedtls_des_crypt_ecb(&ctx_e, y_0, key64_negated);
// ~K_cus = DESenc(z[0], y[0])
mbedtls_des_setkey_enc( &ctx_e, z_0_rev );
mbedtls_des_crypt_ecb(&ctx_e, y_0, key64_negated);
int i;
for (i = 0; i < 8 ; i++)
key64[i] = ~key64_negated[i];
int i;
for (i = 0; i < 8 ; i++)
key64[i] = ~key64_negated[i];
// Can we verify that the key is correct?
// Once again, key is on iclass-format
uint8_t key64_stdformat[8] = {0};
permutekey_rev(key64, key64_stdformat);
// Can we verify that the key is correct?
// Once again, key is on iclass-format
uint8_t key64_stdformat[8] = {0};
permutekey_rev(key64, key64_stdformat);
mbedtls_des_setkey_enc( &ctx_e, key64_stdformat );
mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result);
PrintAndLogDevice(NORMAL, "\n"); PrintAndLogDevice(SUCCESS, "-- High security custom key (Kcus) --");
printvar("[+] Standard format ", key64_stdformat, 8);
printvar("[+] iClass format ", key64, 8);
mbedtls_des_setkey_enc( &ctx_e, key64_stdformat );
mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result);
PrintAndLogDevice(NORMAL, "\n"); PrintAndLogDevice(SUCCESS, "-- High security custom key (Kcus) --");
printvar("[+] Standard format ", key64_stdformat, 8);
printvar("[+] iClass format ", key64, 8);
if (master_key != NULL)
memcpy(master_key, key64, 8);
if (master_key != NULL)
memcpy(master_key, key64, 8);
if (memcmp(z_0,result,4) != 0) {
PrintAndLogDevice(WARNING, "Failed to verify calculated master key (k_cus)! Something is wrong.");
return 1;
} else {
PrintAndLogDevice(NORMAL, "\n"); PrintAndLogDevice(SUCCESS, "Key verified ok!\n");
}
return 0;
if (memcmp(z_0,result,4) != 0) {
PrintAndLogDevice(WARNING, "Failed to verify calculated master key (k_cus)! Something is wrong.");
return 1;
} else {
PrintAndLogDevice(NORMAL, "\n"); PrintAndLogDevice(SUCCESS, "Key verified ok!\n");
}
return 0;
}
/**
* @brief Same as bruteforcefile, but uses a an array of dumpdata instead
@@ -487,36 +487,36 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ){
* @return
*/
int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) {
uint8_t i;
int errors = 0;
size_t itemsize = sizeof(dumpdata);
uint8_t i;
int errors = 0;
size_t itemsize = sizeof(dumpdata);
uint64_t t1 = msclock();
uint64_t t1 = msclock();
dumpdata* attack = (dumpdata* ) calloc(itemsize, sizeof(uint8_t));
dumpdata* attack = (dumpdata* ) calloc(itemsize, sizeof(uint8_t));
for (i = 0 ; i * itemsize < dumpsize ; i++ ) {
memcpy(attack, dump + i * itemsize, itemsize);
errors += bruteforceItem(*attack, keytable);
}
free(attack);
for (i = 0 ; i * itemsize < dumpsize ; i++ ) {
memcpy(attack, dump + i * itemsize, itemsize);
errors += bruteforceItem(*attack, keytable);
}
free(attack);
PrintAndLogDevice(SUCCESS, "time: %" PRIu64 " seconds", (msclock()-t1)/1000);
PrintAndLogDevice(SUCCESS, "time: %" PRIu64 " seconds", (msclock()-t1)/1000);
// Pick out the first 16 bytes of the keytable.
// The keytable is now in 16-bit ints, where the upper 8 bits
// indicate crack-status. Those must be discarded for the
// master key calculation
uint8_t first16bytes[16] = {0};
// Pick out the first 16 bytes of the keytable.
// The keytable is now in 16-bit ints, where the upper 8 bits
// indicate crack-status. Those must be discarded for the
// master key calculation
uint8_t first16bytes[16] = {0};
for (i = 0 ; i < 16 ; i++) {
first16bytes[i] = keytable[i] & 0xFF;
for (i = 0 ; i < 16 ; i++) {
first16bytes[i] = keytable[i] & 0xFF;
if (!(keytable[i] & CRACKED))
PrintAndLogDevice(WARNING, "error, we are missing byte %d, custom key calculation will fail...", i);
}
errors += calculateMasterKey(first16bytes, NULL);
return errors;
if (!(keytable[i] & CRACKED))
PrintAndLogDevice(WARNING, "error, we are missing byte %d, custom key calculation will fail...", i);
}
errors += calculateMasterKey(first16bytes, NULL);
return errors;
}
/**
* Perform a bruteforce against a file which has been saved by pm3
@@ -526,39 +526,39 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) {
* @return
*/
int bruteforceFile(const char *filename, uint16_t keytable[]) {
FILE *f = fopen(filename, "rb");
if (!f) {
PrintAndLogDevice(WARNING, "Failed to read from file '%s'", filename);
return 1;
}
FILE *f = fopen(filename, "rb");
if (!f) {
PrintAndLogDevice(WARNING, "Failed to read from file '%s'", filename);
return 1;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize < 0) {
PrintAndLogDevice(WARNING, "Error, when getting filesize");
fclose(f);
return 1;
}
if (fsize < 0) {
PrintAndLogDevice(WARNING, "Error, when getting filesize");
fclose(f);
return 1;
}
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if ( !dump ) {
PrintAndLogDevice(WARNING, "Failed to allocate memory");
fclose(f);
return 2;
}
size_t bytes_read = fread(dump, 1, fsize, f);
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if ( !dump ) {
PrintAndLogDevice(WARNING, "Failed to allocate memory");
fclose(f);
return 2;
}
size_t bytes_read = fread(dump, 1, fsize, f);
fclose(f);
fclose(f);
if (bytes_read < fsize) {
PrintAndLogDevice(WARNING, "Error, could only read %d bytes (should be %d)", bytes_read, fsize );
}
}
uint8_t res = bruteforceDump(dump, fsize, keytable);
free(dump);
return res;
uint8_t res = bruteforceDump(dump, fsize, keytable);
free(dump);
return res;
}
/**
*
@@ -567,8 +567,8 @@ int bruteforceFile(const char *filename, uint16_t keytable[]) {
* @return
*/
int bruteforceFileNoKeys(const char *filename) {
uint16_t keytable[128] = {0};
return bruteforceFile(filename, keytable);
uint16_t keytable[128] = {0};
return bruteforceFile(filename, keytable);
}
// ---------------------------------------------------------------------------------
@@ -578,66 +578,66 @@ int bruteforceFileNoKeys(const char *filename) {
// TEST CODE BELOW
// ----------------------------------------------------------------------------
int _testBruteforce() {
int errors = 0;
if (true) {
// First test
PrintAndLogDevice(INFO, "Testing crack from dumpfile...");
int errors = 0;
if (true) {
// First test
PrintAndLogDevice(INFO, "Testing crack from dumpfile...");
/**
Expected values for the dumpfile:
High Security Key Table
/**
Expected values for the dumpfile:
High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
**/
uint16_t keytable[128] = {0};
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
**/
uint16_t keytable[128] = {0};
//Test a few variants
if (fileExists("iclass_dump.bin")){
errors |= bruteforceFile("iclass_dump.bin", keytable);
} else if (fileExists("loclass/iclass_dump.bin")){
errors |= bruteforceFile("loclass/iclass_dump.bin", keytable);
} else if (fileExists("client/loclass/iclass_dump.bin")){
errors |= bruteforceFile("client/loclass/iclass_dump.bin", keytable);
} else {
PrintAndLogDevice(WARNING, "Error: The file iclass_dump.bin was not found!");
}
}
return errors;
//Test a few variants
if (fileExists("iclass_dump.bin")){
errors |= bruteforceFile("iclass_dump.bin", keytable);
} else if (fileExists("loclass/iclass_dump.bin")){
errors |= bruteforceFile("loclass/iclass_dump.bin", keytable);
} else if (fileExists("client/loclass/iclass_dump.bin")){
errors |= bruteforceFile("client/loclass/iclass_dump.bin", keytable);
} else {
PrintAndLogDevice(WARNING, "Error: The file iclass_dump.bin was not found!");
}
}
return errors;
}
int _test_iclass_key_permutation() {
uint8_t testcase[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
uint8_t testcase_output[8] = {0};
uint8_t testcase_output_correct[8] = {0x8a,0x0d,0xb9,0x88,0xbb,0xa7,0x90,0xea};
uint8_t testcase_output_rev[8] = {0};
permutekey(testcase, testcase_output);
permutekey_rev(testcase_output, testcase_output_rev);
uint8_t testcase[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
uint8_t testcase_output[8] = {0};
uint8_t testcase_output_correct[8] = {0x8a,0x0d,0xb9,0x88,0xbb,0xa7,0x90,0xea};
uint8_t testcase_output_rev[8] = {0};
permutekey(testcase, testcase_output);
permutekey_rev(testcase_output, testcase_output_rev);
if (memcmp(testcase_output, testcase_output_correct,8) != 0) {
PrintAndLogDevice(WARNING, "Error with iclass key permute!");
printarr("testcase_output", testcase_output, 8);
printarr("testcase_output_correct", testcase_output_correct, 8);
return 1;
if (memcmp(testcase_output, testcase_output_correct,8) != 0) {
PrintAndLogDevice(WARNING, "Error with iclass key permute!");
printarr("testcase_output", testcase_output, 8);
printarr("testcase_output_correct", testcase_output_correct, 8);
return 1;
}
if (memcmp(testcase, testcase_output_rev, 8) != 0) {
PrintAndLogDevice(WARNING, "Error with reverse iclass key permute");
printarr("testcase", testcase, 8);
printarr("testcase_output_rev", testcase_output_rev, 8);
return 1;
}
}
if (memcmp(testcase, testcase_output_rev, 8) != 0) {
PrintAndLogDevice(WARNING, "Error with reverse iclass key permute");
printarr("testcase", testcase, 8);
printarr("testcase_output_rev", testcase_output_rev, 8);
return 1;
}
PrintAndLogDevice(SUCCESS, "Iclass key permutation OK!");
return 0;
PrintAndLogDevice(SUCCESS, "Iclass key permutation OK!");
return 0;
}
int _testHash1() {
@@ -656,7 +656,7 @@ int _testHash1() {
}
int testElite() {
PrintAndLogDevice(INFO, "Testing iClass Elite functinality...");
PrintAndLogDevice(INFO, "Testing iClass Elite functinality...");
PrintAndLogDevice(INFO, "Testing hash2");
uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39};
@@ -682,11 +682,11 @@ int testElite() {
PrintAndLogDevice(SUCCESS, "Hash2 looks fine...");
}
int errors = 0 ;
int errors = 0 ;
PrintAndLogDevice(INFO, "Testing hash1...");
errors += _testHash1();
PrintAndLogDevice(INFO, "Testing key diversification ...");
errors +=_test_iclass_key_permutation();
errors += _testBruteforce();
return errors;
errors += _testBruteforce();
return errors;
}

View File

@@ -47,9 +47,9 @@ void permutekey(uint8_t key[8], uint8_t dest[8]);
*/
void permutekey_rev(uint8_t key[8], uint8_t dest[8]);
//Crack status, see below
#define CRACKED 0x0100
#define BEING_CRACKED 0x0200
#define CRACK_FAILED 0x0400
#define CRACKED 0x0100
#define BEING_CRACKED 0x0200
#define CRACK_FAILED 0x0400
/**
* Perform a bruteforce against a file which has been saved by pm3
@@ -81,9 +81,9 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]);
This is how we expect each 'entry' in a dumpfile to look
**/
typedef struct {
uint8_t csn[8];
uint8_t cc_nr[12];
uint8_t mac[4];
uint8_t csn[8];
uint8_t cc_nr[12];
uint8_t mac[4];
} dumpdata;
/**
@@ -108,12 +108,12 @@ void hash1(uint8_t csn[] , uint8_t k[]);
void hash2(uint8_t *key64, uint8_t *outp_keytable);
/**
* From dismantling iclass-paper:
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
*
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* @param keytable an array (128 bytes) of hash2(kcus)
* @param master_key where to put the master key
* @return 0 for ok, 1 for failz
@@ -127,8 +127,8 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] );
int testElite();
/**
Here are some pretty optimal values that can be used to recover necessary data in only
eight auth attempts.
Here are some pretty optimal values that can be used to recover necessary data in only
eight auth attempts.
// CSN HASH1 Bytes recovered //
{ {0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0} , {0x01,0x01,0x00,0x00,0x45,0x01,0x45,0x45 } ,{0,1 }},
{ {0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0} , {0x02,0x0c,0x01,0x00,0x45,0x01,0x45,0x45} , {2,12}},

View File

@@ -48,480 +48,480 @@
int fileExists(const char *filename) {
#ifdef _WIN32
struct _stat st;
int result = _stat(filename, &st);
struct _stat st;
int result = _stat(filename, &st);
#else
struct stat st;
int result = stat(filename, &st);
struct stat st;
int result = stat(filename, &st);
#endif
return result == 0;
return result == 0;
}
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen) {
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while (fileExists(fileName)) {
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while (fileExists(fileName)) {
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/*Opening file for writing in binary mode*/
FILE *f = fopen(fileName, "wb");
if (!f) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
free(fileName);
return 1;
}
fwrite(data, 1, datalen, f);
fflush(f);
fclose(f);
PrintAndLogDevice(SUCCESS, "saved %u bytes to binary file " _YELLOW_(%s), datalen, fileName);
free(fileName);
return 0;
/*Opening file for writing in binary mode*/
FILE *f = fopen(fileName, "wb");
if (!f) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
free(fileName);
return 1;
}
fwrite(data, 1, datalen, f);
fflush(f);
fclose(f);
PrintAndLogDevice(SUCCESS, "saved %u bytes to binary file " _YELLOW_(%s), datalen, fileName);
free(fileName);
return 0;
}
int saveFileEML(const char *preferredName, const char *suffix, uint8_t* data, size_t datalen, size_t blocksize) {
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
int retval = 0;
int blocks = datalen/blocksize;
uint16_t currblock = 1;
int i,j;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while (fileExists(fileName)) {
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
int retval = 0;
int blocks = datalen/blocksize;
uint16_t currblock = 1;
int i,j;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while (fileExists(fileName)) {
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/*Opening file for writing in text mode*/
FILE *f = fopen(fileName, "w+");
if (!f) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
retval = 1;
goto out;
}
/*Opening file for writing in text mode*/
FILE *f = fopen(fileName, "w+");
if (!f) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
retval = 1;
goto out;
}
for (i = 0; i < datalen; i++) {
fprintf(f, "%02X", data[i] );
for (i = 0; i < datalen; i++) {
fprintf(f, "%02X", data[i] );
// no extra line in the end
if ( (i+1) % blocksize == 0 && currblock != blocks ) {
fprintf(f, "\n");
currblock++;
}
}
// left overs
if ( datalen % blocksize != 0) {
int index = blocks * blocksize;
for (j = 0; j < datalen % blocksize; j++) {
fprintf(f, "%02X", data[index + j] );
}
}
fflush(f);
fclose(f);
PrintAndLogDevice(SUCCESS, "saved %d blocks to text file " _YELLOW_(%s), blocks, fileName);
// no extra line in the end
if ( (i+1) % blocksize == 0 && currblock != blocks ) {
fprintf(f, "\n");
currblock++;
}
}
// left overs
if ( datalen % blocksize != 0) {
int index = blocks * blocksize;
for (j = 0; j < datalen % blocksize; j++) {
fprintf(f, "%02X", data[index + j] );
}
}
fflush(f);
fclose(f);
PrintAndLogDevice(SUCCESS, "saved %d blocks to text file " _YELLOW_(%s), blocks, fileName);
out:
free(fileName);
return retval;
free(fileName);
return retval;
}
int saveFileJSON(const char *preferredName, const char *suffix, JSONFileType ftype, uint8_t* data, size_t datalen) {
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while (fileExists(fileName)) {
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while (fileExists(fileName)) {
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
json_t *root = json_object();
JsonSaveStr(root, "Created", "proxmark3");
switch(ftype) {
case jsfRaw:
JsonSaveStr(root, "FileType", "raw");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
break;
case jsfCardMemory:
JsonSaveStr(root, "FileType", "mfcard");
for (int i = 0; i < (datalen / 16); i++) {
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%d", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
json_t *root = json_object();
JsonSaveStr(root, "Created", "proxmark3");
switch(ftype) {
case jsfRaw:
JsonSaveStr(root, "FileType", "raw");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
break;
case jsfCardMemory:
JsonSaveStr(root, "FileType", "mfcard");
for (int i = 0; i < (datalen / 16); i++) {
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%d", i);
JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
if (i == 0) {
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 4);
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[5], 1);
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[6], 2);
}
if (i == 0) {
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 4);
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[5], 1);
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[6], 2);
}
if (mfIsSectorTrailer(i)) {
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &data[i * 16], 6);
if (mfIsSectorTrailer(i)) {
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &data[i * 16], 6);
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 10], 6);
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 10], 6);
memset(path, 0x00, sizeof(path));
uint8_t *adata = &data[i * 16 + 6];
sprintf(path, "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 6], 4);
memset(path, 0x00, sizeof(path));
uint8_t *adata = &data[i * 16 + 6];
sprintf(path, "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 6], 4);
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i - 3);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i - 3);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i - 2);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(1, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i - 2);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(1, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i - 1);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(2, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i - 1);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(2, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(3, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%d", mfSectorNum(i), i);
JsonSaveStr(root, path, mfGetAccessConditionsDesc(3, adata));
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &adata[3], 1);
}
}
break;
case jsfMfuMemory:
JsonSaveStr(root, "FileType", "mfu");
memset(path, 0x00, sizeof(path));
sprintf(path, "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i));
JsonSaveBufAsHexCompact(root, path, &adata[3], 1);
}
}
break;
case jsfMfuMemory:
JsonSaveStr(root, "FileType", "mfu");
mfu_dump_t* tmp = (mfu_dump_t*)data;
mfu_dump_t* tmp = (mfu_dump_t*)data;
uint8_t uid[7] = {0};
memcpy(uid, tmp->data, 3);
memcpy(uid+3, tmp->data+4, 4);
uint8_t uid[7] = {0};
memcpy(uid, tmp->data, 3);
memcpy(uid+3, tmp->data+4, 4);
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
JsonSaveBufAsHexCompact(root, "$.Card.Tearing", tmp->tearing, sizeof(tmp->tearing));
JsonSaveBufAsHexCompact(root, "$.Card.Pack", tmp->pack, sizeof(tmp->pack));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
JsonSaveStr(root, "$.Card.Counter", "N/A");
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
JsonSaveBufAsHexCompact(root, "$.Card.Tearing", tmp->tearing, sizeof(tmp->tearing));
JsonSaveBufAsHexCompact(root, "$.Card.Pack", tmp->pack, sizeof(tmp->pack));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
JsonSaveStr(root, "$.Card.Counter", "N/A");
// size of header 48b
size_t len = (datalen - DUMP_PREFIX_LENGTH) / 4;
// size of header 48b
size_t len = (datalen - DUMP_PREFIX_LENGTH) / 4;
for (int i = 0; i < len; i++) {
for (int i = 0; i < len; i++) {
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%d", i);
JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4);
}
break;
}
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%d", i);
JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4);
}
break;
}
int res = json_dump_file(root, fileName, JSON_INDENT(2));
if (res) {
PrintAndLogDevice(FAILED, "error: can't save the file: " _YELLOW_(%s), fileName);
json_decref(root);
retval = 200;
goto out;
}
PrintAndLogDevice(SUCCESS, "saved to json file " _YELLOW_(%s), fileName);
json_decref(root);
int res = json_dump_file(root, fileName, JSON_INDENT(2));
if (res) {
PrintAndLogDevice(FAILED, "error: can't save the file: " _YELLOW_(%s), fileName);
json_decref(root);
retval = 200;
goto out;
}
PrintAndLogDevice(SUCCESS, "saved to json file " _YELLOW_(%s), fileName);
json_decref(root);
out:
free(fileName);
return retval;
free(fileName);
return retval;
}
int loadFile(const char *preferredName, const char *suffix, void* data, size_t* datalen) {
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
FILE *f = fopen(fileName, "rb");
if ( !f ) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
free(fileName);
return 1;
}
FILE *f = fopen(fileName, "rb");
if ( !f ) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
free(fileName);
return 1;
}
// get filesize in order to malloc memory
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
// get filesize in order to malloc memory
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if ( fsize < 0 ) {
PrintAndLogDevice(FAILED, "error, when getting filesize");
retval = 1;
goto out;
}
if ( fsize < 0 ) {
PrintAndLogDevice(FAILED, "error, when getting filesize");
retval = 1;
goto out;
}
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if ( !dump ) {
PrintAndLogDevice(FAILED, "error, cannot allocate memory");
retval = 2;
goto out;
}
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if ( !dump ) {
PrintAndLogDevice(FAILED, "error, cannot allocate memory");
retval = 2;
goto out;
}
size_t bytes_read = fread(dump, 1, fsize, f);
size_t bytes_read = fread(dump, 1, fsize, f);
if ( bytes_read != fsize ) {
PrintAndLogDevice(FAILED, "error, bytes read mismatch file size");
free(dump);
retval = 3;
goto out;
}
if ( bytes_read != fsize ) {
PrintAndLogDevice(FAILED, "error, bytes read mismatch file size");
free(dump);
retval = 3;
goto out;
}
memcpy( (data), dump, bytes_read);
free(dump);
memcpy( (data), dump, bytes_read);
free(dump);
PrintAndLogDevice(SUCCESS, "loaded %d bytes from binary file " _YELLOW_(%s), bytes_read, fileName);
PrintAndLogDevice(SUCCESS, "loaded %d bytes from binary file " _YELLOW_(%s), bytes_read, fileName);
*datalen = bytes_read;
*datalen = bytes_read;
out:
fclose(f);
free(fileName);
fclose(f);
free(fileName);
return retval;
return retval;
}
int loadFileEML(const char *preferredName, const char *suffix, void* data, size_t* datalen) {
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
size_t counter = 0;
int retval = 0, hexlen = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
int retval = 0, hexlen = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
FILE *f = fopen(fileName, "r");
if ( !f ) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
retval = 1;
goto out;
}
FILE *f = fopen(fileName, "r");
if ( !f ) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
retval = 1;
goto out;
}
// 128 + 2 newline chars + 1 null terminator
char line[131];
memset(line, 0, sizeof(line));
uint8_t buf[64] = {0x00};
// 128 + 2 newline chars + 1 null terminator
char line[131];
memset(line, 0, sizeof(line));
uint8_t buf[64] = {0x00};
while ( !feof(f) ) {
while ( !feof(f) ) {
memset(line, 0, sizeof(line));
memset(line, 0, sizeof(line));
if (fgets(line, sizeof(line), f) == NULL){
fclose(f);
PrintAndLogEx(FAILED, "File reading error.");
retval = 2;
goto out;
}
if (fgets(line, sizeof(line), f) == NULL){
fclose(f);
PrintAndLogEx(FAILED, "File reading error.");
retval = 2;
goto out;
}
if ( line[0] == '#' )
continue;
if ( line[0] == '#' )
continue;
int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
if (res == 0 || res == 1) {
memcpy(data + counter, buf, hexlen);
counter += hexlen;
}
}
fclose(f);
PrintAndLogDevice(SUCCESS, "loaded %d bytes from text file " _YELLOW_(%s), counter, fileName);
int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
if (res == 0 || res == 1) {
memcpy(data + counter, buf, hexlen);
counter += hexlen;
}
}
fclose(f);
PrintAndLogDevice(SUCCESS, "loaded %d bytes from text file " _YELLOW_(%s), counter, fileName);
if ( datalen )
*datalen = counter;
if ( datalen )
*datalen = counter;
out:
free(fileName);
return retval;
free(fileName);
return retval;
}
int loadFileJSON(const char *preferredName, const char *suffix, void* data, size_t maxdatalen, size_t* datalen) {
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
*datalen = 0;
json_t *root;
json_error_t error;
*datalen = 0;
json_t *root;
json_error_t error;
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
root = json_load_file(fileName, 0, &error);
if (!root) {
PrintAndLog("ERROR: json " _YELLOW_(%s) " error on line %d: %s", fileName, error.line, error.text);
retval = 2;
goto out;
}
root = json_load_file(fileName, 0, &error);
if (!root) {
PrintAndLog("ERROR: json " _YELLOW_(%s) " error on line %d: %s", fileName, error.line, error.text);
retval = 2;
goto out;
}
if (!json_is_object(root)) {
PrintAndLog("ERROR: Invalid json " _YELLOW_(%s) " format. root must be an object.", fileName);
retval = 3;
goto out;
}
if (!json_is_object(root)) {
PrintAndLog("ERROR: Invalid json " _YELLOW_(%s) " format. root must be an object.", fileName);
retval = 3;
goto out;
}
uint8_t *udata = (uint8_t *)data;
char ctype[100] = {0};
JsonLoadStr(root, "$.FileType", ctype);
uint8_t *udata = (uint8_t *)data;
char ctype[100] = {0};
JsonLoadStr(root, "$.FileType", ctype);
if (!strcmp(ctype, "raw")) {
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
}
if (!strcmp(ctype, "raw")) {
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
}
if (!strcmp(ctype, "mfcard")) {
size_t sptr = 0;
for (int i = 0; i < 256; i++) {
if (sptr + 16 > maxdatalen) {
retval = 5;
goto out;
}
if (!strcmp(ctype, "mfcard")) {
size_t sptr = 0;
for (int i = 0; i < 256; i++) {
if (sptr + 16 > maxdatalen) {
retval = 5;
goto out;
}
char path[30] = {0};
sprintf(path, "$.blocks.%d", i);
char path[30] = {0};
sprintf(path, "$.blocks.%d", i);
size_t len = 0;
JsonLoadBufAsHex(root, path, &udata[sptr], 16, &len);
if (!len)
break;
size_t len = 0;
JsonLoadBufAsHex(root, path, &udata[sptr], 16, &len);
if (!len)
break;
sptr += len;
}
sptr += len;
}
*datalen = sptr;
}
*datalen = sptr;
}
if (!strcmp(ctype, "mfu")) {
size_t sptr = 0;
for (int i = 0; i < 256; i++) {
if (sptr + 4 > maxdatalen) {
retval = 5;
goto out;
}
if (!strcmp(ctype, "mfu")) {
size_t sptr = 0;
for (int i = 0; i < 256; i++) {
if (sptr + 4 > maxdatalen) {
retval = 5;
goto out;
}
char path[30] = {0};
sprintf(path, "$.blocks.%d", i);
char path[30] = {0};
sprintf(path, "$.blocks.%d", i);
size_t len = 0;
JsonLoadBufAsHex(root, path, &udata[sptr], 4, &len);
if (!len)
break;
size_t len = 0;
JsonLoadBufAsHex(root, path, &udata[sptr], 4, &len);
if (!len)
break;
sptr += len;
}
sptr += len;
}
*datalen = sptr;
}
*datalen = sptr;
}
PrintAndLog("loaded from JSON file " _YELLOW_(%s), fileName);
PrintAndLog("loaded from JSON file " _YELLOW_(%s), fileName);
out:
json_decref(root);
free(fileName);
return retval;
json_decref(root);
free(fileName);
return retval;
}
int loadFileDICTIONARY(const char *preferredName, const char *suffix, void* data, size_t* datalen, uint8_t keylen, uint16_t* keycnt ) {
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
if ( preferredName == NULL ) return 1;
if ( suffix == NULL ) return 1;
if ( data == NULL ) return 1;
// t5577 == 4bytes
// mifare == 6 bytes
// iclass == 8 bytes
// default to 6 bytes.
if (keylen != 4 && keylen != 6 && keylen != 8) {
keylen = 6;
}
// t5577 == 4bytes
// mifare == 6 bytes
// iclass == 8 bytes
// default to 6 bytes.
if (keylen != 4 && keylen != 6 && keylen != 8) {
keylen = 6;
}
// double up since its chars
keylen <<= 1;
// double up since its chars
keylen <<= 1;
char line[255];
char line[255];
size_t counter = 0;
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
int retval = 0;
int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10);
char * fileName = calloc(size, sizeof(char));
sprintf(fileName,"%s.%s", preferredName, suffix);
FILE *f = fopen(fileName, "r");
if ( !f ) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
retval = 1;
goto out;
}
FILE *f = fopen(fileName, "r");
if ( !f ) {
PrintAndLogDevice(WARNING, "file not found or locked. '" _YELLOW_(%s)"'", fileName);
retval = 1;
goto out;
}
// read file
while ( fgets(line, sizeof(line), f) ) {
// read file
while ( fgets(line, sizeof(line), f) ) {
// add null terminator
line[keylen] = 0;
// add null terminator
line[keylen] = 0;
// smaller keys than expected is skipped
if (strlen(line) < keylen)
continue;
// smaller keys than expected is skipped
if (strlen(line) < keylen)
continue;
// The line start with # is comment, skip
if( line[0] == '#' )
continue;
// The line start with # is comment, skip
if( line[0] == '#' )
continue;
if (!isxdigit(line[0])){
PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_(%2d) "HEX symbols", line, keylen);
continue;
}
if (!isxdigit(line[0])){
PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_(%2d) "HEX symbols", line, keylen);
continue;
}
uint64_t key = strtoull(line, NULL, 16);
uint64_t key = strtoull(line, NULL, 16);
num_to_bytes(key, keylen >> 1, data + counter);
(*keycnt)++;
memset(line, 0, sizeof(line));
counter += (keylen >> 1);
}
fclose(f);
PrintAndLogDevice(SUCCESS, "loaded " _GREEN_(%2d) "keys from dictionary file " _YELLOW_(%s), *keycnt, fileName);
num_to_bytes(key, keylen >> 1, data + counter);
(*keycnt)++;
memset(line, 0, sizeof(line));
counter += (keylen >> 1);
}
fclose(f);
PrintAndLogDevice(SUCCESS, "loaded " _GREEN_(%2d) "keys from dictionary file " _YELLOW_(%s), *keycnt, fileName);
if ( datalen )
*datalen = counter;
if ( datalen )
*datalen = counter;
out:
free(fileName);
return retval;
free(fileName);
return retval;
}
#else //if we're on ARM

View File

@@ -52,9 +52,9 @@
#include "cmdhfmfu.h"
typedef enum {
jsfRaw,
jsfCardMemory,
jsfMfuMemory,
jsfRaw,
jsfCardMemory,
jsfMfuMemory,
} JSONFileType;
int fileExists(const char *filename);
@@ -155,7 +155,7 @@ extern int loadFileDICTIONARY(const char *preferredName, const char *suffix, voi
#define PrintAndLogDevice(level, format, args...) PrintAndLogEx(level, format , ## args)
#else
/**
/**
* Utility function to print to console. This is used consistently within the library instead
* of printf, but it actually only calls printf. The reason to have this method is to
*make it simple to plug this library into proxmark, which has this function already to

File diff suppressed because it is too large Load Diff

View File

@@ -42,9 +42,9 @@
/**
* @brief
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
* ẑ = check(z');
* @param c
* @param k this is where the diversified key is put (should be 8 bytes)

View File

@@ -50,76 +50,76 @@
int unitTests()
{
int errors = testCipherUtils();
errors += testMAC();
errors += doKeyTests(0);
errors += testElite();
int errors = testCipherUtils();
errors += testMAC();
errors += doKeyTests(0);
errors += testElite();
if(errors)
{
PrintAndLogDevice(NORMAL, "OBS! There were errors!!!");
}
return errors;
return errors;
}
int showHelp()
{
PrintAndLogDevice(NORMAL, "Usage: loclass [options]");
PrintAndLogDevice(NORMAL, "Options:");
PrintAndLogDevice(NORMAL, "-t Perform self-test");
PrintAndLogDevice(NORMAL, "-h Show this help");
PrintAndLogDevice(NORMAL, "-f <filename> Bruteforce iclass dumpfile");
PrintAndLogDevice(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses");
PrintAndLogDevice(NORMAL, " The binary format of the file is expected to be as follows: ");
PrintAndLogDevice(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogDevice(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogDevice(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogDevice(NORMAL, " ... totalling N*24 bytes");
PrintAndLogDevice(NORMAL, " Check iclass_dump.bin for an example");
PrintAndLogDevice(NORMAL, "Options:");
PrintAndLogDevice(NORMAL, "-t Perform self-test");
PrintAndLogDevice(NORMAL, "-h Show this help");
PrintAndLogDevice(NORMAL, "-f <filename> Bruteforce iclass dumpfile");
PrintAndLogDevice(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses");
PrintAndLogDevice(NORMAL, " The binary format of the file is expected to be as follows: ");
PrintAndLogDevice(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogDevice(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogDevice(NORMAL, " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
PrintAndLogDevice(NORMAL, " ... totalling N*24 bytes");
PrintAndLogDevice(NORMAL, " Check iclass_dump.bin for an example");
return 0;
return 0;
}
int main (int argc, char **argv)
{
PrintAndLogDevice(NORMAL, "IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n");
PrintAndLogDevice(NORMAL, "Comes with ABSOLUTELY NO WARRANTY");
PrintAndLogDevice(NORMAL, "Released as GPLv2\n");
PrintAndLogDevice(NORMAL, "WARNING");
PrintAndLogDevice(NORMAL, "");
PrintAndLogDevice(NORMAL, "THIS TOOL IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. ");
PrintAndLogDevice(NORMAL, "");
PrintAndLogDevice(NORMAL, "USAGE OF THIS TOOL IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL ");
PrintAndLogDevice(NORMAL, "PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, ");
PrintAndLogDevice(NORMAL, "AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. ");
PrintAndLogDevice(NORMAL, "");
PrintAndLogDevice(NORMAL, "THIS TOOL SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. ");
PrintAndLogDevice(NORMAL, "IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n");
PrintAndLogDevice(NORMAL, "Comes with ABSOLUTELY NO WARRANTY");
PrintAndLogDevice(NORMAL, "Released as GPLv2\n");
PrintAndLogDevice(NORMAL, "WARNING");
PrintAndLogDevice(NORMAL, "");
PrintAndLogDevice(NORMAL, "THIS TOOL IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. ");
PrintAndLogDevice(NORMAL, "");
PrintAndLogDevice(NORMAL, "USAGE OF THIS TOOL IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL ");
PrintAndLogDevice(NORMAL, "PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, ");
PrintAndLogDevice(NORMAL, "AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. ");
PrintAndLogDevice(NORMAL, "");
PrintAndLogDevice(NORMAL, "THIS TOOL SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. ");
char *fileName = NULL;
int c;
while ((c = getopt (argc, argv, "thf:")) != -1)
switch (c)
{
case 't':
return unitTests();
case 'h':
return showHelp();
case 'f':
fileName = optarg;
return bruteforceFileNoKeys(fileName);
case '?':
if (optopt == 'f')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
//default:
//showHelp();
}
showHelp();
return 0;
char *fileName = NULL;
int c;
while ((c = getopt (argc, argv, "thf:")) != -1)
switch (c)
{
case 't':
return unitTests();
case 'h':
return showHelp();
case 'f':
fileName = optarg;
return bruteforceFileNoKeys(fileName);
case '?':
if (optopt == 'f')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
//default:
//showHelp();
}
showHelp();
return 0;
}