Note that there are some explanatory texts on larger screens.

plurals
  1. POISO 9797-1 Algorithm 1 [CBC-MAC] in C#
    primarykey
    data
    text
    <p>It seems that there're 6 variations to CBC-MAC algorithm. I've been trying to match the MAC algorithm on the PINPad 1000SE [which per manual is ISO 9797-1 Algorithm 1].</p> <p>I got an excellent start from <a href="http://bytes.com/topic/net/answers/654069-iso-iec-9797-1-cbc-mac-using-vb-net" rel="nofollow noreferrer">here</a>.</p> <p>And I coded the algorithm as below:</p> <pre><code>public static byte[] CalculateMAC(this IPinPad pinpad, byte[] message, byte[] key) { //Divide the key with Key1[ first 64 bits] and key2 [last 64 bits] var key1 = new byte[8]; Array.Copy(key, 0, key1, 0, 8); var key2 = new byte[8]; Array.Copy(key, 8, key2, 0, 8); //64 bits //divide the message into 8 bytes blocks //pad the last block with "80" and "00","00","00" until it reaches 8 bytes //if the message already can be divided by 8, then add //another block "80 00 00 00 00 00 00 00" Action&lt;byte[], int&gt; prepArray = (bArr, offset) =&gt; { bArr[offset] = 0; //80 for (var i = offset + 1; i &lt; bArr.Length; i++) bArr[i] = 0; }; var length = message.Length; var mod = length &gt; 8? length % 8: length - 8; var newLength = length + ((mod &lt; 0) ? -mod : (mod &gt; 0) ? 8 - mod : 0); //var newLength = length + ((mod &lt; 0) ? -mod : (mod &gt; 0) ? 8 - mod : 8); Debug.Assert(newLength % 8 == 0); var arr = new byte[newLength]; Array.Copy(message, 0, arr, 0, length); //Encoding.ASCII.GetBytes(message, 0, length, arr, 0); prepArray(arr, length); //use initial vector {0,0,0,0,0,0,0,0} var vector = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; //encrypt by DES CBC algorith with the first key KEY 1 var des = new DESCryptoServiceProvider { Mode = CipherMode.CBC }; var cryptor = des.CreateEncryptor(key1, vector); var outputBuffer = new byte[arr.Length]; cryptor.TransformBlock(arr, 0, arr.Length, outputBuffer, 0); //Decrypt the result by DES ECB with the second key KEY2 [Original suggestion] //Now I'm Encrypting var decOutputBuffer = new byte[outputBuffer.Length]; des.Mode = CipherMode.ECB; var decryptor = des.CreateEncryptor(key2, vector); //var decryptor = des.CreateDecryptor(key2, vector); decryptor.TransformBlock(outputBuffer, 0, outputBuffer.Length, decOutputBuffer, 0); //Encrypt the result by DES ECB with the first key KEY1 var finalOutputBuffer = new byte[decOutputBuffer.Length]; var cryptor2 = des.CreateEncryptor(key1, vector); cryptor2.TransformBlock(decOutputBuffer, 0, decOutputBuffer.Length, finalOutputBuffer, 0); //take the first 4 bytes as the MAC var rval = new byte[4]; Array.Copy(finalOutputBuffer, 0, rval, 0, 4); return rval; } </code></pre> <p>Then I discovered there're 3 padding schemes and the one that gave me a start may not necessarily be right. The manual came to my rescue again. It seems the device only pads with 0s. Additional block is also nowhere mentioned so I made the below changes:</p> <pre><code> Action&lt;byte[], int&gt; prepArray = (bArr, offset) =&gt; { bArr[offset] = 0; ... } </code></pre> <p>No additional block (if mod 0 [divisible by 8] do not change array length)</p> <pre><code>var newLength = length + ((mod &lt; 0) ? -mod : (mod &gt; 0) ? 8 - mod : 0); </code></pre> <p>The original suggestion wanted me to decrypt at the second step... but Valery <a href="http://www.derkeiler.com/Newsgroups/microsoft.public.dotnet.security/2005-04/0180.html" rel="nofollow noreferrer">here</a> suggests that it's encrypt all the way. So I changed Decrypt to Encrypt. But still I'm unable to get the requisite MAC...</p> <p>Manual says for key "6AC292FAA1315B4D8234B3A3D7D5933A" [since the key should be 16 bytes, I figured the key here's hex string so I took byte values of 6A, C2, 92, FA... new byte[] { 106, 194, 146, ...] the MAC should be 7B,40,BA,95 [4 bytes] if the message is [0x1a + byte array of MENTERODOMETER]</p> <p>Can someone help? Please?</p> <hr> <p>Since Pinpad requires that the first character in message is a 0x1a...</p> <pre><code>public static byte[] CalculateAugmentedMAC(this IPinPad pinpad, string message, byte[] key) { var arr = new byte[message.Length + 1]; var source = Encoding.ASCII.GetBytes(message); arr[0] = 0x1a; //ClearScreenIndicator Array.Copy(source, 0, arr, 1, source.Length); return CalculateMAC(pinpad, arr, key); } </code></pre> <p>I'm calling the code above with this input:</p> <pre><code>var result = pad.CalculateAugmentedMAC("MENTERODOMETER", new byte[] { 106, 194, 146, 250, 161, 49, 91, 77, 130, 52, 179, 163, 215, 213, 147, 58 }); </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload