first cut at displaying access conditions for each block from trailer data
[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         my $v = unpack('v',(substr($card, 0x10 + ( $i * 2 ), 2)));
71         my $cluster_id = unpack('HH', (( $v & 0xff00 ) >> 8) );
72         my $full_id = sprintf "%04x",$v;
73         printf "MAD sector %-2d %04x [%s]\n%s\n", $i, $v
74                 , $function_clusters->{ $cluster_id }
75                 , $mad_id->{$full_id} || "FIXME: add $full_id from MAD_overview.pdf to __DATA__ at end of $0"
76                 ;
77
78         my $pos = 0x40 * $i;
79
80         my $c1 = ( ord(substr($card,$pos+0x37,1)) & 0xf0 ) >> 4;
81         my $c2 = ( ord(substr($card,$pos+0x38,1)) & 0x0f );
82         my $c3 = ( ord(substr($card,$pos+0x38,1)) & 0xf0 ) >> 4;
83
84         foreach my $j ( 0 .. 3 ) {
85                 my $offset = $pos + $j * 0x10;
86                 my $block = substr($card, $offset, 0x10);
87                 my $mask = 1 << $j;
88                 my $cond
89                         = ( ( $c1 & $mask ) * 4 )
90                         + ( ( $c2 & $mask ) * 2 )
91                         + ( ( $c3 & $mask ) * 1 )
92                         ;
93                 $cond >>= $j;
94
95                 printf "%04x %s %03b %s\n", $offset, unpack('H*',$block)
96                         , $cond
97                         , $j < 3 ? $access_condition_data->{$cond} : $access_condition_trailer->{$cond}
98                         ;
99         }
100
101
102         printf "KEY A:%s | %s | B:%s\n"
103                 ,unpack('H*',substr($card,$pos+0x30   ,6))
104                 ,unpack('H*',substr($card,$pos+0x30+6 ,4))
105                 ,unpack('H*',substr($card,$pos+0x30+10,6))
106                 ;
107
108         if ( $v == 0x0004 ) {
109                 # RLE encoded card holder information
110                 my $data = substr( $card, $pos, 0x30);
111                 my $o = 0;
112                 my $types = {
113                         0b00 => 'surname',
114                         0b01 => 'given name',
115                         0b10 => 'sex',
116                         0b11 => 'any',
117                 };
118                 while ( substr($data,$o,1) ne "\x00" ) {
119                         my $len = ord(substr($data,$o,1));
120                         my $type = ( $len & 0b11000000 ) >> 6;
121                         $len     =   $len & 0b00111111;
122                         my $dump = substr($data,$o+1,$len-1);
123                         $dump = '0x' . unpack('H*', $dump) if $type == 0b11; # any
124                         printf "%-10s %2d %s\n", $types->{$type}, $len, $dump;
125                         $o += $len + 1;
126                 }
127         } elsif ( $v == 0x0015 ) {
128                 printf "Card number: %s\n", unpack('h*',substr($card,$pos + 0x04,6));
129         }
130
131         print "\n";
132
133 }
134
135 __DATA__
136 00    card administration
137 01-07 miscellaneous applications
138 08    airlines
139 09    ferry trafic
140 10    railway services
141 12    transport
142 18    city traffic
143 19    Czech Railways
144 20    bus services
145 21    multi modal transit
146 28    taxi
147 30    road toll
148 38    company services
149 40    city card services
150 47-48 access control & security
151 49    VIGIK
152 4A    Ministry of Defence, Netherlands
153 4B    Bosch Telecom, Germany
154 4A    Ministry of Defence, Netherlands
155 4C    European Union Institutions
156 50    ski ticketing
157 51-54 access control & security
158 58    academic services
159 60    food
160 68    non food trade
161 70    hotel
162 75    airport services
163 78    car rental
164 79    Dutch government
165 80    administration services
166 88    electronic purse
167 90    television
168 91    cruise ship
169 95    IOPTA
170 97    Metering
171 98    telephone
172 A0    health services
173 A8    warehouse
174 B0    electronic trade
175 B8    banking
176 C0    entertainment & sports
177 C8    car parking
178 C9    Fleet Management
179 D0    fuel, gasoline
180 D8    info services
181 E0    press
182 E1    NFC Forum
183 E8    computer
184 F0    mail
185 F8-FF miscellaneous applications
186
187 0000    sector free
188 0001    sector defective
189 0002    sector reserved
190 0003    DIR continuted
191 0004    card holder
192
193 0015 - card administration MIKROELEKTRONIKA spol.s.v.MIKROELEKTRONIKA spol.s.v.o. worldwide 1 01.02.2007 Card publisher info
194 0016 - card administration Mikroelektronika spol.s.r.o., Kpt.Mikroelektronika spol.s.r.o., Kpt. PoEurope    1 10.10.2007 Issuer information
195
196 071C - miscellaneous applications MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe       1 01.12.2008 Customer profile
197 071D - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Customer profile
198 071E - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Bonus counter
199
200 1835 - city traffic KORID LK, spol.s.r.o.       KORID LK, spol.s.r.o.        Europe         2 08.09.2008 Eticket
201 1836 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe         1 01.12.2008 Prepaid coupon 1S
202 1837 - city traffic ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o.   EUROPE,Croatia 1 01.04.2009 Prepaid coupon
203 1838 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o.  Europe         1 01.05.2009 Prepaid coupon
204 1839 - city traffic Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o  EUROPE,Czech R 1 01.08.2009 Prepaid coupon
205 183B - city traffic UNICARD S.A.                UNICARD S.A.                 Poland        15 01.01.2010 city traffic services
206
207 2061 - bus services Mikroelektronika spol.s r.o. Mikroelektronika spol.s r.o. Europe     1 01.08.2008 Electronic ticket
208 2062 - bus services ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o EUROPE,Croatia 1 01.04.2009 Electronic tiicket
209 2063 - bus services MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe       3 01.05.2009 electronic ticket
210
211 887B - electronic purse ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia  4 01.04.2009 Electronic purse
212 887C - electronic purse MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe         4 01.05.2009 electronic purse
213 887D - electronic purse Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o EUROPE,Czech R 4 01.08.2009 Electronic purse
214