Skip to content

Commit 3ee5280

Browse files
committed
upd seader
1 parent 3659155 commit 3ee5280

22 files changed

+1590
-84
lines changed

non_catalog_apps/seader/application.fam

+6-1
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,24 @@ App(
1717
],
1818
fap_icon="icons/logo.png",
1919
fap_category="NFC",
20-
fap_version="2.0",
20+
fap_version="2.1",
2121
fap_author="bettse",
2222
# fap_extbuild=(
2323
# ExtFile(
2424
# path="${FAP_SRC_DIR}/lib/asn1/asn_system.h",
2525
# command="asn1c -D ${FAP_SRC_DIR}/lib/asn1 -no-gen-example -pdu=all ${FAP_SRC_DIR}/seader.asn1"
2626
# ),
2727
# ),
28+
fap_libs=["mbedtls"],
2829
fap_private_libs=[
2930
Lib(
3031
name="asn1",
3132
cflags=["-Wno-error"],
3233
),
34+
Lib(
35+
name="loclass",
36+
cflags=["-O3"],
37+
),
3338
],
3439
fap_weburl="https://seader.ericbetts.dev",
3540
fap_icon_assets="icons",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
//-----------------------------------------------------------------------------
2+
// Borrowed initially from https://github.com/holiman/loclass
3+
// Copyright (C) 2014 Martin Holst Swende
4+
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
5+
//
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
//
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
//
16+
// See LICENSE.txt for the text of the license.
17+
//-----------------------------------------------------------------------------
18+
// WARNING
19+
//
20+
// THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
21+
//
22+
// USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
23+
// PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
24+
// AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
25+
//
26+
// THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
27+
//-----------------------------------------------------------------------------
28+
// It is a reconstruction of the cipher engine used in iClass, and RFID techology.
29+
//
30+
// The implementation is based on the work performed by
31+
// Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
32+
// Milosch Meriac in the paper "Dismantling IClass".
33+
//-----------------------------------------------------------------------------
34+
/*
35+
This file contains an optimized version of the MAC-calculation algorithm. Some measurements on
36+
a std laptop showed it runs in about 1/3 of the time:
37+
38+
Std: 0.428962
39+
Opt: 0.151609
40+
41+
Additionally, it is self-reliant, not requiring e.g. bitstreams from the cipherutils, thus can
42+
be easily dropped into a code base.
43+
44+
The optimizations have been performed in the following steps:
45+
* Parameters passed by reference instead of by value.
46+
* Iteration instead of recursion, un-nesting recursive loops into for-loops.
47+
* Handling of bytes instead of individual bits, for less shuffling and masking
48+
* Less creation of "objects", structs, and instead reuse of alloc:ed memory
49+
* Inlining some functions via #define:s
50+
51+
As a consequence, this implementation is less generic. Also, I haven't bothered documenting this.
52+
For a thorough documentation, check out the MAC-calculation within cipher.c instead.
53+
54+
-- MHS 2015
55+
**/
56+
57+
/**
58+
59+
The runtime of opt_doTagMAC_2() with the MHS optimized version was 403 microseconds on Proxmark3.
60+
This was still to slow for some newer readers which didn't want to wait that long.
61+
62+
Further optimizations to speedup the MAC calculations:
63+
* Optimized opt_Tt logic
64+
* Look up table for opt_select
65+
* Removing many unnecessary bit maskings (& 0x1)
66+
* updating state in place instead of alternating use of a second state structure
67+
* remove the necessity to reverse bits of input and output bytes
68+
69+
opt_doTagMAC_2() now completes in 270 microseconds.
70+
71+
-- piwi 2019
72+
**/
73+
74+
/**
75+
add the possibility to do iCLASS on device only
76+
-- iceman 2020
77+
**/
78+
79+
#include "optimized_cipher.h"
80+
#include "optimized_elite.h"
81+
#include "optimized_ikeys.h"
82+
#include "optimized_cipherutils.h"
83+
84+
static const uint8_t loclass_opt_select_LUT[256] = {
85+
00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, 01, 02, 03, 00, 02, 03, 00, 01,
86+
05, 06, 06, 05, 06, 07, 05, 04, 06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06,
87+
07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06, 06, 05, 04, 07, 04, 05, 06, 07,
88+
02, 01, 01, 02, 00, 01, 03, 02, 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06,
89+
00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00, 05, 06, 07, 04, 06, 07, 04, 05,
90+
05, 06, 06, 05, 06, 07, 05, 04, 02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06,
91+
03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, 02, 01, 00, 03, 00, 01, 02, 03,
92+
02, 01, 01, 02, 00, 01, 03, 02, 03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02,
93+
04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00, 01, 02, 03, 00, 02, 03, 00, 01,
94+
05, 06, 06, 05, 06, 07, 05, 04, 04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04,
95+
01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00};
96+
97+
/********************** the table above has been generated with this code: ********
98+
#include "util.h"
99+
static void init_opt_select_LUT(void) {
100+
for (int r = 0; r < 256; r++) {
101+
uint8_t r_ls2 = r << 2;
102+
uint8_t r_and_ls2 = r & r_ls2;
103+
uint8_t r_or_ls2 = r | r_ls2;
104+
uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3);
105+
uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r;
106+
uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r;
107+
loclass_opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1);
108+
}
109+
print_result("", loclass_opt_select_LUT, 256);
110+
}
111+
***********************************************************************************/
112+
113+
static inline void loclass_opt_successor(const uint8_t* k, LoclassState_t* s, uint8_t y) {
114+
uint16_t Tt = s->t & 0xc533;
115+
Tt = Tt ^ (Tt >> 1);
116+
Tt = Tt ^ (Tt >> 4);
117+
Tt = Tt ^ (Tt >> 10);
118+
Tt = Tt ^ (Tt >> 8);
119+
120+
s->t = (s->t >> 1);
121+
s->t |= (Tt ^ (s->r >> 7) ^ (s->r >> 3)) << 15;
122+
123+
uint8_t opt_B = s->b;
124+
opt_B ^= s->b >> 6;
125+
opt_B ^= s->b >> 5;
126+
opt_B ^= s->b >> 4;
127+
128+
s->b = s->b >> 1;
129+
s->b |= (opt_B ^ s->r) << 7;
130+
131+
uint8_t Tt1 = Tt & 0x01;
132+
uint8_t opt_select = loclass_opt_select_LUT[s->r] ^ Tt1 ^ ((Tt1 ^ (y & 0x01)) << 1);
133+
134+
uint8_t r = s->r;
135+
s->r = (k[opt_select] ^ s->b) + s->l;
136+
s->l = s->r + r;
137+
}
138+
139+
static inline void loclass_opt_suc(
140+
const uint8_t* k,
141+
LoclassState_t* s,
142+
const uint8_t* in,
143+
uint8_t length,
144+
bool add32Zeroes) {
145+
for(int i = 0; i < length; i++) {
146+
uint8_t head = in[i];
147+
#pragma GCC unroll 8
148+
for(int j = 0; j < 8; j++) {
149+
loclass_opt_successor(k, s, head);
150+
head >>= 1;
151+
}
152+
}
153+
// For tag MAC, an additional 32 zeroes
154+
if(add32Zeroes) {
155+
for(int i = 0; i < 32; i++) {
156+
loclass_opt_successor(k, s, 0);
157+
}
158+
}
159+
}
160+
161+
static inline void loclass_opt_output(const uint8_t* k, LoclassState_t* s, uint8_t* buffer) {
162+
#pragma GCC unroll 4
163+
for(uint8_t times = 0; times < 4; times++) {
164+
uint8_t bout = 0;
165+
bout |= (s->r & 0x4) >> 2;
166+
loclass_opt_successor(k, s, 0);
167+
bout |= (s->r & 0x4) >> 1;
168+
loclass_opt_successor(k, s, 0);
169+
bout |= (s->r & 0x4);
170+
loclass_opt_successor(k, s, 0);
171+
bout |= (s->r & 0x4) << 1;
172+
loclass_opt_successor(k, s, 0);
173+
bout |= (s->r & 0x4) << 2;
174+
loclass_opt_successor(k, s, 0);
175+
bout |= (s->r & 0x4) << 3;
176+
loclass_opt_successor(k, s, 0);
177+
bout |= (s->r & 0x4) << 4;
178+
loclass_opt_successor(k, s, 0);
179+
bout |= (s->r & 0x4) << 5;
180+
loclass_opt_successor(k, s, 0);
181+
buffer[times] = bout;
182+
}
183+
}
184+
185+
static void loclass_opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out) {
186+
LoclassState_t _init = {
187+
((k[0] ^ 0x4c) + 0xEC) & 0xFF, // l
188+
((k[0] ^ 0x4c) + 0x21) & 0xFF, // r
189+
0x4c, // b
190+
0xE012 // t
191+
};
192+
193+
loclass_opt_suc(k, &_init, input, 12, false);
194+
loclass_opt_output(k, &_init, out);
195+
}
196+
197+
static void loclass_opt_MAC_N(uint8_t* k, uint8_t* input, uint8_t in_size, uint8_t* out) {
198+
LoclassState_t _init = {
199+
((k[0] ^ 0x4c) + 0xEC) & 0xFF, // l
200+
((k[0] ^ 0x4c) + 0x21) & 0xFF, // r
201+
0x4c, // b
202+
0xE012 // t
203+
};
204+
205+
loclass_opt_suc(k, &_init, input, in_size, false);
206+
loclass_opt_output(k, &_init, out);
207+
}
208+
209+
void loclass_opt_doReaderMAC(uint8_t* cc_nr_p, uint8_t* div_key_p, uint8_t mac[4]) {
210+
uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0};
211+
loclass_opt_MAC(div_key_p, cc_nr_p, dest);
212+
memcpy(mac, dest, 4);
213+
}
214+
215+
void loclass_opt_doReaderMAC_2(
216+
LoclassState_t _init,
217+
uint8_t* nr,
218+
uint8_t mac[4],
219+
const uint8_t* div_key_p) {
220+
loclass_opt_suc(div_key_p, &_init, nr, 4, false);
221+
loclass_opt_output(div_key_p, &_init, mac);
222+
}
223+
224+
void loclass_doMAC_N(uint8_t* in_p, uint8_t in_size, uint8_t* div_key_p, uint8_t mac[4]) {
225+
uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0};
226+
loclass_opt_MAC_N(div_key_p, in_p, in_size, dest);
227+
memcpy(mac, dest, 4);
228+
}
229+
230+
void loclass_opt_doTagMAC(uint8_t* cc_p, const uint8_t* div_key_p, uint8_t mac[4]) {
231+
LoclassState_t _init = {
232+
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF, // l
233+
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF, // r
234+
0x4c, // b
235+
0xE012 // t
236+
};
237+
loclass_opt_suc(div_key_p, &_init, cc_p, 12, true);
238+
loclass_opt_output(div_key_p, &_init, mac);
239+
}
240+
241+
/**
242+
* The tag MAC can be divided (both can, but no point in dividing the reader mac) into
243+
* two functions, since the first 8 bytes are known, we can pre-calculate the state
244+
* reached after feeding CC to the cipher.
245+
* @param cc_p
246+
* @param div_key_p
247+
* @return the cipher state
248+
*/
249+
LoclassState_t loclass_opt_doTagMAC_1(uint8_t* cc_p, const uint8_t* div_key_p) {
250+
LoclassState_t _init = {
251+
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF, // l
252+
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF, // r
253+
0x4c, // b
254+
0xE012 // t
255+
};
256+
loclass_opt_suc(div_key_p, &_init, cc_p, 8, false);
257+
return _init;
258+
}
259+
260+
/**
261+
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
262+
* this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag
263+
* MAC response.
264+
* @param _init - precalculated cipher state
265+
* @param nr - the reader challenge
266+
* @param mac - where to store the MAC
267+
* @param div_key_p - the key to use
268+
*/
269+
void loclass_opt_doTagMAC_2(
270+
LoclassState_t _init,
271+
uint8_t* nr,
272+
uint8_t mac[4],
273+
const uint8_t* div_key_p) {
274+
loclass_opt_suc(div_key_p, &_init, nr, 4, true);
275+
loclass_opt_output(div_key_p, &_init, mac);
276+
}
277+
278+
/**
279+
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
280+
* this function is fed only the NR, and generates both the reader and tag MACs.
281+
* @param _init - precalculated cipher state
282+
* @param nr - the reader challenge
283+
* @param rmac - where to store the reader MAC
284+
* @param tmac - where to store the tag MAC
285+
* @param div_key_p - the key to use
286+
*/
287+
void loclass_opt_doBothMAC_2(
288+
LoclassState_t _init,
289+
uint8_t* nr,
290+
uint8_t rmac[4],
291+
uint8_t tmac[4],
292+
const uint8_t* div_key_p) {
293+
LoclassState_t* s = &_init;
294+
loclass_opt_suc(div_key_p, s, nr, 4, false);
295+
loclass_opt_output(div_key_p, s, rmac);
296+
loclass_opt_output(div_key_p, s, tmac);
297+
}
298+
299+
void loclass_iclass_calc_div_key(
300+
const uint8_t* csn,
301+
const uint8_t* key,
302+
uint8_t* div_key,
303+
bool elite) {
304+
if(elite) {
305+
uint8_t keytable[128] = {0};
306+
uint8_t key_index[8] = {0};
307+
uint8_t key_sel[8] = {0};
308+
uint8_t key_sel_p[8] = {0};
309+
loclass_hash2(key, keytable);
310+
loclass_hash1(csn, key_index);
311+
for(uint8_t i = 0; i < 8; i++) key_sel[i] = keytable[key_index[i]];
312+
313+
//Permute from iclass format to standard format
314+
loclass_permutekey_rev(key_sel, key_sel_p);
315+
loclass_diversifyKey(csn, key_sel_p, div_key);
316+
} else {
317+
loclass_diversifyKey(csn, key, div_key);
318+
}
319+
}

0 commit comments

Comments
 (0)