-
Notifications
You must be signed in to change notification settings - Fork 208
/
Copy pathmifare_classic.ksy
250 lines (242 loc) · 6.88 KB
/
mifare_classic.ksy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
meta:
id: mifare_classic
title: Mifare Classic RFID tag dump
file-extension: mfd
xref:
wikidata:
- Q29000512 # MIFARE Classic 1k
- Q29000513 # MIFARE Classic 4k
license: BSD-2-Clause
ks-version: 0.9
endian: le
doc-ref: |
https://github.com/nfc-tools/libnfc
https://www.nxp.com/docs/en/data-sheet/MF1S70YYX_V1.pdf
doc: |
You can get a dump for testing from this link:
<https://github.com/zhovner/mfdread/raw/master/dump.mfd>
seq:
- id: sectors
size: ((_index >= 32)?4:1)*4*16 #sorry for this doubling of `block_size` (16), but we need `sector` be self-sufficient so we cannot use _root there
type: sector(_index == 0)
repeat: eos
types:
key:
seq:
- id: key
size: 6
sector:
params:
- id: has_manufacturer
type: bool
seq:
- id: manufacturer
type: manufacturer
if: has_manufacturer
- id: data_filler
-orig-id: abtData
size: _io.size - _io.pos - 16 # sizeof(trailer)
type: filler
- id: trailer
type: trailer
instances:
block_size:
value: 16
data:
value: data_filler.data
blocks:
pos: 0
io: data_filler._io
size: block_size
repeat: eos
values:
pos: 0
io: data_filler._io
type: values
types:
values:
seq:
- id: values
type: value_block
repeat: eos
types:
value_block:
seq:
- id: valuez
type: u4
repeat: expr
repeat-expr: 3
- id: addrz
type: u1
repeat: expr
repeat-expr: 4
instances:
value_valid:
value: 'valuez[0]==~valuez[1] and valuez[0]==valuez[2]'
addr_valid:
value: 'addrz[0]==~addrz[1] and addrz[0]==addrz[2] and addrz[1]==addrz[3]'
valid:
value: 'value_valid and addr_valid'
addr:
value: 'addrz[0]'
if: valid
value:
value: valuez[0]
if: valid
filler:
doc: "only to create _io"
seq:
- id: data
size: _io.size
manufacturer:
seq:
- id: nuid
-orig-id: abtUID
type: u4
doc: beware for 7bytes UID it goes over next fields
- id: bcc
-orig-id: btBCC
type: u1
- id: sak # beware it's not always exactly SAK
-orig-id: btSAK
type: u1
- id: atqa
-orig-id: abtATQA
type: u2
- id: manufacturer
-orig-id: abtManufacturer
size: 8
doc: may contain manufacture date as BCD
trailer:
seq:
- id: key_a
-orig-id: abtKeyA
type: key
- id: access_bits
-orig-id: abtAccessBits
size: 3
type: access_conditions
- id: user_byte
-orig-id: abtAccessBits
type: u1
- id: key_b
-orig-id: abtKeyB
type: key
instances:
ac_bits:
value: 3
acs_in_sector:
value: 4
ac_count_of_chunks:
value: ac_bits*2 #6
types:
access_conditions:
seq:
- id: raw_chunks
type: b4 # _parent.acs_in_sector
repeat: expr
repeat-expr: _parent.ac_count_of_chunks
instances:
remaps:
pos: 0
repeat: expr
repeat-expr: _parent.ac_bits
type: chunk_bit_remap(_index)
chunks:
pos: 0
type: valid_chunk(raw_chunks[remaps[_index].inv_chunk_no], raw_chunks[remaps[_index].chunk_no])
repeat: expr
repeat-expr: _parent.ac_bits
acs_raw:
pos: 0
type: ac(_index)
repeat: expr
repeat-expr: _parent.acs_in_sector
data_acs:
pos: 0
type: data_ac(acs_raw[_index])
repeat: expr
repeat-expr: _parent.acs_in_sector-1
trailer_ac:
pos: 0
type: trailer_ac(acs_raw[_parent.acs_in_sector-1])
types:
chunk_bit_remap:
params:
- id: bit_no
type: u1
instances:
shift_value:
value: (bit_no==1?-1:1)
chunk_no:
value: '((inv_chunk_no+shift_value+_parent._parent.ac_count_of_chunks)%_parent._parent.ac_count_of_chunks)'
inv_chunk_no:
value: 'bit_no+shift_value'
valid_chunk:
params:
- id: inv_chunk
type: u1
- id: chunk
type: u1
doc: "c3 c2 c1 c0"
instances:
valid:
value: inv_chunk ^ chunk == 0b1111
ac:
params:
- id: index
type: u1
instances:
bits:
pos: 0
repeat: expr
repeat-expr: _parent._parent.ac_bits
type: ac_bit(index, _parent.chunks[_index].chunk)
val:
value: (bits[2].n << 2) | (bits[1].n << 1) | bits[0].n
doc: "c3 c2 c1"
inv_shift_val:
value: (bits[0].n << 2) | (bits[1].n << 1) | bits[2].n
types:
ac_bit:
params:
- id: i
type: u1
- id: chunk
type: u1
instances:
n:
value: (chunk >> i) & 1
b:
value: n == 1
trailer_ac:
params:
- id: ac
type: ac
instances:
can_read_key_b:
value: ac.inv_shift_val <= 0b010
doc: key A is required
can_write_keys:
value: "(ac.inv_shift_val+1)%3 != 0 and (ac.inv_shift_val<6)"
can_write_access_bits:
value: ac.bits[2].b
key_b_controls_write:
value: not can_read_key_b
data_ac:
params:
- id: ac
type: ac
instances:
read_key_a_required:
value: ac.val <= 0b100
read_key_b_required:
value: ac.val <= 0b110
write_key_a_required:
value: ac.val == 0
write_key_b_required:
value: (not read_key_a_required or read_key_b_required) and not ac.bits[0].b
increment_available:
value: (not ac.bits[0].b and not read_key_a_required and not read_key_b_required) or (not ac.bits[0].b and read_key_a_required and read_key_b_required)
decrement_available:
value: (ac.bits[1].b or not ac.bits[0].b) and not ac.bits[2].b