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.
You are missing at least the padding mode. The ICAO technical specification uses bit padding (at least one byte valued
80, then one to seven00valued bytes until you reach the end of the block.