19f957a110727b7074c21ca93a761d76d24eff29
[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
9
10 use Data::Dump qw(dump);
11
12 # http://www.nxp.com/acrobat_download2/other/identification/MAD_overview.pdf
13 my $mad_id = {
14         0x0000 => 'sector free',
15         0x0001 => 'sector defective',
16         0x0002 => 'sector reserved',
17         0x0003 => 'DIR continuted',
18         0x0004 => 'card holder',
19         # ...
20         0x0015 => 'card administration - MIKROELEKTRONIKA spol.s.v.M',
21
22         0x071D => 'miscellaneous applications - ZAGREBACKI Holding d.o.o. [1] Customer profile',
23         0x071E => 'miscellaneous applications - ZAGREBACKI Holding d.o.o. [1] Bonus counter',
24
25         0x1837 => 'city traffic - ZAGREBACKI Holding d.o.o. [1] Prepaid coupon',
26
27         0x2062 => 'bus services - ZAGREBACKI Holding d.o.o. [1] electronic ticket',
28
29         0x887B => 'electronic purse - ZAGREBACKI Holding d.o.o. [4]',
30 };
31
32 local $/ = undef;
33 my $card = <>;
34
35 die "expected 4096 bytes, got ",length($card), " bytes\n"
36         unless length $card == 4096;
37
38 foreach my $i ( 0 .. 15 ) {
39         my $v = unpack('v',(substr($card, 0x10 + ( $i * 2 ), 2)));
40         printf "MAD sector %-2d %04x %s\n", $i, $v, $mad_id->{$v} || '?';
41
42         foreach my $j ( 0 .. 3 ) {
43                 my $offset = 0x40 * $i + $j * 0x10;
44                 my $block = substr($card, $offset, 0x10);
45                 printf "%04x %s\n", $offset, unpack('H*',$block);
46         }
47
48         if ( $v == 0x0004 ) {
49                 # RLE encoded card holder information
50                 my $data = substr( $card, 0x40 * $i, 0x30);
51                 my $o = 0;
52                 my $types = {
53                         0b00 => 'surname',
54                         0b01 => 'given name',
55                         0b10 => 'sex',
56                         0b11 => 'any',
57                 };
58                 while ( substr($data,$o,1) ne "\x00" ) {
59                         my $len = ord(substr($data,$o,1));
60                         my $type = ( $len & 0b11000000 ) >> 6;
61                         $len     =   $len & 0b00111111;
62                         my $dump = substr($data,$o+1,$len-1);
63                         $dump = '0x' . unpack('H*', $dump) if $type == 0b11; # any
64                         printf "%-10s %2d %s\n", $types->{$type}, $len, $dump;
65                         $o += $len + 1;
66                 }
67         }
68
69 }