using NFC; using NFC.ISO7816_4; using NFC.Mifare_DESFire; using NFC.NXP_MIFARE_DESFire.Exceptions; using NSubstitute; using NSubstitute.Core; using NUnit.Framework; using PCSC.Iso7816; using System; using System.Collections.Generic; using System.Net; namespace NFC_Test { [TestFixture] public class MIFARE_DESFire_V2_Test { #region Helper Methods [Test] public void GenerateDefaultKey() { uint i = 16; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] data = desfire.GenerateEmptyKey(i); for(int e = 0; e < i; e++) { if(data[e] != 0x00) { Assert.Fail("Data is not 0x00"); } } } [Test] public void CheckAPDUResponse__NULL() { MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(null); }); } [Test] public void CheckAPDUResponse__UNKNOWN() { APDUResponse response = new APDUResponse() { SW1 = 0x00, SW2 = 0x00 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__OPERATION_OK() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); desfire.CheckAPDUResponse(response); } [Test] public void CheckAPDUResponse__NO_CHANGES() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x0C }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); desfire.CheckAPDUResponse(response); } [Test] public void CheckAPDUResponse__ILLEGAL_COMMAND_CODE() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x1C }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__INTEGRITY_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x1E }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__NO_SUCH_KEY() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x40 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__LENGTH_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x7E }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__PERMISSION_DENIED() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x9D }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__PARAMETER_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x9E }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__AUTHENTICATION_DELAY() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xAD }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__AUTHENTICATION_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xAE }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__ADDITIONAL_FRAME() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); desfire.CheckAPDUResponse(response); } [Test] public void CheckAPDUResponse__BOUNDARY_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xBE }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__COMMAND_ABORTED() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xCA }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__DUPLICATE_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xDE }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__FILE_NOT_FOUND() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xF0 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } #endregion #region Crypto Operation [Test] public void ExtractLastBlock() { byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; byte[] expected_lastblock = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] lastblock = desfire.ExtractLastBlock(data, 8); Assert.AreEqual(expected_lastblock, lastblock); } [Test] public void ExtractLastBlock_WrongBlocksize() { byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { byte[] lastblock = desfire.ExtractLastBlock(data, 7); }); } [Test] public void ExtractLastBlock_Null() { byte[] data = null; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { byte[] lastblock = desfire.ExtractLastBlock(data, 7); }); } [Test] public void RotateLeft() { byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 }; byte[] expected_data_left = new byte[] { 0x02, 0x03, 0x04, 0x01 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] data_left = desfire.RotateLeft(data); Assert.AreEqual(expected_data_left, data_left); } [Test] public void RotateLeft_Null() { MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { byte[] lastblock = desfire.RotateLeft(null); }); } [Test] public void RotateRight() { byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 }; byte[] expected_data_left = new byte[] { 0x04, 0x01, 0x02, 0x03 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] data_left = desfire.RotateRight(data); Assert.AreEqual(expected_data_left, data_left); } [Test] public void RotateRight_Null() { MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { byte[] lastblock = desfire.RotateRight(null); }); } [Test] public void Concatenate() { byte[] data_a = new byte[] { 0x01, 0x02, 0x03, 0x04 }; byte[] data_b = new byte[] { 0x05, 0x06, 0x07, 0x08 }; byte[] expected_data_c = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] data_c = desfire.Concatenate(data_a, data_b); Assert.AreEqual(expected_data_c, data_c); } [Test] public void Concatenate_Null() { MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { byte[] lastblock = desfire.Concatenate(null, null); }); } [Test] public void XOR() { byte[] data_a = new byte[] { 0x00, 0xF0, 0x00, 0xF0 }; byte[] data_b = new byte[] { 0x0F, 0x00, 0x0F, 0x00 }; byte[] expected_data_c = new byte[] { 0x0F, 0xF0, 0x0F, 0xF0 }; MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] data_c = desfire.XOR(data_a, data_b); Assert.AreEqual(expected_data_c, data_c); } [Test] public void XOR_null() { MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); Assert.Throws( delegate { byte[] lastblock = desfire.XOR(null, null); }); } [Test] public void GenerateSessionKey_AES() { MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); byte[] rndA = desfire.ConvertFromHexString("bc14dfde20074617e45a8822f06fdd91"); Console.WriteLine(desfire.ConvertToHexString(rndA)); byte[] rndB = desfire.ConvertFromHexString("482ddc54426e6dee560413b8d95471f5"); Console.WriteLine(desfire.ConvertToHexString(rndB)); byte[] expected_sessionkey = desfire.ConvertFromHexString("bc14dfde482ddc54f06fdd91d95471f5"); Console.WriteLine(desfire.ConvertToHexString(expected_sessionkey)); byte[] sessionkey = desfire.GenerateSesionKey_AES(rndA, rndB); Console.WriteLine(desfire.ConvertToHexString(sessionkey)); Assert.AreEqual(expected_sessionkey, sessionkey); } #endregion #region DESFire Commands [Test] public void AuthenticateISO_DES() { ICard card = Substitute.For(); MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); APDUResponse response_challenge_request = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF, Body = desfire.ConvertFromHexString("5D994CE085F24089") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, Body = desfire.ConvertFromHexString("913C6DED84221C41") }; byte[] rndA = desfire.ConvertFromHexString("849B36C5F8BF4A09"); byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000"); card.Transmit(Arg.Is(x => x.INS == 0x1A)).Returns(response_challenge_request); card.Transmit(Arg.Is(x => x.INS == 0xAF)).Returns(response_challenge_response); desfire.AuthenticateISO_DES(0x00, key, rndA); byte[] expected_sessionkey = desfire.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759"); byte[] expected_iv = desfire.GenerateEmptyKey(8); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); Assert.AreEqual(expected_iv, desfire._IV); } [Test] public void AuthenticateISO_AES() { ICard card = Substitute.For(); MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); APDUResponse response_challenge_request = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF, Body = desfire.ConvertFromHexString("43a28e28c653df83cd85039714bccb51") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, Body = desfire.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f") }; byte[] rndA = desfire.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1"); byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000"); card.Transmit(Arg.Is(x => x.INS == 0xAA)).Returns(response_challenge_request); card.Transmit(Arg.Is(x => x.INS == 0xAF)).Returns(response_challenge_response); desfire.AuthenticateISO_AES(0x00, key, rndA); byte[] expected_sessionkey = desfire.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703"); byte[] expected_iv = desfire.GenerateEmptyKey(16); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); Assert.AreEqual(expected_iv, desfire._IV); } [Test] public void ChangeKey_AES() { ICard card = Substitute.For(); MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00 }; byte[] new_key = desfire.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530"); byte[] sessionkey = desfire.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3"); byte[] iv = desfire.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; card.Transmit(null).ReturnsForAnyArgs(response); desfire.ChangeKey_AES(0x00, new_key, 0x10); } #endregion } }