Created
December 1, 2011 13:42
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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