I am trying to calculate the MAC using
Cryptographic checksums are calculated using ISOIEC 9797-1 MAC algorithm 3 with block cipher DES, zero IV (8 bytes), and 1S09797-1 padding method 2. The MAC length MUST be 8 bytes
from Technical Report PM for Machine Readable Travel Documents offering ICC read-only access Release : 1.1 Date : October 01. 2004.
I am using the example values from the report:
Kenc: AB 94 FD EC F2 67 4F DF B9 B3 91 F8 5D 7F 76 F2
Kmac: 79 62 D9 EC E0 3D 1A CD 4C 76 08 9D CE 13 15 43
eIFD: 72 C2 9C 23 71 CC 9B DB 65 B7 79 B8 E8 D3 7B 29 EC C1 54 AA 56 A8 79 9F AE 2F 49 8F 76 ED 92 F2
However, I am not getting the same MAC and not sure how I need to go about it. My first attempt was:
MACTripleDES mac = new System.Security.Cryptography.MACTripleDES(Kmac);
mac.Initialize();
mac.Padding = PaddingMode.None;
mac.Key = Kmac;
mIfd = mac.TransformFinalBlock(eIfd, 0, eIfd.Length);
Result:
mIFD:1C DE 09 70 4C 0D 9B 12
Expected:
mIFD:5F 14 48 EE A8 AD 90 A7
Then I tried to manually do every step as I understand "ISO/IEC 9797-1 MAC algorithm 3 with block cipher DES, zero IV (8 bytes), and 1S09797-1 padding method 2" with the following: (I based this on Rasmus Faber's answer, but splitting the data into 64bit blocks for Iteration steps)
byte[] key1 = new byte[8];
Array.Copy(kMAC, 0, key1, 0, 8);
byte[] key2 = new byte[8];
Array.Copy(kMAC, 8, key2, 0, 8);
Console.WriteLine("key1:{0}", Hex.BytesToSpacedHexString(key1));
Console.WriteLine("key2:{0}", Hex.BytesToSpacedHexString(key2));
// Plit the blocks
byte[] d1 = new byte[8];
byte[] d2 = new byte[8];
byte[] d3 = new byte[8];
byte[] d4 = new byte[8];
Array.Copy(eIfd, 0, d1, 0, 8);
Array.Copy(eIfd, 8, d2, 0, 8);
Array.Copy(eIfd, 16, d3, 0, 8);
Array.Copy(eIfd, 24, d4, 0, 8);
DES des1 = DES.Create();
des1.BlockSize = 64;
des1.Key = key1;
des1.Mode = CipherMode.CBC;
des1.Padding = PaddingMode.None;
des1.IV = new byte[8];
DES des2 = DES.Create();
des2.BlockSize = 64;
des2.Key = key2;
des2.Mode = CipherMode.CBC;
des2.Padding = PaddingMode.None;
des2.IV = new byte[8];
// MAC Algorithm 3
// Initial Transformation 1
byte[] h1 = des1.CreateEncryptor().TransformFinalBlock(d1, 0, 8);
// Iteration on the rest of blocks
// XOR
byte[] int2 = new byte[8];
for (int i = 0; i < 8; i++)
int2[i] = (byte)(h1[i] ^ d2[i]);
// Encrypt
byte[] h2 = des1.CreateEncryptor().TransformFinalBlock(int2, 0, 8);
// XOR
byte[] int3 = new byte[8];
for (int i = 0; i < 8; i++)
int3[i] = (byte)(h2[i] ^ d3[i]);
// Encrypt
byte[] h3 = des1.CreateEncryptor().TransformFinalBlock(int3, 0, 8);
// XOR
byte[] int4 = new byte[8];
for (int i = 0; i < 8; i++)
int4[i] = (byte)(h3[i] ^ d4[i]);
// Encrypt
byte[] h4 = des1.CreateEncryptor().TransformFinalBlock(int4, 0, 8);
// Output Transformation 3
byte[] h4decrypt = des2.CreateDecryptor().TransformFinalBlock(h4, 0, 8);
mIfd = des1.CreateEncryptor().TransformFinalBlock(h4decrypt, 0, 8);
Console.WriteLine("mIFD:{0}", Hex.BytesToSpacedHexString(mIfd));
The output was:
eIFD:72 C2 9C 23 71 CC 9B DB 65 B7 79 B8 E8 D3 7B 29 EC C1 54 AA 56 A8 79 9F AE 2F 49 8F 76 ED 92 F2
key1:79 62 D9 EC E0 3D 1A CD
key2:4C 76 08 9D CE 13 15 43
Result:
mIFD:AA E3 F3 51 32 ED 34 65
Expected:
mIFD:5F 14 48 EE A8 AD 90 A7
In both cases it was different as expected. What am I missing?
Thank you for your time.
Thanks to owlstead, the trick was that one has to pad even though the data string was exactly 32 bytes. For the people who need the full code. The code to MAC hash for
eIFD:72 C2 9C 23 71 CC 9B DB 65 B7 79 B8 E8 D3 7B 29 EC C1 54 AA 56 A8 79 9F AE 2F 49 8F 76 ED 92 F2
data string looks as follows:
// Split the 16 byte MAC key into two keys
byte[] key1 = new byte[8];
Array.Copy(kMAC, 0, key1, 0, 8);
byte[] key2 = new byte[8];
Array.Copy(kMAC, 8, key2, 0, 8);
Console.WriteLine("key1:{0}", Hex.BytesToSpacedHexString(key1));
Console.WriteLine("key2:{0}", Hex.BytesToSpacedHexString(key2));
// Padd the data with Padding Method 2 (Bit Padding)
System.IO.MemoryStream out_Renamed = new System.IO.MemoryStream();
out_Renamed.Write(eIfd, 0, eIfd.Length);
out_Renamed.WriteByte((byte)(0x80));
while (out_Renamed.Length % 8 != 0)
{
out_Renamed.WriteByte((byte)0x00);
}
byte[] eIfd_padded = out_Renamed.ToArray();
Console.WriteLine("eIfd_padded:{0}", Hex.BytesToSpacedHexString(eIfd_padded));
// Split the blocks
byte[] d1 = new byte[8];
byte[] d2 = new byte[8];
byte[] d3 = new byte[8];
byte[] d4 = new byte[8];
byte[] d5 = new byte[8];
Array.Copy(eIfd_padded, 0, d1, 0, 8);
Array.Copy(eIfd_padded, 8, d2, 0, 8);
Array.Copy(eIfd_padded, 16, d3, 0, 8);
Array.Copy(eIfd_padded, 24, d4, 0, 8);
Array.Copy(eIfd_padded, 32, d5, 0, 8);
DES des1 = DES.Create();
des1.BlockSize = 64;
des1.Key = key1;
des1.Mode = CipherMode.CBC;
des1.Padding = PaddingMode.None;
des1.IV = new byte[8];
DES des2 = DES.Create();
des2.BlockSize = 64;
des2.Key = key2;
des2.Mode = CipherMode.CBC;
des2.Padding = PaddingMode.None;
des2.IV = new byte[8];
// MAC Algorithm 3
// Initial Transformation 1
byte[] h1 = des1.CreateEncryptor().TransformFinalBlock(d1, 0, 8);
// Iteration on the rest of blocks
// XOR
byte[] int2 = new byte[8];
for (int i = 0; i < 8; i++)
int2[i] = (byte)(h1[i] ^ d2[i]);
// Encrypt
byte[] h2 = des1.CreateEncryptor().TransformFinalBlock(int2, 0, 8);
// XOR
byte[] int3 = new byte[8];
for (int i = 0; i < 8; i++)
int3[i] = (byte)(h2[i] ^ d3[i]);
// Encrypt
byte[] h3 = des1.CreateEncryptor().TransformFinalBlock(int3, 0, 8);
// XOR
byte[] int4 = new byte[8];
for (int i = 0; i < 8; i++)
int4[i] = (byte)(h3[i] ^ d4[i]);
// Encrypt
byte[] h4 = des1.CreateEncryptor().TransformFinalBlock(int4, 0, 8);
// XOR
byte[] int5 = new byte[8];
for (int i = 0; i < 8; i++)
int5[i] = (byte)(h4[i] ^ d5[i]);
// Encrypt
byte[] h5 = des1.CreateEncryptor().TransformFinalBlock(int5, 0, 8);
// Output Transformation 3
byte[] h5decrypt = des2.CreateDecryptor().TransformFinalBlock(h5, 0, 8);
byte[] mIfd = des1.CreateEncryptor().TransformFinalBlock(h5decrypt, 0, 8);
Console.WriteLine("mIFD:{0}", Hex.BytesToSpacedHexString(mIfd));
You are missing at least the padding mode. The ICAO technical specification uses bit padding (at least one byte valued 80
, then one to seven 00
valued bytes until you reach the end of the block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With