diff --git a/armsrc/Makefile b/armsrc/Makefile
index c00706522..be4351d83 100644
--- a/armsrc/Makefile
+++ b/armsrc/Makefile
@@ -10,12 +10,12 @@ APP_INCLUDES = apps.h
#remove one of the following defines and comment out the relevant line
#in the next section to remove that particular feature from compilation
-APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -fno-strict-aliasing
+APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -DON_DEVICE -fno-strict-aliasing
#-DWITH_LCD
#SRC_LCD = fonts.c LCD.c
SRC_LF = lfops.c hitag2.c lfsampling.c
-SRC_ISO15693 = iso15693.c iso15693tools.c
+SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
SRC_ISO14443b = iso14443.c
SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c
@@ -43,6 +43,8 @@ ARMSRC = fpgaloader.c \
legic_prng.c \
iclass.c \
BigBuf.c \
+ cipher.c \
+ cipherutils.c\
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
diff --git a/armsrc/cipher.c b/armsrc/cipher.c
new file mode 100644
index 000000000..7c9cc873a
--- /dev/null
+++ b/armsrc/cipher.c
@@ -0,0 +1,272 @@
+/*****************************************************************************
+ * 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 .
+ *
+ *
+ *
+ ****************************************************************************/
+
+
+#include "cipher.h"
+#include "cipherutils.h"
+#include
+#include
+#include
+#include
+#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
diff --git a/armsrc/cipher.h b/armsrc/cipher.h
new file mode 100644
index 000000000..bdea94322
--- /dev/null
+++ b/armsrc/cipher.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ * 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 .
+ *
+ *
+ *
+ ****************************************************************************/
+
+
+#ifndef CIPHER_H
+#define CIPHER_H
+#include
+
+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
diff --git a/armsrc/cipherutils.c b/armsrc/cipherutils.c
new file mode 100644
index 000000000..c00e2be2d
--- /dev/null
+++ b/armsrc/cipherutils.c
@@ -0,0 +1,292 @@
+/*****************************************************************************
+ * 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 .
+ *
+ *
+ *
+ ****************************************************************************/
+
+#include
+#include
+#include
+#include "cipherutils.h"
+#ifndef ON_DEVICE
+#include "fileutils.h"
+#endif
+/**
+ *
+ * @brief Return and remove the first bit (x0) in the stream :
+ * @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:
+ * @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
diff --git a/armsrc/cipherutils.h b/armsrc/cipherutils.h
new file mode 100644
index 000000000..ee4939e3e
--- /dev/null
+++ b/armsrc/cipherutils.h
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ * 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 .
+ *
+ *
+ *
+ ****************************************************************************/
+
+
+#ifndef CIPHERUTILS_H
+#define CIPHERUTILS_H
+#include
+#include
+#include
+
+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
diff --git a/armsrc/iclass.c b/armsrc/iclass.c
index 816cb9041..def6cc978 100644
--- a/armsrc/iclass.c
+++ b/armsrc/iclass.c
@@ -48,7 +48,8 @@
#include "../common/iso14443crc.h"
#include "../common/iso15693tools.h"
//#include "iso15693tools.h"
-
+#include "cipher.h"
+#include "protocols.h"
static int timeout = 4096;
@@ -967,8 +968,11 @@ static void CodeIClassTagSOF()
// Convert from last byte pos to length
ToSendMax++;
}
+#define MODE_SIM_CSN 0
+#define MODE_EXIT_AFTER_MAC 1
+#define MODE_FULLSIM 2
-int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf);
+int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf);
/**
* @brief SimulateIClass simulates an iClass card.
* @param arg0 type of simulation
@@ -990,15 +994,20 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
// Enable and clear the trace
set_tracing(TRUE);
clear_trace();
+ //Use the emulator memory for SIM
+ uint8_t *emulator = BigBuf_get_EM_addr();
- uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
if(simType == 0) {
// Use the CSN from commandline
- memcpy(csn_crc, datain, 8);
- doIClassSimulation(csn_crc,0,NULL);
+ memcpy(emulator, datain, 8);
+ doIClassSimulation(MODE_SIM_CSN,NULL);
}else if(simType == 1)
{
- doIClassSimulation(csn_crc,0,NULL);
+ //Default CSN
+ uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
+ // Use the CSN from commandline
+ memcpy(emulator, csn_crc, 8);
+ doIClassSimulation(MODE_SIM_CSN,NULL);
}
else if(simType == 2)
{
@@ -1013,8 +1022,8 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
{
// The usb data is 512 bytes, fitting 65 8-byte CSNs in there.
- memcpy(csn_crc, datain+(i*8), 8);
- if(doIClassSimulation(csn_crc,1,mac_responses+i*8))
+ memcpy(emulator, datain+(i*8), 8);
+ if(doIClassSimulation(MODE_EXIT_AFTER_MAC,mac_responses+i*8))
{
cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8);
return; // Button pressed
@@ -1022,6 +1031,9 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
}
cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8);
+ }else if(simType == 3){
+ //This is 'full sim' mode, where we use the emulator storage for data.
+ doIClassSimulation(MODE_FULLSIM, NULL);
}
else{
// We may want a mode here where we hardcode the csns to use (from proxclone).
@@ -1031,29 +1043,40 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
Dbprintf("Done...");
}
+
/**
* @brief Does the actual simulation
* @param csn - csn to use
* @param breakAfterMacReceived if true, returns after reader MAC has been received.
*/
-int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf)
+int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
{
+ // free eventually allocated BigBuf memory
+ BigBuf_free_keep_EM();
+ uint8_t *csn = BigBuf_get_EM_addr();
+ uint8_t *emulator = csn;
+ uint8_t sof_data[] = { 0x0F} ;
// CSN followed by two CRC bytes
- uint8_t response1[] = { 0x0F} ;
- uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- uint8_t response3[] = { 0,0,0,0,0,0,0,0,0,0};
- memcpy(response3,csn,sizeof(response3));
+ uint8_t anticoll_data[10] = { 0 };
+ uint8_t csn_data[10] = { 0 };
+ memcpy(csn_data,csn,sizeof(csn_data));
Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
- // e-Purse
- uint8_t response4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Construct anticollision-CSN
- rotateCSN(response3,response2);
+ rotateCSN(csn_data,anticoll_data);
// Compute CRC on both CSNs
- ComputeCrc14443(CRC_ICLASS, response2, 8, &response2[8], &response2[9]);
- ComputeCrc14443(CRC_ICLASS, response3, 8, &response3[8], &response3[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]);
+
+ // e-Purse
+ uint8_t card_challenge_data[8] = { 0x00 };
+ if(simulationMode == MODE_FULLSIM)
+ {
+ //Card challenge, a.k.a e-purse is on block 2
+ memcpy(card_challenge_data,emulator + (8 * 2) , 8);
+ }
int exitLoop = 0;
// Reader 0a
@@ -1067,28 +1090,26 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
int modulated_response_size;
uint8_t* trace_data = NULL;
int trace_data_size = 0;
- //uint8_t sof = 0x0f;
- // free eventually allocated BigBuf memory
- BigBuf_free();
+
// Respond SOF -- takes 1 bytes
- uint8_t *resp1 = BigBuf_malloc(2);
- int resp1Len;
+ uint8_t *resp_sof = BigBuf_malloc(2);
+ int resp_sof_Len;
// Anticollision CSN (rotated CSN)
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
- uint8_t *resp2 = BigBuf_malloc(28);
- int resp2Len;
+ uint8_t *resp_anticoll = BigBuf_malloc(28);
+ int resp_anticoll_len;
// CSN
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
- uint8_t *resp3 = BigBuf_malloc(30);
- int resp3Len;
+ uint8_t *resp_csn = BigBuf_malloc(30);
+ int resp_csn_len;
// e-Purse
// 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit)
- uint8_t *resp4 = BigBuf_malloc(20);
- int resp4Len;
+ uint8_t *resp_cc = BigBuf_malloc(20);
+ int resp_cc_len;
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
memset(receivedCmd, 0x44, MAX_FRAME_SIZE);
@@ -1099,20 +1120,22 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
// First card answer: SOF
CodeIClassTagSOF();
- memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
+ memcpy(resp_sof, ToSend, ToSendMax); resp_sof_Len = ToSendMax;
// Anticollision CSN
- CodeIClassTagAnswer(response2, sizeof(response2));
- memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax;
+ CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data));
+ memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax;
// CSN
- CodeIClassTagAnswer(response3, sizeof(response3));
- memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax;
+ CodeIClassTagAnswer(csn_data, sizeof(csn_data));
+ memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax;
// e-Purse
- CodeIClassTagAnswer(response4, sizeof(response4));
- memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;
+ CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data));
+ memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax;
+ //This is used for responding to READ-block commands
+ uint8_t *data_response = BigBuf_malloc(8 * 2 + 2);
// Start from off (no field generated)
//FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@@ -1149,38 +1172,59 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
LED_C_ON();
// Okay, look at the command now.
- if(receivedCmd[0] == 0x0a ) {
+ if(receivedCmd[0] == ICLASS_CMD_ACTALL ) {
// Reader in anticollission phase
- modulated_response = resp1; modulated_response_size = resp1Len; //order = 1;
- trace_data = response1;
- trace_data_size = sizeof(response1);
- } else if(receivedCmd[0] == 0x0c) {
+ modulated_response = resp_sof; modulated_response_size = resp_sof_Len; //order = 1;
+ trace_data = sof_data;
+ trace_data_size = sizeof(sof_data);
+ } else if(receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) {
// Reader asks for anticollission CSN
- modulated_response = resp2; modulated_response_size = resp2Len; //order = 2;
- trace_data = response2;
- trace_data_size = sizeof(response2);
+ modulated_response = resp_anticoll; modulated_response_size = resp_anticoll_len; //order = 2;
+ trace_data = anticoll_data;
+ trace_data_size = sizeof(anticoll_data);
//DbpString("Reader requests anticollission CSN:");
- } else if(receivedCmd[0] == 0x81) {
+ } else if(receivedCmd[0] == ICLASS_CMD_SELECT) {
// Reader selects anticollission CSN.
// Tag sends the corresponding real CSN
- modulated_response = resp3; modulated_response_size = resp3Len; //order = 3;
- trace_data = response3;
- trace_data_size = sizeof(response3);
+ modulated_response = resp_csn; modulated_response_size = resp_csn_len; //order = 3;
+ trace_data = csn_data;
+ trace_data_size = sizeof(csn_data);
//DbpString("Reader selects anticollission CSN:");
- } else if(receivedCmd[0] == 0x88) {
+ } else if(receivedCmd[0] == ICLASS_CMD_READCHECK_KD) {
// Read e-purse (88 02)
- modulated_response = resp4; modulated_response_size = resp4Len; //order = 4;
- trace_data = response4;
- trace_data_size = sizeof(response4);
+ modulated_response = resp_cc; modulated_response_size = resp_cc_len; //order = 4;
+ trace_data = card_challenge_data;
+ trace_data_size = sizeof(card_challenge_data);
LED_B_ON();
- } else if(receivedCmd[0] == 0x05) {
+ } else if(receivedCmd[0] == ICLASS_CMD_CHECK) {
// Reader random and reader MAC!!!
- // Do not respond
+ if(simulationMode == MODE_FULLSIM)
+ { //This is what we must do..
+ //Reader just sent us NR and MAC(k,cc * nr)
+ //The diversified key should be stored on block 3
+ //However, from a typical dump, the key will not be there
+ uint8_t *diversified_key = { 0 };
+ //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;
+ CodeIClassTagAnswer(trace_data , trace_data_size);
+ memcpy(data_response, ToSend, ToSendMax);
+ modulated_response = data_response;
+ modulated_response_size = ToSendMax;
+ }else
+ { //Not fullsim, we don't respond
// We do not know what to answer, so lets keep quiet
- modulated_response = resp1; modulated_response_size = 0; //order = 5;
+ modulated_response = resp_sof; modulated_response_size = 0;
trace_data = NULL;
trace_data_size = 0;
- if (breakAfterMacReceived){
+ if (simulationMode == MODE_EXIT_AFTER_MAC){
// dbprintf:ing ...
Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x"
,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
@@ -1194,12 +1238,24 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
}
exitLoop = true;
}
- } else if(receivedCmd[0] == 0x00 && len == 1) {
+ }
+
+ } else if(receivedCmd[0] == ICLASS_CMD_HALT && len == 1) {
// Reader ends the session
- modulated_response = resp1; modulated_response_size = 0; //order = 0;
+ modulated_response = resp_sof; modulated_response_size = 0; //order = 0;
trace_data = NULL;
trace_data_size = 0;
- } else {
+ } else if(simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4){
+ //Read block
+ uint16_t blk = receivedCmd[1];
+ trace_data = emulator+(blk << 3);
+ trace_data_size = 8;
+ CodeIClassTagAnswer(trace_data , trace_data_size);
+ memcpy(data_response, ToSend, ToSendMax);
+ modulated_response = data_response;
+ modulated_response_size = ToSendMax;
+ }
+ else {
//#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44
// Never seen this command before
Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x",
@@ -1208,7 +1264,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
receivedCmd[3], receivedCmd[4], receivedCmd[5],
receivedCmd[6], receivedCmd[7], receivedCmd[8]);
// Do not respond
- modulated_response = resp1; modulated_response_size = 0; //order = 0;
+ modulated_response = resp_sof; modulated_response_size = 0; //order = 0;
trace_data = NULL;
trace_data_size = 0;
}
@@ -1605,6 +1661,17 @@ void ReaderIClass(uint8_t arg0) {
if(read_status == 1) datasize = 8;
if(read_status == 2) datasize = 16;
+ //Todo, read the public blocks 1,5 aswell:
+ //
+ // 0 : CSN (we already have)
+ // 1 : Configuration
+ // 2 : e-purse (we already have)
+ // (3,4 write-only)
+ // 5 Application issuer area
+ //
+ //Then we can 'ship' back the 8 * 5 bytes of data,
+ // with 0xFF:s in block 3 and 4.
+
LED_B_ON();
//Send back to client, but don't bother if we already sent this
if(memcmp(last_csn, card_data, 8) != 0)
diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c
index 138814b7e..7af065ea1 100644
--- a/armsrc/lfsampling.c
+++ b/armsrc/lfsampling.c
@@ -12,7 +12,7 @@
#include "string.h"
#include "lfsampling.h"
-
+#include "cipherutils.h"
sample_config config = { 1, 8, 1, 95, 0 } ;
void printConfig()
@@ -55,20 +55,20 @@ sample_config* getSamplingConfig()
{
return &config;
}
-
+/*
typedef struct {
uint8_t * buffer;
uint32_t numbits;
uint32_t position;
} BitstreamOut;
-
+*/
/**
* @brief Pushes bit onto the stream
* @param stream
* @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 bitpos = stream->position & 7;
@@ -76,7 +76,7 @@ void pushBit( BitstreamOut* stream, uint8_t bit)
stream->position++;
stream->numbits++;
}
-
+*/
/**
* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna.
diff --git a/client/Makefile b/client/Makefile
index 48a18c94b..43e686036 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -103,6 +103,7 @@ CMDSRCS = nonce2key/crapto1.c\
cmdscript.c\
pm3_bitlib.c\
aes.c\
+ protocols.c\
COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o)
diff --git a/client/cmddata.c b/client/cmddata.c
index 2c67c29a8..cfccc5b34 100644
--- a/client/cmddata.c
+++ b/client/cmddata.c
@@ -339,11 +339,11 @@ int Cmdaskmandemod(const char *Cmd)
PrintAndLog(" , 1 for invert output");
PrintAndLog(" [set maximum allowed errors], default = 100.");
PrintAndLog("");
- PrintAndLog(" sample: data askmandemod = demod an ask/manchester tag from GraphBuffer");
- PrintAndLog(" : data askmandemod 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32");
- PrintAndLog(" : data askmandemod 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data");
- PrintAndLog(" : data askmandemod 1 = demod an ask/manchester tag from GraphBuffer while inverting data");
- PrintAndLog(" : data askmandemod 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
+ 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;
}
@@ -520,13 +520,13 @@ int Cmdaskrawdemod(const char *Cmd)
PrintAndLog(" [set maximum allowed errors], default = 100");
PrintAndLog(" , 'a' to attempt demod with ask amplification, default = no amp");
PrintAndLog("");
- PrintAndLog(" sample: data askrawdemod = demod an ask tag from GraphBuffer");
- PrintAndLog(" : data askrawdemod a = demod an ask tag from GraphBuffer, amplified");
- PrintAndLog(" : data askrawdemod 32 = demod an ask tag from GraphBuffer using a clock of RF/32");
- PrintAndLog(" : data askrawdemod 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data");
- PrintAndLog(" : data askrawdemod 1 = demod an ask tag from GraphBuffer while inverting data");
- PrintAndLog(" : data askrawdemod 64 1 0 = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
- PrintAndLog(" : data askrawdemod 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(" sample: data rawdemod ar = demod an ask tag from GraphBuffer");
+ PrintAndLog(" : data rawdemod ar a = demod an ask tag from GraphBuffer, amplified");
+ PrintAndLog(" : data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32");
+ PrintAndLog(" : data rawdemod ar 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data");
+ PrintAndLog(" : data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data");
+ PrintAndLog(" : data rawdemod ar 64 1 0 = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
+ 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;
}
uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0};
@@ -836,13 +836,13 @@ int CmdFSKrawdemod(const char *Cmd)
PrintAndLog(" [fchigh], larger field clock length, omit for autodetect");
PrintAndLog(" [fclow], small field clock length, omit for autodetect");
PrintAndLog("");
- PrintAndLog(" sample: data fskrawdemod = demod an fsk tag from GraphBuffer using autodetect");
- PrintAndLog(" : data fskrawdemod 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc");
- PrintAndLog(" : data fskrawdemod 1 = demod an fsk tag from GraphBuffer using autodetect, invert output");
- PrintAndLog(" : data fskrawdemod 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc");
- PrintAndLog(" : data fskrawdemod 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer");
- PrintAndLog(" : data fskrawdemod 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer");
- PrintAndLog(" : data fskrawdemod 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer");
+ 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
@@ -1943,6 +1943,7 @@ int CmdTuneSamples(const char *Cmd)
PrintAndLog("\n");
GraphTraceLen = 256;
ShowGraphWindow();
+ RepaintGraphWindow();
}
return 0;
@@ -2385,24 +2386,24 @@ static command_t CommandTable[] =
{"help", CmdHelp, 1, "This help"},
{"amp", CmdAmp, 1, "Amplify peaks"},
//{"askdemod", Cmdaskdemod, 1, "<0 or 1> -- Attempt to demodulate simple ASK tags"},
- {"askedgedetect", CmdAskEdgeDetect, 1, "[threshold] Adjust Graph for manual ask demod using length of sample differences to detect the edge of a wave - default = 25"},
- {"askem410xdemod",CmdAskEM410xDemod, 1, "[clock] [invert<0|1>] [maxErr] -- Attempt to demodulate ASK/Manchester tags and output binary (args optional)"},
+ {"askedgedetect", CmdAskEdgeDetect, 1, "[threshold] Adjust Graph for manual ask demod using length of sample differences to detect the edge of a wave (default = 25)"},
+ {"askem410xdemod",CmdAskEM410xDemod, 1, "[clock] [invert<0|1>] [maxErr] -- Demodulate an EM410x tag from GraphBuffer (args optional)"},
//{"askmandemod", Cmdaskmandemod, 1, "[clock] [invert<0|1>] [maxErr] -- Attempt to demodulate ASK/Manchester tags and output binary (args optional)"},
//{"askrawdemod", Cmdaskrawdemod, 1, "[clock] [invert<0|1>] -- Attempt to demodulate ASK tags and output bin (args optional)"},
{"autocorr", CmdAutoCorr, 1, " -- Autocorrelation over window"},
- {"biphaserawdecode",CmdBiphaseDecodeRaw,1,"[offset] [invert<0|1>] Biphase decode bin stream in demod buffer (offset = 0|1 bits to shift the decode start)"},
+ {"biphaserawdecode",CmdBiphaseDecodeRaw,1,"[offset] [invert<0|1>] Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"},
{"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"},
//{"bitstream", CmdBitstream, 1, "[clock rate] -- Convert waveform into a bitstream"},
{"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"},
{"dec", CmdDec, 1, "Decimate samples"},
- {"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"},
+ {"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"},
//{"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"},
- {"fskawiddemod", CmdFSKdemodAWID, 1, "Demodulate graph window as an AWID FSK tag using raw"},
+ {"fskawiddemod", CmdFSKdemodAWID, 1, "Demodulate an AWID FSK tag from GraphBuffer"},
//{"fskfcdetect", CmdFSKfcDetect, 1, "Try to detect the Field Clock of an FSK wave"},
- {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate graph window as a HID FSK tag using raw"},
- {"fskiodemod", CmdFSKdemodIO, 1, "Demodulate graph window as an IO Prox tag FSK using raw"},
- {"fskpyramiddemod",CmdFSKdemodPyramid,1, "Demodulate graph window as a Pyramid FSK tag using raw"},
- {"fskparadoxdemod",CmdFSKdemodParadox,1, "Demodulate graph window as a Paradox FSK tag using raw"},
+ {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate a HID FSK tag from GraphBuffer"},
+ {"fskiodemod", CmdFSKdemodIO, 1, "Demodulate an IO Prox FSK tag from GraphBuffer"},
+ {"fskpyramiddemod",CmdFSKdemodPyramid,1, "Demodulate a Pyramid FSK tag from GraphBuffer"},
+ {"fskparadoxdemod",CmdFSKdemodParadox,1, "Demodulate a Paradox FSK tag from GraphBuffer"},
//{"fskrawdemod", CmdFSKrawdemod, 1, "[clock rate] [invert] [rchigh] [rclow] Demodulate graph window from FSK to bin (clock = 50)(invert = 1|0)(rchigh = 10)(rclow=8)"},
{"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"},
{"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"},
@@ -2412,18 +2413,18 @@ static command_t CommandTable[] =
{"ltrim", CmdLtrim, 1, " -- Trim samples from left of trace"},
{"rtrim", CmdRtrim, 1, " -- Trim samples from right of trace"},
//{"mandemod", CmdManchesterDemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
- {"manrawdecode", Cmdmandecoderaw, 1, "Manchester decode binary stream already in graph buffer"},
+ {"manrawdecode", Cmdmandecoderaw, 1, "Manchester decode binary stream in DemodBuffer"},
{"manmod", CmdManchesterMod, 1, "[clock rate] -- Manchester modulate a binary stream"},
{"norm", CmdNorm, 1, "Normalize max/min to +/-128"},
//{"nrzdetectclock",CmdDetectNRZClockRate, 1, "Detect ASK, PSK, or NRZ clock rate"},
//{"nrzrawdemod", CmdNRZrawDemod, 1, "[clock] [invert<0|1>] [maxErr] -- Attempt to demodulate nrz tags and output binary (args optional)"},
{"plot", CmdPlot, 1, "Show graph window (hit 'h' in window for keystroke help)"},
//{"pskdetectclock",CmdDetectPSKClockRate, 1, "Detect ASK, PSK, or NRZ clock rate"},
- {"pskindalademod",CmdIndalaDecode, 1, "[clock] [invert<0|1>] -- Attempt to demodulate psk1 indala tags and output ID binary & hex (args optional)"},
+ {"pskindalademod",CmdIndalaDecode, 1, "[clock] [invert<0|1>] -- Demodulate an indala tag (PSK1) from GraphBuffer (args optional)"},
//{"psk1rawdemod", CmdPSK1rawDemod, 1, "[clock] [invert<0|1>] [maxErr] -- Attempt to demodulate psk1 tags and output binary (args optional)"},
//{"psk2rawdemod", CmdPSK2rawDemod, 1, "[clock] [invert<0|1>] [maxErr] -- Attempt to demodulate psk2 tags and output binary (args optional)"},
- {"rawdemod", CmdRawDemod, 1, "[modulation] ... -see help (h option) - Attempt to demodulate the data in the GraphBuffer and output binary"},
- {"samples", CmdSamples, 0, "[512 - 40000] -- Get raw samples for graph window"},
+ {"rawdemod", CmdRawDemod, 1, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"},
+ {"samples", CmdSamples, 0, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"},
{"save", CmdSave, 1, " -- Save trace (from graph window)"},
{"scale", CmdScale, 1, " -- Set cursor display scale"},
{"setdebugmode", CmdSetDebugMode, 1, "<0|1> -- Turn on or off Debugging Mode for demods"},
diff --git a/client/cmdhf.c b/client/cmdhf.c
index 7f1246cc3..d279c9e64 100644
--- a/client/cmdhf.c
+++ b/client/cmdhf.c
@@ -23,6 +23,7 @@
#include "cmdhficlass.h"
#include "cmdhfmf.h"
#include "cmdhfmfu.h"
+#include "protocols.h"
static int CmdHelp(const char *Cmd);
@@ -33,175 +34,6 @@ int CmdHFTune(const char *Cmd)
return 0;
}
-//The following data is taken from http://www.proxmark.org/forum/viewtopic.php?pid=13501#p13501
-/*
-ISO14443A (usually NFC tags)
- 26 (7bits) = REQA
- 30 = Read (usage: 30+1byte block number+2bytes ISO14443A-CRC - answer: 16bytes)
- A2 = Write (usage: A2+1byte block number+4bytes data+2bytes ISO14443A-CRC - answer: 0A [ACK] or 00 [NAK])
- 52 (7bits) = WUPA (usage: 52(7bits) - answer: 2bytes ATQA)
- 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
- 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK)
- 95 20 = Anticollision of cascade level2
- 95 70 = Select of cascade level2
- 50 00 = Halt (usage: 5000+2bytes ISO14443A-CRC - no answer from card)
-Mifare
- 60 = Authenticate with KeyA
- 61 = Authenticate with KeyB
- 40 (7bits) = Used to put Chinese Changeable UID cards in special mode (must be followed by 43 (8bits) - answer: 0A)
- C0 = Decrement
- C1 = Increment
- C2 = Restore
- B0 = Transfer
-Ultralight C
- A0 = Compatibility Write (to accomodate MIFARE commands)
- 1A = Step1 Authenticate
- AF = Step2 Authenticate
-
-
-ISO14443B
- 05 = REQB
- 1D = ATTRIB
- 50 = HALT
-SRIX4K (tag does not respond to 05)
- 06 00 = INITIATE
- 0E xx = SELECT ID (xx = Chip-ID)
- 0B = Get UID
- 08 yy = Read Block (yy = block number)
- 09 yy dd dd dd dd = Write Block (yy = block number; dd dd dd dd = data to be written)
- 0C = Reset to Inventory
- 0F = Completion
- 0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate)
-
-
-ISO15693
- MANDATORY COMMANDS (all ISO15693 tags must support those)
- 01 = Inventory (usage: 260100+2bytes ISO15693-CRC - answer: 12bytes)
- 02 = Stay Quiet
- OPTIONAL COMMANDS (not all tags support them)
- 20 = Read Block (usage: 0220+1byte block number+2bytes ISO15693-CRC - answer: 4bytes)
- 21 = Write Block (usage: 0221+1byte block number+4bytes data+2bytes ISO15693-CRC - answer: 4bytes)
- 22 = Lock Block
- 23 = Read Multiple Blocks (usage: 0223+1byte 1st block to read+1byte last block to read+2bytes ISO15693-CRC)
- 25 = Select
- 26 = Reset to Ready
- 27 = Write AFI
- 28 = Lock AFI
- 29 = Write DSFID
- 2A = Lock DSFID
- 2B = Get_System_Info (usage: 022B+2bytes ISO15693-CRC - answer: 14 or more bytes)
- 2C = Read Multiple Block Security Status (usage: 022C+1byte 1st block security to read+1byte last block security to read+2bytes ISO15693-CRC)
-
-EM Microelectronic CUSTOM COMMANDS
- A5 = Active EAS (followed by 1byte IC Manufacturer code+1byte EAS type)
- A7 = Write EAS ID (followed by 1byte IC Manufacturer code+2bytes EAS value)
- B8 = Get Protection Status for a specific block (followed by 1byte IC Manufacturer code+1byte block number+1byte of how many blocks after the previous is needed the info)
- E4 = Login (followed by 1byte IC Manufacturer code+4bytes password)
-NXP/Philips CUSTOM COMMANDS
- A0 = Inventory Read
- A1 = Fast Inventory Read
- A2 = Set EAS
- A3 = Reset EAS
- A4 = Lock EAS
- A5 = EAS Alarm
- A6 = Password Protect EAS
- A7 = Write EAS ID
- A8 = Read EPC
- B0 = Inventory Page Read
- B1 = Fast Inventory Page Read
- B2 = Get Random Number
- B3 = Set Password
- B4 = Write Password
- B5 = Lock Password
- B6 = Bit Password Protection
- B7 = Lock Page Protection Condition
- B8 = Get Multiple Block Protection Status
- B9 = Destroy SLI
- BA = Enable Privacy
- BB = 64bit Password Protection
- 40 = Long Range CMD (Standard ISO/TR7003:1990)
- */
-
-#define ICLASS_CMD_ACTALL 0x0A
-#define ICLASS_CMD_READ_OR_IDENTIFY 0x0C
-#define ICLASS_CMD_SELECT 0x81
-#define ICLASS_CMD_PAGESEL 0x84
-#define ICLASS_CMD_READCHECK_KD 0x88
-#define ICLASS_CMD_READCHECK_KC 0x18
-#define ICLASS_CMD_CHECK 0x05
-#define ICLASS_CMD_DETECT 0x0F
-#define ICLASS_CMD_HALT 0x00
-#define ICLASS_CMD_UPDATE 0x87
-#define ICLASS_CMD_ACT 0x8E
-#define ICLASS_CMD_READ4 0x06
-
-
-#define ISO14443A_CMD_REQA 0x26
-#define ISO14443A_CMD_READBLOCK 0x30
-#define ISO14443A_CMD_WUPA 0x52
-#define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93
-#define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95
-#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ?
-#define ISO14443A_CMD_HALT 0x50
-#define ISO14443A_CMD_RATS 0xE0
-
-#define MIFARE_AUTH_KEYA 0x60
-#define MIFARE_AUTH_KEYB 0x61
-#define MIFARE_MAGICMODE 0x40
-#define MIFARE_CMD_INC 0xC0
-#define MIFARE_CMD_DEC 0xC1
-#define MIFARE_CMD_RESTORE 0xC2
-#define MIFARE_CMD_TRANSFER 0xB0
-
-#define MIFARE_ULC_WRITE 0xA0
-#define MIFARE_ULC_AUTH_1 0x1A
-#define MIFARE_ULC_AUTH_2 0xAF
-
-/**
-06 00 = INITIATE
-0E xx = SELECT ID (xx = Chip-ID)
-0B = Get UID
-08 yy = Read Block (yy = block number)
-09 yy dd dd dd dd = Write Block (yy = block number; dd dd dd dd = data to be written)
-0C = Reset to Inventory
-0F = Completion
-0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate)
-**/
-
-#define ISO14443B_REQB 0x05
-#define ISO14443B_ATTRIB 0x1D
-#define ISO14443B_HALT 0x50
-#define ISO14443B_INITIATE 0x06
-#define ISO14443B_SELECT 0x0E
-#define ISO14443B_GET_UID 0x0B
-#define ISO14443B_READ_BLK 0x08
-#define ISO14443B_WRITE_BLK 0x09
-#define ISO14443B_RESET 0x0C
-#define ISO14443B_COMPLETION 0x0F
-#define ISO14443B_AUTHENTICATE 0x0A
-
-//First byte is 26
-#define ISO15693_INVENTORY 0x01
-#define ISO15693_STAYQUIET 0x02
-//First byte is 02
-#define ISO15693_READBLOCK 0x20
-#define ISO15693_WRITEBLOCK 0x21
-#define ISO15693_LOCKBLOCK 0x22
-#define ISO15693_READ_MULTI_BLOCK 0x23
-#define ISO15693_SELECT 0x25
-#define ISO15693_RESET_TO_READY 0x26
-#define ISO15693_WRITE_AFI 0x27
-#define ISO15693_LOCK_AFI 0x28
-#define ISO15693_WRITE_DSFID 0x29
-#define ISO15693_LOCK_DSFID 0x2A
-#define ISO15693_GET_SYSTEM_INFO 0x2B
-#define ISO15693_READ_MULTI_SECSTATUS 0x2C
-
-
-#define ISO_14443A 0
-#define ICLASS 1
-#define ISO_14443B 2
-
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c
index 6c92893ae..31f7ba973 100644
--- a/client/cmdhficlass.c
+++ b/client/cmdhficlass.c
@@ -29,6 +29,7 @@
#include "loclass/ikeys.h"
#include "loclass/elite_crack.h"
#include "loclass/fileutils.h"
+#include "protocols.h"
static int CmdHelp(const char *Cmd);
@@ -53,6 +54,21 @@ int CmdHFiClassSnoop(const char *Cmd)
SendCommand(&c);
return 0;
}
+int usage_hf_iclass_sim()
+{
+ PrintAndLog("Usage: hf iclass sim