improve AID - administration codes
[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 is free
198 0001    sector is defect, e.g. access keys are destroyed or unknown
199 0002    sector is reserved
200 0003    sector contains additional directory info (useful only for future cards)
201 0004    sector contains card holder information in ASCII format.
202 0005    sector not applicable (above memory size)
203
204 0015 - card administration MIKROELEKTRONIKA spol.s.v.MIKROELEKTRONIKA spol.s.v.o. worldwide 1 01.02.2007 Card publisher info
205 0016 - card administration Mikroelektronika spol.s.r.o., Kpt.Mikroelektronika spol.s.r.o., Kpt. PoEurope    1 10.10.2007 Issuer information
206
207 071C - miscellaneous applications MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe       1 01.12.2008 Customer profile
208 071D - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Customer profile
209 071E - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Bonus counter
210
211 1835 - city traffic KORID LK, spol.s.r.o.       KORID LK, spol.s.r.o.        Europe         2 08.09.2008 Eticket
212 1836 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe         1 01.12.2008 Prepaid coupon 1S
213 1837 - city traffic ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o.   EUROPE,Croatia 1 01.04.2009 Prepaid coupon
214 1838 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o.  Europe         1 01.05.2009 Prepaid coupon
215 1839 - city traffic Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o  EUROPE,Czech R 1 01.08.2009 Prepaid coupon
216 183B - city traffic UNICARD S.A.                UNICARD S.A.                 Poland        15 01.01.2010 city traffic services
217
218 2061 - bus services Mikroelektronika spol.s r.o. Mikroelektronika spol.s r.o. Europe     1 01.08.2008 Electronic ticket
219 2062 - bus services ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o EUROPE,Croatia 1 01.04.2009 Electronic tiicket
220 2063 - bus services MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe       3 01.05.2009 electronic ticket
221
222 887B - electronic purse ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia  4 01.04.2009 Electronic purse
223 887C - electronic purse MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe         4 01.05.2009 electronic purse
224 887D - electronic purse Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o EUROPE,Czech R 4 01.08.2009 Electronic purse
225