7 # MIFARE Application Directory (MAD)
8 # http://www.nxp.com/acrobat_download2/other/identification/MAD_overview.pdf
10 use Data::Dump qw(dump);
12 my $debug = $ENV{DEBUG} || 0;
14 my $function_clusters;
20 my ( $code, $function ) = split(/\s+/,$_,2);
22 if ( $code =~ m/^($h{2})-($h{2})$/ ) {
23 foreach my $c ( hex($1) .. hex($2) ) {
24 $function_clusters->{ unpack('HH',$c) } = $function;
26 } elsif ( $code =~ m/^($h{2})$/ ) {
27 $function_clusters->{ lc $code } = $function;
28 } elsif ( $code =~ m/^($h{4})$/ ) {
29 $mad_id->{ lc $1 } = $function;
31 die "can't parse __DATA__ line $.\n$_\n";
35 my $access_condition_data = {
36 0b000 => 'R:AB W:AB I:AB DTR:AB transport conf',
37 0b010 => 'R:AB W:-- I:-- DTR:-- r/w block',
38 0b100 => 'R:AB W:-B I:-- DTR:-- r/w block',
39 0b110 => 'R:AB W:-B I:-B DTR:AB r/w block',
40 0b001 => 'R:AB W:-- I:-- DTR:AB value block',
41 0b011 => 'R:-B W:-B I:-- DTR:-- value block',
42 0b101 => 'R:-B W:-- I:-- DTR:-- r/w block',
43 0b111 => 'R:-- W:-- I:-- DTR:-- r/w block',
46 my $access_condition_trailer = {
47 0b000 => 'R/W: KEYA:-/A ACCESS:A-/- DATB:A/A ?',
48 0b010 => 'R/W: KEYA:-/- ACCESS:A-/- DATB:A/- ?'.
49 0b100 => 'R/W: KEYA:-/B ACCESS:AB/- KEYB:-/B',
50 0b110 => 'R/W: KEYA:-/- ACCESS:AB/- KEYB:-/-',
51 0b001 => 'R/W: KEYA:-/A ACCESS:A-/A DATB:A/A ? transport conf',
52 0b011 => 'R/W: KEYA:-/B ACCESS:AB/B KEYB:-/B',
53 0b101 => 'R/W: KEYA:-/- ACCESS:AB/B KEYB:-/-',
54 0b111 => 'R/W: KEYA:-/- ACCESS:AB/- KEYB:-/-',
59 warn "# function_clusters ",dump($function_clusters);
60 warn "# mad_id ", dump($mad_id);
66 die "expected 4096 bytes, got ",length($card), " bytes\n"
67 unless length $card == 4096;
69 my ( $ADV, $MA, $DA );
71 foreach my $i ( 0 .. 15 ) {
74 # General purpose byte (GPB)
75 my $GBP = ord(substr($card,0x39,1));
78 printf "manufacturer block\nSerial number: %s\nCB: %s\nmanufacturer data: %s\n"
79 , unpack('H*',substr($card,0,4))
80 , unpack('H*',substr($card,4,1))
81 , unpack('H*',substr($card,5,11))
85 $ADV = $GBP & 0b00000011;
86 $MA = $GBP & 0b01000000;
87 $DA = $GBP & 0b10000000;
88 printf "ADV (MAD version code): %d %s\n", $ADV,
89 printf "MA (multiapplication): %s\n", $MA ? 'yes' : 'monoaplication';
90 printf "DA (MAD available): %s%s\n", $DA ? 'yes' : 'no',
91 substr($card,$pos+0x30,6) eq "\xA0\xA1\xA2\xA3\xA4\xA5" ? ' public' : '';
93 printf "Info byte (publisher sector): %x\n", ord(substr($card,0x11,1));
95 my $mad_offset = 0x10 + ( $i * 2 );
96 my $v = unpack('v',(substr($card, $mad_offset, 2)));
97 my $cluster_id = unpack('HH', (( $v & 0xff00 ) >> 8) );
98 my $full_id = sprintf "%04x",$v;
99 printf "MAD sector %-2d@%x %04x [%s]\n%s\n", $i, $mad_offset, $v
100 , $function_clusters->{ $cluster_id }
101 , $mad_id->{$full_id} || "FIXME: add $full_id from MAD_overview.pdf to __DATA__ at end of $0"
104 if ( $v == 0x0004 ) {
105 # RLE encoded card holder information
106 my $data = substr( $card, $pos, 0x30);
110 0b01 => 'given name',
114 while ( substr($data,$o,1) ne "\x00" ) {
115 my $len = ord(substr($data,$o,1));
116 my $type = ( $len & 0b11000000 ) >> 6;
117 $len = $len & 0b00111111;
118 my $dump = substr($data,$o+1,$len-1);
119 $dump = '0x' . unpack('H*', $dump) if $type == 0b11; # any
120 printf "%-10s %2d %s\n", $types->{$type}, $len, $dump;
123 } elsif ( $v == 0x0015 ) {
124 printf "Card number: %s\n", unpack('h*',substr($card,$pos + 0x04,6));
128 printf "# sector %-2d\n", $i;
131 my $c1 = ( ord(substr($card,$pos+0x37,1)) & 0xf0 ) >> 4;
132 my $c2 = ( ord(substr($card,$pos+0x38,1)) & 0x0f );
133 my $c3 = ( ord(substr($card,$pos+0x38,1)) & 0xf0 ) >> 4;
135 foreach my $j ( 0 .. 3 ) {
136 my $offset = $pos + $j * 0x10;
137 my $block = substr($card, $offset, 0x10);
140 = ( ( $c1 & $mask ) * 4 )
141 + ( ( $c2 & $mask ) * 2 )
142 + ( ( $c3 & $mask ) * 1 )
146 my $hex = unpack('H*',$block);
147 $hex =~ s/(....)/$1 /g;
149 if ( $ENV{SWAP} && $j < 3 ) {
150 my $hex_sw = unpack('h*',$block);
151 $hex_sw =~ s/(....)/$1 /g;
152 $hex .= " | $hex_sw";
155 printf "%04x %s %03b %s\n", $offset, $hex
157 , $j < 3 ? $access_condition_data->{$cond} : $access_condition_trailer->{$cond}
162 printf "KEY A:%s | %s GDP: %s | B:%s\n"
163 ,unpack('H*',substr($card,$pos+0x30 ,6))
164 ,unpack('H*',substr($card,$pos+0x30+6 ,3))
165 ,unpack('H*',substr($card,$pos+0x30+9 ,1))
166 ,unpack('H*',substr($card,$pos+0x30+10,6))
174 00 card administration
175 01-07 miscellaneous applications
183 21 multi modal transit
187 40 city card services
188 47-48 access control & security
190 4A Ministry of Defence, Netherlands
191 4B Bosch Telecom, Germany
192 4A Ministry of Defence, Netherlands
193 4C European Union Institutions
195 51-54 access control & security
203 80 administration services
214 C0 entertainment & sports
223 F8-FF miscellaneous applications
226 0001 sector is defect, e.g. access keys are destroyed or unknown
227 0002 sector is reserved
228 0003 sector contains additional directory info (useful only for future cards)
229 0004 sector contains card holder information in ASCII format.
230 0005 sector not applicable (above memory size)
232 0015 - card administration MIKROELEKTRONIKA spol.s.v.MIKROELEKTRONIKA spol.s.v.o. worldwide 1 01.02.2007 Card publisher info
233 0016 - card administration Mikroelektronika spol.s.r.o., Kpt.Mikroelektronika spol.s.r.o., Kpt. PoEurope 1 10.10.2007 Issuer information
235 071C - miscellaneous applications MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe 1 01.12.2008 Customer profile
236 071D - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Customer profile
237 071E - miscellaneous applications ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Bonus counter
239 1835 - city traffic KORID LK, spol.s.r.o. KORID LK, spol.s.r.o. Europe 2 08.09.2008 Eticket
240 1836 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o., Europe 1 01.12.2008 Prepaid coupon 1S
241 1837 - city traffic ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 1 01.04.2009 Prepaid coupon
242 1838 - city traffic MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe 1 01.05.2009 Prepaid coupon
243 1839 - city traffic Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o EUROPE,Czech R 1 01.08.2009 Prepaid coupon
244 183B - city traffic UNICARD S.A. UNICARD S.A. Poland 15 01.01.2010 city traffic services
246 2061 - bus services Mikroelektronika spol.s r.o. Mikroelektronika spol.s r.o. Europe 1 01.08.2008 Electronic ticket
247 2062 - bus services ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o EUROPE,Croatia 1 01.04.2009 Electronic tiicket
248 2063 - bus services MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe 3 01.05.2009 electronic ticket
250 887B - electronic purse ZAGREBACKI Holding d.o.o. MIKROELEKTRONIKA spol.s.r.o. EUROPE,Croatia 4 01.04.2009 Electronic purse
251 887C - electronic purse MIKROELEKTRONIKA spol.s.r. MIKROELEKTRONIKA spol.s.r.o. Europe 4 01.05.2009 electronic purse
252 887D - electronic purse Mikroelektronika spol.s r.o Mikroelektronika spol.s r.o EUROPE,Czech R 4 01.08.2009 Electronic purse