Skip to content

Instantly share code, notes, and snippets.

@mbenedettini
Created December 1, 2011 13:42
Show Gist options
  • Save mbenedettini/1416802 to your computer and use it in GitHub Desktop.
Save mbenedettini/1416802 to your computer and use it in GitHub Desktop.
Perl implementation of Mifare AES-128 simmetric key diversification, as described in document AN10922
use Crypt::Rijndael;
my $key = pack("H*", "00112233445566778899AABBCCDDEEFF");
my $zero = pack("H*", "00000000000000000000000000000000");
my $const_rb = pack("H*", "00000000000000000000000000000087");
my $bytes_const_rb = unpack("A*", $const_rb);
my $k0 = Crypt::Rijndael->new($key, Crypt::Rijndael::MODE_CBC() )->encrypt($zero);
print "k0: " . unpack("H*", $k0) . "\n";
my @k0_bits = split("", unpack("B*", $k0));
my $k0_msb = $k0_bits[0];
print "k0 msb: $k0_msb\n";
# Shift K0 1 bit to the left
my @k0_bits_shifted = @k0_bits;
shift(@k0_bits_shifted);
push(@k0_bits_shifted, '0');
my $k1;
if (not $k0_msb) {
print "NOT XORing to obtain K1\n";
$k1 = pack("B*", @k0_bits_shifted);
}
else {
print "XORing with const_rb to obtain K1\n";
my $bytes_k0_shifted = unpack("A*", pack("B*", join('', @k0_bits_shifted)));
$k1 = pack("A*", $bytes_k0_shifted ^ $bytes_const_rb );
}
print "k1: " . unpack("H*", $k1) . "\n";
my @k1_bits = split("", unpack("B*", $k1));
my $k1_msb = $k1_bits[0];
print "k1 msb: $k1_msb\n";
my @k1_bits_shifted = @k1_bits;
shift(@k1_bits_shifted);
push(@k1_bits_shifted, '0');
my $k2;
if (not $k1_msb) {
print "NOT XORing to obtain K2\n";
$k2 = pack("B*", @k0_bits_shifted);
}
else {
print "XORing with const_rb to obtain K2\n";
my $bytes_k1_shifted = unpack("A*", pack("B*", join('', @k1_bits_shifted)));
$k2 = pack("A*", $bytes_k1_shifted ^ $bytes_const_rb );
}
my $k2_hex = unpack("H*", $k2);
print "k2: $k2_hex\n";
my $div_constant = pack("H*", '01');
my $uid = pack("H*", '04782E21801D80');
my $aid = pack("H*", '3042F5');
my $sysid = pack("H*", '4E585020416275');
my $m = $uid . $aid . $sysid;
print "m: " . unpack("H*", $m) . "\n";
my $d = $div_constant . $m;
my $padded = 0;
if (length($d) < 32) {
# Padding is needed
$padded = 1;
$d = $d . pack("H*", "80");
while (length($d) < 32) {
$d = $d . pack("H*", "00");
}
}
print "d: " . unpack("H*", $d) . "\n";
my $xor_operand;
if ($padded) {
$xor_operand = $k2;
}
else {
$xor_operand = $k1;
}
# XOR last 16-byte block with $xor_operand
my $xored_d = substr($d, 0, 16) . ( unpack("A*", substr($d, 16, 16)) ^ unpack("A*", $xor_operand) );
print "xored_d: " . unpack("H*", $xored_d) . "\n";
my $ek_xored_d = Crypt::Rijndael->new($key, Crypt::Rijndael::MODE_CBC() )->encrypt($xored_d);
print "ek_ored_d: " . unpack("H*", $ek_xored_d) . "\n";
my $cmac = substr($ek_xored_d, 16, 16);
print "cmac: " . unpack("H*", $cmac) . "\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment