From: Martin Holst Swende Date: Thu, 19 Feb 2015 09:51:10 +0000 (+0100) Subject: Merge pull request #68 from iceman1001/feature X-Git-Tag: v2.0.0-rc1~5^2 X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/0387cd3393d87edf07cdd37dc942b6e561ce499a?hp=0853ffa29c28b82cebdeaccdad273df6bd453c76 Merge pull request #68 from iceman1001/feature ADD: identifications. --- diff --git a/armsrc/Makefile b/armsrc/Makefile index fb693006..be08e56b 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 APP_CFLAGS += -I. diff --git a/armsrc/cipher.c b/armsrc/cipher.c new file mode 100644 index 00000000..7c9cc873 --- /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 00000000..bdea9432 --- /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 00000000..c00e2be2 --- /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 00000000..ee4939e3 --- /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 2a0ba0d2..a976217d 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -47,7 +47,8 @@ // different initial value (CRC_ICLASS) #include "iso14443crc.h" #include "iso15693tools.h" - +#include "cipher.h" +#include "protocols.h" static int timeout = 4096; @@ -965,8 +966,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 @@ -988,15 +992,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) { @@ -1011,8 +1020,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 @@ -1020,6 +1029,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). @@ -1029,29 +1041,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 @@ -1065,28 +1088,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); @@ -1097,20 +1118,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); @@ -1147,57 +1170,90 @@ 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 - // We do not know what to answer, so lets keep quiet - modulated_response = resp1; modulated_response_size = 0; //order = 5; - trace_data = NULL; - trace_data_size = 0; - if (breakAfterMacReceived){ - // 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]); - Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len, - receivedCmd[0], receivedCmd[1], receivedCmd[2], - receivedCmd[3], receivedCmd[4], receivedCmd[5], - receivedCmd[6], receivedCmd[7], receivedCmd[8]); - if (reader_mac_buf != NULL) - { - memcpy(reader_mac_buf,receivedCmd+1,8); + 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 = resp_sof; modulated_response_size = 0; + trace_data = NULL; + trace_data_size = 0; + 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]); + Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len, + receivedCmd[0], receivedCmd[1], receivedCmd[2], + receivedCmd[3], receivedCmd[4], receivedCmd[5], + receivedCmd[6], receivedCmd[7], receivedCmd[8]); + if (reader_mac_buf != NULL) + { + memcpy(reader_mac_buf,receivedCmd+1,8); + } + exitLoop = true; } - 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", @@ -1206,7 +1262,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; } @@ -1603,6 +1659,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 138814b7..7af065ea 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 e63581ba..20e17d7d 100644 --- a/client/Makefile +++ b/client/Makefile @@ -94,6 +94,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 4d79eeae..7b666c26 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -333,11 +333,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; } @@ -514,13 +514,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}; @@ -830,13 +830,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 @@ -1937,6 +1937,7 @@ int CmdTuneSamples(const char *Cmd) PrintAndLog("\n"); GraphTraceLen = 256; ShowGraphWindow(); + RepaintGraphWindow(); } return 0; @@ -2379,24 +2380,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"}, @@ -2406,18 +2407,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 7f1246cc..d279c9e6 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 6c92893a..31f7ba97 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