easily dump unique mifare cards, remembering keys
[perl-Mifare-MAD.git] / nfc-card-dumper.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 use RFID::Libnfc::Reader;
6 use RFID::Libnfc::Constants;
7 use File::Slurp;
8 use Digest::MD5 qw(md5_hex);
9
10 use Data::Dump qw(dump);
11
12 my $keyfile = shift @ARGV;
13
14 my $r = RFID::Libnfc::Reader->new(debug => 1);
15 if ($r->init()) {
16     printf ("Reader: %s\n", $r->name);
17     my $tag = $r->connect(IM_ISO14443A_106);
18
19     if ($tag) {
20         $tag->dump_info;
21     } else {
22         warn "No TAG";
23         exit -1;
24     }
25
26         my $uid = sprintf "%02x%02x%02x%02x", unpack('C4', $tag->{_nai}->abtUid);
27         # @{ $tag->uid }; # FIXME this doesn't work with tags which have 00 in UID!
28
29         warn "UID: $uid\n";
30
31         $keyfile ||= "cards/$uid.key";
32
33         if ( -e $keyfile ) {
34                 warn "# loading keys from $keyfile";
35             $tag->load_keys($keyfile);
36                 warn "## _keys = ", dump($tag->{_keys});
37         }
38
39     $tag->select if ($tag->can("select")); 
40
41         my $card;
42
43         print STDERR "reading";
44     for (my $i = 0; $i < $tag->blocks; $i++) {
45         if (my $data = $tag->read_block($i)) {
46             # if we are dumping an ultralight token, 
47             # we receive 16 bytes (while a block is 4bytes long)
48             # so we can skip next 3 blocks
49             $i += 3 if ($tag->type eq "ULTRA");
50                         $card .= $data;
51                         print STDERR "$i ";
52         } else {
53             die $tag->error."\n";
54         }
55     }
56         print STDERR "done\n";
57
58         # re-insert keys into dump
59         my $keys = $tag->{_keys} || die "can't find _keys";
60         foreach my $i ( 0 .. $#$keys ) {
61                 my $o = $i * 0x40 + 0x30;
62                 last if $o > length($card);
63                 $card
64                         = substr($card, 0,   $o) . $keys->[$i]->[0]
65                         . substr($card, $o+6, 4) . $keys->[$i]->[1]
66                         . substr($card, $o+16)
67                         ;
68                 warn "sector $i keys re-inserted at $o\n";
69         }
70
71         my $md5 = md5_hex($card);
72         if ( glob "cards/$uid.md5.*" ) {
73                 warn "SKIPPING, same dump allready exits\n";
74         } else {
75
76                 my $out_file = "cards/$uid.$md5";
77                 write_file $out_file, $card;
78                 print "$out_file ", -s $out_file, " bytes\n";
79                 if ( ! -e "cards/$uid.key" ) {
80                         symlink $out_file, "cards/$uid.key" || die "cards/$uid.key: $!";
81                         warn "using keys as default for card $uid\n";
82                 }
83                 system "./mifare-mad.pl $out_file | vi -R -";
84         }
85
86 }
87