1
+ #include "picopass_i.h"
1
2
#include "picopass_poller_i.h"
2
3
3
4
#include "../loclass/optimized_cipher.h"
@@ -95,7 +96,7 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
95
96
instance -> data -> AA1 [PICOPASS_CSN_BLOCK_INDEX ].data [7 ]);
96
97
97
98
PicopassBlock block = {};
98
- error = picopass_poller_read_block (instance , 1 , & block );
99
+ error = picopass_poller_read_block (instance , PICOPASS_CONFIG_BLOCK_INDEX , & block );
99
100
if (error != PicopassErrorNone ) {
100
101
instance -> state = PicopassPollerStateFail ;
101
102
break ;
@@ -116,6 +117,27 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
116
117
instance -> data -> AA1 [PICOPASS_CONFIG_BLOCK_INDEX ].data [6 ],
117
118
instance -> data -> AA1 [PICOPASS_CONFIG_BLOCK_INDEX ].data [7 ]);
118
119
120
+ error = picopass_poller_read_block (instance , PICOPASS_SECURE_EPURSE_BLOCK_INDEX , & block );
121
+ if (error != PicopassErrorNone ) {
122
+ instance -> state = PicopassPollerStateFail ;
123
+ break ;
124
+ }
125
+ memcpy (
126
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data ,
127
+ block .data ,
128
+ sizeof (PicopassBlock ));
129
+ FURI_LOG_D (
130
+ TAG ,
131
+ "epurse %02x%02x%02x%02x%02x%02x%02x%02x" ,
132
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [0 ],
133
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [1 ],
134
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [2 ],
135
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [3 ],
136
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [4 ],
137
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [5 ],
138
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [6 ],
139
+ instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data [7 ]);
140
+
119
141
error = picopass_poller_read_block (instance , 5 , & block );
120
142
if (error != PicopassErrorNone ) {
121
143
instance -> state = PicopassPollerStateFail ;
@@ -165,10 +187,114 @@ NfcCommand picopass_poller_check_security(PicopassPoller* instance) {
165
187
166
188
if (instance -> data -> pacs .se_enabled ) {
167
189
FURI_LOG_D (TAG , "SE enabled" );
168
- instance -> state = PicopassPollerStateFail ;
190
+ instance -> state = PicopassPollerStateNrMacAuth ;
169
191
} else {
170
192
instance -> state = PicopassPollerStateAuth ;
171
193
}
194
+ return command ;
195
+ }
196
+
197
+ NfcCommand picopass_poller_nr_mac_auth (PicopassPoller * instance ) {
198
+ NfcCommand command = NfcCommandContinue ;
199
+ Picopass * picopass = instance -> context ;
200
+ PicopassDevice * dev = picopass -> dev ;
201
+
202
+ uint8_t * csn = instance -> data -> AA1 [PICOPASS_CSN_BLOCK_INDEX ].data ;
203
+ uint8_t * epurse = instance -> data -> AA1 [PICOPASS_SECURE_EPURSE_BLOCK_INDEX ].data ;
204
+
205
+ FuriString * temp_str = furi_string_alloc ();
206
+ FuriString * filename = furi_string_alloc ();
207
+ FlipperFormat * file = flipper_format_file_alloc (dev -> storage );
208
+ PicopassMac mac = {};
209
+
210
+ for (size_t i = 0 ; i < PICOPASS_BLOCK_LEN ; i ++ ) {
211
+ furi_string_cat_printf (filename , "%02x" , csn [i ]);
212
+ }
213
+ furi_string_cat_printf (filename , "_" );
214
+ for (size_t i = 0 ; i < PICOPASS_BLOCK_LEN ; i ++ ) {
215
+ furi_string_cat_printf (filename , "%02x" , epurse [i ]);
216
+ }
217
+
218
+ furi_string_printf (
219
+ temp_str , "%s/%s%s" , STORAGE_APP_DATA_PATH_PREFIX , furi_string_get_cstr (filename ), ".mac" );
220
+
221
+ FURI_LOG_D (TAG , "Looking for %s" , furi_string_get_cstr (temp_str ));
222
+ uint8_t nr_mac [PICOPASS_BLOCK_LEN ];
223
+
224
+ // Presume failure unless all steps are successful and the state is made "read block"
225
+ instance -> state = PicopassPollerStateFail ;
226
+ do {
227
+ //check for file
228
+ if (!flipper_format_file_open_existing (file , furi_string_get_cstr (temp_str ))) break ;
229
+ // FURI_LOG_D(TAG, "Found %s", furi_string_get_cstr(temp_str));
230
+
231
+ furi_string_printf (temp_str , "NR-MAC" );
232
+ if (!flipper_format_read_hex (
233
+ file , furi_string_get_cstr (temp_str ), nr_mac , PICOPASS_BLOCK_LEN ))
234
+ break ;
235
+ memcpy (mac .data , nr_mac + 4 , PICOPASS_MAC_LEN );
236
+ /*
237
+ FURI_LOG_D(
238
+ TAG,
239
+ "Read nr-mac: %02x %02x %02x %02x %02x %02x %02x %02x",
240
+ nr_mac[0],
241
+ nr_mac[1],
242
+ nr_mac[2],
243
+ nr_mac[3],
244
+ nr_mac[4],
245
+ nr_mac[5],
246
+ nr_mac[6],
247
+ nr_mac[7]);
248
+ FURI_LOG_D(
249
+ TAG, "MAC: %02x %02x %02x %02x", mac.data[0], mac.data[1], mac.data[2], mac.data[3]);
250
+ */
251
+
252
+ uint8_t ccnr [12 ] = {};
253
+ PicopassReadCheckResp read_check_resp = {};
254
+ PicopassError error = picopass_poller_read_check (instance , & read_check_resp );
255
+ if (error == PicopassErrorTimeout ) {
256
+ instance -> event .type = PicopassPollerEventTypeCardLost ;
257
+ instance -> callback (instance -> event , instance -> context );
258
+ instance -> state = PicopassPollerStateDetect ;
259
+ break ;
260
+ } else if (error != PicopassErrorNone ) {
261
+ FURI_LOG_E (TAG , "Read check failed: %d" , error );
262
+ break ;
263
+ }
264
+ memcpy (ccnr , read_check_resp .data , sizeof (PicopassReadCheckResp )); // last 4 bytes left 0
265
+
266
+ /*
267
+ FURI_LOG_D(
268
+ TAG,
269
+ "CCNR: %02x %02x %02x %02x %02x %02x %02x %02x",
270
+ ccnr[0],
271
+ ccnr[1],
272
+ ccnr[2],
273
+ ccnr[3],
274
+ ccnr[4],
275
+ ccnr[5],
276
+ ccnr[6],
277
+ ccnr[7]);
278
+ */
279
+
280
+ //use mac
281
+ PicopassCheckResp check_resp = {};
282
+ error = picopass_poller_check (instance , nr_mac , & mac , & check_resp );
283
+ if (error == PicopassErrorNone ) {
284
+ memcpy (instance -> mac .data , mac .data , sizeof (PicopassMac ));
285
+ if (instance -> mode == PicopassPollerModeRead ) {
286
+ picopass_poller_prepare_read (instance );
287
+ instance -> state = PicopassPollerStateReadBlock ;
288
+ // Set to non-zero keys to allow emulation
289
+ memset (instance -> data -> AA1 [PICOPASS_SECURE_KD_BLOCK_INDEX ].data , 0xff , PICOPASS_BLOCK_LEN );
290
+ memset (instance -> data -> AA1 [PICOPASS_SECURE_KC_BLOCK_INDEX ].data , 0xff , PICOPASS_BLOCK_LEN );
291
+ }
292
+ }
293
+
294
+ } while (false);
295
+ furi_string_free (temp_str );
296
+ furi_string_free (filename );
297
+ flipper_format_free (file );
172
298
173
299
return command ;
174
300
}
@@ -234,7 +360,7 @@ NfcCommand picopass_poller_auth_handler(PicopassPoller* instance) {
234
360
loclass_opt_doReaderMAC (ccnr , div_key , mac .data );
235
361
236
362
PicopassCheckResp check_resp = {};
237
- error = picopass_poller_check (instance , & mac , & check_resp );
363
+ error = picopass_poller_check (instance , NULL , & mac , & check_resp );
238
364
if (error == PicopassErrorNone ) {
239
365
FURI_LOG_I (TAG , "Found key" );
240
366
memcpy (instance -> mac .data , mac .data , sizeof (PicopassMac ));
@@ -457,6 +583,7 @@ static const PicopassPollerStateHandler picopass_poller_state_handler[PicopassPo
457
583
[PicopassPollerStateSelect ] = picopass_poller_select_handler ,
458
584
[PicopassPollerStatePreAuth ] = picopass_poller_pre_auth_handler ,
459
585
[PicopassPollerStateCheckSecurity ] = picopass_poller_check_security ,
586
+ [PicopassPollerStateNrMacAuth ] = picopass_poller_nr_mac_auth ,
460
587
[PicopassPollerStateAuth ] = picopass_poller_auth_handler ,
461
588
[PicopassPollerStateReadBlock ] = picopass_poller_read_block_handler ,
462
589
[PicopassPollerStateWriteBlock ] = picopass_poller_write_block_handler ,
0 commit comments