dump manufacturer block
[perl-Mifare-MAD.git] / mifare-mad.pl
1 #!/usr/bin/perl
2
3 use warnings;
4 use strict;
5
6 # based on AN10787
7 # MIFARE Application Directory (MAD)
8 # http://www.nxp.com/acrobat_download2/other/identification/MAD_overview.pdf
9
10 use Data::Dump qw(dump);
11
12 my $debug = $ENV{DEBUG} || 0;
13
14 my $function_clusters;
15 my $mad_id;
16
17 while(<DATA>) {
18         chomp;
19         next if m/^#?\s*$/;
20         my ( $code, $function ) = split(/\s+/,$_,2);
21         my $h = '[0-9A-F]';
22         if ( $code =~ m/^($h{2})-($h{2})$/ ) {
23                 foreach my $c ( hex($1) .. hex($2) ) {
24                         $function_clusters->{ unpack('HH',$c) } = $function;
25                 }
26         } elsif ( $code =~ m/^($h{2})$/ ) {
27                 $function_clusters->{ lc $code } = $function;
28         } elsif ( $code =~ m/^($h{4})$/ ) {
29                 $mad_id->{ lc $1 } = $function;
30         } else {
31                 die "can't parse __DATA__ line $.\n$_\n";
32         }
33 }
34
35 my $access_condition_data = {
36 0b000 => 'R:AB W:AB I:AB DTR:AB',
37 0b010 => 'R:AB W:-- I:-- DTR:--',
38 0b100 => 'R:AB W:-B I:-- DTR:--', 
39 0b110 => 'R:AB W:-B I:-B DTR:AB',
40 0b001 => 'R:AB W:-- I:-- DTR:AB',
41 0b011 => 'R:-B W:-B I:-- DTR:--',
42 0b101 => 'R:-B W:-- I:-- DTR:--',
43 0b111 => 'R:-- W:-- I:-- DTR:--',
44 };
45
46 my $access_condition_trailer = {
47 0b000 => 'R/W: KEYSECXA:-/A ACCESS COND:A-/- KEYSECXB:A/A',
48 0b010 => 'R/W: KEYSECXA:-/- ACCESS COND:A-/- KEYSECXB:A/-',
49 0b100 => 'R/W: KEYSECXA:-/B ACCESS COND:AB/- KEYSECXB:-/B',
50 0b110 => 'R/W: KEYSECXA:-/- ACCESS COND:AB/- KEYSECXB:-/-',
51 0b001 => 'R/W: KEYSECXA:-/A ACCESS COND:A-/A KEYSECXB:A/A',
52 0b011 => 'R/W: KEYSECXA:-/B ACCESS COND:AB/B KEYSECXB:-/B',
53 0b101 => 'R/W: KEYSECXA:-/- ACCESS COND:AB/B KEYSECXB:-/-',
54 0b111 => 'R/W: KEYSECXA:-/- ACCESS COND:AB/- KEYSECXB:-/-',
55 };
56
57
58 if ( $debug ) {
59         warn "# function_clusters ",dump($function_clusters);
60         warn "# mad_id ", dump($mad_id);
61 }
62
63 local $/ = undef;
64 my $card = <>;
65
66 die "expected 4096 bytes, got ",length($card), " bytes\n"
67         unless length $card == 4096;
68
69 foreach my $i ( 0 .. 15 ) {
70
71         my $pos = 0x40 * $i;
72
73         if ( $i == 0 ) {
74                 printf "manufacturer block\nSerial number: %s\nCB: %s\nmanufacturer data: %s\n"
75                         , unpack('H*',substr($card,0,4))
76                         , unpack('H*',substr($card,4,1))
77                         , unpack('H*',substr($card,5,11))
78                         ;
79         } else {
80                 my $v = unpack('v',(substr($card, 0x10 + ( $i * 2 ), 2)));
81                 my $cluster_id = unpack('HH', (( $v & 0xff00 ) >> 8) );
82                 my $full_id = sprintf "%04x",$v;
83                 printf "MAD sector %-2d %04x [%s]\n%s\n", $i, $v
84                         , $function_clusters->{ $cluster_id }
85                         , $mad_id->{$full_id} || "FIXME: add $full_id from MAD_overview.pdf to __DATA__ at end of $0"
86                         ;
87
88                 if ( $v == 0x0004 ) {
89                         # RLE encoded card holder information
90                         my $data = substr( $card, $pos, 0x30);
91                         my $o = 0;
92                         my $types = {
93                                 0b00 => 'surname',
94                                 0b01 => 'given name',
95                                 0b10 => 'sex',
96                                 0b11 => 'any',
97                         };
98                         while ( substr($data,$o,1) ne "\x00" ) {
99                                 my $len = ord(substr($data,$o,1));
100                                 my $type = ( $len & 0b11000000 ) >> 6;
101                                 $len     =   $len & 0b00111111;
102                                 my $dump = substr($data,$o+1,$len-1);
103                                 $dump = '0x' . unpack('H*', $dump) if $type == 0b11; # any
104                                 printf "%-10s %2d %s\n", $types->{$type}, $len, $dump;
105                                 $o += $len + 1;
106                         }
107                 } elsif ( $v == 0x0015 ) {
108                         printf "Card number: %s\n", unpack('h*',substr($card,$pos + 0x04,6));
109                 }
110
111         }
112
113         my $c1 = ( ord(substr($card,$pos+0x37,1)) & 0xf0 ) >> 4;
114         my $c2 = ( ord(substr($card,$pos+0x38,1)) & 0x0f );
115         my $c3 = ( ord(substr($card,$pos+0x38,1)) & 0xf0 ) >> 4;
116
117         foreach my $j ( 0 .. 3 ) {
118                 my $offset = $pos + $j * 0x10;
119                 my $block = substr($card, $offset, 0x10);
120                 my $mask = 1 << $j;
121                 my $cond
122                         = ( ( $c1 & $mask ) * 4 )
123                         + ( ( $c2 & $mask ) * 2 )
124                         + ( ( $c3 & $mask ) * 1 )
125                         ;
126                 $cond >>= $j;
127
128                 printf "%04x %s %03b %s\n", $offset, unpack('H*',$block)
129                         , $cond
130                         , $j < 3 ? $access_condition_data->{$cond} : $access_condition_trailer->{$cond}
131                         ;
132         }
133
134
135         printf "KEY A:%s | %s | B:%s\n"
136                 ,unpack('H*',substr($card,$pos+0x30   ,6))
137                 ,unpack('H*',substr($card,$pos+0x30+6 ,4))
138                 ,unpack('H*',substr($card,$pos+0x30+10,6))
139                 ;
140
141         print "\n";
142
143 }
144
145 __DATA__
146 00    card administration
147 01-07 miscellaneous applications
148 08    airlines
149 09    ferry trafic
150 10    railway services
151 12    transport
152 18    city traffic
153 19    Czech Railways
154 20    bus services
155 21    multi modal transit
156 28    taxi
157 30    road toll
158 38    company services
159 40    city card services
160 47-48 access control & security
161 49    VIGIK
162 4A    Ministry of Defence, Netherlands
163 4B    Bosch Telecom, Germany
164 4A    Ministry of Defence, Netherlands
165 4C    European Union Institutions
166 50    ski ticketing
167 51-54 access control & security
168 58    academic services
169 60    food
170 68    non food trade
171 70    hotel
172 75    airport services
173 78    car rental
174 79    Dutch government
175 80    administration services
176 88    electronic purse
177 90    television
178 91    cruise ship
179 95    IOPTA
180 97    Metering
181 98    telephone
182 A0    health services
183 A8    warehouse
184 B0    electronic trade
185 B8    banking
186 C0    entertainment & sports
187 C8    car parking
188 C9    Fleet Management
189 D0    fuel, gasoline
190 D8    info services
191 E0    press
192 E1    NFC Forum
193 E8    computer
194 F0    mail
195 F8-FF miscellaneous applications
196
197 0000    sector free
198 0001    sector defective
199 0002    sector reserved
200 0003    DIR continuted
201 0004    card holder
202
203 0015 - card administration MIKROELEKTRONIKA spol.s.v.MIKROELEKTRONIKA spol.s.v.o. worldwide 1 01.02.2007 Card publisher info
204 0016 - card administration Mikroelektronika spol.s.r.o., Kpt.Mikroelektronika spol.s.r.o., Kpt. PoEurope    1 10.10.2007 Issuer information
205
206 071C - miscellaneous applications MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe       1 01.12.2008 Customer profile
207 071D - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Customer profile
208 071E - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Bonus counter
209
210 1835 - city traffic KORID LK, spol.s.r.o.       KORID LK, spol.s.r.o.        Europe         2 08.09.2008 Eticket
211 1836 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe         1 01.12.2008 Prepaid coupon 1S
212 1837 - city traffic ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o.   EUROPE,Croatia 1 01.04.2009 Prepaid coupon
213 1838 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o.  Europe         1 01.05.2009 Prepaid coupon
214 1839 - city traffic Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o  EUROPE,Czech R 1 01.08.2009 Prepaid coupon
215 183B - city traffic UNICARD S.A.                UNICARD S.A.                 Poland        15 01.01.2010 city traffic services
216
217 2061 - bus services Mikroelektronika spol.s r.o. Mikroelektronika spol.s r.o. Europe     1 01.08.2008 Electronic ticket
218 2062 - bus services ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o EUROPE,Croatia 1 01.04.2009 Electronic tiicket
219 2063 - bus services MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe       3 01.05.2009 electronic ticket
220
221 887B - electronic purse ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia  4 01.04.2009 Electronic purse
222 887C - electronic purse MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe         4 01.05.2009 electronic purse
223 887D - electronic purse Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o EUROPE,Czech R 4 01.08.2009 Electronic purse
224