#include "Crypto1.h" /* avoid compiler complaining at the shift macros */ #pragma GCC diagnostic ignored "-Wuninitialized" // 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 /* Buffer size and parity offset */ #include "../Codec/ISO14443-2A.h" /* Table lookup for odd parity */ #include "../Common.h" /* 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 */ /* avoid including avr-Files in case of test */ #ifndef CODEC_BUFFER_SIZE #define CODEC_BUFFER_SIZE 256 #endif #ifndef ISO14443A_BUFFER_PARITY_OFFSET #define ISO14443A_BUFFER_PARITY_OFFSET (CODEC_BUFFER_SIZE/2) #endif #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) #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) /* Generate odd parity bit */ #define ODD_PARITY(val) \ (__extension__({ \ uint8_t __p = (uint8_t)(val); \ __p ^= ((__p >> 4)|(__p << 4)) ; \ __p ^= __p >> 2 ; \ ((--__p) >> 1) & 1; /* see "avr/util.h" */ \ })) #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) { register uint8_t Temp0, Temp1, Temp2; uint8_t Feedback; /* 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, Even1, Even2; register uint8_t Odd0, Odd1, Odd2; uint8_t KeyStream; uint8_t Feedback; uint8_t Out; uint8_t In; uint8_t 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); /* Encrypt Nonce */ *CardNonce++ ^= KeyStream; /* Encrypt 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[8], bool Decrypt) { /* state registers */ register uint8_t Even0, Even1, Even2; register uint8_t Odd0, Odd1, Odd2; uint8_t KeyStream; uint8_t Feedback; uint8_t Out; uint8_t In; uint8_t 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); CardNonce[NONCE_SIZE] = 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; uint8_t Feedback; uint8_t 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; uint8_t Feedback; uint8_t 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); } /* 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 = 0; uint8_t Feedback; uint8_t 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 Count) { /* state registers */ register uint8_t Even0, Even1, Even2; register uint8_t Odd0, Odd1, Odd2; uint8_t KeyStream = 0; uint8_t Feedback; uint8_t 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); Buffer[ISO14443A_BUFFER_PARITY_OFFSET] = 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); } 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); } } }