diff --git a/firmware/application/Makefile b/firmware/application/Makefile index a4f065f..f248a1a 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -18,6 +18,7 @@ SRC_FILES += \ $(PROJ_DIR)/rfid/crc_utils.c \ $(PROJ_DIR)/rfid/hex_utils.c \ $(PROJ_DIR)/rfid/mf1_crapto1.c \ + $(PROJ_DIR)/rfid/mf1_crypto1.c \ $(PROJ_DIR)/rfid/parity.c \ $(PROJ_DIR)/rfid/nfctag/tag_emulation.c \ $(PROJ_DIR)/rfid/nfctag/tag_persistence.c \ diff --git a/firmware/application/src/rfid/mf1_crypto1.c b/firmware/application/src/rfid/mf1_crypto1.c new file mode 100644 index 0000000..bfc2203 --- /dev/null +++ b/firmware/application/src/rfid/mf1_crypto1.c @@ -0,0 +1,1226 @@ +#include "mf1_crypto1.h" +#include "parity.h" + + +#define __inline__ inline +#define ODD_PARITY oddparity8 + + +// uncomment if platform is not avr +#define NO_INLINE_ASM 1 + +#define PRNG_MASK 0x002D0000UL +/* x^16 + x^14 + x^13 + x^11 + 1 */ + +#define PRNG_SIZE 4 /* Bytes */ +#define NONCE_SIZE 4 /* Bytes */ + +#define LFSR_MASK_EVEN 0x2010E1UL +#define LFSR_MASK_ODD 0x3A7394UL +/* x^48 + x^43 + x^39 + x^38 + x^36 + x^34 + x^33 + x^31 + x^29 + + * x^24 + x^23 + x^21 + x^19 + x^13 + x^9 + x^7 + x^6 + x^5 + 1 */ + +#define LFSR_SIZE 6 /* Bytes */ + +// Functions fa, fb and fc in filter output network. Definitions taken from Timo Kasper's thesis +#define FA(x3, x2, x1, x0) ( \ + ( (x0 | x1) ^ (x0 & x3) ) ^ ( x2 & ( (x0 ^ x1) | x3 ) ) \ +) + +#define FB(x3, x2, x1, x0) ( \ + ( (x0 & x1) | x2 ) ^ ( (x0 ^ x1) & (x2 | x3) ) \ +) + +#define FC(x4, x3, x2, x1, x0) ( \ + ( x0 | ( (x1 | x4) & (x3 ^ x4) ) ) ^ ( ( x0 ^ (x1 & x3) ) & ( (x2 ^ x3) | (x1 & x4) ) ) \ +) + + +/* For AVR only */ +#ifndef NO_INLINE_ASM + + +/* Special macros for optimized usage of the xmega */ +/* see http://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc */ + +/* Split byte into odd and even nibbles- */ +/* Used for LFSR setup. */ +#define SPLIT_BYTE(__even, __odd, __byte) \ + __asm__ __volatile__ ( \ + "lsr %2" "\n\t" \ + "ror %0" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %1" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %0" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %1" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %0" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %1" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %0" "\n\t" \ + "lsr %2" "\n\t" \ + "ror %1" \ + : "+r" (__even), \ + "+r" (__odd), \ + "+r" (__byte) \ + : \ + : "r0" ) + +/* Shift half LFSR state stored in three registers */ +/* Input is bit 0 of __in */ +#define SHIFT24(__b0, __b1, __b2, __in) \ + __asm__ __volatile__ ( \ + "lsr %3" "\n\t" \ + "ror %2" "\n\t" \ + "ror %1" "\n\t" \ + "ror %0" \ + : "+r" (__b0), \ + "+r" (__b1), \ + "+r" (__b2), \ + "+r" (__in) \ + : \ + : ) + +/* Shift half LFSR state stored in three registers */ +/* Input is bit 0 of __in */ +/* decrypt with __stream if bit 0 of __decrypt is set */ +#define SHIFT24_COND_DECRYPT(__b0, __b1, __b2, __in, __stream, __decrypt) \ + __asm__ __volatile__ ( \ + "sbrc %5, 0" "\n\t" \ + "eor %3, %4" "\n\t" \ + "lsr %3" "\n\t" \ + "ror %2" "\n\t" \ + "ror %1" "\n\t" \ + "ror %0" \ + : "+r" (__b0), \ + "+r" (__b1), \ + "+r" (__b2), \ + "+r" (__in) \ + : "r" (__stream), \ + "r" (__decrypt) \ + : "r0" ) + +/* Shift a byte with input from an other byte */ +/* Input is bit 0 of __in */ +#define SHIFT8(__byte, __in) \ + __asm__ __volatile__ ( \ + "lsr %1" "\n\t" \ + "ror %0" \ + : "+r" (__byte), \ + "+r" (__in) \ + : \ + : "r0" ) +/* End AVR specific */ +#else + +/* Plattform independend code */ + +#define SPLIT_BYTE(__even, __odd, __byte) \ + __even = (__even >> 1) | (__byte<<7); __byte>>=1; \ + __odd = (__odd >> 1) | (__byte<<7); __byte>>=1; \ + __even = (__even >> 1) | (__byte<<7); __byte>>=1; \ + __odd = (__odd >> 1) | (__byte<<7); __byte>>=1; \ + __even = (__even >> 1) | (__byte<<7); __byte>>=1; \ + __odd = (__odd >> 1) | (__byte<<7); __byte>>=1; \ + __even = (__even >> 1) | (__byte<<7); __byte>>=1; \ + __odd = (__odd >> 1) | (__byte<<7) + +#define SHIFT24(__b0, __b1, __b2, __in) \ + __b0 = (__b0>>1) | (__b1<<7); \ + __b1 = (__b1>>1) | (__b2<<7); \ + __b2 = (__b2>>1) | ((__in)<<7) + +#define SHIFT24_COND_DECRYPT(__b0, __b1, __b2, __in, __stream, __decrypt) \ + __b0 = (__b0>>1) | (__b1<<7); \ + __b1 = (__b1>>1) | (__b2<<7); \ + __b2 = (__b2>>1) | (((__in)^((__stream)&(__decrypt)))<<7) + +#define SHIFT8(__byte, __in) __byte = (__byte>>1) | ((__in)<<7) + + +#endif + +/* Space/speed tradoff. */ +/* We want speed, so we have to pay with size. */ +/* If we combine the A und B Filtertables and precalculate the values */ +/* for each state byte, we get the following tables which gives a */ +/* faster calculation of the filter output */ +/* Table of the filter A/B output per byte */ +static const uint8_t abFilterTable[3][256] = { + /* for Odd[0] */ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 + }, + /* for Odd[1] */ + { + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, + 0x04, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06 + }, + /* for Odd[2] */ + { + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x18, + 0x10, 0x10, 0x18, 0x10, 0x18, 0x18, 0x10, 0x18 + } +}; + +/* Standard FC table, feedback at bit 0 */ +static const uint8_t TableC0[32] = { + /* fc with Input {4,3,2,1,0} = (0,0,0,0,0) to (1,1,1,1,1) */ + FC(0, 0, 0, 0, 0), FC(0, 0, 0, 0, 1), FC(0, 0, 0, 1, 0), FC(0, 0, 0, 1, 1), + FC(0, 0, 1, 0, 0), FC(0, 0, 1, 0, 1), FC(0, 0, 1, 1, 0), FC(0, 0, 1, 1, 1), + FC(0, 1, 0, 0, 0), FC(0, 1, 0, 0, 1), FC(0, 1, 0, 1, 0), FC(0, 1, 0, 1, 1), + FC(0, 1, 1, 0, 0), FC(0, 1, 1, 0, 1), FC(0, 1, 1, 1, 0), FC(0, 1, 1, 1, 1), + FC(1, 0, 0, 0, 0), FC(1, 0, 0, 0, 1), FC(1, 0, 0, 1, 0), FC(1, 0, 0, 1, 1), + FC(1, 0, 1, 0, 0), FC(1, 0, 1, 0, 1), FC(1, 0, 1, 1, 0), FC(1, 0, 1, 1, 1), + FC(1, 1, 0, 0, 0), FC(1, 1, 0, 0, 1), FC(1, 1, 0, 1, 0), FC(1, 1, 0, 1, 1), + FC(1, 1, 1, 0, 0), FC(1, 1, 1, 0, 1), FC(1, 1, 1, 1, 0), FC(1, 1, 1, 1, 1) +}; + +/* Special table for byte processing, feedback at bit 7 */ +static const uint8_t TableC7[32] = { + /* fc with Input {4,3,2,1,0} = (0,0,0,0,0) to (1,1,1,1,1) */ + FC(0, 0, 0, 0, 0) << 7, FC(0, 0, 0, 0, 1) << 7, FC(0, 0, 0, 1, 0) << 7, FC(0, 0, 0, 1, 1) << 7, + FC(0, 0, 1, 0, 0) << 7, FC(0, 0, 1, 0, 1) << 7, FC(0, 0, 1, 1, 0) << 7, FC(0, 0, 1, 1, 1) << 7, + FC(0, 1, 0, 0, 0) << 7, FC(0, 1, 0, 0, 1) << 7, FC(0, 1, 0, 1, 0) << 7, FC(0, 1, 0, 1, 1) << 7, + FC(0, 1, 1, 0, 0) << 7, FC(0, 1, 1, 0, 1) << 7, FC(0, 1, 1, 1, 0) << 7, FC(0, 1, 1, 1, 1) << 7, + FC(1, 0, 0, 0, 0) << 7, FC(1, 0, 0, 0, 1) << 7, FC(1, 0, 0, 1, 0) << 7, FC(1, 0, 0, 1, 1) << 7, + FC(1, 0, 1, 0, 0) << 7, FC(1, 0, 1, 0, 1) << 7, FC(1, 0, 1, 1, 0) << 7, FC(1, 0, 1, 1, 1) << 7, + FC(1, 1, 0, 0, 0) << 7, FC(1, 1, 0, 0, 1) << 7, FC(1, 1, 0, 1, 0) << 7, FC(1, 1, 0, 1, 1) << 7, + FC(1, 1, 1, 0, 0) << 7, FC(1, 1, 1, 0, 1) << 7, FC(1, 1, 1, 1, 0) << 7, FC(1, 1, 1, 1, 1) << 7 +}; + +/* Special table for nibble processing (e.g. ack), feedback at bit 3 */ +static const uint8_t TableC3[32] = { + /* fc with Input {4,3,2,1,0} = (0,0,0,0,0) to (1,1,1,1,1) */ + FC(0, 0, 0, 0, 0) << 3, FC(0, 0, 0, 0, 1) << 3, FC(0, 0, 0, 1, 0) << 3, FC(0, 0, 0, 1, 1) << 3, + FC(0, 0, 1, 0, 0) << 3, FC(0, 0, 1, 0, 1) << 3, FC(0, 0, 1, 1, 0) << 3, FC(0, 0, 1, 1, 1) << 3, + FC(0, 1, 0, 0, 0) << 3, FC(0, 1, 0, 0, 1) << 3, FC(0, 1, 0, 1, 0) << 3, FC(0, 1, 0, 1, 1) << 3, + FC(0, 1, 1, 0, 0) << 3, FC(0, 1, 1, 0, 1) << 3, FC(0, 1, 1, 1, 0) << 3, FC(0, 1, 1, 1, 1) << 3, + FC(1, 0, 0, 0, 0) << 3, FC(1, 0, 0, 0, 1) << 3, FC(1, 0, 0, 1, 0) << 3, FC(1, 0, 0, 1, 1) << 3, + FC(1, 0, 1, 0, 0) << 3, FC(1, 0, 1, 0, 1) << 3, FC(1, 0, 1, 1, 0) << 3, FC(1, 0, 1, 1, 1) << 3, + FC(1, 1, 0, 0, 0) << 3, FC(1, 1, 0, 0, 1) << 3, FC(1, 1, 0, 1, 0) << 3, FC(1, 1, 0, 1, 1) << 3, + FC(1, 1, 1, 0, 0) << 3, FC(1, 1, 1, 0, 1) << 3, FC(1, 1, 1, 1, 0) << 3, FC(1, 1, 1, 1, 1) << 3 +}; + +/* Filter Output Macros */ +/* Output at bit 7 for optimized byte processing */ +#define CRYPTO1_FILTER_OUTPUT_B7_24(__O0, __O1, __O2) TableC7[ abFilterTable[0][__O0] | \ + abFilterTable[1][__O1] | \ + abFilterTable[2][__O2]] + +/* Output at bit 3 for optimized nibble processing */ +#define CRYPTO1_FILTER_OUTPUT_B3_24(__O0, __O1, __O2) TableC3[ abFilterTable[0][__O0] | \ + abFilterTable[1][__O1] | \ + abFilterTable[2][__O2]] + +/* Output at bit 0 for general purpose */ +#define CRYPTO1_FILTER_OUTPUT_B0_24(__O0, __O1, __O2) TableC0[ abFilterTable[0][__O0] | \ + abFilterTable[1][__O1] | \ + abFilterTable[2][__O2]] + +/* Split Crypto1 state into even and odd bits */ +/* to speed up the output filter network */ +/* Put both into one struct to enable relative adressing */ +typedef struct { + uint8_t Even[LFSR_SIZE / 2]; + uint8_t Odd[LFSR_SIZE / 2]; +} Crypto1LfsrState_t; +static Crypto1LfsrState_t State = { { 0 }, { 0 } }; + + +/* Debug output of state */ +void Crypto1GetState(uint8_t *pEven, uint8_t *pOdd) { + if (pEven) { + pEven[0] = State.Even[0]; + pEven[1] = State.Even[1]; + pEven[2] = State.Even[2]; + } + if (pOdd) { + pOdd[0] = State.Odd[0]; + pOdd[1] = State.Odd[1]; + pOdd[2] = State.Odd[2]; + } + +} + +/* Proceed LFSR by one clock cycle */ +/* Prototype to force inlining */ +static __inline__ uint8_t Crypto1LFSRbyteFeedback(uint8_t E0, + uint8_t E1, + uint8_t E2, + uint8_t O0, + uint8_t O1, + uint8_t O2) __attribute__((always_inline)); +static uint8_t Crypto1LFSRbyteFeedback(uint8_t E0, + uint8_t E1, + uint8_t E2, + uint8_t O0, + uint8_t O1, + uint8_t O2) { + uint8_t Feedback; + + /* Calculate feedback according to LFSR taps. XOR all state bytes + * into a single bit. */ + Feedback = E0 & (uint8_t)(LFSR_MASK_EVEN); + Feedback ^= E1 & (uint8_t)(LFSR_MASK_EVEN >> 8); + Feedback ^= E2 & (uint8_t)(LFSR_MASK_EVEN >> 16); + + Feedback ^= O0 & (uint8_t)(LFSR_MASK_ODD); + Feedback ^= O1 & (uint8_t)(LFSR_MASK_ODD >> 8); + Feedback ^= O2 & (uint8_t)(LFSR_MASK_ODD >> 16); + + /* fold 8 into 1 bit */ + Feedback ^= ((Feedback >> 4) | (Feedback << 4)); /* Compiler uses a swap for this (fast!) */ + Feedback ^= Feedback >> 2; + Feedback ^= Feedback >> 1; + + return (Feedback); +} + +/* Proceed LFSR by one clock cycle */ +/* Prototype to force inlining */ +static __inline__ void Crypto1LFSR(uint8_t In) __attribute__((always_inline)); +static void Crypto1LFSR(uint8_t In) { + uint8_t Feedback; + register uint8_t Temp0, Temp1, Temp2; + + /* Load even state. */ + Temp0 = State.Even[0]; + Temp1 = State.Even[1]; + Temp2 = State.Even[2]; + + + /* Calculate feedback according to LFSR taps. XOR all 6 state bytes + * into a single bit. */ + Feedback = Temp0 & (uint8_t)(LFSR_MASK_EVEN >> 0); + Feedback ^= Temp1 & (uint8_t)(LFSR_MASK_EVEN >> 8); + Feedback ^= Temp2 & (uint8_t)(LFSR_MASK_EVEN >> 16); + + Feedback ^= State.Odd[0] & (uint8_t)(LFSR_MASK_ODD >> 0); + Feedback ^= State.Odd[1] & (uint8_t)(LFSR_MASK_ODD >> 8); + Feedback ^= State.Odd[2] & (uint8_t)(LFSR_MASK_ODD >> 16); + + Feedback ^= ((Feedback >> 4) | (Feedback << 4)); /* Compiler uses a swap for this (fast!) */ + Feedback ^= Feedback >> 2; + Feedback ^= Feedback >> 1; + + /* Now the shifting of the Crypto1 state gets more complicated when + * split up into even/odd parts. After some hard thinking, one can + * see that after one LFSR clock cycle + * - the new even state becomes the old odd state + * - the new odd state becomes the old even state right-shifted by 1. */ + SHIFT24(Temp0, Temp1, Temp2, Feedback); + + /* Convert even state back into byte array and swap odd/even state + * as explained above. */ + State.Even[0] = State.Odd[0]; + State.Even[1] = State.Odd[1]; + State.Even[2] = State.Odd[2]; + + State.Odd[0] = Temp0; + State.Odd[1] = Temp1; + State.Odd[2] = Temp2; +} + +uint8_t Crypto1FilterOutput(void) { + return (CRYPTO1_FILTER_OUTPUT_B0_24(State.Odd[0], State.Odd[1], State.Odd[2])); +} + +/* Setup LFSR split into odd and even states, feed in uid ^nonce */ +/* Version for first (not nested) authentication. */ +void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4]) { + // state registers + register uint8_t Even0 = 0x00, Even1 = 0x00, Even2 = 0x00; + register uint8_t Odd0 = 0x00, Odd1 = 0x00, Odd2 = 0x00; + uint8_t KeyStream, Feedback, Out, In, ByteCount; + + KeyStream = *Key++; + SPLIT_BYTE(Even0, Odd0, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even0, Odd0, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even1, Odd1, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even1, Odd1, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even2, Odd2, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even2, Odd2, KeyStream); + + for (ByteCount = 0; ByteCount < NONCE_SIZE; ByteCount++) { + In = *CardNonce ^ *Uid++; + + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + In >>= 1; + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 4 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 5 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 6 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 7 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + *CardNonce++ ^= KeyStream; // Encrypt Nonce byte + } + // save state + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; +} + +/* Setup LFSR split into odd and even states, feed in uid ^nonce */ +/* Vesion for nested authentication. */ +/* Also generates encrypted parity bits at CardNonce[4]..[7] */ +/* Use: Decrypt = false for the tag, Decrypt = true for the reader */ +void Crypto1SetupNested(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], uint8_t NonceParity[4], bool Decrypt) { + // state registers + register uint8_t Even0 = 0x00, Even1 = 0x00, Even2 = 0x00; + register uint8_t Odd0 = 0x00, Odd1 = 0x00, Odd2 = 0x00; + uint8_t KeyStream, Feedback, Out, In, ByteCount; + + KeyStream = *Key++; + SPLIT_BYTE(Even0, Odd0, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even0, Odd0, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even1, Odd1, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even1, Odd1, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even2, Odd2, KeyStream); + KeyStream = *Key++; + SPLIT_BYTE(Even2, Odd2, KeyStream); + + /* Get first filter output */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + + for (ByteCount = 0; ByteCount < NONCE_SIZE; ByteCount++) { + In = *CardNonce ^ *Uid++; + + /* we can reuse the filter output used to decrypt the parity bit! */ + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Even0, Even1, Even2, Feedback, Out, Decrypt); + + /* Bit 1 */ + In >>= 1; + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Odd0, Odd1, Odd2, Feedback, Out, Decrypt); + + /* Bit 2 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Even0, Even1, Even2, Feedback, Out, Decrypt); + + /* Bit 3 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Odd0, Odd1, Odd2, Feedback, Out, Decrypt); + + /* Bit 4 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Even0, Even1, Even2, Feedback, Out, Decrypt); + + /* Bit 5 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Odd0, Odd1, Odd2, Feedback, Out, Decrypt); + + /* Bit 6 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Even0, Even1, Even2, Feedback, Out, Decrypt); + + /* Bit 7 */ + In >>= 1; + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + Feedback ^= In; + SHIFT24_COND_DECRYPT(Odd0, Odd1, Odd2, Feedback, Out, Decrypt); + + /* Generate parity bit */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + In = *CardNonce; + Feedback = ODD_PARITY(In); + // Store parity bit to out buffer + *NonceParity++ = Out ^ Feedback; /* Encrypted parity at Offset 4*/ + + /* Encrypt byte */ + *CardNonce++ = In ^ KeyStream; + } + /* save state */ + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; +} + +/* Crypto1Auth is similar to Crypto1Byte but */ +/* EncryptedReaderNonce is decrypted and fed back */ +void Crypto1Auth(uint8_t EncryptedReaderNonce[NONCE_SIZE]) { + /* registers to hold temporary LFSR state */ + register uint8_t Even0, Even1, Even2; + register uint8_t Odd0, Odd1, Odd2; + uint8_t In, Feedback, i; + + /* read state */ + Even0 = State.Even[0]; + Even1 = State.Even[1]; + Even2 = State.Even[2]; + Odd0 = State.Odd[0]; + Odd1 = State.Odd[1]; + Odd2 = State.Odd[2]; + + /* 4 Bytes */ + for (i = 0; i < NONCE_SIZE; i++) { + In = EncryptedReaderNonce[i]; + + /* Bit 0 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + /* remember Odd/Even swap has been omitted! */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 4 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 5 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 6 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) + ^ Feedback + ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 7 */ + Feedback = CRYPTO1_FILTER_OUTPUT_B0_24(Even0, Even1, Even2); + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) + ^ Feedback + ^ In; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + } + // save state + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; +} + +/* Crypto1Nibble generates keystrem for a nibble (4 bit) */ +/* no input to the LFSR */ +uint8_t Crypto1Nibble(void) { + /* state registers */ + register uint8_t Even0, Even1, Even2; + register uint8_t Odd0, Odd1, Odd2; + uint8_t KeyStream, Feedback, Out; + + /* read state */ + Even0 = State.Even[0]; + Even1 = State.Even[1]; + Even2 = State.Even[2]; + Odd0 = State.Odd[0]; + Odd1 = State.Odd[1]; + Odd2 = State.Odd[2]; + + /* Bit 0, initialise keystream */ + KeyStream = CRYPTO1_FILTER_OUTPUT_B3_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + Out = CRYPTO1_FILTER_OUTPUT_B3_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + Out = CRYPTO1_FILTER_OUTPUT_B3_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + Out = CRYPTO1_FILTER_OUTPUT_B3_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* save state */ + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; + + return (KeyStream); +} + +/* Crypto1Byte generates keystrem for a byte (8 bit) */ +/* no input to the LFSR */ +uint8_t Crypto1Byte(void) { + /* state registers */ + register uint8_t Even0, Even1, Even2; + register uint8_t Odd0, Odd1, Odd2; + uint8_t KeyStream, Feedback, Out; + + /* read state */ + Even0 = State.Even[0]; + Even1 = State.Even[1]; + Even2 = State.Even[2]; + Odd0 = State.Odd[0]; + Odd1 = State.Odd[1]; + Odd2 = State.Odd[2]; + + /* Bit 0, initialise keystream */ + KeyStream = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 4 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 5 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 6 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 7 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* save state */ + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; + + return (KeyStream); +} + +/* Crypto1ByteArray transcrypts array of bytes */ +/* No input to the LFSR */ +/* Avoids load/store of the LFSR-state for each byte! */ +/* Enhacement for the original function Crypto1Byte() */ +void Crypto1ByteArray(uint8_t *Buffer, uint8_t Count) { + /* state registers */ + register uint8_t Even0, Even1, Even2; + register uint8_t Odd0, Odd1, Odd2; + uint8_t KeyStream, Feedback, Out; + + /* read state */ + Even0 = State.Even[0]; + Even1 = State.Even[1]; + Even2 = State.Even[2]; + Odd0 = State.Odd[0]; + Odd1 = State.Odd[1]; + Odd2 = State.Odd[2]; + + while (Count--) { + /* Bit 0, initialise keystream */ + KeyStream = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 4 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 5 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 6 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 7 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Transcrypt and increment buffer address */ + *Buffer++ ^= KeyStream; + } + + /* save state */ + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; +} + +/* Crypto1ByteArrayWithParity encrypts an array of bytes */ +/* and generates the parity bits */ +/* No input to the LFSR */ +/* Avoids load/store of the LFSR-state for each byte! */ +/* The filter output used to encrypt the parity is */ +/* reused to encrypt bit 0 in the next byte. */ +void Crypto1ByteArrayWithParity(uint8_t *Buffer, uint8_t *Parity, uint8_t Count) { + /* state registers */ + register uint8_t Even0, Even1, Even2; + register uint8_t Odd0, Odd1, Odd2; + // KeyStream is direct to use, must to init. + uint8_t KeyStream = 0x00, Feedback, Out; + + /* read state */ + Even0 = State.Even[0]; + Even1 = State.Even[1]; + Even2 = State.Even[2]; + Odd0 = State.Odd[0]; + Odd1 = State.Odd[1]; + Odd2 = State.Odd[2]; + + /* First pass needs output, next pass uses parity bit! */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + + while (Count--) { + /* Bit 0, initialise keystream from parity */ + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 4 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 5 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 6 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2); + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 7 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2); + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Next bit encodes parity */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + *Parity++ = ODD_PARITY(*Buffer) ^ Out; + + /* encode Byte */ + *Buffer++ ^= KeyStream; + } + /* save state */ + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; +} + +/* Crypto1ByteArrayWithParity encrypts an array of bytes */ +/* and generates the parity bits */ +/* No input to the LFSR */ +/* Avoids load/store of the LFSR-state for each byte! */ +/* The filter output used to encrypt the parity is */ +/* reused to encrypt bit 0 in the next byte. */ +void Crypto1ByteArrayWithParityHasIn(uint8_t *Buffer, uint8_t *Parity, uint8_t Count) { + /* state registers */ + register uint8_t Even0, Even1, Even2; + register uint8_t Odd0, Odd1, Odd2; + // KeyStream is direct to use, must to init. + uint8_t KeyStream = 0x00, Feedback, Out; + + /* read state */ + Even0 = State.Even[0]; + Even1 = State.Even[1]; + Even2 = State.Even[2]; + Odd0 = State.Odd[0]; + Odd1 = State.Odd[1]; + Odd2 = State.Odd[2]; + + /* First pass needs output, next pass uses parity bit! */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + + while (Count--) { + uint8_t In = *Buffer; + + /* Bit 0, initialise keystream from parity */ + SHIFT8(KeyStream, Out); + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 1 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 2 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 3 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 4 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 5 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Bit 6 */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Odd0, Odd1, Odd2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Even0, Even1, Even2, Odd0, Odd1, Odd2) ^ In; + In >>= 1; + SHIFT24(Even0, Even1, Even2, Feedback); + + /* Bit 7 */ + /* remember Odd/Even swap has been omitted! */ + Out = CRYPTO1_FILTER_OUTPUT_B7_24(Even0, Even1, Even2); + KeyStream = (KeyStream >> 1) | Out; + Feedback = Crypto1LFSRbyteFeedback(Odd0, Odd1, Odd2, Even0, Even1, Even2) ^ In; + In >>= 1; + SHIFT24(Odd0, Odd1, Odd2, Feedback); + + /* Next bit encodes parity */ + Out = CRYPTO1_FILTER_OUTPUT_B0_24(Odd0, Odd1, Odd2); + *Parity++ = ODD_PARITY(*Buffer) ^ Out; + + /* encode Byte */ + *Buffer++ ^= KeyStream; + } + /* save state */ + State.Even[0] = Even0; + State.Even[1] = Even1; + State.Even[2] = Even2; + State.Odd[0] = Odd0; + State.Odd[1] = Odd1; + State.Odd[2] = Odd2; +} + +/* Function Crypto1PRNG */ +/* New version of the PRNG wich can calculate multiple */ +/* feedback bits at once! */ +/* Feedback mask = 0x2d = 101101 binary */ +/* Because pattern 101 is repeated, only 2 shifts are neccessary! */ +/* Feedback ^= Feedback >> 3; folds 101 101 to 101 */ +/* Feedback ^= Feedback >> 2; folds 101 => 1 */ +/* With these two lines not only bit 0 is calculated, */ +/* but all the bits which do no overlap with the feedback! */ +/* I.e. the 10 leading zeros in the feedback mask bits */ +/* gives us a total of 11 valid feedback bits! */ +/* The ClockCount for the PRNG is always multiple of 32! */ +/* Up tp 11 Bits can be calculated at once */ +/* Split into chunks of 11+11+10 = 32 bits */ +/* This avoids a calculated number of shifts */ +void Crypto1PRNG(uint8_t State[4], uint8_t ClockCount) { + /* For ease of processing convert the state into a 32 bit integer first */ + uint32_t Temp; + uint16_t Feedback; + + Temp = (uint32_t) State[0] << 0; + Temp |= (uint32_t) State[1] << 8; + Temp |= (uint32_t) State[2] << 16; + Temp |= (uint32_t) State[3] << 24; + + /* PRNG is always a multiple of 32! */ + /* Up tp 11 Bits can be calculated at once */ + /* Split into chunks of 11+11+10 = 32 bits */ + while (ClockCount >= 32) { + Feedback = (uint16_t)(Temp >> 16); + Feedback ^= Feedback >> 3; /* 2d = 101101, fold 101 101 => 101 */ + Feedback ^= Feedback >> 2; /* fold 101 => 1 */ + /* Cycle LFSR and feed back. */ + Temp = (Temp >> 11) | (((uint32_t)Feedback) << (32 - 11)); + + /* Same for the next 11 Bits */ + Feedback = (uint16_t)(Temp >> 16); + Feedback ^= Feedback >> 3; /* 2d = 101101, fold 101 101 => 101 */ + Feedback ^= Feedback >> 2; /* fold 101 => 1 */ + Temp = (Temp >> 11) | (((uint32_t)Feedback) << (32 - 11)); + + /* Remaining 10 bits */ + Feedback = (uint16_t)(Temp >> 16); + Feedback ^= Feedback >> 3; /* 2d = 101101, fold 101 101 => 101 */ + Feedback ^= Feedback >> 2; /* fold 101 => 1 */ + Temp = (Temp >> 10) | (((uint32_t)Feedback) << (32 - 10)); + + /* Now 32 bits are fed back */ + ClockCount -= 32; + } + + /* Store back state */ + State[0] = (uint8_t)(Temp >> 0); + State[1] = (uint8_t)(Temp >> 8); + State[2] = (uint8_t)(Temp >> 16); + State[3] = (uint8_t)(Temp >> 24); +} + +/* prng_successor + * helper used to obscure the keystream during authentication + */ +uint32_t Crypto1FreePRNG(uint32_t x, uint32_t n) { + x = __builtin_bswap32(x); + + while (n--) + x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + + return __builtin_bswap32(x); +} + + +void Crypto1EncryptWithParity(uint8_t *Buffer, uint8_t BitCount) { + uint8_t i = 0; + while (i < BitCount) { + Buffer[i / 8] ^= + CRYPTO1_FILTER_OUTPUT_B0_24(State.Odd[0], State.Odd[1], State.Odd[2]) + << (i % 8); + if (++i % 9 != 0) // only shift, if this was no parity bit + Crypto1LFSR(0); + } +} + +void Crypto1ReaderAuthWithParity(uint8_t PlainReaderAnswerWithParityBits[9]) { + uint8_t i = 0, feedback; + while (i < 72) { + feedback = PlainReaderAnswerWithParityBits[i / 8] >> (i % 8); + PlainReaderAnswerWithParityBits[i / 8] ^= + CRYPTO1_FILTER_OUTPUT_B0_24(State.Odd[0], State.Odd[1], State.Odd[2]) + << (i % 8); + if (++i % 9 != 0) { // only shift, if this was no parity bit + if (i <= 36) + Crypto1LFSR(feedback & 1); + else + Crypto1LFSR(0); + } + } +} diff --git a/firmware/application/src/rfid/mf1_crypto1.h b/firmware/application/src/rfid/mf1_crypto1.h new file mode 100644 index 0000000..ee3338b --- /dev/null +++ b/firmware/application/src/rfid/mf1_crypto1.h @@ -0,0 +1,42 @@ +#ifndef CRYPTO1_H +#define CRYPTO1_H + +#include +#include + +// debug to use +void Crypto1GetState(uint8_t *pEven, uint8_t *pOdd); + +/* Gets the current keystream-bit, without shifting the internal LFSR */ +uint8_t Crypto1FilterOutput(void); + +/* Set up Crypto1 cipher using the given Key, Uid and CardNonce. Also encrypts + * the CardNonce in-place while in non-linear mode. */ +void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4]); +/* Same for nested auth. NonceParity[0]..[3] will contain the parity bits after return */ +void Crypto1SetupNested(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], uint8_t NonceParity[4], bool Decrypt); + +/* Load the decrypted ReaderNonce into the Crypto1 state LFSR */ +void Crypto1Auth(uint8_t EncryptedReaderNonce[4]); + +/* Encrypt/Decrypt array */ +void Crypto1ByteArray(uint8_t *Buffer, uint8_t Count); +void Crypto1ByteArrayWithParity(uint8_t *Buffer, uint8_t *Parity, uint8_t Count); +void Crypto1ByteArrayWithParityHasIn(uint8_t *Buffer, uint8_t *Parity, uint8_t Count); + +/* Generate 4 Bits of key stream */ +uint8_t Crypto1Nibble(void); +/* Generate 8 Bits of key stream */ +uint8_t Crypto1Byte(void); + +/* Execute 'ClockCount' cycles on the PRNG state 'State' */ +void Crypto1PRNG(uint8_t State[4], uint8_t ClockCount); +uint32_t Crypto1FreePRNG(uint32_t x, uint32_t n); + +/* Encrypts buffer with consideration of parity bits */ +void Crypto1EncryptWithParity(uint8_t *Buffer, uint8_t BitCount); + +/* Encrypts buffer with LFSR feedback within reader nonce and considers parity bits */ +void Crypto1ReaderAuthWithParity(uint8_t PlainReaderAnswerWithParityBits[9]); + +#endif //CRYPTO1_H diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 39a4f31..3c27f13 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -3,10 +3,15 @@ #include "nfc_mf1.h" #include "nfc_14a.h" #include "hex_utils.h" -#include "crypto1_helper.h" #include "fds_util.h" #include "tag_persistence.h" +#ifdef NFC_MF1_FAST_SIM +#include "mf1_crypto1.h" +#else +#include "crypto1_helper.h" +#endif + #define NRF_LOG_MODULE_NAME tag_mf1 #include "nrf_log.h" #include "nrf_log_ctrl.h" @@ -188,9 +193,12 @@ static nfc_tag_mf1_tx_buffer_t m_tag_tx_buffer; // 保存当前正在模拟的MF1的具体类型 static tag_specific_type_t m_tag_type; +// Fast simulate is enable, we use internal crypto1 instance from 'mf1_crypto1.c' +#ifndef NFC_MF1_FAST_SIM // mifare classic crypto1 static struct Crypto1State mpcs = {0, 0}; static struct Crypto1State *pcs = &mpcs; +#endif // 定义指向存放侦测的数据的buffer // 将此数据放置在休眠保留的RAM中,以节约写入到Flash的时间和空间 @@ -402,11 +410,13 @@ static bool check_block_max_overflow(uint8_t block) { return block > block_max; } +#ifndef NFC_MF1_FAST_SIM void mf1_prng_by_bytes(uint8_t *nonces, uint32_t n) { uint32_t nonces_u32 = bytes_to_num(nonces, 4); nonces_u32 = prng_successor(nonces_u32, n); num_to_bytes(nonces_u32, 4, nonces); } +#endif /** @brief mf1状态机 * @param data 来自读头数据 @@ -431,7 +441,9 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { m_gen1a_state = GEN1A_STATE_UNLOCKED_RW_WAIT; // 更新GEN1A状态机 m_mf1_state = MF1_STATE_UNAUTH; // 更新MF1状态机 nfc_tag_14a_tx_nbit_delay_window(ACK_VALUE, 4); // 回复读卡器gen1a标签解锁后门成功 +#ifndef NFC_MF1_FAST_SIM crypto1_deinit(pcs); // Reset crypto1 handler +#endif } else { m_gen1a_state = GEN1A_STATE_DISABLE; // 如果发现并没有走过第一步的话,直接重置gen1a状态机 } @@ -485,14 +497,22 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { for (uint8_t i = 0; i < sizeof(ReaderResponse); i++) { ReaderResponse[i] = CardNonce[i]; } +#ifdef NFC_MF1_FAST_SIM + Crypto1PRNG(ReaderResponse, 64); +#else mf1_prng_by_bytes(ReaderResponse, 64); +#endif // 根据读卡器的应答预先计算我们的应答 for (uint8_t i = 0; i < sizeof(CardResponse); i++) { CardResponse[i] = ReaderResponse[i]; } +#ifdef NFC_MF1_FAST_SIM + Crypto1PRNG(CardResponse, 32); +#else mf1_prng_by_bytes(CardResponse, 32); - +#endif + // 记录验证日志 append_mf1_auth_log_step1(KeyInUse, false, BlockAuth, CardNonce); @@ -505,6 +525,16 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { m_tag_tx_buffer.tx_raw_buffer[2] = CardNonce[2]; m_tag_tx_buffer.tx_raw_buffer[3] = CardNonce[3]; +#ifdef NFC_MF1_FAST_SIM + Crypto1Setup( + // 根据当前的指令类型选择验证A或者B秘钥 + KeyInUse ? m_tag_trailer_info->keyb : m_tag_trailer_info->keya, + // 传入当前使用的防冲撞的UID + m_shadow_coll_res.uid, + // 传入一个明文的随机数,这个随机数将会被用于解密后续的通信 + CardNonce + ); +#else // 设置crypto1密钥流,丢弃之前的加密状态 crypto1_deinit(pcs); // 加载密钥流 @@ -514,6 +544,7 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { ); // 设置密钥流 crypto1_word(pcs, bytes_to_num(m_shadow_coll_res.uid, 4) ^ bytes_to_num(CardNonce, 4), 0); +#endif // 回应明文随机数给读卡器 nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_raw_buffer, 4, false); break; @@ -581,16 +612,19 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { if (szDataBits == 64) { // 拷贝读卡器回应的NR + AR append_mf1_auth_log_step2(p_data, &p_data[4]); - +#ifdef NFC_MF1_FAST_SIM + // Reader delivers an encrypted nonce. We use it to setup the crypto1 LFSR in nonlinear feedback mode. Furthermore it delivers an encrypted answer. Decrypt and check it + Crypto1Auth(&p_data[0]); + Crypto1ByteArray(&p_data[4], 4); +#else // NR,是读卡器生成的随机数 uint32_t nr = bytes_to_num(p_data, 4); // AR,是卡片加密我们第一步回应的随机数的加密后的数据 uint32_t ar = bytes_to_num(&p_data[4], 4); - // --- crypto crypto1_word(pcs, nr, 1); num_to_bytes(ar ^ crypto1_word(pcs, 0, 0), 4, &p_data[4]); - +#endif // 验证读卡器返回来的随机数是不是我们发送的 if ((p_data[4] == ReaderResponse[0]) && (p_data[5] == ReaderResponse[1]) && (p_data[6] == ReaderResponse[2]) && (p_data[7] == ReaderResponse[3])) { // 读取器已通过身份验证。加密预计算的卡应答数据并生成奇偶校验位。 @@ -598,10 +632,12 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { m_tag_tx_buffer.tx_raw_buffer[1] = CardResponse[1]; m_tag_tx_buffer.tx_raw_buffer[2] = CardResponse[2]; m_tag_tx_buffer.tx_raw_buffer[3] = CardResponse[3]; - // 加密且计算奇偶校验位 +#ifdef NFC_MF1_FAST_SIM + Crypto1ByteArrayWithParity(m_tag_tx_buffer.tx_raw_buffer, m_tag_tx_buffer.tx_bit_parity, 4); +#else mf_crypto1_encrypt(pcs, m_tag_tx_buffer.tx_raw_buffer, 4, m_tag_tx_buffer.tx_bit_parity); - +#endif // 验证成功了,需要进入已经验证成功的状态 m_mf1_state = MF1_STATE_AUTHED; // 进行打包,将奇偶校验位进行拼接后返回 @@ -624,7 +660,11 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { case MF1_STATE_AUTHED: { if (szDataBits == 32) { // 在这种状态下,所有通信都被加密。因此,我们首先必须解密读头发送过来的数据。 +#ifdef NFC_MF1_FAST_SIM + Crypto1ByteArray(p_data, 4); +#else mf_crypto1_decryptEx(pcs, p_data, 4, p_data); +#endif // 解密完成后,检查CRC是否正确,我们必须要确保数据过来的数据无误! if (nfc_tag_14a_checks_crc(p_data, 4)) { switch (p_data[0]) { @@ -660,10 +700,12 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { } // 无论如何,回复的数据都要计算CRC nfc_tag_14a_append_crc(m_tag_tx_buffer.tx_raw_buffer, NFC_TAG_MF1_DATA_SIZE); - // 加密和计算奇偶校验位后回复给读卡器 +#ifdef NFC_MF1_FAST_SIM + Crypto1ByteArrayWithParity(m_tag_tx_buffer.tx_raw_buffer, m_tag_tx_buffer.tx_bit_parity, NFC_TAG_MF1_FRAME_SIZE); +#else mf_crypto1_encrypt(pcs, m_tag_tx_buffer.tx_raw_buffer, NFC_TAG_MF1_FRAME_SIZE, m_tag_tx_buffer.tx_bit_parity); - +#endif // 合并奇偶校验位到数据帧 m_tag_tx_buffer.tx_frame_bit_size = nfc_tag_14a_wrap_frame(m_tag_tx_buffer.tx_raw_buffer, 144, m_tag_tx_buffer.tx_bit_parity, m_tag_tx_buffer.tx_warp_frame); // 启动发送 @@ -676,48 +718,74 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { // 直接重置14a的状态机,让标签休眠 nfc_tag_14a_set_state(NFC_TAG_STATE_14A_HALTED); // 告知一下读头此操作不被允许 +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); +#endif } else { // 正常的写入命令。存储地址并准备接收即将到来的数据。 CurrentAddress = p_data[1]; m_mf1_state = MF1_STATE_WRITE; // 进行ACK响应,告知读头我们已经准备好了 +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(ACK_VALUE ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); +#endif } return; } - // 尽管我觉下面的三个case的代码有点蠢,除了设置状态机不同其他的相同,但是空间换时间吧算是(心理安慰) + // 尽管我觉下面的三个case的代码有点蠢,除了设置状态机不同其他的都相同,但是空间换时间吧算是(心理安慰) case CMD_DECREMENT: { CurrentAddress = p_data[1]; m_mf1_state = MF1_STATE_DECREMENT; +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(ACK_VALUE ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); +#endif break; } case CMD_INCREMENT: { CurrentAddress = p_data[1]; m_mf1_state = MF1_STATE_INCREMENT; +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(ACK_VALUE ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); +#endif break; } case CMD_RESTORE: { CurrentAddress = p_data[1]; m_mf1_state = MF1_STATE_RESTORE; +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(ACK_VALUE ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); +#endif break; } case CMD_TRANSFER: { + uint8_t status; // 此处先不判断当前的写入模式,以写入模式控制写入 if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DENIED) { // 这个模式下直接拒绝操作 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); + status = NAK_INVALID_OPERATION_TBIV; } else if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DECEIVE) { // 这个模式下回应ACK,但是不写入到RAM里面 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); + status = ACK_VALUE; } else { // 将全局块缓冲区写回指令参数指定的块地址 memcpy(m_tag_information->memory[p_data[1]], m_data_block_buffer, MEM_BYTES_PER_BLOCK); - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); + status = ACK_VALUE; } +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(status ^ Crypto1Nibble(), 4); +#else + nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, status), 4); +#endif break; } case CMD_AUTH_A: @@ -758,13 +826,21 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { for (uint8_t i = 0; i < sizeof(ReaderResponse); i++) { ReaderResponse[i] = CardNonce[i]; } +#ifdef NFC_MF1_FAST_SIM + Crypto1PRNG(ReaderResponse, 64); +#else mf1_prng_by_bytes(ReaderResponse, 64); +#endif // 根据读卡器的应答预先计算我们的应答 for (uint8_t i = 0; i < sizeof(CardResponse); i++) { CardResponse[i] = ReaderResponse[i]; } +#ifdef NFC_MF1_FAST_SIM + Crypto1PRNG(CardResponse, 32); +#else mf1_prng_by_bytes(CardResponse, 32); +#endif // 记录嵌套验证信息 append_mf1_auth_log_step1(KeyInUse, true, BlockAuth, CardNonce); @@ -777,7 +853,23 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { m_tag_tx_buffer.tx_raw_buffer[1] = CardNonce[1]; m_tag_tx_buffer.tx_raw_buffer[2] = CardNonce[2]; m_tag_tx_buffer.tx_raw_buffer[3] = CardNonce[3]; - + +#ifdef NFC_MF1_FAST_SIM + /* Setup crypto1 cipher. Discard in-place encrypted CardNonce. */ + Crypto1SetupNested( + // 根据当前的指令类型选择验证A或者B秘钥 + KeyInUse ? m_tag_trailer_info->keyb : m_tag_trailer_info->keya, + // 传入当前使用的防冲撞的UID + m_shadow_coll_res.uid, + // 传入一个明文的随机数,这个随机数将被加密并通过此缓冲区传出 + m_tag_tx_buffer.tx_raw_buffer, + // 传入一个保存随机数的奇偶校验位的缓冲区 + m_tag_tx_buffer.tx_bit_parity, + // 根据函数解释 Use: Decrypt = false for the tag, Decrypt = true for the reader + // 我们目前是标签角色,因此传入false + false + ); +#else // 设置crypto1密钥流,丢弃之前的加密状态 crypto1_deinit(pcs); // 加载密钥流 @@ -789,7 +881,7 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { uint8_t m_auth_nt_keystream[4]; num_to_bytes(bytes_to_num(m_shadow_coll_res.uid, 4) ^ bytes_to_num(CardNonce, 4), 4, m_auth_nt_keystream); mf_crypto1_encryptEx(pcs, CardNonce, m_auth_nt_keystream, m_tag_tx_buffer.tx_raw_buffer, 4, m_tag_tx_buffer.tx_bit_parity); - +#endif // 嵌套验证的情况下,进行组帧后回复一个加密的随机数,带奇偶校验位不带CRC m_tag_tx_buffer.tx_frame_bit_size = nfc_tag_14a_wrap_frame(m_tag_tx_buffer.tx_raw_buffer, 32, m_tag_tx_buffer.tx_bit_parity, m_tag_tx_buffer.tx_warp_frame); nfc_tag_14a_tx_bits(m_tag_tx_buffer.tx_warp_frame, m_tag_tx_buffer.tx_frame_bit_size); @@ -801,7 +893,11 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { // 如果一切正常,那么我们应该直接让卡片休眠,而且不能回应任何消息给读头 nfc_tag_14a_set_state(NFC_TAG_STATE_14A_HALTED); } else { +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); +#endif } break; } @@ -809,13 +905,21 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { // 读头发了不知道什么鬼指令,我们没法处理, // 因此任务此次通信异常,需要将状态重置,并且回应读头我们不支持这个指令 nfc_tag_14a_set_state(NFC_TAG_STATE_14A_IDLE); +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); +#endif break; } } } else { // crc有误,返回错误码告知 +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); +#else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); +#endif break; } } else { @@ -827,45 +931,58 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { } case MF1_STATE_WRITE: { + uint8_t status; // 当前处于写入状态机,我们需要确保接收到的数据是足够的长度的 if (szDataBits == 144) { // 解密我们接收到的16字节的待写入数据和2字节的CRCA +#ifdef NFC_MF1_FAST_SIM + Crypto1ByteArray(p_data, NFC_TAG_MF1_FRAME_SIZE); +#else mf_crypto1_decryptEx(pcs, p_data, NFC_TAG_MF1_FRAME_SIZE, p_data); +#endif // 校验数据的CRC,再次确保收到的数据无误 if (nfc_tag_14a_checks_crc(p_data, NFC_TAG_MF1_FRAME_SIZE)) { // 此处先不判断当前的写入模式,以写入模式控制写入 if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DENIED) { // 这个模式下直接拒绝操作 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); + status = NAK_INVALID_OPERATION_TBIV; } else if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DECEIVE) { // 这个模式下回应ACK,但是不写入到RAM里面 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); + status = ACK_VALUE; } else { // 其他剩余的模式都可以更新数据到标签的RAM中 memcpy(m_tag_information->memory[CurrentAddress], p_data, NFC_TAG_MF1_DATA_SIZE); - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, ACK_VALUE), 4); + status = ACK_VALUE; } } else { - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_CRC_PARITY_ERROR_TBIV), 4); + status = NAK_CRC_PARITY_ERROR_TBIV; } } else { - // 当前处于接收写卡的数据的状态,但是收到的数据的长度不对! - // 我们直接返回crc错误的信息给读头 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_CRC_PARITY_ERROR_TBIV), 4); + status = NAK_CRC_PARITY_ERROR_TBIV; } // 无论如何,操作结束后都将让标签回到验证空闲状态 m_mf1_state = MF1_STATE_AUTHED; +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(status ^ Crypto1Nibble(), 4); +#else + nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, status), 4); +#endif break; } case MF1_STATE_DECREMENT: case MF1_STATE_INCREMENT: case MF1_STATE_RESTORE: { + uint8_t status; if (szDataBits == (MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH) * 8) { // 当我们到达这里时,前面已经发出了递减、递增或恢复命令,读取器现在正在发送数据。 // 首先,解密数据并检查CRC。将请求的块地址中的数据读取到全局块缓冲器中,并检查完整性。 // 然后,如果需要,根据发出的命令进行加或减,并将块存储回全局块缓冲区。 +#ifdef NFC_MF1_FAST_SIM + Crypto1ByteArray(p_data, MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH); +#else mf_crypto1_decryptEx(pcs, p_data, MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH, p_data); +#endif // 解密后必须要校验CRC,避免使用了出错的数据 if (nfc_tag_14a_checks_crc(p_data, MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH)) { // 先复制一份操作的块数据到全局缓冲区中 @@ -888,19 +1005,25 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) { ValueToBlock(m_data_block_buffer, value_block); // 这三个操作的第二步,也就是本步不需要回应读头 // 因此当程序执行到这一步时,就可以回到已验证可以等待指令的状态了 + break; } else { // 这里的应答码或许是错误的,或许根本不需要应答 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_OTHER_ERROR), 4); + status = NAK_OTHER_ERROR; } } else { // CRC错误 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_CRC_PARITY_ERROR_TBIV), 4); + status = NAK_CRC_PARITY_ERROR_TBIV; } } else { // 长度错误,但是也算到CRC错误里面 - nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_CRC_PARITY_ERROR_TBIV), 4); + status = NAK_CRC_PARITY_ERROR_TBIV; } m_mf1_state = MF1_STATE_AUTHED; +#ifdef NFC_MF1_FAST_SIM + nfc_tag_14a_tx_nbit(status ^ Crypto1Nibble(), 4); +#else + nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, status), 4); +#endif break; } @@ -943,9 +1066,11 @@ nfc_tag_14a_coll_res_referen_t* get_miafre_coll_res() { void nfc_tag_mf1_reset_handler() { m_mf1_state = MF1_STATE_UNAUTH; m_gen1a_state = GEN1A_STATE_DISABLE; - + +#ifndef NFC_MF1_FAST_SIM // Must to reset pcs handler - crypto1_deinit(pcs); + crypto1_deinit(pcs); +#endif } /** @brief 获得信息结构体存放有效的信息的长度 diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h index f3c97cb..2a8a228 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h @@ -3,6 +3,8 @@ #include "nfc_14a.h" +// Exchange space for time. +#define NFC_MF1_FAST_SIM // Fast simulate enable(Implement By ChameleonMini Repo) #define NFC_TAG_MF1_DATA_SIZE 16 #define NFC_TAG_MF1_FRAME_SIZE (NFC_TAG_MF1_DATA_SIZE + NFC_TAG_14A_CRC_LENGTH)