mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-12-28 19:31:19 +08:00
Further implementation of iclass 'fullsim'. Moved protocol definitions to shared file. Had to add some loclass-function to arm-side to support authentication in fullsim mode
This commit is contained in:
parent
9a9bcea82b
commit
b67f7ec359
17 changed files with 1157 additions and 268 deletions
|
@ -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.
|
||||
|
|
272
armsrc/cipher.c
Normal file
272
armsrc/cipher.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "cipher.h"
|
||||
#include "cipherutils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#ifndef ON_DEVICE
|
||||
#include "fileutils.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
|
||||
* consisting of the following four components:
|
||||
* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
|
||||
* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
|
||||
* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
|
||||
* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
|
||||
**/
|
||||
typedef struct {
|
||||
uint8_t l;
|
||||
uint8_t r;
|
||||
uint8_t b;
|
||||
uint16_t t;
|
||||
} State;
|
||||
|
||||
/**
|
||||
* Definition 2. The feedback function for the top register T : F 16/2 → F 2
|
||||
* is defined as
|
||||
* T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 .
|
||||
**/
|
||||
bool T(State state)
|
||||
{
|
||||
bool x0 = state.t & 0x8000;
|
||||
bool x1 = state.t & 0x4000;
|
||||
bool x5 = state.t & 0x0400;
|
||||
bool x7 = state.t & 0x0100;
|
||||
bool x10 = state.t & 0x0020;
|
||||
bool x11 = state.t & 0x0010;
|
||||
bool x14 = state.t & 0x0002;
|
||||
bool x15 = state.t & 0x0001;
|
||||
return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
|
||||
}
|
||||
/**
|
||||
* Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as
|
||||
* B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 .
|
||||
**/
|
||||
bool B(State state)
|
||||
{
|
||||
bool x1 = state.b & 0x40;
|
||||
bool x2 = state.b & 0x20;
|
||||
bool x3 = state.b & 0x10;
|
||||
bool x7 = state.b & 0x01;
|
||||
|
||||
return x1 ^ x2 ^ x3 ^ x7;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
|
||||
* F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
|
||||
* z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 ∨ r 4 )
|
||||
* z 1 = (r 0 ∨ r 2 ) ⊕ (r 5 ∨ r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y
|
||||
* z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x
|
||||
**/
|
||||
uint8_t _select(bool x, bool y, uint8_t r)
|
||||
{
|
||||
bool r0 = r >> 7 & 0x1;
|
||||
bool r1 = r >> 6 & 0x1;
|
||||
bool r2 = r >> 5 & 0x1;
|
||||
bool r3 = r >> 4 & 0x1;
|
||||
bool r4 = r >> 3 & 0x1;
|
||||
bool r5 = r >> 2 & 0x1;
|
||||
bool r6 = r >> 1 & 0x1;
|
||||
bool r7 = r & 0x1;
|
||||
|
||||
bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4);
|
||||
bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
|
||||
bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x;
|
||||
|
||||
// The three bitz z0.. z1 are packed into a uint8_t:
|
||||
// 00000ZZZ
|
||||
//Return value is a uint8_t
|
||||
uint8_t retval = 0;
|
||||
retval |= (z0 << 2) & 4;
|
||||
retval |= (z1 << 1) & 2;
|
||||
retval |= z2 & 1;
|
||||
|
||||
// Return value 0 <= retval <= 7
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8
|
||||
* be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s ′ =
|
||||
* l ′ , r ′ , t ′ , b ′ is defined as
|
||||
* t ′ := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l ⊞ r
|
||||
* b ′ := (B(b) ⊕ r 7 )b 0 . . . b 6 r ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l
|
||||
*
|
||||
* @param s - state
|
||||
* @param k - array containing 8 bytes
|
||||
**/
|
||||
State successor(uint8_t* k, State s, bool y)
|
||||
{
|
||||
bool r0 = s.r >> 7 & 0x1;
|
||||
bool r4 = s.r >> 3 & 0x1;
|
||||
bool r7 = s.r & 0x1;
|
||||
|
||||
State successor = {0,0,0,0};
|
||||
|
||||
successor.t = s.t >> 1;
|
||||
successor.t |= (T(s) ^ r0 ^ r4) << 15;
|
||||
|
||||
successor.b = s.b >> 1;
|
||||
successor.b |= (B(s) ^ r7) << 7;
|
||||
|
||||
bool Tt = T(s);
|
||||
|
||||
successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
|
||||
successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
|
||||
|
||||
return successor;
|
||||
}
|
||||
/**
|
||||
* We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and
|
||||
* an input y ∈ F 2 and outputs the successor state s ′ . We overload the function suc
|
||||
* to multiple bit input x ∈ F n 2 which we define as
|
||||
* @param k - array containing 8 bytes
|
||||
**/
|
||||
State suc(uint8_t* k,State s, BitstreamIn *bitstream)
|
||||
{
|
||||
if(bitsLeft(bitstream) == 0)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
bool lastbit = tailBit(bitstream);
|
||||
return successor(k,suc(k,s,bitstream), lastbit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition 5 (Output). Define the function output which takes an internal
|
||||
* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
|
||||
* on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as
|
||||
* output(k, s, ǫ) = ǫ
|
||||
* output(k, s, x 0 . . . x n ) = output(s) · output(k, s ′ , x 1 . . . x n )
|
||||
* where s ′ = suc(k, s, x 0 ).
|
||||
**/
|
||||
void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out)
|
||||
{
|
||||
if(bitsLeft(in) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pushBit(out,(s.r >> 2) & 1);
|
||||
//Remove first bit
|
||||
uint8_t x0 = headBit(in);
|
||||
State ss = successor(k,s,x0);
|
||||
output(k,ss,in, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition 6 (Initial state). Define the function init which takes as input a
|
||||
* key k ∈ (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b >
|
||||
**/
|
||||
|
||||
State init(uint8_t* k)
|
||||
{
|
||||
State s = {
|
||||
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
|
||||
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
|
||||
0x4c, // b
|
||||
0xE012 // t
|
||||
};
|
||||
return s;
|
||||
}
|
||||
void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
|
||||
{
|
||||
uint8_t zeroes_32[] = {0,0,0,0};
|
||||
BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
|
||||
State initState = suc(k,init(k),&input);
|
||||
output(k,initState,&input_32_zeroes,&out);
|
||||
}
|
||||
|
||||
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
|
||||
{
|
||||
uint8_t cc_nr[13] = { 0 };
|
||||
uint8_t div_key[8];
|
||||
//cc_nr=(uint8_t*)malloc(length+1);
|
||||
|
||||
memcpy(cc_nr,cc_nr_p,12);
|
||||
memcpy(div_key,div_key_p,8);
|
||||
|
||||
reverse_arraybytes(cc_nr,12);
|
||||
BitstreamIn bitstream = {cc_nr,12 * 8,0};
|
||||
uint8_t dest []= {0,0,0,0,0,0,0,0};
|
||||
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
|
||||
MAC(div_key,bitstream, out);
|
||||
//The output MAC must also be reversed
|
||||
reverse_arraybytes(dest, sizeof(dest));
|
||||
memcpy(mac, dest, 4);
|
||||
//free(cc_nr);
|
||||
return;
|
||||
}
|
||||
#ifndef ON_DEVICE
|
||||
int testMAC()
|
||||
{
|
||||
prnlog("[+] Testing MAC calculation...");
|
||||
|
||||
//From the "dismantling.IClass" paper:
|
||||
uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
|
||||
//From the paper
|
||||
uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
|
||||
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
|
||||
|
||||
uint8_t calculated_mac[4] = {0};
|
||||
doMAC(cc_nr,div_key, calculated_mac);
|
||||
|
||||
if(memcmp(calculated_mac, correct_MAC,4) == 0)
|
||||
{
|
||||
prnlog("[+] MAC calculation OK!");
|
||||
|
||||
}else
|
||||
{
|
||||
prnlog("[+] FAILED: MAC calculation failed:");
|
||||
printarr(" Calculated_MAC", calculated_mac, 4);
|
||||
printarr(" Correct_MAC ", correct_MAC, 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
49
armsrc/cipher.h
Normal file
49
armsrc/cipher.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
#include <stdint.h>
|
||||
|
||||
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
|
||||
#ifndef ON_DEVICE
|
||||
int testMAC();
|
||||
#endif
|
||||
|
||||
#endif // CIPHER_H
|
290
armsrc/cipherutils.c
Normal file
290
armsrc/cipherutils.c
Normal file
|
@ -0,0 +1,290 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "fileutils.h"
|
||||
#include "cipherutils.h"
|
||||
/**
|
||||
*
|
||||
* @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
bool headBit( BitstreamIn *stream)
|
||||
{
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = (stream->position++) & 7; // mask out 00000111
|
||||
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
|
||||
}
|
||||
/**
|
||||
* @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
bool tailBit( BitstreamIn *stream)
|
||||
{
|
||||
int bitpos = stream->numbits -1 - (stream->position++);
|
||||
|
||||
int bytepos= bitpos >> 3;
|
||||
bitpos &= 7;
|
||||
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
|
||||
}
|
||||
/**
|
||||
* @brief Pushes bit onto the stream
|
||||
* @param stream
|
||||
* @param bit
|
||||
*/
|
||||
void pushBit( BitstreamOut* stream, bool bit)
|
||||
{
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = stream->position & 7;
|
||||
*(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos);
|
||||
stream->position++;
|
||||
stream->numbits++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pushes the lower six bits onto the stream
|
||||
* as b0 b1 b2 b3 b4 b5 b6
|
||||
* @param stream
|
||||
* @param bits
|
||||
*/
|
||||
void push6bits( BitstreamOut* stream, uint8_t bits)
|
||||
{
|
||||
pushBit(stream, bits & 0x20);
|
||||
pushBit(stream, bits & 0x10);
|
||||
pushBit(stream, bits & 0x08);
|
||||
pushBit(stream, bits & 0x04);
|
||||
pushBit(stream, bits & 0x02);
|
||||
pushBit(stream, bits & 0x01);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief bitsLeft
|
||||
* @param stream
|
||||
* @return number of bits left in stream
|
||||
*/
|
||||
int bitsLeft( BitstreamIn *stream)
|
||||
{
|
||||
return stream->numbits - stream->position;
|
||||
}
|
||||
/**
|
||||
* @brief numBits
|
||||
* @param stream
|
||||
* @return Number of bits stored in stream
|
||||
*/
|
||||
int numBits(BitstreamOut *stream)
|
||||
{
|
||||
return stream->numbits;
|
||||
}
|
||||
|
||||
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
|
||||
{
|
||||
while (len--) {
|
||||
dest[len] = (uint8_t) n;
|
||||
n >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t x_bytes_to_num(uint8_t* src, size_t len)
|
||||
{
|
||||
uint64_t num = 0;
|
||||
while (len--)
|
||||
{
|
||||
num = (num << 8) | (*src);
|
||||
src++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
uint8_t reversebytes(uint8_t b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
return b;
|
||||
}
|
||||
void reverse_arraybytes(uint8_t* arr, size_t len)
|
||||
{
|
||||
uint8_t i;
|
||||
for( i =0; i< len ; i++)
|
||||
{
|
||||
arr[i] = reversebytes(arr[i]);
|
||||
}
|
||||
}
|
||||
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len)
|
||||
{
|
||||
uint8_t i;
|
||||
for( i =0; i< len ; i++)
|
||||
{
|
||||
dest[i] = reversebytes(arr[i]);
|
||||
}
|
||||
}
|
||||
#ifndef ON_DEVICE
|
||||
void printarr(char * name, uint8_t* arr, int len)
|
||||
{
|
||||
int cx;
|
||||
size_t outsize = 40+strlen(name)+len*5;
|
||||
char* output = malloc(outsize);
|
||||
memset(output, 0,outsize);
|
||||
|
||||
int i ;
|
||||
cx = snprintf(output,outsize, "uint8_t %s[] = {", name);
|
||||
for(i =0 ; i< len ; i++)
|
||||
{
|
||||
cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte
|
||||
}
|
||||
cx += snprintf(output+cx,outsize-cx,"};");
|
||||
prnlog(output);
|
||||
}
|
||||
|
||||
void printvar(char * name, uint8_t* arr, int len)
|
||||
{
|
||||
int cx;
|
||||
size_t outsize = 40+strlen(name)+len*2;
|
||||
char* output = malloc(outsize);
|
||||
memset(output, 0,outsize);
|
||||
|
||||
int i ;
|
||||
cx = snprintf(output,outsize,"%s = ", name);
|
||||
for(i =0 ; i< len ; i++)
|
||||
{
|
||||
cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte
|
||||
}
|
||||
|
||||
prnlog(output);
|
||||
}
|
||||
|
||||
void printarr_human_readable(char * title, uint8_t* arr, int len)
|
||||
{
|
||||
int cx;
|
||||
size_t outsize = 100+strlen(title)+len*4;
|
||||
char* output = malloc(outsize);
|
||||
memset(output, 0,outsize);
|
||||
|
||||
|
||||
int i;
|
||||
cx = snprintf(output,outsize, "\n\t%s\n", title);
|
||||
for(i =0 ; i< len ; i++)
|
||||
{
|
||||
if(i % 16 == 0)
|
||||
cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i );
|
||||
cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i));
|
||||
}
|
||||
prnlog(output);
|
||||
free(output);
|
||||
}
|
||||
#endif
|
||||
//-----------------------------
|
||||
// Code for testing below
|
||||
//-----------------------------
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
int testBitStream()
|
||||
{
|
||||
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
|
||||
uint8_t output [] = {0,0,0,0,0,0,0,0};
|
||||
BitstreamIn in = { input, sizeof(input) * 8,0};
|
||||
BitstreamOut out ={ output, 0,0}
|
||||
;
|
||||
while(bitsLeft(&in) > 0)
|
||||
{
|
||||
pushBit(&out, headBit(&in));
|
||||
//printf("Bits left: %d\n", bitsLeft(&in));
|
||||
//printf("Bits out: %d\n", numBits(&out));
|
||||
}
|
||||
if(memcmp(input, output, sizeof(input)) == 0)
|
||||
{
|
||||
prnlog(" Bitstream test 1 ok");
|
||||
}else
|
||||
{
|
||||
prnlog(" Bitstream test 1 failed");
|
||||
uint8_t i;
|
||||
for(i = 0 ; i < sizeof(input) ; i++)
|
||||
{
|
||||
prnlog(" IN %02x, OUT %02x", input[i], output[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testReversedBitstream()
|
||||
{
|
||||
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
|
||||
uint8_t reverse [] = {0,0,0,0,0,0,0,0};
|
||||
uint8_t output [] = {0,0,0,0,0,0,0,0};
|
||||
BitstreamIn in = { input, sizeof(input) * 8,0};
|
||||
BitstreamOut out ={ output, 0,0};
|
||||
BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0};
|
||||
BitstreamOut reversed_out ={ reverse,0 ,0};
|
||||
|
||||
while(bitsLeft(&in) > 0)
|
||||
{
|
||||
pushBit(&reversed_out, tailBit(&in));
|
||||
}
|
||||
while(bitsLeft(&reversed_in) > 0)
|
||||
{
|
||||
pushBit(&out, tailBit(&reversed_in));
|
||||
}
|
||||
if(memcmp(input, output, sizeof(input)) == 0)
|
||||
{
|
||||
prnlog(" Bitstream test 2 ok");
|
||||
}else
|
||||
{
|
||||
prnlog(" Bitstream test 2 failed");
|
||||
uint8_t i;
|
||||
for(i = 0 ; i < sizeof(input) ; i++)
|
||||
{
|
||||
prnlog(" IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int testCipherUtils(void)
|
||||
{
|
||||
prnlog("[+] Testing some internals...");
|
||||
int retval = 0;
|
||||
retval |= testBitStream();
|
||||
retval |= testReversedBitstream();
|
||||
return retval;
|
||||
}
|
||||
#endif
|
76
armsrc/cipherutils.h
Normal file
76
armsrc/cipherutils.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef CIPHERUTILS_H
|
||||
#define CIPHERUTILS_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t * buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
} BitstreamIn;
|
||||
|
||||
typedef struct {
|
||||
uint8_t * buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
}BitstreamOut;
|
||||
|
||||
bool headBit( BitstreamIn *stream);
|
||||
bool tailBit( BitstreamIn *stream);
|
||||
void pushBit( BitstreamOut *stream, bool bit);
|
||||
int bitsLeft( BitstreamIn *stream);
|
||||
#ifndef ON_DEVICE
|
||||
int testCipherUtils(void);
|
||||
int testMAC();
|
||||
void printarr(char * name, uint8_t* arr, int len);
|
||||
void printvar(char * name, uint8_t* arr, int len);
|
||||
void printarr_human_readable(char * title, uint8_t* arr, int len);
|
||||
#endif
|
||||
void push6bits( BitstreamOut* stream, uint8_t bits);
|
||||
void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ;
|
||||
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
|
||||
uint64_t x_bytes_to_num(uint8_t* src, size_t len);
|
||||
uint8_t reversebytes(uint8_t b);
|
||||
void reverse_arraybytes(uint8_t* arr, size_t len);
|
||||
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len);
|
||||
#endif // CIPHERUTILS_H
|
215
armsrc/iclass.c
215
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)
|
||||
|
|
|
@ -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.
|
||||
|
|
170
client/cmdhf.c
170
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)
|
||||
{
|
||||
|
|
|
@ -364,6 +364,8 @@ int CmdHFiClassReader_Dump(const char *Cmd)
|
|||
snprintf(filename, 100,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
CSN[0],CSN[1],CSN[2],CSN[3],
|
||||
CSN[4],CSN[5],CSN[6],CSN[7]);
|
||||
//Place the div_key in block 3
|
||||
memcpy(iclass_data+(3*8), div_key, 8);
|
||||
saveFile(filename,"bin",iclass_data, iclass_datalen );
|
||||
}
|
||||
//Aaaand we're finished
|
||||
|
|
|
@ -39,14 +39,14 @@
|
|||
|
||||
#include "cipher.h"
|
||||
#include "cipherutils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
//#include "fileutils.h"
|
||||
uint8_t keytable[] = { 0,0,0,0,0,0,0,0};
|
||||
#ifndef ON_DEVICE
|
||||
#include "fileutils.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
|
||||
|
@ -221,27 +221,27 @@ void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
|
|||
output(k,initState,&input_32_zeroes,&out);
|
||||
}
|
||||
|
||||
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4])
|
||||
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
|
||||
{
|
||||
uint8_t *cc_nr;
|
||||
uint8_t cc_nr[13] = { 0 };
|
||||
uint8_t div_key[8];
|
||||
cc_nr=(uint8_t*)malloc(length+1);
|
||||
memcpy(cc_nr,cc_nr_p,length);
|
||||
//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,length);
|
||||
BitstreamIn bitstream = {cc_nr,length * 8,0};
|
||||
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);
|
||||
//printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
|
||||
free(cc_nr);
|
||||
//free(cc_nr);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
int testMAC()
|
||||
{
|
||||
prnlog("[+] Testing MAC calculation...");
|
||||
|
@ -253,7 +253,7 @@ int testMAC()
|
|||
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
|
||||
|
||||
uint8_t calculated_mac[4] = {0};
|
||||
doMAC(cc_nr, 12,div_key, calculated_mac);
|
||||
doMAC(cc_nr,div_key, calculated_mac);
|
||||
|
||||
if(memcmp(calculated_mac, correct_MAC,4) == 0)
|
||||
{
|
||||
|
@ -269,3 +269,4 @@ int testMAC()
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,9 @@
|
|||
#define CIPHER_H
|
||||
#include <stdint.h>
|
||||
|
||||
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]);
|
||||
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
|
||||
|
|
|
@ -214,7 +214,7 @@ void printarr_human_readable(char * title, uint8_t* arr, int len)
|
|||
// Code for testing below
|
||||
//-----------------------------
|
||||
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
int testBitStream()
|
||||
{
|
||||
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
|
||||
|
@ -287,3 +287,4 @@ int testCipherUtils(void)
|
|||
retval |= testReversedBitstream();
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -59,9 +59,10 @@ 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();
|
||||
#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);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef ON_DEVICE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -108,3 +109,10 @@ void prnlog(char *fmt, ...)
|
|||
PrintAndLog(buffer);
|
||||
|
||||
}
|
||||
#else //if we're on ARM
|
||||
void prnlog(char *fmt,...)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
|
||||
#ifndef FILEUTILS_H
|
||||
#define FILEUTILS_H
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
|
||||
/**
|
||||
* @brief Utility function to save data to a file. This method takes a preferred name, but if that
|
||||
* file already exists, it tries with another name until it finds something suitable.
|
||||
|
@ -50,6 +53,8 @@
|
|||
*/
|
||||
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
|
||||
|
||||
int fileExists(const char *filename);
|
||||
#endif //ON_DEVICE
|
||||
|
||||
/**
|
||||
* Utility function to print to console. This is used consistently within the library instead
|
||||
|
@ -59,5 +64,4 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si
|
|||
* @param fmt
|
||||
*/
|
||||
void prnlog(char *fmt, ...);
|
||||
int fileExists(const char *filename);
|
||||
#endif // FILEUTILS_H
|
||||
|
|
108
common/protocols.c
Normal file
108
common/protocols.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t app_limit;
|
||||
uint8_t otp[2];
|
||||
uint8_t block_writelock;
|
||||
uint8_t chip_config;
|
||||
uint8_t mem_config;
|
||||
uint8_t eas;
|
||||
uint8_t fuses;
|
||||
}picopass_conf_block;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t csn[8];
|
||||
picopass_conf_block conf;
|
||||
uint8_t epurse[8];
|
||||
uint8_t key_d[8];
|
||||
uint8_t key_c[8];
|
||||
uint8_t app_issuer_area[8];
|
||||
|
||||
}picopass_hdr;
|
||||
|
||||
#define FUSE_FPERS 0x80
|
||||
#define FUSE_CODING1 0x40
|
||||
#define FUSE_CODING0 0x20
|
||||
#define FUSE_CRYPT1 0x10
|
||||
#define FUSE_CRYPT0 0x08
|
||||
#define FUSE_FPROD1 0x04
|
||||
#define FUSE_FPROD0 0x02
|
||||
#define FUSE_RA 0x01
|
||||
|
||||
//#define prnt printf
|
||||
void prnt(char *fmt,...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
vprintf(fmt, argptr);
|
||||
printf(" "); // cleaning prompt
|
||||
va_end(argptr);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
uint8_t isset(uint8_t val, uint8_t mask)
|
||||
{
|
||||
return (val & mask);
|
||||
}
|
||||
|
||||
uint8_t notset(uint8_t val, uint8_t mask){
|
||||
return !(val & mask);
|
||||
}
|
||||
|
||||
void fuse_config(const picopass_hdr *hdr)
|
||||
{
|
||||
uint8_t fuses = hdr->conf.fuses;
|
||||
|
||||
if (isset(fuses,FUSE_FPERS))prnt(" Mode: Personalization [Programmable]");
|
||||
else prnt(" Mode: Application [Locked]");
|
||||
|
||||
if (isset(fuses, FUSE_CODING1))
|
||||
prnt(" Coding: RFU");
|
||||
else
|
||||
{
|
||||
if( isset( fuses , FUSE_CODING0)) prnt(" Coding: ISO 14443-2 B/ISO 15693");
|
||||
else prnt(" Coding: ISO 14443B only");
|
||||
}
|
||||
if( isset (fuses,FUSE_CRYPT1 | FUSE_CRYPT0 )) prnt(" Crypt: Secured page, keys not locked");
|
||||
if( isset (fuses,FUSE_CRYPT1) && notset( fuses, FUSE_CRYPT0 )) prnt(" Crypt: Secured page, keys not locked");
|
||||
if( notset (fuses,FUSE_CRYPT1) && isset( fuses, FUSE_CRYPT0 )) prnt(" Crypt: Non secured page");
|
||||
if( notset (fuses,FUSE_CRYPT1) && notset( fuses, FUSE_CRYPT0 )) prnt(" Crypt: No auth possible. Read only if RA is enabled");
|
||||
|
||||
if( isset( fuses, FUSE_RA)) prnt(" RA: Read access enabled");
|
||||
else prnt(" RA: Read access not enabled");
|
||||
}
|
||||
void mem_config(const picopass_hdr *hdr)
|
||||
{
|
||||
uint8_t mem = hdr->conf.mem_config;
|
||||
if( isset (mem, 0x80)) prnt(" Mem: 16KBits (255 * 8 bytes)");
|
||||
else prnt(" Mem: 2 KBits ( 32 * 8 bytes)");
|
||||
|
||||
}
|
||||
void applimit_config(const picopass_hdr *hdr)
|
||||
{
|
||||
uint8_t applimit = hdr->conf.app_limit;
|
||||
prnt(" AA1: blocks 6-%d", applimit);
|
||||
prnt(" AA2: blocks %d-", (applimit+1));
|
||||
}
|
||||
void print_picopass_info(const picopass_hdr *hdr)
|
||||
{
|
||||
fuse_config(hdr);
|
||||
mem_config(hdr);
|
||||
applimit_config(hdr);
|
||||
}
|
||||
void test()
|
||||
{
|
||||
picopass_hdr hdr = {0x27,0xaf,0x48,0x01,0xf9,0xff,0x12,0xe0,0x12,0xff,0xff,0xff,0x7f,0x1f,0xff,0x3c};
|
||||
prnt("Picopass configuration:");
|
||||
print_picopass_info(&hdr);
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
test();
|
||||
return 0;
|
||||
}
|
174
common/protocols.h
Normal file
174
common/protocols.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
#ifndef PROTOCOLS_H
|
||||
#define PROTOCOLS_H
|
||||
|
||||
//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
|
||||
|
||||
|
||||
#endif // PROTOCOLS_H
|
Loading…
Reference in a new issue