diff --git a/Firmware/Chameleon-Mini/Application/Crypto1.c b/Firmware/Chameleon-Mini/Application/Crypto1.c index 9af3215..a73ebdb 100644 --- a/Firmware/Chameleon-Mini/Application/Crypto1.c +++ b/Firmware/Chameleon-Mini/Application/Crypto1.c @@ -1,4 +1,5 @@ #include "Crypto1.h" +#include "Common.h" /* avoid compiler complaining at the shift macros */ #pragma GCC diagnostic ignored "-Wuninitialized" @@ -16,157 +17,301 @@ #define LFSR_SIZE 6 /* Bytes */ -const uint8_t TableA[32] PROGMEM = { // for first, third and fourth - 0,0,1,1,0,1,0,0, - 0,1,0,0,1,1,1,1, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0 +/* 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) ) ) \ +) + +/* Create tables from function fa, fb and fc for faster access */ +static const uint8_t TableAB[5][16] = { + { /* fa with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 0 */ + FA(0,0,0,0) << 0, FA(0,0,0,1) << 0, FA(0,0,1,0) << 0, FA(0,0,1,1) << 0, + FA(0,1,0,0) << 0, FA(0,1,0,1) << 0, FA(0,1,1,0) << 0, FA(0,1,1,1) << 0, + FA(1,0,0,0) << 0, FA(1,0,0,1) << 0, FA(1,0,1,0) << 0, FA(1,0,1,1) << 0, + FA(1,1,0,0) << 0, FA(1,1,0,1) << 0, FA(1,1,1,0) << 0, FA(1,1,1,1) << 0, + }, + { /* fb with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 1 */ + FB(0,0,0,0) << 1, FB(0,0,0,1) << 1, FB(0,0,1,0) << 1, FB(0,0,1,1) << 1, + FB(0,1,0,0) << 1, FB(0,1,0,1) << 1, FB(0,1,1,0) << 1, FB(0,1,1,1) << 1, + FB(1,0,0,0) << 1, FB(1,0,0,1) << 1, FB(1,0,1,0) << 1, FB(1,0,1,1) << 1, + FB(1,1,0,0) << 1, FB(1,1,0,1) << 1, FB(1,1,1,0) << 1, FB(1,1,1,1) << 1, + }, + { /* fb with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 2 */ + FB(0,0,0,0) << 2, FB(0,0,0,1) << 2, FB(0,0,1,0) << 2, FB(0,0,1,1) << 2, + FB(0,1,0,0) << 2, FB(0,1,0,1) << 2, FB(0,1,1,0) << 2, FB(0,1,1,1) << 2, + FB(1,0,0,0) << 2, FB(1,0,0,1) << 2, FB(1,0,1,0) << 2, FB(1,0,1,1) << 2, + FB(1,1,0,0) << 2, FB(1,1,0,1) << 2, FB(1,1,1,0) << 2, FB(1,1,1,1) << 2, + }, + { /* fa with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 3 */ + FA(0,0,0,0) << 3, FA(0,0,0,1) << 3, FA(0,0,1,0) << 3, FA(0,0,1,1) << 3, + FA(0,1,0,0) << 3, FA(0,1,0,1) << 3, FA(0,1,1,0) << 3, FA(0,1,1,1) << 3, + FA(1,0,0,0) << 3, FA(1,0,0,1) << 3, FA(1,0,1,0) << 3, FA(1,0,1,1) << 3, + FA(1,1,0,0) << 3, FA(1,1,0,1) << 3, FA(1,1,1,0) << 3, FA(1,1,1,1) << 3, + }, + { /* fb with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 4 */ + FB(0,0,0,0) << 4, FB(0,0,0,1) << 4, FB(0,0,1,0) << 4, FB(0,0,1,1) << 4, + FB(0,1,0,0) << 4, FB(0,1,0,1) << 4, FB(0,1,1,0) << 4, FB(0,1,1,1) << 4, + FB(1,0,0,0) << 4, FB(1,0,0,1) << 4, FB(1,0,1,0) << 4, FB(1,0,1,1) << 4, + FB(1,1,0,0) << 4, FB(1,1,0,1) << 4, FB(1,1,1,0) << 4, FB(1,1,1,1) << 4, + } }; -const uint8_t TableB[32] PROGMEM = { // for second and fifth - 0,0,0,1,1,1,0,0, - 1,0,0,1,1,0,1,1, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0 +static const uint8_t TableC[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), }; -uint32_t StateOdd; -uint32_t StateEven; - -static uint8_t Crypto1ByteAuth(uint8_t In, uint8_t AuthSet) -{ - uint8_t KeyStream = 0; - uint8_t i; - - /* Generate 8 keystream-bits */ - for (i=0; i<8; i++) { - - /* Calculate next bit and add to KeyStream */ - uint8_t Out = Crypto1Bit(In&1,AuthSet); - - In>>=1; - KeyStream>>=1; - if(Out) { - KeyStream |= (1<<7); - } - - } +static uint8_t StateOdd[LFSR_SIZE/2]; +static uint8_t StateEven[LFSR_SIZE/2]; + +uint8_t Crypto1FilterOutput(void) { + /* Calculate the functions fa, fb. + * Note that only bits {4...23} of the odd state + * get fed into these function. + * The tables are designed to hold mask values, which + * can simply be ORed together to produce the resulting + * 5 bits that are used to lookup the output bit. + */ + uint8_t Sum = 0; + + Sum |= TableAB[0][(StateOdd[0] >> 4) & 0x0F]; + Sum |= TableAB[1][(StateOdd[1] >> 0) & 0x0F]; + Sum |= TableAB[2][(StateOdd[1] >> 4) & 0x0F]; + Sum |= TableAB[3][(StateOdd[2] >> 0) & 0x0F]; + Sum |= TableAB[4][(StateOdd[2] >> 4) & 0x0F]; + + return TableC[Sum]; +} - return KeyStream; +/* Proceed LFSR by one clock cycle */ +static void Crypto1LFSR(uint8_t In) { + uint8_t Feedback = 0; + + /* Calculate feedback according to LFSR taps. XOR all 6 state bytes + * into a single bit. */ + Feedback ^= StateEven[0] & (uint8_t) (LFSR_MASK_EVEN >> 0); + Feedback ^= StateEven[1] & (uint8_t) (LFSR_MASK_EVEN >> 8); + Feedback ^= StateEven[2] & (uint8_t) (LFSR_MASK_EVEN >> 16); + + Feedback ^= StateOdd[0] & (uint8_t) (LFSR_MASK_ODD >> 0); + Feedback ^= StateOdd[1] & (uint8_t) (LFSR_MASK_ODD >> 8); + Feedback ^= StateOdd[2] & (uint8_t) (LFSR_MASK_ODD >> 16); + + Feedback ^= Feedback >> 4; + 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. + * For shifting the even state, we convert it into a 32 bit int first */ + uint32_t Temp = 0; + Temp |= ((uint32_t) StateEven[0] << 0); + Temp |= ((uint32_t) StateEven[1] << 8); + Temp |= ((uint32_t) StateEven[2] << 16); + + /* Proceed LFSR. Try to force compiler not to shift the unneded upper bits. */ + Temp = (Temp >> 1) & 0x00FFFFFF; + + /* Calculate MSBit of even state as input bit to LFSR */ + if ( (Feedback & 0x01) ^ In ) { + Temp |= (uint32_t) 1 << (8 * LFSR_SIZE/2 - 1); + } + + /* Convert even state back into byte array and swap odd/even state + * as explained above. */ + StateEven[0] = StateOdd[0]; + StateEven[1] = StateOdd[1]; + StateEven[2] = StateOdd[2]; + + StateOdd[0] = (uint8_t) (Temp >> 0); + StateOdd[1] = (uint8_t) (Temp >> 8); + StateOdd[2] = (uint8_t) (Temp >> 16); } -void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4]) +void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], uint8_t CardNonceParity[4]) { - - StateOdd = 0; - StateEven = 0; - - int i = 0, j = 0; - for(i = 0 ; i < 6 ; i++) { - - for(j = 7 ; j > 0 ; j -= 2) { - StateOdd = StateOdd << 1 | (Key[i]>>((j-1) ^ 7)&1); - StateEven = StateEven << 1 | (Key[i]>>((j) ^ 7)&1); - } - } - - for(i=0; i<4; i++) { - CardNonce[i] ^= Crypto1ByteAuth(Uid[i] ^ CardNonce[i], 0); - } - + uint8_t i; + + /* Again, one trade off when splitting up the state into even/odd parts + * is that loading the key into the state becomes a little more difficult. + * The inner loop generates 8 even and 8 odd bits from 16 key bits and + * the outer loop stores them. */ + for (i=0; i<(LFSR_SIZE/2); i++) { + uint8_t EvenByte = 0; + uint8_t OddByte = 0; + uint16_t KeyWord = ((uint16_t) Key[2*i+1] << 8) | Key[2*i+0]; + + for (uint8_t j=0; j<8; j++) { + EvenByte >>= 1; + OddByte >>= 1; + + if (KeyWord & (1<<0)) { + EvenByte |= 0x80; + } + + if (KeyWord & (1<<1)) { + OddByte |= 0x80; + } + + KeyWord >>= 2; + } + + StateEven[i] = EvenByte; + StateOdd[i] = OddByte; + } + + + /* Use Uid XOR CardNonce as feed-in and do 32 clocks on the + * Crypto1 LFSR.*/ + for (i=0; i<4; i++) { + uint8_t Mask = 1; + uint8_t Keystream = 0; + uint8_t Nonce = CardNonce[i]; + uint8_t Temp = Uid[i] ^ Nonce; + for (uint8_t j=0; j<8; j++, Mask<<=1, Temp>>=1) { + uint8_t Out = Crypto1FilterOutput(); + /* Store the keystream for later use */ + if (Out) + Keystream |= Mask; + Crypto1LFSR(Temp & 0x01); + } + CardNonce[i] = Nonce ^ Keystream; + if (CardNonceParity) + CardNonceParity[i] = ODD_PARITY(Nonce) ^ Crypto1FilterOutput(); + } } void Crypto1Auth(uint8_t EncryptedReaderNonce[4]) { - uint8_t i; - - /* Calculate Authentication on Nonce */ - for(i = 0 ; i < 4 ; i++) { - Crypto1ByteAuth(EncryptedReaderNonce[i],1); - } + uint32_t Temp = 0; + + /* For ease of processing, we convert the encrypted reader nonce + * into a 32 bit integer */ + Temp |= (uint32_t) EncryptedReaderNonce[0] << 0; + Temp |= (uint32_t) EncryptedReaderNonce[1] << 8; + Temp |= (uint32_t) EncryptedReaderNonce[2] << 16; + Temp |= (uint32_t) EncryptedReaderNonce[3] << 24; + + uint8_t i; + + for (i=0; i<32; i++) { + /* Decrypt one output bit of the given encrypted nonce using the + * filter output as keystream. */ + uint8_t Out = Crypto1FilterOutput(); + uint8_t Bit = Out ^ (Temp & 0x01); + + /* Feed back the bit to load the LFSR with the (decrypted) nonce */ + Crypto1LFSR(Bit); + Temp >>= 1; + } } uint8_t Crypto1Byte(void) { - uint8_t KeyStream = 0; - uint8_t i; + uint8_t KeyStream = 0; + uint8_t i; + + /* Generate 8 keystream-bits */ + for (i=0; i<8; i++) { - /* Generate 8 keystream-bits */ - for (i=0; i<8; i++) { + /* Calculate output of function-network and cycle LFSR with no + * additional input, thus linearly! */ + uint8_t Out = Crypto1FilterOutput(); + Crypto1LFSR(0); - /* Calculate next bit and add to KeyStream */ - uint8_t Out = Crypto1Bit(0,0); + /* Store keystream bit */ + KeyStream >>= 1; - KeyStream>>=1; - if(Out) { - KeyStream |= (1<<7); - } - - } + if (Out) { + KeyStream |= (1<<7); + } + } - return KeyStream; + return KeyStream; } uint8_t Crypto1Nibble(void) { - uint8_t KeyStream = 0; - uint8_t i; + uint8_t KeyStream = 0; + uint8_t i; + + /* Generate 4 keystream-bits */ + for (i=0; i<4; i++) { - /* Generate 4 keystream-bits */ - for (i=0; i<4; i++) { + /* Calculate output of function-network and cycle LFSR with no + * additional input, thus linearly! */ + uint8_t Out = Crypto1FilterOutput(); + Crypto1LFSR(0); - /* Calculate next bit and add to KeyStream */ - uint8_t Out = Crypto1Bit(0,0); + /* Store keystream bit */ + KeyStream >>= 1; - KeyStream>>=1; - if(Out) { - KeyStream |= (1<<7); - } - - } + if (Out) { + KeyStream |= (1<<3); + } + } - return KeyStream; + return KeyStream; } void Crypto1PRNG(uint8_t State[4], uint16_t ClockCount) { - while(ClockCount--) { - /* Actually, the PRNG is a 32 bit register with the upper 16 bit - * used as a LFSR. Furthermore only mask-byte 2 contains feedback at all. - * We rely on the compiler to optimize this for us here. - * XOR all tapped bits to a single feedback bit. */ - uint8_t Feedback = 0; - - Feedback ^= State[0] & (uint8_t) (PRNG_MASK >> 0); - Feedback ^= State[1] & (uint8_t) (PRNG_MASK >> 8); - Feedback ^= State[2] & (uint8_t) (PRNG_MASK >> 16); - Feedback ^= State[3] & (uint8_t) (PRNG_MASK >> 24); - - Feedback ^= Feedback >> 4; - Feedback ^= Feedback >> 2; - Feedback ^= Feedback >> 1; - - /* For ease of processing convert the state into a 32 bit integer first */ - uint32_t Temp = 0; - - Temp |= (uint32_t) State[0] << 0; - Temp |= (uint32_t) State[1] << 8; - Temp |= (uint32_t) State[2] << 16; - Temp |= (uint32_t) State[3] << 24; - - /* Cycle LFSR and feed back. */ - Temp >>= 1; - - if (Feedback & 0x01) { - Temp |= (uint32_t) 1 << (8 * PRNG_SIZE - 1); - } - - /* 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); - } + while(ClockCount--) { + /* Actually, the PRNG is a 32 bit register with the upper 16 bit + * used as a LFSR. Furthermore only mask-byte 2 contains feedback at all. + * We rely on the compiler to optimize this for us here. + * XOR all tapped bits to a single feedback bit. */ + uint8_t Feedback = 0; + + Feedback ^= State[0] & (uint8_t) (PRNG_MASK >> 0); + Feedback ^= State[1] & (uint8_t) (PRNG_MASK >> 8); + Feedback ^= State[2] & (uint8_t) (PRNG_MASK >> 16); + Feedback ^= State[3] & (uint8_t) (PRNG_MASK >> 24); + + Feedback ^= Feedback >> 4; + Feedback ^= Feedback >> 2; + Feedback ^= Feedback >> 1; + + /* For ease of processing convert the state into a 32 bit integer first */ + uint32_t Temp = 0; + + Temp |= (uint32_t) State[0] << 0; + Temp |= (uint32_t) State[1] << 8; + Temp |= (uint32_t) State[2] << 16; + Temp |= (uint32_t) State[3] << 24; + + /* Cycle LFSR and feed back. */ + Temp >>= 1; + + if (Feedback & 0x01) { + Temp |= (uint32_t) 1 << (8 * PRNG_SIZE - 1); + } + + /* 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); + } } diff --git a/Firmware/Chameleon-Mini/Application/Crypto1.h b/Firmware/Chameleon-Mini/Application/Crypto1.h index 0b32058..85d673c 100644 --- a/Firmware/Chameleon-Mini/Application/Crypto1.h +++ b/Firmware/Chameleon-Mini/Application/Crypto1.h @@ -2,15 +2,13 @@ #define CRYPTO1_H #include -#include "Crypto1_asm.h" #include -/* 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]); + * the CardNonce in-place while in non-linear mode. + * If CardNonceParity is not null, saves parity for nested authentication */ +void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], uint8_t CardNonceParity[4]); + /* Load the decrypted ReaderNonce into the Crypto1 state LFSR */ void Crypto1Auth(uint8_t EncryptedReaderNonce[4]); @@ -21,10 +19,9 @@ uint8_t Crypto1Byte(void); /* Generate 4 Bits of key stream */ uint8_t Crypto1Nibble(void); -/* Generate 1 Bit of key stream */ -uint8_t Crypto1Bit(uint8_t In, uint8_t AuthFilter); - /* Execute 'ClockCount' cycles on the PRNG state 'State' */ void Crypto1PRNG(uint8_t State[4], uint16_t ClockCount); +uint8_t Crypto1FilterOutput(void); + #endif //CRYPTO1_H diff --git a/Firmware/Chameleon-Mini/Application/Crypto1_asm.S b/Firmware/Chameleon-Mini/Application/Crypto1_asm.S deleted file mode 100644 index 840b407..0000000 --- a/Firmware/Chameleon-Mini/Application/Crypto1_asm.S +++ /dev/null @@ -1,192 +0,0 @@ -#include "Crypto1_asm.h" - -.global Crypto1FilterOutput -.global Crypto1Bit -.global Crypto1Proceed - -Crypto1FilterOutput: ; sped up filter function for crypto1 - push r18 - push r17 ; push registers we want to use - these need to be preserved, try and switch to better ones later - push r16 - lds r22, StateOdd - lds r23, StateOdd+1 - lds r24, StateOdd+2 - mov r21, r22 ; set up each shift value into register - andi r22, 0xf - mov r20, r23 - andi r23, 0xf - andi r24, 0xf - swap r21 - andi r21, 0x0f - swap r20 - andi r20, 0x0f - ldi r17, 0x0a ; set shift constant 0xEC57E80A - not using reserved registers to save push and pop cycles hence the weird choices - ldi r16, 0xe8 - ldi r27, 0x57 - ldi r26, 0xec - ldi ZH, hi8(TableA) ; set up first space for lookup - ldi ZL, lo8(TableA) - add ZL, r22 - adc ZH, r1 - lpm r22, Z - cpi r22, 0 - breq Crypto1FilterOutputEndShiftSixteenBit - mov r16, r26 ; this will shift 16 bits in two operations rather than the ton it usually takes - mov r17, r27 -Crypto1FilterOutputEndShiftSixteenBit: - ldi ZH, hi8(TableB) ; set up first space for lookup - ldi ZL, lo8(TableB) - add ZL, r21 - adc ZH, r1 - lpm r21, Z - cpi r21, 0 - breq Crypto1FilterOutputEndShiftEightBit - mov r17, r16 -Crypto1FilterOutputEndShiftEightBit: - ldi ZH, hi8(TableA) ; set up first space for lookup - ldi ZL, lo8(TableA) - add ZL, r23 - adc ZH, r1 - lpm r23, Z - cpi r23, 0 - breq Crypto1FilterOutputEndShiftFourBit - swap r17 - andi r17, 0x0f ; may not be necessary -Crypto1FilterOutputEndShiftFourBit: - ldi ZH, hi8(TableA) - ldi ZL, lo8(TableA) - add ZL, r20 - adc ZH, r1 - lpm r20, Z - cpi r20, 0 ; if its zero, skip - breq Crypto1FilterOutputEndShiftTwoBit - lsr r17 - lsr r17 -Crypto1FilterOutputEndShiftTwoBit: - ldi ZH, hi8(TableB) - ldi ZL, lo8(TableB) - add ZL, r24 - adc ZH, r1 - lpm r24, Z - cpi r24, 0 - breq Crypto1FilterOutputEndShiftOneBit - lsr r17 -Crypto1FilterOutputEndShiftOneBit: - andi r17, 0x01 - mov r24, r17 - pop r16 - pop r17 - pop r18 - ret - -Crypto1Proceed: - # 16 bit shift - eor r22, r24 - # 8 bit shift - eor r22, r23 - # 4 bit shift - mov r23, r22 - swap r23 - eor r22, r23 - andi r22, 0x0f - # load shift value - endianness different to above to save an operation - ldi r24, 0x96 - ldi r23, 0x69 - # shift value loop - cpi r22, 0 ; if its zero, skip - breq Crypto1ProceedSixteenBitShiftDone -Crypto1ProceedSixteenBitShiftCheck: - lsr r23 - ror r24 - dec r22 - cpi r22, 0 - brne Crypto1ProceedSixteenBitShiftCheck -Crypto1ProceedSixteenBitShiftDone: - andi r24, 0x01 - ret - -Crypto1Bit: - push r24 ; first param - push r22 ; second param - lds r22, (StateOdd) - lds r23, (StateOdd+1) - lds r24, (StateOdd+2) - rcall Crypto1FilterOutput - mov r25, r24 ; r25 contains filter output - r30 and r31 upper bits for calculations - mov r0, r24 - ldi r30, 0x00 - ldi r31, 0x00 - lds r18, (StateEven) - lds r19, (StateEven+1) - lds r20, (StateEven+2) - lds r22, (StateOdd) - lds r23, (StateOdd+1) - lds r24, (StateOdd+2) - pop r26 ; second param - pop r27 ; first param - - and r25, r26 - eor r25, r27 - - push r16 - ; and xor state 1 with 0x29CE5C - ldi r16, 0x5c - and r22, r16 - ldi r16, 0xce - and r23, r16 - ldi r16, 0x29 - and r24, r16 - eor r25, r22 - eor r30, r23 - eor r31, r24 - - ; and xor state 0 with 0x0x870804 - ldi r16, 0x04 - and r18, r16 - ldi r16, 0x08 - and r19, r16 - ldi r16, 0x87 - and r20, r16 - - eor r25, r18 - eor r30, r19 - eor r31, r20 - - ; reload again, seriously need to improve this - lds r18, (StateEven) - lds r19, (StateEven+1) - lds r20, (StateEven+2) - - lsl r18 - rol r19 - rol r20 - - ; use parity function - r22,r23,r24 - push r24 - push r23 - push r22 - mov r22, r25 - mov r23, r30 - mov r24, r31 - rcall Crypto1Proceed - mov r16, r24 - pop r22 - pop r23 - pop r24 - or r18,r16 - pop r16 - lds r22, (StateOdd) - lds r23, (StateOdd+1) - lds r24, (StateOdd+2) - - ; store in opposite registers - sts (StateEven), r22 - sts (StateEven+1), r23 - sts (StateEven+2), r24 - - sts(StateOdd), r18 - sts(StateOdd+1), r19 - sts(StateOdd+2), r20 - - mov r24, r0 - ret \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Application/Crypto1_asm.h b/Firmware/Chameleon-Mini/Application/Crypto1_asm.h deleted file mode 100644 index 8c194e0..0000000 --- a/Firmware/Chameleon-Mini/Application/Crypto1_asm.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef CRYPTO1_ASM_H -#define CRYPTO1_ASM_H - - -#endif diff --git a/Firmware/Chameleon-Mini/Application/MifareClassic.c b/Firmware/Chameleon-Mini/Application/MifareClassic.c index eed9d2c..dbe19b9 100644 --- a/Firmware/Chameleon-Mini/Application/MifareClassic.c +++ b/Firmware/Chameleon-Mini/Application/MifareClassic.c @@ -631,7 +631,7 @@ uint16_t MifareClassicAppProcess(uint8_t* Buffer, uint16_t BitCount) Buffer[i] = CardNonce[i]; /* Setup crypto1 cipher. Discard in-place encrypted CardNonce. */ - Crypto1Setup(Key, Uid, CardNonce); + Crypto1Setup(Key, Uid, CardNonce, NULL); return CMD_AUTH_RB_FRAME_SIZE * BITS_PER_BYTE; } else { @@ -777,6 +777,7 @@ uint16_t MifareClassicAppProcess(uint8_t* Buffer, uint16_t BitCount) uint8_t Key[6]; uint8_t Uid[4]; uint8_t CardNonce[4] = {0x01}; + uint8_t CardNonceParity[4]; /* Generate a random nonce and read UID and key from memory */ //RandomGetBuffer(CardNonce, sizeof(CardNonce)); @@ -799,17 +800,19 @@ uint16_t MifareClassicAppProcess(uint8_t* Buffer, uint16_t BitCount) Crypto1PRNG(CardResponse, 32); - /* Setup crypto1 cipher. */ - Crypto1Setup(Key, Uid, CardNonce); + /* Setup crypto1 cipher for nested authentication. */ + Crypto1Setup(Key, Uid, CardNonce, CardNonceParity); - for (uint8_t i=0; i compile - - compile - compile diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index eb8933f..393dc58 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -102,7 +102,7 @@ OPTIMIZATION = s SRC += $(TARGET).c LUFADescriptors.c System.c Configuration.c Random.c Common.c Memory.c Button.c Settings.c LED.c Map.c AntennaLevel.c Uart.c SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Terminal/CommandLine.c SRC += Codec/Codec.c Codec/ISO14443-2A.c -SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Crypto1_asm.S Application/Detection.c +SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Detection.c SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = src/LUFA/LUFA CC_FLAGS = -Werror -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -DFLASH_DATA_SIZE=$(FLASH_DATA_SIZE) -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) -DBUILD_DATE=$(BUILD_DATE) -DCOMMIT_ID=\"$(COMMIT_ID)\" $(SETTINGS)