Conflicts:
	armsrc/crapto1.c
	armsrc/iclass.c
	client/nonce2key/crapto1.c
This commit is contained in:
iceman1001 2015-03-06 09:02:15 +01:00
commit 3ac59c7fed
23 changed files with 726 additions and 964 deletions

View file

@ -43,8 +43,7 @@ ARMSRC = fpgaloader.c \
legic_prng.c \ legic_prng.c \
iclass.c \ iclass.c \
BigBuf.c \ BigBuf.c \
cipher.c \ optimized_cipher.c
cipherutils.c\
# stdint.h provided locally until GCC 4.5 becomes C99 compliant # stdint.h provided locally until GCC 4.5 becomes C99 compliant

View file

@ -1,272 +0,0 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
****************************************************************************/
#include "cipher.h"
#include "cipherutils.h"
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#ifndef ON_DEVICE
#include "fileutils.h"
#endif
/**
* 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 .
**/
typedef struct {
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 .
**/
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;
}
/**
* 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;
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
**/
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 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;
// Return value 0 <= retval <= 7
return retval;
}
/**
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k (F 82 ) 8
* be a key and y F 2 be the input bit. Then, the successor cipher state s =
* l , r , t , b is defined as
* t := (T (t) r 0 r 4 )t 0 . . . t 14 l := (k [select(T (t),y,r)] b ) l r
* b := (B(b) r 7 )b 0 . . . b 6 r := (k [select(T (t),y,r)] b ) l
*
* @param s - state
* @param k - array containing 8 bytes
**/
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;
State successor = {0,0,0,0};
successor.t = s.t >> 1;
successor.t |= (T(s) ^ r0 ^ r4) << 15;
successor.b = s.b >> 1;
successor.b |= (B(s) ^ r7) << 7;
bool Tt = T(s);
successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
return successor;
}
/**
* 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);
}
/**
* 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);
}
/**
* Definition 6 (Initial state). Define the function init which takes as input a
* key k (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b >
**/
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;
}
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);
}
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
{
uint8_t cc_nr[13] = { 0 };
uint8_t div_key[8];
//cc_nr=(uint8_t*)malloc(length+1);
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);
return;
}
#ifndef ON_DEVICE
int testMAC()
{
prnlog("[+] 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};
uint8_t calculated_mac[4] = {0};
doMAC(cc_nr,div_key, calculated_mac);
if(memcmp(calculated_mac, correct_MAC,4) == 0)
{
prnlog("[+] MAC calculation OK!");
}else
{
prnlog("[+] FAILED: MAC calculation failed:");
printarr(" Calculated_MAC", calculated_mac, 4);
printarr(" Correct_MAC ", correct_MAC, 4);
return 1;
}
return 0;
}
#endif

View file

@ -1,49 +0,0 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
****************************************************************************/
#ifndef CIPHER_H
#define CIPHER_H
#include <stdint.h>
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
#ifndef ON_DEVICE
int testMAC();
#endif
#endif // CIPHER_H

View file

@ -1,292 +0,0 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
****************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "cipherutils.h"
#ifndef ON_DEVICE
#include "fileutils.h"
#endif
/**
*
* @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
* @param stream
* @return
*/
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;
}
/**
* @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
* @param stream
* @return
*/
bool tailBit( BitstreamIn *stream)
{
int bitpos = stream->numbits -1 - (stream->position++);
int bytepos= bitpos >> 3;
bitpos &= 7;
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Pushes bit onto the stream
* @param stream
* @param bit
*/
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++;
}
/**
* @brief Pushes the lower six bits onto the stream
* as b0 b1 b2 b3 b4 b5 b6
* @param stream
* @param bits
*/
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);
}
/**
* @brief bitsLeft
* @param stream
* @return number of bits left in stream
*/
int bitsLeft( BitstreamIn *stream)
{
return stream->numbits - stream->position;
}
/**
* @brief numBits
* @param stream
* @return Number of bits stored in stream
*/
int numBits(BitstreamOut *stream)
{
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;
}
}
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;
}
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;
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]);
}
}
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]);
}
}
#ifndef ON_DEVICE
void printarr(char * name, uint8_t* arr, int len)
{
int cx;
size_t outsize = 40+strlen(name)+len*5;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i ;
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,"};");
prnlog(output);
}
void printvar(char * name, uint8_t* arr, int len)
{
int cx;
size_t outsize = 40+strlen(name)+len*2;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i ;
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
}
prnlog(output);
}
void printarr_human_readable(char * title, uint8_t* arr, int len)
{
int cx;
size_t outsize = 100+strlen(title)+len*4;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i;
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));
}
prnlog(output);
free(output);
}
#endif
//-----------------------------
// Code for testing below
//-----------------------------
#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));
}
if(memcmp(input, output, sizeof(input)) == 0)
{
prnlog(" Bitstream test 1 ok");
}else
{
prnlog(" Bitstream test 1 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
prnlog(" 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};
while(bitsLeft(&in) > 0)
{
pushBit(&reversed_out, tailBit(&in));
}
while(bitsLeft(&reversed_in) > 0)
{
pushBit(&out, tailBit(&reversed_in));
}
if(memcmp(input, output, sizeof(input)) == 0)
{
prnlog(" Bitstream test 2 ok");
}else
{
prnlog(" Bitstream test 2 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
prnlog(" IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
}
return 1;
}
return 0;
}
int testCipherUtils(void)
{
prnlog("[+] Testing some internals...");
int retval = 0;
retval |= testBitStream();
retval |= testReversedBitstream();
return retval;
}
#endif

View file

@ -1,76 +0,0 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
****************************************************************************/
#ifndef CIPHERUTILS_H
#define CIPHERUTILS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
} BitstreamIn;
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
}BitstreamOut;
bool headBit( BitstreamIn *stream);
bool tailBit( BitstreamIn *stream);
void pushBit( BitstreamOut *stream, bool bit);
int bitsLeft( BitstreamIn *stream);
#ifndef ON_DEVICE
int testCipherUtils(void);
int testMAC();
void printarr(char * name, uint8_t* arr, int len);
void printvar(char * name, uint8_t* arr, int len);
void printarr_human_readable(char * title, uint8_t* arr, int len);
#endif
void push6bits( BitstreamOut* stream, uint8_t bits);
void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ;
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t x_bytes_to_num(uint8_t* src, size_t len);
uint8_t reversebytes(uint8_t b);
void reverse_arraybytes(uint8_t* arr, size_t len);
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len);
#endif // CIPHERUTILS_H

View file

@ -34,6 +34,7 @@ static void __attribute__((constructor)) fill_lut()
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;
uint32_t tmp;
if(it > rit) if(it > rit)
return; return;
@ -43,13 +44,19 @@ static void quicksort(uint32_t* const start, uint32_t* const stop)
++it; ++it;
else if(*rit > *start) else if(*rit > *start)
--rit; --rit;
else else {
*it ^= ( (*it ^= *rit ), *rit ^= *it); tmp = *it;
*it = *rit;
*rit = tmp;
}
if(*rit >= *start) if(*rit >= *start)
--rit; --rit;
if(rit != start) if(rit != start) {
*rit ^= ( (*rit ^= *start), *start ^= *rit); tmp = *rit;
*rit = *start;
*start = tmp;
}
quicksort(start, rit - 1); quicksort(start, rit - 1);
quicksort(rit + 1, stop); quicksort(rit + 1, stop);
@ -319,9 +326,12 @@ uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
{ {
int out; int out;
uint8_t ret; uint8_t ret;
uint32_t tmp;
s->odd &= 0xffffff; s->odd &= 0xffffff;
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); tmp = s->odd;
s->odd = s->even;
s->even = tmp;
out = s->even & 1; out = s->even & 1;
out ^= LF_POLY_EVEN & (s->even >>= 1); out ^= LF_POLY_EVEN & (s->even >>= 1);
@ -440,7 +450,7 @@ check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
} }
return sl + good; return sl + good;
} }
/** lfsr_common_prefix /** lfsr_common_prefix

View file

@ -1,21 +1,21 @@
/* crypto1.c /* crypto1.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, Boston, Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, US 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>
@ -37,8 +37,8 @@ void crypto1_create(struct Crypto1State *s, uint64_t key)
void crypto1_destroy(struct Crypto1State *state) void crypto1_destroy(struct Crypto1State *state)
{ {
// free(state); // free(state);
state->odd = 0; state->odd = 0;
state->even = 0; state->even = 0;
} }
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
{ {
@ -51,6 +51,7 @@ void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
{ {
uint32_t feedin; uint32_t feedin;
uint32_t tmp;
uint8_t ret = filter(s->odd); uint8_t ret = filter(s->odd);
feedin = ret & !!is_encrypted; feedin = ret & !!is_encrypted;
@ -59,7 +60,9 @@ uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
feedin ^= LF_POLY_EVEN & s->even; feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | parity(feedin); s->even = s->even << 1 | parity(feedin);
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); tmp = s->odd;
s->odd = s->even;
s->even = tmp;
return ret; return ret;
} }

View file

@ -48,8 +48,8 @@
#include "../common/iso14443crc.h" #include "../common/iso14443crc.h"
#include "../common/iso15693tools.h" #include "../common/iso15693tools.h"
//#include "iso15693tools.h" //#include "iso15693tools.h"
#include "cipher.h"
#include "protocols.h" #include "protocols.h"
#include "optimized_cipher.h"
static int timeout = 4096; static int timeout = 4096;
@ -1043,6 +1043,10 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
Dbprintf("Done..."); Dbprintf("Done...");
} }
void AppendCrc(uint8_t* data, int len)
{
ComputeCrc14443(CRC_ICLASS,data,len,data+len,data+len+1);
}
/** /**
* @brief Does the actual simulation * @brief Does the actual simulation
@ -1054,6 +1058,8 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
// free eventually allocated BigBuf memory // free eventually allocated BigBuf memory
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
State cipher_state;
// State cipher_state_reserve;
uint8_t *csn = BigBuf_get_EM_addr(); uint8_t *csn = BigBuf_get_EM_addr();
uint8_t *emulator = csn; uint8_t *emulator = csn;
uint8_t sof_data[] = { 0x0F} ; uint8_t sof_data[] = { 0x0F} ;
@ -1070,12 +1076,20 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
ComputeCrc14443(CRC_ICLASS, anticoll_data, 8, &anticoll_data[8], &anticoll_data[9]); ComputeCrc14443(CRC_ICLASS, anticoll_data, 8, &anticoll_data[8], &anticoll_data[9]);
ComputeCrc14443(CRC_ICLASS, csn_data, 8, &csn_data[8], &csn_data[9]); ComputeCrc14443(CRC_ICLASS, csn_data, 8, &csn_data[8], &csn_data[9]);
uint8_t diversified_key[8] = { 0 };
// e-Purse // e-Purse
uint8_t card_challenge_data[8] = { 0x00 }; uint8_t card_challenge_data[8] = { 0x00 };
if(simulationMode == MODE_FULLSIM) if(simulationMode == MODE_FULLSIM)
{ {
//The diversified key should be stored on block 3
//Get the diversified key from emulator memory
memcpy(diversified_key, emulator+(8*3),8);
//Card challenge, a.k.a e-purse is on block 2 //Card challenge, a.k.a e-purse is on block 2
memcpy(card_challenge_data,emulator + (8 * 2) , 8); memcpy(card_challenge_data,emulator + (8 * 2) , 8);
//Precalculate the cipher state, feeding it the CC
cipher_state = opt_doTagMAC_1(card_challenge_data,diversified_key);
} }
int exitLoop = 0; int exitLoop = 0;
@ -1087,7 +1101,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
// Tag CSN // Tag CSN
uint8_t *modulated_response; uint8_t *modulated_response;
int modulated_response_size; int modulated_response_size = 0;
uint8_t* trace_data = NULL; uint8_t* trace_data = NULL;
int trace_data_size = 0; int trace_data_size = 0;
@ -1134,8 +1148,12 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data));
memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax;
//This is used for responding to READ-block commands //This is used for responding to READ-block commands or other data which is dynamically generated
uint8_t *data_response = BigBuf_malloc(8 * 2 + 2); //First the 'trace'-data, not encoded for FPGA
uint8_t *data_generic_trace = BigBuf_malloc(8 + 2);//8 bytes data + 2byte CRC is max tag answer
//Then storage for the modulated data
//Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
uint8_t *data_response = BigBuf_malloc( (8+2) * 2 + 2);
// Start from off (no field generated) // Start from off (no field generated)
//FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -1155,9 +1173,9 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
LED_A_ON(); LED_A_ON();
bool buttonPressed = false; bool buttonPressed = false;
uint8_t response_delay = 1;
while(!exitLoop) { while(!exitLoop) {
response_delay = 1;
LED_B_OFF(); LED_B_OFF();
//Signal tracer //Signal tracer
// Can be used to get a trigger for an oscilloscope.. // Can be used to get a trigger for an oscilloscope..
@ -1199,25 +1217,18 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
} else if(receivedCmd[0] == ICLASS_CMD_CHECK) { } else if(receivedCmd[0] == ICLASS_CMD_CHECK) {
// Reader random and reader MAC!!! // Reader random and reader MAC!!!
if(simulationMode == MODE_FULLSIM) if(simulationMode == MODE_FULLSIM)
{ //This is what we must do.. {
//Reader just sent us NR and MAC(k,cc * nr) //NR, from reader, is in receivedCmd +1
//The diversified key should be stored on block 3 opt_doTagMAC_2(cipher_state,receivedCmd+1,data_generic_trace,diversified_key);
//However, from a typical dump, the key will not be there
uint8_t *diversified_key = { 0 }; trace_data = data_generic_trace;
//Get the diversified key from emulator memory
memcpy(diversified_key, emulator+(8*3),8);
uint8_t ccnr[12] = { 0 };
//Put our cc there (block 2)
memcpy(ccnr, emulator + (8 * 2), 8);
//Put nr there
memcpy(ccnr+8, receivedCmd+1,4);
//Now, calc MAC
doMAC(ccnr,diversified_key, trace_data);
trace_data_size = 4; trace_data_size = 4;
CodeIClassTagAnswer(trace_data , trace_data_size); CodeIClassTagAnswer(trace_data , trace_data_size);
memcpy(data_response, ToSend, ToSendMax); memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response; modulated_response = data_response;
modulated_response_size = ToSendMax; modulated_response_size = ToSendMax;
response_delay = 0;//We need to hurry here...
//exitLoop = true;
}else }else
{ //Not fullsim, we don't respond { //Not fullsim, we don't respond
// We do not know what to answer, so lets keep quiet // We do not know what to answer, so lets keep quiet
@ -1248,12 +1259,39 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
} else if(simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4){ } else if(simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4){
//Read block //Read block
uint16_t blk = receivedCmd[1]; uint16_t blk = receivedCmd[1];
trace_data = emulator+(blk << 3); //Take the data...
trace_data_size = 8; memcpy(data_generic_trace, emulator+(blk << 3),8);
//Add crc
AppendCrc(data_generic_trace, 8);
trace_data = data_generic_trace;
trace_data_size = 10;
CodeIClassTagAnswer(trace_data , trace_data_size); CodeIClassTagAnswer(trace_data , trace_data_size);
memcpy(data_response, ToSend, ToSendMax); memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response; modulated_response = data_response;
modulated_response_size = ToSendMax; modulated_response_size = ToSendMax;
}else if(receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == MODE_FULLSIM)
{//Probably the reader wants to update the nonce. Let's just ignore that for now.
// OBS! If this is implemented, don't forget to regenerate the cipher_state
//We're expected to respond with the data+crc, exactly what's already in the receivedcmd
//receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b|
//Take the data...
memcpy(data_generic_trace, receivedCmd+2,8);
//Add crc
AppendCrc(data_generic_trace, 8);
trace_data = data_generic_trace;
trace_data_size = 10;
CodeIClassTagAnswer(trace_data , trace_data_size);
memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response;
modulated_response_size = ToSendMax;
}
else if(receivedCmd[0] == ICLASS_CMD_PAGESEL)
{//Pagesel
//Pagesel enables to select a page in the selected chip memory and return its configuration block
//Chips with a single page will not answer to this command
// It appears we're fine ignoring this.
//Otherwise, we should answer 8bytes (block) + 2bytes CRC
} }
else { else {
//#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44
@ -1280,7 +1318,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
A legit tag has about 380us delay between reader EOT and tag SOF. A legit tag has about 380us delay between reader EOT and tag SOF.
**/ **/
if(modulated_response_size > 0) { if(modulated_response_size > 0) {
SendIClassAnswer(modulated_response, modulated_response_size, 1); SendIClassAnswer(modulated_response, modulated_response_size, response_delay);
t2r_time = GetCountSspClk(); t2r_time = GetCountSspClk();
} }

View file

@ -12,7 +12,7 @@
#include "string.h" #include "string.h"
#include "lfsampling.h" #include "lfsampling.h"
#include "cipherutils.h"
sample_config config = { 1, 8, 1, 95, 0 } ; sample_config config = { 1, 8, 1, 95, 0 } ;
void printConfig() void printConfig()
@ -55,20 +55,19 @@ sample_config* getSamplingConfig()
{ {
return &config; return &config;
} }
/*
typedef struct { typedef struct {
uint8_t * buffer; uint8_t * buffer;
uint32_t numbits; uint32_t numbits;
uint32_t position; uint32_t position;
} BitstreamOut; } BitstreamOut;
*/
/** /**
* @brief Pushes bit onto the stream * @brief Pushes bit onto the stream
* @param stream * @param stream
* @param bit * @param bit
*/ */
/*void pushBit( BitstreamOut* stream, uint8_t bit) void pushBit( BitstreamOut* stream, uint8_t bit)
{ {
int bytepos = stream->position >> 3; // divide by 8 int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7; int bitpos = stream->position & 7;
@ -76,7 +75,7 @@ typedef struct {
stream->position++; stream->position++;
stream->numbits++; stream->numbits++;
} }
*/
/** /**
* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna. * if not already loaded, sets divisor and starts up the antenna.

View file

@ -942,12 +942,12 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if (workFlags & 0x01) { if (workFlags & 0x01) {
if(!iso14443a_select_card(uid, NULL, &cuid)) { if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break; //break;
}; };
if(mifare_classic_halt(NULL, cuid)) { if(mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break; //break;
}; };
}; };

288
armsrc/optimized_cipher.c Normal file
View file

@ -0,0 +1,288 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
****************************************************************************/
/**
This file contains an optimized version of the MAC-calculation algorithm. Some measurements on
a std laptop showed it runs in about 1/3 of the time:
Std: 0.428962
Opt: 0.151609
Additionally, it is self-reliant, not requiring e.g. bitstreams from the cipherutils, thus can
be easily dropped into a code base.
The optimizations have been performed in the following steps:
* Parameters passed by reference instead of by value.
* Iteration instead of recursion, un-nesting recursive loops into for-loops.
* Handling of bytes instead of individual bits, for less shuffling and masking
* Less creation of "objects", structs, and instead reuse of alloc:ed memory
* Inlining some functions via #define:s
As a consequence, this implementation is less generic. Also, I haven't bothered documenting this.
For a thorough documentation, check out the MAC-calculation within cipher.c instead.
-- MHS 2015
**/
#include "optimized_cipher.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14)^ (s->t >> 10)^ (s->t >> 8)^ (s->t >> 5)^ (s->t >> 4)^ (s->t >> 1)^ s->t))
#define opt_B(s) (((s->b >> 6) ^ (s->b >> 5) ^ (s->b >> 4) ^ (s->b)) & 0x1)
#define opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\
|(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\
|(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x))
/*
* Some background on the expression above can be found here...
uint8_t xopt__select(bool x, bool y, uint8_t r)
{
uint8_t r_ls2 = r << 2;
uint8_t r_and_ls2 = r & r_ls2;
uint8_t r_or_ls2 = r | r_ls2;
//r: r0 r1 r2 r3 r4 r5 r6 r7
//r_ls2: r2 r3 r4 r5 r6 r7 0 0
// z0
// z1
// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original
uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3);
// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original
uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1);
// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original
uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r ^ x;
return (z0 & 4) | (z1 & 2) | (z2 & 1);
}
*/
void opt_successor(const uint8_t* k, State *s, bool y, State* successor)
{
uint8_t Tt = 1 & opt_T(s);
successor->t = (s->t >> 1);
successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15;
successor->b = s->b >> 1;
successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7;
successor->r = (k[opt__select(Tt,y,s->r)] ^ successor->b) + s->l ;
successor->l = successor->r+s->r;
}
void opt_suc(const uint8_t* k,State* s, uint8_t *in, uint8_t length, bool add32Zeroes)
{
State x2;
int i;
uint8_t head = 0;
for(i =0 ; i < length ; i++)
{
head = 1 & (in[i] >> 7);
opt_successor(k,s,head,&x2);
head = 1 & (in[i] >> 6);
opt_successor(k,&x2,head,s);
head = 1 & (in[i] >> 5);
opt_successor(k,s,head,&x2);
head = 1 & (in[i] >> 4);
opt_successor(k,&x2,head,s);
head = 1 & (in[i] >> 3);
opt_successor(k,s,head,&x2);
head = 1 & (in[i] >> 2);
opt_successor(k,&x2,head,s);
head = 1 & (in[i] >> 1);
opt_successor(k,s,head,&x2);
head = 1 & in[i];
opt_successor(k,&x2,head,s);
}
//For tag MAC, an additional 32 zeroes
if(add32Zeroes)
for(i =0 ; i < 16 ; i++)
{
opt_successor(k,s,0,&x2);
opt_successor(k,&x2,0,s);
}
}
void opt_output(const uint8_t* k,State* s, uint8_t *buffer)
{
uint8_t times = 0;
uint8_t bout = 0;
State temp = {0,0,0,0};
for( ; times < 4 ; times++)
{
bout =0;
bout |= (s->r & 0x4) << 5;
opt_successor(k,s,0,&temp);
bout |= (temp.r & 0x4) << 4;
opt_successor(k,&temp,0,s);
bout |= (s->r & 0x4) << 3;
opt_successor(k,s,0,&temp);
bout |= (temp.r & 0x4) << 2;
opt_successor(k,&temp,0,s);
bout |= (s->r & 0x4) << 1;
opt_successor(k,s,0,&temp);
bout |= (temp.r & 0x4) ;
opt_successor(k,&temp,0,s);
bout |= (s->r & 0x4) >> 1;
opt_successor(k,s,0,&temp);
bout |= (temp.r & 0x4) >> 2;
opt_successor(k,&temp,0,s);
buffer[times] = bout;
}
}
void opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out)
{
State _init = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(k,&_init,input,12, false);
//printf("\noutp ");
opt_output(k,&_init, out);
}
uint8_t rev_byte(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void opt_reverse_arraybytecpy(uint8_t* dest, uint8_t *src, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
dest[i] = rev_byte(src[i]);
}
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
{
static uint8_t cc_nr[12];
opt_reverse_arraybytecpy(cc_nr, cc_nr_p,12);
uint8_t dest []= {0,0,0,0,0,0,0,0};
opt_MAC(div_key_p,cc_nr, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest,4);
return;
}
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4])
{
static uint8_t cc_nr[8+4+4];
opt_reverse_arraybytecpy(cc_nr, cc_p,12);
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p,&_init,cc_nr, 12,true);
uint8_t dest []= {0,0,0,0};
opt_output(div_key_p,&_init, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest,4);
return;
}
/**
* The tag MAC can be divided (both can, but no point in dividing the reader mac) into
* two functions, since the first 8 bytes are known, we can pre-calculate the state
* reached after feeding CC to the cipher.
* @param cc_p
* @param div_key_p
* @return the cipher state
*/
State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p)
{
static uint8_t cc_nr[8];
opt_reverse_arraybytecpy(cc_nr, cc_p,8);
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p,&_init,cc_nr, 8,false);
return _init;
}
/**
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
* this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag
* MAC response.
* @param _init - precalculated cipher state
* @param nr - the reader challenge
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p)
{
static uint8_t _nr [4];
opt_reverse_arraybytecpy(_nr, nr, 4);
opt_suc(div_key_p,&_init,_nr, 4, true);
//opt_suc(div_key_p,&_init,nr, 4, false);
uint8_t dest []= {0,0,0,0};
opt_output(div_key_p,&_init, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest,4);
return;
}

48
armsrc/optimized_cipher.h Normal file
View file

@ -0,0 +1,48 @@
#ifndef OPTIMIZED_CIPHER_H
#define OPTIMIZED_CIPHER_H
#include <stdint.h>
/**
* 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 .
**/
typedef struct {
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
} State;
/** The reader MAC is MAC(key, CC * NR )
**/
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
/**
* The tag MAC is MAC(key, CC * NR * 32x0))
*/
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]);
/**
* The tag MAC can be divided (both can, but no point in dividing the reader mac) into
* two functions, since the first 8 bytes are known, we can pre-calculate the state
* reached after feeding CC to the cipher.
* @param cc_p
* @param div_key_p
* @return the cipher state
*/
State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p);
/**
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
* this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag
* MAC response.
* @param _init - precalculated cipher state
* @param nr - the reader challenge
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p);
#endif // OPTIMIZED_CIPHER_H

View file

@ -227,7 +227,7 @@ void printBitStream(uint8_t BitStream[], uint32_t bitLen)
return; return;
} }
//by marshmellow //by marshmellow
//print EM410x ID in multiple formats //print 64 bit EM410x ID in multiple formats
void printEM410x(uint64_t id) void printEM410x(uint64_t id)
{ {
if (id !=0){ if (id !=0){
@ -317,36 +317,19 @@ int CmdAskEM410xDemod(const char *Cmd)
printDemodBuff(); printDemodBuff();
} }
PrintAndLog("EM410x pattern found: "); PrintAndLog("EM410x pattern found: ");
if (BitLen > 64) PrintAndLog("\nWarning! Length not what is expected - Length: %d bits\n",BitLen);
printEM410x(lo); printEM410x(lo);
return 1; return 1;
} }
return 0; return 0;
} }
//by marshmellow int ASKmanDemod(const char *Cmd, bool verbose, bool emSearch)
//takes 3 arguments - clock, invert, maxErr as integers
//attempts to demodulate ask while decoding manchester
//prints binary found and saves in graphbuffer for further commands
int Cmdaskmandemod(const char *Cmd)
{ {
int invert=0; int invert=0;
int clk=0; int clk=0;
int maxErr=100; int maxErr=100;
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod am [clock] <0|1> [maxError]");
PrintAndLog(" [set clock as integer] optional, if not set, autodetect.");
PrintAndLog(" <invert>, 1 for invert output");
PrintAndLog(" [set maximum allowed errors], default = 100.");
PrintAndLog("");
PrintAndLog(" sample: data rawdemod am = demod an ask/manchester tag from GraphBuffer");
PrintAndLog(" : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32");
PrintAndLog(" : data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data");
PrintAndLog(" : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data");
PrintAndLog(" : data rawdemod am 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
return 0;
}
uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0};
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
if (invert != 0 && invert != 1) { if (invert != 0 && invert != 1) {
@ -366,33 +349,58 @@ int Cmdaskmandemod(const char *Cmd)
if (g_debugMode==1) PrintAndLog("no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk); if (g_debugMode==1) PrintAndLog("no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk);
return 0; return 0;
} }
PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,BitLen); if (verbose) PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,BitLen);
//output //output
if (errCnt>0){ if (errCnt>0){
PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); if (verbose) PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt);
} }
PrintAndLog("ASK/Manchester decoded bitstream:"); if (verbose) PrintAndLog("ASK/Manchester decoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits
setDemodBuf(BitStream,BitLen,0); setDemodBuf(BitStream,BitLen,0);
printDemodBuff(); if (verbose) printDemodBuff();
uint64_t lo =0; uint64_t lo =0;
size_t idx=0; size_t idx=0;
lo = Em410xDecode(BitStream, &BitLen, &idx); if (emSearch){
if (lo>0){ lo = Em410xDecode(BitStream, &BitLen, &idx);
//set GraphBuffer for clone or sim command if (lo>0){
setDemodBuf(BitStream, BitLen, idx); //set GraphBuffer for clone or sim command
if (g_debugMode){ setDemodBuf(BitStream, BitLen, idx);
PrintAndLog("DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, BitLen); if (g_debugMode){
printDemodBuff(); PrintAndLog("DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, BitLen);
printDemodBuff();
}
if (verbose) PrintAndLog("EM410x pattern found: ");
if (verbose) printEM410x(lo);
return 1;
} }
PrintAndLog("EM410x pattern found: ");
printEM410x(lo);
return 1;
} }
return 1; return 1;
} }
//by marshmellow
//takes 3 arguments - clock, invert, maxErr as integers
//attempts to demodulate ask while decoding manchester
//prints binary found and saves in graphbuffer for further commands
int Cmdaskmandemod(const char *Cmd)
{
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod am [clock] <0|1> [maxError]");
PrintAndLog(" [set clock as integer] optional, if not set, autodetect.");
PrintAndLog(" <invert>, 1 for invert output");
PrintAndLog(" [set maximum allowed errors], default = 100.");
PrintAndLog("");
PrintAndLog(" sample: data rawdemod am = demod an ask/manchester tag from GraphBuffer");
PrintAndLog(" : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32");
PrintAndLog(" : data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data");
PrintAndLog(" : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data");
PrintAndLog(" : data rawdemod am 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
return 0;
}
return ASKmanDemod(Cmd, TRUE, TRUE);
}
//by marshmellow //by marshmellow
//manchester decode //manchester decode
//stricktly take 10 and 01 and convert to 0 and 1 //stricktly take 10 and 01 and convert to 0 and 1
@ -505,13 +513,53 @@ int CmdBiphaseDecodeRaw(const char *Cmd)
//takes 4 arguments - clock, invert, maxErr as integers and amplify as char //takes 4 arguments - clock, invert, maxErr as integers and amplify as char
//attempts to demodulate ask only //attempts to demodulate ask only
//prints binary found and saves in graphbuffer for further commands //prints binary found and saves in graphbuffer for further commands
int Cmdaskrawdemod(const char *Cmd) int ASKrawDemod(const char *Cmd, bool verbose)
{ {
int invert=0; int invert=0;
int clk=0; int clk=0;
int maxErr=100; int maxErr=100;
uint8_t askAmp = 0; uint8_t askAmp = 0;
char amp = param_getchar(Cmd, 0); char amp = param_getchar(Cmd, 0);
uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0};
sscanf(Cmd, "%i %i %i %c", &clk, &invert, &maxErr, &amp);
if (invert != 0 && invert != 1) {
if (verbose) PrintAndLog("Invalid argument: %s", Cmd);
return 0;
}
if (clk==1){
invert=1;
clk=0;
}
if (amp == 'a' || amp == 'A') askAmp=1;
size_t BitLen = getFromGraphBuf(BitStream);
if (BitLen==0) return 0;
int errCnt=0;
errCnt = askrawdemod(BitStream, &BitLen, &clk, &invert, maxErr, askAmp);
if (errCnt==-1||BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first)
if (verbose) PrintAndLog("no data found");
if (g_debugMode==1 && verbose) PrintAndLog("errCnt: %d, BitLen: %d, clk: %d, invert: %d", errCnt, BitLen, clk, invert);
return 0;
}
if (verbose) PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d", clk, invert, BitLen);
//move BitStream back to DemodBuffer
setDemodBuf(BitStream,BitLen,0);
//output
if (errCnt>0 && verbose){
PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d", errCnt);
}
if (verbose){
PrintAndLog("ASK demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits
printBitStream(BitStream,BitLen);
}
return 1;
}
//by marshmellow - see ASKrawDemod
int Cmdaskrawdemod(const char *Cmd)
{
char cmdp = param_getchar(Cmd, 0); char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 12 || cmdp == 'h' || cmdp == 'H') { if (strlen(Cmd) > 12 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod ar [clock] <invert> [maxError] [amplify]"); PrintAndLog("Usage: data rawdemod ar [clock] <invert> [maxError] [amplify]");
@ -529,40 +577,7 @@ int Cmdaskrawdemod(const char *Cmd)
PrintAndLog(" : data rawdemod ar 64 1 0 a = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); PrintAndLog(" : data rawdemod ar 64 1 0 a = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp");
return 0; return 0;
} }
uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; return ASKrawDemod(Cmd, TRUE);
sscanf(Cmd, "%i %i %i %c", &clk, &invert, &maxErr, &amp);
if (invert != 0 && invert != 1) {
PrintAndLog("Invalid argument: %s", Cmd);
return 0;
}
if (clk==1){
invert=1;
clk=0;
}
if (amp == 'a' || amp == 'A') askAmp=1;
size_t BitLen = getFromGraphBuf(BitStream);
if (BitLen==0) return 0;
int errCnt=0;
errCnt = askrawdemod(BitStream, &BitLen, &clk, &invert, maxErr, askAmp);
if (errCnt==-1||BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first)
PrintAndLog("no data found");
if (g_debugMode==1) PrintAndLog("errCnt: %d, BitLen: %d, clk: %d, invert: %d", errCnt, BitLen, clk, invert);
return 0;
}
PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d", clk, invert, BitLen);
//move BitStream back to DemodBuffer
setDemodBuf(BitStream,BitLen,0);
//output
if (errCnt>0){
PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d", errCnt);
}
PrintAndLog("ASK demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits
printBitStream(BitStream,BitLen);
return 1;
} }
int CmdAutoCorr(const char *Cmd) int CmdAutoCorr(const char *Cmd)
@ -820,7 +835,7 @@ int CmdDetectClockRate(const char *Cmd)
//fsk raw demod and print binary //fsk raw demod and print binary
//takes 4 arguments - Clock, invert, fchigh, fclow //takes 4 arguments - Clock, invert, fchigh, fclow
//defaults: clock = 50, invert=1, fchigh=10, fclow=8 (RF/10 RF/8 (fsk2a)) //defaults: clock = 50, invert=1, fchigh=10, fclow=8 (RF/10 RF/8 (fsk2a))
int CmdFSKrawdemod(const char *Cmd) int FSKrawDemod(const char *Cmd, bool verbose)
{ {
//raw fsk demod no manchester decoding no start bit finding just get binary from wave //raw fsk demod no manchester decoding no start bit finding just get binary from wave
//set defaults //set defaults
@ -828,23 +843,7 @@ int CmdFSKrawdemod(const char *Cmd)
int invert=0; int invert=0;
int fchigh=0; int fchigh=0;
int fclow=0; int fclow=0;
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod fs [clock] <invert> [fchigh] [fclow]");
PrintAndLog(" [set clock as integer] optional, omit for autodetect.");
PrintAndLog(" <invert>, 1 for invert output, can be used even if the clock is omitted");
PrintAndLog(" [fchigh], larger field clock length, omit for autodetect");
PrintAndLog(" [fclow], small field clock length, omit for autodetect");
PrintAndLog("");
PrintAndLog(" sample: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect");
PrintAndLog(" : data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc");
PrintAndLog(" : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output");
PrintAndLog(" : data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc");
PrintAndLog(" : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer");
PrintAndLog(" : data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer");
PrintAndLog(" : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer");
return 0;
}
//set options from parameters entered with the command //set options from parameters entered with the command
sscanf(Cmd, "%i %i %i %i", &rfLen, &invert, &fchigh, &fclow); sscanf(Cmd, "%i %i %i %i", &rfLen, &invert, &fchigh, &fclow);
@ -876,22 +875,50 @@ int CmdFSKrawdemod(const char *Cmd)
rfLen = detectFSKClk(BitStream, BitLen, fchigh, fclow); rfLen = detectFSKClk(BitStream, BitLen, fchigh, fclow);
if (rfLen == 0) rfLen = 50; if (rfLen == 0) rfLen = 50;
} }
PrintAndLog("Args invert: %d - Clock:%d - fchigh:%d - fclow: %d",invert,rfLen,fchigh, fclow); if (verbose) PrintAndLog("Args invert: %d - Clock:%d - fchigh:%d - fclow: %d",invert,rfLen,fchigh, fclow);
int size = fskdemod(BitStream,BitLen,(uint8_t)rfLen,(uint8_t)invert,(uint8_t)fchigh,(uint8_t)fclow); int size = fskdemod(BitStream,BitLen,(uint8_t)rfLen,(uint8_t)invert,(uint8_t)fchigh,(uint8_t)fclow);
if (size>0){ if (size>0){
PrintAndLog("FSK decoded bitstream:");
setDemodBuf(BitStream,size,0); setDemodBuf(BitStream,size,0);
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits
if(size > (8*32)+2) size = (8*32)+2; //only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size if(size > (8*32)+2) size = (8*32)+2; //only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size
if (verbose) {
PrintAndLog("FSK decoded bitstream:");
printBitStream(BitStream,size); printBitStream(BitStream,size);
}
return 1; return 1;
} else{ } else{
PrintAndLog("no FSK data found"); if (verbose) PrintAndLog("no FSK data found");
} }
return 0; return 0;
} }
//by marshmellow
//fsk raw demod and print binary
//takes 4 arguments - Clock, invert, fchigh, fclow
//defaults: clock = 50, invert=1, fchigh=10, fclow=8 (RF/10 RF/8 (fsk2a))
int CmdFSKrawdemod(const char *Cmd)
{
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod fs [clock] <invert> [fchigh] [fclow]");
PrintAndLog(" [set clock as integer] optional, omit for autodetect.");
PrintAndLog(" <invert>, 1 for invert output, can be used even if the clock is omitted");
PrintAndLog(" [fchigh], larger field clock length, omit for autodetect");
PrintAndLog(" [fclow], small field clock length, omit for autodetect");
PrintAndLog("");
PrintAndLog(" sample: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect");
PrintAndLog(" : data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc");
PrintAndLog(" : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output");
PrintAndLog(" : data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc");
PrintAndLog(" : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer");
PrintAndLog(" : data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer");
PrintAndLog(" : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer");
return 0;
}
return FSKrawDemod(Cmd, TRUE);
}
//by marshmellow (based on existing demod + holiman's refactor) //by marshmellow (based on existing demod + holiman's refactor)
//HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded) //HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded)
//print full HID Prox ID and some bit format details if found //print full HID Prox ID and some bit format details if found
@ -1013,9 +1040,12 @@ int CmdFSKdemodParadox(const char *Cmd)
} }
uint32_t fc = ((hi & 0x3)<<6) | (lo>>26); uint32_t fc = ((hi & 0x3)<<6) | (lo>>26);
uint32_t cardnum = (lo>>10)&0xFFFF; uint32_t cardnum = (lo>>10)&0xFFFF;
uint32_t rawLo = bytebits_to_byte(BitStream+idx+64,32);
uint32_t rawHi = bytebits_to_byte(BitStream+idx+32,32);
uint32_t rawHi2 = bytebits_to_byte(BitStream+idx,32);
PrintAndLog("Paradox TAG ID: %x%08x - FC: %d - Card: %d - Checksum: %02x", PrintAndLog("Paradox TAG ID: %x%08x - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x",
hi>>10, (hi & 0x3)<<26 | (lo>>10), fc, cardnum, (lo>>2) & 0xFF ); hi>>10, (hi & 0x3)<<26 | (lo>>10), fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo);
setDemodBuf(BitStream,BitLen,idx); setDemodBuf(BitStream,BitLen,idx);
if (g_debugMode){ if (g_debugMode){
PrintAndLog("DEBUG: idx: %d, len: %d, Printing Demod Buffer:", idx, BitLen); PrintAndLog("DEBUG: idx: %d, len: %d, Printing Demod Buffer:", idx, BitLen);
@ -1185,16 +1215,16 @@ int CmdFSKdemodAWID(const char *Cmd)
fc = bytebits_to_byte(BitStream+9, 8); fc = bytebits_to_byte(BitStream+9, 8);
cardnum = bytebits_to_byte(BitStream+17, 16); cardnum = bytebits_to_byte(BitStream+17, 16);
code1 = bytebits_to_byte(BitStream+8,fmtLen); code1 = bytebits_to_byte(BitStream+8,fmtLen);
PrintAndLog("AWID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo); PrintAndLog("AWID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo);
} else { } else {
cardnum = bytebits_to_byte(BitStream+8+(fmtLen-17), 16); cardnum = bytebits_to_byte(BitStream+8+(fmtLen-17), 16);
if (fmtLen>32){ if (fmtLen>32){
code1 = bytebits_to_byte(BitStream+8,fmtLen-32); code1 = bytebits_to_byte(BitStream+8,fmtLen-32);
code2 = bytebits_to_byte(BitStream+8+(fmtLen-32),32); code2 = bytebits_to_byte(BitStream+8+(fmtLen-32),32);
PrintAndLog("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x%08x, Raw: %x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); PrintAndLog("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
} else{ } else{
code1 = bytebits_to_byte(BitStream+8,fmtLen); code1 = bytebits_to_byte(BitStream+8,fmtLen);
PrintAndLog("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x, Raw: %x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); PrintAndLog("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
} }
} }
if (g_debugMode){ if (g_debugMode){
@ -1305,21 +1335,21 @@ int CmdFSKdemodPyramid(const char *Cmd)
fc = bytebits_to_byte(BitStream+73, 8); fc = bytebits_to_byte(BitStream+73, 8);
cardnum = bytebits_to_byte(BitStream+81, 16); cardnum = bytebits_to_byte(BitStream+81, 16);
code1 = bytebits_to_byte(BitStream+72,fmtLen); code1 = bytebits_to_byte(BitStream+72,fmtLen);
PrintAndLog("Pyramid ID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %x%08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi3, rawHi2, rawHi, rawLo); PrintAndLog("Pyramid ID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %08x%08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi3, rawHi2, rawHi, rawLo);
} else if (fmtLen==45){ } else if (fmtLen==45){
fmtLen=42; //end = 10 bits not 7 like 26 bit fmt fmtLen=42; //end = 10 bits not 7 like 26 bit fmt
fc = bytebits_to_byte(BitStream+53, 10); fc = bytebits_to_byte(BitStream+53, 10);
cardnum = bytebits_to_byte(BitStream+63, 32); cardnum = bytebits_to_byte(BitStream+63, 32);
PrintAndLog("Pyramid ID Found - BitLength: %d, FC: %d, Card: %d - Raw: %x%08x%08x%08x", fmtLen, fc, cardnum, rawHi3, rawHi2, rawHi, rawLo); PrintAndLog("Pyramid ID Found - BitLength: %d, FC: %d, Card: %d - Raw: %08x%08x%08x%08x", fmtLen, fc, cardnum, rawHi3, rawHi2, rawHi, rawLo);
} else { } else {
cardnum = bytebits_to_byte(BitStream+81, 16); cardnum = bytebits_to_byte(BitStream+81, 16);
if (fmtLen>32){ if (fmtLen>32){
//code1 = bytebits_to_byte(BitStream+(size-fmtLen),fmtLen-32); //code1 = bytebits_to_byte(BitStream+(size-fmtLen),fmtLen-32);
//code2 = bytebits_to_byte(BitStream+(size-32),32); //code2 = bytebits_to_byte(BitStream+(size-32),32);
PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo); PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo);
} else{ } else{
//code1 = bytebits_to_byte(BitStream+(size-fmtLen),fmtLen); //code1 = bytebits_to_byte(BitStream+(size-fmtLen),fmtLen);
PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo); PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo);
} }
} }
if (g_debugMode){ if (g_debugMode){
@ -1449,7 +1479,7 @@ int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating
//by marshmellow //by marshmellow
//attempt to psk1 demod graph buffer //attempt to psk1 demod graph buffer
int PSKDemod(const char *Cmd, uint8_t verbose) int PSKDemod(const char *Cmd, bool verbose)
{ {
int invert=0; int invert=0;
int clk=0; int clk=0;
@ -1460,7 +1490,7 @@ int PSKDemod(const char *Cmd, uint8_t verbose)
clk=0; clk=0;
} }
if (invert != 0 && invert != 1) { if (invert != 0 && invert != 1) {
PrintAndLog("Invalid argument: %s", Cmd); if (verbose) PrintAndLog("Invalid argument: %s", Cmd);
return -1; return -1;
} }
uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0};
@ -1469,11 +1499,11 @@ int PSKDemod(const char *Cmd, uint8_t verbose)
int errCnt=0; int errCnt=0;
errCnt = pskRawDemod(BitStream, &BitLen,&clk,&invert); errCnt = pskRawDemod(BitStream, &BitLen,&clk,&invert);
if (errCnt > maxErr){ if (errCnt > maxErr){
if (g_debugMode==1) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); if (g_debugMode==1 && verbose) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt);
return -1; return -1;
} }
if (errCnt<0|| BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first) if (errCnt<0|| BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first)
if (g_debugMode==1) PrintAndLog("no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); if (g_debugMode==1 && verbose) PrintAndLog("no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt);
return -1; return -1;
} }
if (verbose) PrintAndLog("Tried PSK Demod using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen); if (verbose) PrintAndLog("Tried PSK Demod using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen);
@ -1567,27 +1597,12 @@ int CmdIndalaDecode(const char *Cmd)
// takes 3 arguments - clock, invert, maxErr as integers // takes 3 arguments - clock, invert, maxErr as integers
// attempts to demodulate nrz only // attempts to demodulate nrz only
// prints binary found and saves in demodbuffer for further commands // prints binary found and saves in demodbuffer for further commands
int CmdNRZrawDemod(const char *Cmd)
int NRZrawDemod(const char *Cmd, bool verbose)
{ {
int invert=0; int invert=0;
int clk=0; int clk=0;
int maxErr=100; int maxErr=100;
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod nr [clock] <0|1> [maxError]");
PrintAndLog(" [set clock as integer] optional, if not set, autodetect.");
PrintAndLog(" <invert>, 1 for invert output");
PrintAndLog(" [set maximum allowed errors], default = 100.");
PrintAndLog("");
PrintAndLog(" sample: data nrzrawdemod = demod a nrz/direct tag from GraphBuffer");
PrintAndLog(" : data nrzrawdemod 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32");
PrintAndLog(" : data nrzrawdemod 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data");
PrintAndLog(" : data nrzrawdemod 1 = demod a nrz/direct tag from GraphBuffer while inverting data");
PrintAndLog(" : data nrzrawdemod 64 1 0 = demod a nrz/direct tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
return 0;
}
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
if (clk==1){ if (clk==1){
invert=1; invert=1;
@ -1603,27 +1618,48 @@ int CmdNRZrawDemod(const char *Cmd)
int errCnt=0; int errCnt=0;
errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert, maxErr); errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert, maxErr);
if (errCnt > maxErr){ if (errCnt > maxErr){
if (g_debugMode==1) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); if (g_debugMode==1 && verbose) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt);
return 0; return 0;
} }
if (errCnt<0|| BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first) if (errCnt<0|| BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first)
if (g_debugMode==1) PrintAndLog("no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); if (g_debugMode==1 && verbose) PrintAndLog("no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt);
return 0; return 0;
} }
PrintAndLog("Tried NRZ Demod using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen); if (verbose)
PrintAndLog("Tried NRZ Demod using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen);
//prime demod buffer for output //prime demod buffer for output
setDemodBuf(BitStream,BitLen,0); setDemodBuf(BitStream,BitLen,0);
if (errCnt>0){ if (errCnt>0 && verbose){
PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt);
}else{
} }
if (verbose) {
PrintAndLog("NRZ demoded bitstream:"); PrintAndLog("NRZ demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits
printDemodBuff(); printDemodBuff();
}
return 1; return 1;
} }
int CmdNRZrawDemod(const char *Cmd)
{
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data rawdemod nr [clock] <0|1> [maxError]");
PrintAndLog(" [set clock as integer] optional, if not set, autodetect.");
PrintAndLog(" <invert>, 1 for invert output");
PrintAndLog(" [set maximum allowed errors], default = 100.");
PrintAndLog("");
PrintAndLog(" sample: data nrzrawdemod = demod a nrz/direct tag from GraphBuffer");
PrintAndLog(" : data nrzrawdemod 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32");
PrintAndLog(" : data nrzrawdemod 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data");
PrintAndLog(" : data nrzrawdemod 1 = demod a nrz/direct tag from GraphBuffer while inverting data");
PrintAndLog(" : data nrzrawdemod 64 1 0 = demod a nrz/direct tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
return 0;
}
return NRZrawDemod(Cmd, TRUE);
}
// by marshmellow // by marshmellow
// takes 3 arguments - clock, invert, maxErr as integers // takes 3 arguments - clock, invert, maxErr as integers
// attempts to demodulate psk only // attempts to demodulate psk only
@ -1645,7 +1681,7 @@ int CmdPSK1rawDemod(const char *Cmd)
PrintAndLog(" : data psk1rawdemod 64 1 0 = demod a psk1 tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); PrintAndLog(" : data psk1rawdemod 64 1 0 = demod a psk1 tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
return 0; return 0;
} }
errCnt = PSKDemod(Cmd, 1); errCnt = PSKDemod(Cmd, TRUE);
//output //output
if (errCnt<0){ if (errCnt<0){
if (g_debugMode) PrintAndLog("Error demoding: %d",errCnt); if (g_debugMode) PrintAndLog("Error demoding: %d",errCnt);
@ -1653,7 +1689,6 @@ int CmdPSK1rawDemod(const char *Cmd)
} }
if (errCnt>0){ if (errCnt>0){
PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt);
}else{
} }
PrintAndLog("PSK demoded bitstream:"); PrintAndLog("PSK demoded bitstream:");
// Now output the bitstream to the scrollback by line of 16 bits // Now output the bitstream to the scrollback by line of 16 bits

View file

@ -16,7 +16,7 @@ command_t * CmdDataCommands();
int CmdData(const char *Cmd); int CmdData(const char *Cmd);
void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx); void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx);
void printDemodBuff(); void printDemodBuff();
void printBitStream(uint8_t BitStream[], uint32_t bitLen);
int CmdAmp(const char *Cmd); int CmdAmp(const char *Cmd);
int Cmdaskdemod(const char *Cmd); int Cmdaskdemod(const char *Cmd);
int CmdAskEM410xDemod(const char *Cmd); int CmdAskEM410xDemod(const char *Cmd);
@ -60,6 +60,11 @@ int CmdThreshold(const char *Cmd);
int CmdDirectionalThreshold(const char *Cmd); int CmdDirectionalThreshold(const char *Cmd);
int CmdZerocrossings(const char *Cmd); int CmdZerocrossings(const char *Cmd);
int CmdIndalaDecode(const char *Cmd); int CmdIndalaDecode(const char *Cmd);
int ASKmanDemod(const char *Cmd, bool verbose, bool emSearch);
int ASKrawDemod(const char *Cmd, bool verbose);
int FSKrawDemod(const char *Cmd, bool verbose);
int PSKDemod(const char *Cmd, bool verbose);
int NRZrawDemod(const char *Cmd, bool verbose);
#define MAX_DEMOD_BUF_LEN (1024*128) #define MAX_DEMOD_BUF_LEN (1024*128)
extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];

View file

@ -288,35 +288,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
uint8_t *parityBytes = trace + tracepos; uint8_t *parityBytes = trace + tracepos;
tracepos += parity_len; tracepos += parity_len;
//Check the CRC status
//--- Draw the data column
//char line[16][110];
char line[16][110];
for (int j = 0; j < data_len && j/16 < 16; j++) {
int oddparity = 0x01;
int k;
for (k=0 ; k<8 ; k++) {
oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
}
uint8_t parityBits = parityBytes[j>>3];
if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]);
} else {
snprintf(line[j/16]+(( j % 16) * 4),110, "%02x ", frame[j]);
}
}
if(data_len == 0)
{
if(data_len == 0){
sprintf(line[0],"<empty trace - possible error>");
}
}
//--- Draw the CRC column
uint8_t crcStatus = 2; uint8_t crcStatus = 2;
if (data_len > 2) { if (data_len > 2) {
@ -344,6 +316,43 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
//0 CRC-command, CRC not ok //0 CRC-command, CRC not ok
//1 CRC-command, CRC ok //1 CRC-command, CRC ok
//2 Not crc-command //2 Not crc-command
//--- Draw the data column
//char line[16][110];
char line[16][110];
for (int j = 0; j < data_len && j/16 < 16; j++) {
int oddparity = 0x01;
int k;
for (k=0 ; k<8 ; k++) {
oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
}
uint8_t parityBits = parityBytes[j>>3];
if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]);
} else {
snprintf(line[j/16]+(( j % 16) * 4),110, "%02x ", frame[j]);
}
}
if(crcStatus == 1)
{//CRC-command
char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4)-1;
(*pos1) = '[';
char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4)-2;
(*pos2) = ']';
}
if(data_len == 0)
{
if(data_len == 0){
sprintf(line[0],"<empty trace - possible error>");
}
}
//--- Draw the CRC column
char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " "));
EndOfTransmissionTimestamp = timestamp + duration; EndOfTransmissionTimestamp = timestamp + duration;

View file

@ -668,9 +668,9 @@ int CmdHF15CmdRaw (const char *cmd) {
*/ */
int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) { int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) {
int temp; int temp;
uint8_t *req=c->d.asBytes; uint8_t *req = c->d.asBytes;
uint8_t uid[8] = {0x00}; uint8_t uid[8] = {0x00};
uint32_t reqlen=0; uint32_t reqlen = 0;
// strip // strip
while (**cmd==' ' || **cmd=='\t') (*cmd)++; while (**cmd==' ' || **cmd=='\t') (*cmd)++;
@ -763,10 +763,10 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
UsbCommand resp; UsbCommand resp;
uint8_t *recv; uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
uint8_t *req=c.d.asBytes; uint8_t *req = c.d.asBytes;
int reqlen=0; int reqlen = 0;
char cmdbuf[100]; char cmdbuf[100];
char *cmd=cmdbuf; char *cmd = cmdbuf;
char output[2048]=""; char output[2048]="";
int i; int i;
@ -782,13 +782,11 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
PrintAndLog(" s selected tag"); PrintAndLog(" s selected tag");
PrintAndLog(" u unaddressed mode"); PrintAndLog(" u unaddressed mode");
PrintAndLog(" * scan for tag"); PrintAndLog(" * scan for tag");
PrintAndLog(" start#: page number to start 0-255");
PrintAndLog(" count#: number of pages");
return 0; return 0;
} }
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1); prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1);
reqlen=c.arg[0]; reqlen = c.arg[0];
reqlen=AddCrc(req,reqlen); reqlen=AddCrc(req,reqlen);
c.arg[0]=reqlen; c.arg[0]=reqlen;

View file

@ -1023,6 +1023,7 @@ int CmdHF14AMf1kSim(const char *Cmd)
PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)");
PrintAndLog(""); PrintAndLog("");
PrintAndLog(" sample: hf mf sim u 0a0a0a0a "); PrintAndLog(" sample: hf mf sim u 0a0a0a0a ");
PrintAndLog(" : hf mf sim u 0a0a0a0a i x");
return 0; return 0;
} }
uint8_t pnr = 0; uint8_t pnr = 0;

View file

@ -158,20 +158,6 @@ local _keys = {
'eff603e1efe9', 'eff603e1efe9',
'644672bd4afe', '644672bd4afe',
'b5ff67cba951',
}
--[[
Kiev metro cards
--]]
'8fe644038790',
'f14ee7cae863',
'632193be1c3c',
'569369c5a0e5',
'9de89e070277',
'eff603e1efe9',
'644672bd4afe',
'b5ff67cba951', 'b5ff67cba951',
} }

View file

@ -135,7 +135,7 @@ local Utils =
while IN>0 do while IN>0 do
I=I+1 I=I+1
IN , D = math.floor(IN/B), math.modf(IN,B)+1 IN , D = math.floor(IN/B), math.modf(IN,B)+1
OUT=string.sub(K,D,D)..OUT OUT = string.sub(K,D,D)..OUT
end end
return OUT return OUT
end, end,
@ -191,6 +191,30 @@ local Utils =
return table.concat(t) return table.concat(t)
end, end,
Chars2num = function(s)
return (s:byte(1)*16777216)+(s:byte(2)*65536)+(s:byte(3)*256)+(s:byte(4))
end,
-- use length of string to determine 8,16,32,64 bits
bytes_to_int = function(str,endian,signed)
local t={str:byte(1,-1)}
if endian=="big" then --reverse bytes
local tt={}
for k=1,#t do
tt[#t-k+1]=t[k]
end
t=tt
end
local n=0
for k=1,#t do
n=n+t[k]*2^((k-1)*8)
end
if signed then
n = (n > 2^(#t*8-1) -1) and (n - 2^(#t*8)) or n -- if last bit set, negative.
end
return n
end,
-- function convertStringToBytes(str) -- function convertStringToBytes(str)
-- local bytes = {} -- local bytes = {}
-- local strLength = string.len(str) -- local strLength = string.len(str)

View file

@ -46,7 +46,7 @@ typedef struct bucket_info {
} bucket_info[2][0x100]; } bucket_info[2][0x100];
uint32_t numbuckets; uint32_t numbuckets;
} bucket_info_t; } bucket_info_t;
static void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop, static void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
uint32_t* const ostart, uint32_t* const ostop, uint32_t* const ostart, uint32_t* const ostop,
@ -55,28 +55,28 @@ static void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
uint32_t *p1, *p2; uint32_t *p1, *p2;
uint32_t *start[2]; uint32_t *start[2];
uint32_t *stop[2]; uint32_t *stop[2];
start[0] = estart; start[0] = estart;
stop[0] = estop; stop[0] = estop;
start[1] = ostart; start[1] = ostart;
stop[1] = ostop; stop[1] = ostop;
// init buckets to be empty // init buckets to be empty
for (uint32_t i = 0; i < 2; i++) { for (uint32_t i = 0; i < 2; i++) {
for (uint32_t j = 0x00; j <= 0xff; j++) { for (uint32_t j = 0x00; j <= 0xff; j++) {
bucket[i][j].bp = bucket[i][j].head; bucket[i][j].bp = bucket[i][j].head;
} }
} }
// sort the lists into the buckets based on the MSB (contribution bits) // sort the lists into the buckets based on the MSB (contribution bits)
for (uint32_t i = 0; i < 2; i++) { for (uint32_t i = 0; i < 2; i++) {
for (p1 = start[i]; p1 <= stop[i]; p1++) { for (p1 = start[i]; p1 <= stop[i]; p1++) {
uint32_t bucket_index = (*p1 & 0xff000000) >> 24; uint32_t bucket_index = (*p1 & 0xff000000) >> 24;
*(bucket[i][bucket_index].bp++) = *p1; *(bucket[i][bucket_index].bp++) = *p1;
} }
} }
// write back intersecting buckets as sorted list. // write back intersecting buckets as sorted list.
// fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets. // fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets.
uint32_t nonempty_bucket; uint32_t nonempty_bucket;
@ -147,9 +147,9 @@ extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in
*p ^= in; *p ^= in;
} else { // drop } else { // drop
*p-- = *(*end)--; *p-- = *(*end)--;
}
} }
}
} }
@ -159,7 +159,7 @@ extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in
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)) { // replace if(filter(*tbl) ^ filter(*tbl | 1)) { // replace
*tbl |= filter(*tbl) ^ bit; *tbl |= filter(*tbl) ^ bit;
} else if(filter(*tbl) == bit) { // insert } else if(filter(*tbl) == bit) { // insert
@ -206,13 +206,13 @@ recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
} }
bucket_sort_intersect(e_head, e_tail, o_head, o_tail, &bucket_info, bucket); bucket_sort_intersect(e_head, e_tail, o_head, o_tail, &bucket_info, bucket);
for (int i = bucket_info.numbuckets - 1; i >= 0; i--) { for (int i = bucket_info.numbuckets - 1; i >= 0; i--) {
sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks, sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks,
bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks, bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks,
rem, sl, in, bucket); rem, sl, in, bucket);
} }
return sl; return sl;
} }
/** lfsr_recovery /** lfsr_recovery
@ -251,7 +251,7 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in)
} }
} }
// initialize statelists: add all possible states which would result into the rightmost 2 bits of the keystream // initialize statelists: add all possible states which would result into the rightmost 2 bits of the keystream
for(i = 1 << 20; i >= 0; --i) { for(i = 1 << 20; i >= 0; --i) {
if(filter(i) == (oks & 1)) if(filter(i) == (oks & 1))
@ -282,7 +282,7 @@ out:
for (uint32_t i = 0; i < 2; i++) for (uint32_t i = 0; i < 2; i++)
for (uint32_t j = 0; j <= 0xff; j++) for (uint32_t j = 0; j <= 0xff; j++)
free(bucket[i][j].head); free(bucket[i][j].head);
return statelist; return statelist;
} }
@ -382,9 +382,12 @@ struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3)
void lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) void lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
{ {
int out; int out;
uint32_t tmp;
s->odd &= 0xffffff; s->odd &= 0xffffff;
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); tmp = s->odd;
s->odd = s->even;
s->even = tmp;
out = s->even & 1; out = s->even & 1;
out ^= LF_POLY_EVEN & (s->even >>= 1); out ^= LF_POLY_EVEN & (s->even >>= 1);
@ -489,20 +492,20 @@ brute_top(uint32_t prefix, uint32_t rresp, unsigned char parities[8][8],
for(c = 0; c < 8; ++c) { for(c = 0; c < 8; ++c) {
s.odd = odd ^ fastfwd[1][c]; s.odd = odd ^ fastfwd[1][c];
s.even = even ^ fastfwd[0][c]; s.even = even ^ fastfwd[0][c];
lfsr_rollback_bit(&s, 0, 0); lfsr_rollback_bit(&s, 0, 0);
lfsr_rollback_bit(&s, 0, 0); lfsr_rollback_bit(&s, 0, 0);
lfsr_rollback_bit(&s, 0, 0); lfsr_rollback_bit(&s, 0, 0);
lfsr_rollback_word(&s, 0, 0); lfsr_rollback_word(&s, 0, 0);
lfsr_rollback_word(&s, prefix | c << 5, 1); lfsr_rollback_word(&s, prefix | c << 5, 1);
sl->odd = s.odd; sl->odd = s.odd;
sl->even = s.even; sl->even = s.even;
if (no_chk) if (no_chk)
break; break;
ks1 = crypto1_word(&s, prefix | c << 5, 1); ks1 = crypto1_word(&s, prefix | c << 5, 1);
ks2 = crypto1_word(&s,0,0); ks2 = crypto1_word(&s,0,0);
ks3 = crypto1_word(&s, 0,0); ks3 = crypto1_word(&s, 0,0);
@ -521,7 +524,7 @@ brute_top(uint32_t prefix, uint32_t rresp, unsigned char parities[8][8],
} }
return ++sl; return ++sl;
} }
/** lfsr_common_prefix /** lfsr_common_prefix
@ -542,13 +545,13 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8],
odd = lfsr_prefix_ks(ks, 1); odd = lfsr_prefix_ks(ks, 1);
even = lfsr_prefix_ks(ks, 0); even = lfsr_prefix_ks(ks, 0);
statelist = malloc((sizeof *statelist) << 21); //how large should be? statelist = malloc((sizeof *statelist) << 21); //how large should be?
if(!statelist || !odd || !even) if(!statelist || !odd || !even)
{ {
free(statelist); free(statelist);
free(odd); free(odd);
free(even); free(even);
return 0; return 0;
} }
s = statelist; s = statelist;
@ -560,7 +563,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8],
s = brute_top(pfx, rr, par, *o, *e, s, no_par); s = brute_top(pfx, rr, par, *o, *e, s, no_par);
} }
s->odd = s->even = -1; s->odd = s->even = -1;
//printf("state count = %d\n",s-statelist); //printf("state count = %d\n",s-statelist);
free(odd); free(odd);

View file

@ -1,21 +1,21 @@
/* crypto1.c /* crypto1.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, Boston, Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, US 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>
@ -49,6 +49,7 @@ void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
{ {
uint32_t feedin; uint32_t feedin;
uint32_t tmp;
uint8_t ret = filter(s->odd); uint8_t ret = filter(s->odd);
feedin = ret & !!is_encrypted; feedin = ret & !!is_encrypted;
@ -57,7 +58,9 @@ uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
feedin ^= LF_POLY_EVEN & s->even; feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | parity(feedin); s->even = s->even << 1 | parity(feedin);
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); tmp = s->odd;
s->odd = s->even;
s->even = tmp;
return ret; return ret;
} }

Binary file not shown.

View file

@ -35,10 +35,12 @@ wire tag_modulation = ssp_dout & !lf_field;
wire reader_modulation = !ssp_dout & lf_field & pck_divclk; wire reader_modulation = !ssp_dout & lf_field & pck_divclk;
// No logic, straight through. // No logic, straight through.
assign pwr_oe1 = 1'b0; // not used in LF mode assign pwr_oe1 = 1'b0; // not used in LF mode
assign pwr_oe3 = 1'b0; // base antenna load = 33 Ohms
// when modulating, add another 33 Ohms and 10k Ohms in parallel:
assign pwr_oe2 = tag_modulation; assign pwr_oe2 = tag_modulation;
assign pwr_oe3 = tag_modulation; assign pwr_oe4 = tag_modulation;
assign pwr_oe4 = tag_modulation;
assign ssp_clk = cross_lo; assign ssp_clk = cross_lo;
assign pwr_lo = reader_modulation; assign pwr_lo = reader_modulation;
assign pwr_hi = 1'b0; assign pwr_hi = 1'b0;