run mfoc on cards for which we don't know 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                 } elsif ( $tag->error =~ m/auth/ ) {
53                         warn $tag->error,"\n";
54
55                         # disconnect from reader so we can run mfoc
56                         RFID::Libnfc::nfc_disconnect($r->{_pdi});
57
58                         my $file = "cards/$uid.key";
59                         unlink $file;
60                         warn "# finding keys for card $uid with: mfoc -O $file\n";
61                         exec "mfoc -O $file" || die $!;
62         } else {
63             die $tag->error."\n";
64         }
65     }
66         print STDERR "done\n";
67
68         # re-insert keys into dump
69         my $keys = $tag->{_keys} || die "can't find _keys";
70         foreach my $i ( 0 .. $#$keys ) {
71                 my $o = $i * 0x40 + 0x30;
72                 last if $o > length($card);
73                 $card
74                         = substr($card, 0,   $o) . $keys->[$i]->[0]
75                         . substr($card, $o+6, 4) . $keys->[$i]->[1]
76                         . substr($card, $o+16)
77                         ;
78                 warn "sector $i keys re-inserted at $o\n";
79         }
80
81         my $md5 = md5_hex($card);
82         if ( glob "cards/$uid.$md5.*" ) {
83                 warn "SKIPPING, same dump allready exits\n";
84         } else {
85                 my $out_file = "cards/$uid.$md5";
86                 write_file $out_file, $card;
87                 print "$out_file ", -s $out_file, " bytes\n";
88                 if ( ! -e "cards/$uid.key" ) {
89                         symlink $out_file, "cards/$uid.key" || die "cards/$uid.key: $!";
90                         warn "using keys as default for card $uid\n";
91                 }
92                 system "./mifare-mad.pl $out_file | vi -R -";
93         }
94
95 }
96