1
+ #ifndef CRYPTO1_H
2
+ #define CRYPTO1_H
3
+
4
+ #include <inttypes.h>
5
+ #include "mfkey.h"
6
+ #include <nfc/protocols/mf_classic/mf_classic.h>
7
+
8
+ #define LF_POLY_ODD (0x29CE5C)
9
+ #define LF_POLY_EVEN (0x870804)
10
+ #define BIT (x , n ) ((x) >> (n) & 1)
11
+ #define BEBIT (x , n ) BIT(x, (n) ^ 24)
12
+ #define SWAPENDIAN (x ) \
13
+ ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
14
+
15
+ static inline uint32_t prng_successor (uint32_t x , uint32_t n );
16
+ static inline int filter (uint32_t const x );
17
+ static inline uint8_t evenparity32 (uint32_t x );
18
+ static inline void update_contribution (unsigned int data [], int item , int mask1 , int mask2 );
19
+ void crypto1_get_lfsr (struct Crypto1State * state , MfClassicKey * lfsr );
20
+ static inline uint32_t crypt_word (struct Crypto1State * s );
21
+ static inline void crypt_word_noret (struct Crypto1State * s , uint32_t in , int x );
22
+ static inline uint32_t crypt_word_ret (struct Crypto1State * s , uint32_t in , int x );
23
+ static inline void rollback_word_noret (struct Crypto1State * s , uint32_t in , int x );
24
+
25
+ static const uint8_t lookup1 [256 ] = {
26
+ 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 , 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 ,
27
+ 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 , 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 ,
28
+ 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 , 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 ,
29
+ 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 , 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 ,
30
+ 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 , 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 ,
31
+ 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 ,
32
+ 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 , 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 ,
33
+ 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 ,
34
+ 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 , 0 , 0 , 16 , 16 , 0 , 16 , 0 , 0 ,
35
+ 0 , 16 , 0 , 0 , 16 , 16 , 16 , 16 , 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 ,
36
+ 8 , 8 , 24 , 24 , 8 , 24 , 8 , 8 , 8 , 24 , 8 , 8 , 24 , 24 , 24 , 24 };
37
+ static const uint8_t lookup2 [256 ] = {
38
+ 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 , 4 , 4 , 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 ,
39
+ 4 , 4 , 4 , 2 , 2 , 6 , 6 , 2 , 6 , 2 , 2 , 2 , 6 , 2 , 2 , 6 , 6 , 6 , 6 , 2 , 2 , 6 , 6 , 2 , 6 , 2 , 2 , 2 , 6 ,
40
+ 2 , 2 , 6 , 6 , 6 , 6 , 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 , 4 , 4 , 2 , 2 , 6 , 6 , 2 , 6 , 2 ,
41
+ 2 , 2 , 6 , 2 , 2 , 6 , 6 , 6 , 6 , 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 , 4 , 4 , 0 , 0 , 4 , 4 ,
42
+ 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 , 4 , 4 , 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 , 4 , 4 , 2 ,
43
+ 2 , 6 , 6 , 2 , 6 , 2 , 2 , 2 , 6 , 2 , 2 , 6 , 6 , 6 , 6 , 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 ,
44
+ 4 , 4 , 0 , 0 , 4 , 4 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 4 , 4 , 4 , 4 , 2 , 2 , 6 , 6 , 2 , 6 , 2 , 2 , 2 , 6 , 2 ,
45
+ 2 , 6 , 6 , 6 , 6 , 2 , 2 , 6 , 6 , 2 , 6 , 2 , 2 , 2 , 6 , 2 , 2 , 6 , 6 , 6 , 6 , 2 , 2 , 6 , 6 , 2 , 6 , 2 , 2 ,
46
+ 2 , 6 , 2 , 2 , 6 , 6 , 6 , 6 , 2 , 2 , 6 , 6 , 2 , 6 , 2 , 2 , 2 , 6 , 2 , 2 , 6 , 6 , 6 , 6 };
47
+
48
+ static inline int filter (uint32_t const x ) {
49
+ uint32_t f ;
50
+ f = lookup1 [x & 0xff ] | lookup2 [(x >> 8 ) & 0xff ];
51
+ f |= 0x0d938 >> (x >> 16 & 0xf ) & 1 ;
52
+ return BIT (0xEC57E80A , f );
53
+ }
54
+
55
+ #ifndef __ARM_ARCH_7EM__
56
+ static inline uint8_t evenparity32 (uint32_t x ) {
57
+ return __builtin_parity (x );
58
+ }
59
+ #endif
60
+
61
+ #ifdef __ARM_ARCH_7EM__
62
+ static inline uint8_t evenparity32 (uint32_t x ) {
63
+ uint32_t result ;
64
+ __asm__ volatile ("eor r1, %[x], %[x], lsr #16 \n\t" // r1 = x ^ (x >> 16)
65
+ "eor r1, r1, r1, lsr #8 \n\t" // r1 = r1 ^ (r1 >> 8)
66
+ "eor r1, r1, r1, lsr #4 \n\t" // r1 = r1 ^ (r1 >> 4)
67
+ "eor r1, r1, r1, lsr #2 \n\t" // r1 = r1 ^ (r1 >> 2)
68
+ "eor r1, r1, r1, lsr #1 \n\t" // r1 = r1 ^ (r1 >> 1)
69
+ "and %[result], r1, #1 \n\t" // result = r1 & 1
70
+ : [result ] "=r" (result )
71
+ : [x ] "r" (x )
72
+ : "r1" );
73
+ return result ;
74
+ }
75
+ #endif
76
+
77
+ static inline void update_contribution (unsigned int data [], int item , int mask1 , int mask2 ) {
78
+ int p = data [item ] >> 25 ;
79
+ p = p << 1 | evenparity32 (data [item ] & mask1 );
80
+ p = p << 1 | evenparity32 (data [item ] & mask2 );
81
+ data [item ] = p << 24 | (data [item ] & 0xffffff );
82
+ }
83
+
84
+ static inline uint32_t crypt_word (struct Crypto1State * s ) {
85
+ // "in" and "x" are always 0 (last iteration)
86
+ uint32_t res_ret = 0 ;
87
+ uint32_t feedin , t ;
88
+ for (int i = 0 ; i <= 31 ; i ++ ) {
89
+ res_ret |= (filter (s -> odd ) << (24 ^ i )); //-V629
90
+ feedin = LF_POLY_EVEN & s -> even ;
91
+ feedin ^= LF_POLY_ODD & s -> odd ;
92
+ s -> even = s -> even << 1 | (evenparity32 (feedin ));
93
+ t = s -> odd , s -> odd = s -> even , s -> even = t ;
94
+ }
95
+ return res_ret ;
96
+ }
97
+
98
+ static inline void crypt_word_noret (struct Crypto1State * s , uint32_t in , int x ) {
99
+ uint8_t ret ;
100
+ uint32_t feedin , t , next_in ;
101
+ for (int i = 0 ; i <= 31 ; i ++ ) {
102
+ next_in = BEBIT (in , i );
103
+ ret = filter (s -> odd );
104
+ feedin = ret & (!!x );
105
+ feedin ^= LF_POLY_EVEN & s -> even ;
106
+ feedin ^= LF_POLY_ODD & s -> odd ;
107
+ feedin ^= !!next_in ;
108
+ s -> even = s -> even << 1 | (evenparity32 (feedin ));
109
+ t = s -> odd , s -> odd = s -> even , s -> even = t ;
110
+ }
111
+ return ;
112
+ }
113
+
114
+ static inline uint32_t crypt_word_ret (struct Crypto1State * s , uint32_t in , int x ) {
115
+ uint32_t ret = 0 ;
116
+ uint32_t feedin , t , next_in ;
117
+ uint8_t next_ret ;
118
+ for (int i = 0 ; i <= 31 ; i ++ ) {
119
+ next_in = BEBIT (in , i );
120
+ next_ret = filter (s -> odd );
121
+ feedin = next_ret & (!!x );
122
+ feedin ^= LF_POLY_EVEN & s -> even ;
123
+ feedin ^= LF_POLY_ODD & s -> odd ;
124
+ feedin ^= !!next_in ;
125
+ s -> even = s -> even << 1 | (evenparity32 (feedin ));
126
+ t = s -> odd , s -> odd = s -> even , s -> even = t ;
127
+ ret |= next_ret << (24 ^ i );
128
+ }
129
+ return ret ;
130
+ }
131
+
132
+ static inline void rollback_word_noret (struct Crypto1State * s , uint32_t in , int x ) {
133
+ uint8_t ret ;
134
+ uint32_t feedin , t , next_in ;
135
+ for (int i = 31 ; i >= 0 ; i -- ) {
136
+ next_in = BEBIT (in , i );
137
+ s -> odd &= 0xffffff ;
138
+ t = s -> odd , s -> odd = s -> even , s -> even = t ;
139
+ ret = filter (s -> odd );
140
+ feedin = ret & (!!x );
141
+ feedin ^= s -> even & 1 ;
142
+ feedin ^= LF_POLY_EVEN & (s -> even >>= 1 );
143
+ feedin ^= LF_POLY_ODD & s -> odd ;
144
+ feedin ^= !!next_in ;
145
+ s -> even |= (evenparity32 (feedin )) << 23 ;
146
+ }
147
+ return ;
148
+ }
149
+
150
+ static inline uint32_t prng_successor (uint32_t x , uint32_t n ) {
151
+ SWAPENDIAN (x );
152
+ while (n -- ) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21 ) << 31 ;
153
+ return SWAPENDIAN (x );
154
+ }
155
+
156
+ #endif // CRYPTO1_H
0 commit comments