using NFC; using NFC.Mifare_DESFire.Enums; using NFC.ISO7816_4; using NFC.Mifare_DESFire; using NFC.NXP_MIFARE_DESFire.Exceptions; using NSubstitute; using NUnit.Framework; using System; namespace NFC_Unit_Test.NXP_MIFARE_DESFire { [TestFixture] public class MIFARE_DESFire_Test { #region Helper Methods [Test] public void GenerateEmptyArray() { uint i = 16; MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data = desfire.GenerateEmptyArray(i); for (int e = 0; e < i; e++) { if (data[e] != 0x00) { Assert.Fail("Data is not 0x00"); } } } [Test] public void GetSubArray() { byte[] array = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }; byte[] expected_subarray = new byte[] { 0x02, 0x03, 0x04 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.AreEqual(expected_subarray, desfire.GetSubArray(array, 1, 3)); } [Test] public void CheckAPDUResponse__NULL() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(null); }); } [Test] public void CheckAPDUResponse__UNKNOWN() { APDUResponse response = new APDUResponse() { SW1 = 0x00, SW2 = 0x00 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__OPERATION_OK() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); desfire.CheckAPDUResponse(response); } [Test] public void CheckAPDUResponse__NO_CHANGES() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x0C }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); desfire.CheckAPDUResponse(response); } [Test] public void CheckAPDUResponse__ILLEGAL_COMMAND_CODE() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x1C }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__INTEGRITY_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x1E }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__NO_SUCH_KEY() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x40 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__LENGTH_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x7E }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__PERMISSION_DENIED() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x9D }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__PARAMETER_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x9E }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__AUTHENTICATION_DELAY() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xAD }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__AUTHENTICATION_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xAE }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__ADDITIONAL_FRAME() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); desfire.CheckAPDUResponse(response); } [Test] public void CheckAPDUResponse__BOUNDARY_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xBE }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__COMMAND_ABORTED() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xCA }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__DUPLICATE_ERROR() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xDE }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.CheckAPDUResponse(response); }); } [Test] public void CheckAPDUResponse__FILE_NOT_FOUND() { APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0xF0 }; MIFARE_DESFire desfire = new MIFARE_DESFire(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 desfire = new MIFARE_DESFire(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 desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { byte[] lastblock = desfire.ExtractLastBlock(data, 7); }); } [Test] public void ExtractLastBlock_Null() { byte[] data = null; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { byte[] lastblock = desfire.ExtractLastBlock(data, 7); }); } [Test] public void ExpandToBlockSize() { byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; byte[] expected_lastblock = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] lastblock = desfire.ExpandToBlockSize(data, 8); Assert.AreEqual(expected_lastblock, lastblock); } [Test] public void ExpandToBlockSize_Null() { byte[] data = null; MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { byte[] lastblock = desfire.ExpandToBlockSize(data, 8); }); } [Test] public void RotateLeft() { byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 }; byte[] expected_data_left = new byte[] { 0x02, 0x03, 0x04, 0x01 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data_left = desfire.RotateLeft(data); Assert.AreEqual(expected_data_left, data_left); } [Test] public void RotateLeft_Null() { MIFARE_DESFire desfire = new MIFARE_DESFire(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 desfire = new MIFARE_DESFire(null); byte[] data_left = desfire.RotateRight(data); Assert.AreEqual(expected_data_left, data_left); } [Test] public void RotateRight_Null() { MIFARE_DESFire desfire = new MIFARE_DESFire(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 desfire = new MIFARE_DESFire(null); byte[] data_c = desfire.Concatenate(data_a, data_b); Assert.AreEqual(expected_data_c, data_c); } [Test] public void Concatenate_ABC() { byte[] data_a = new byte[] { 0x01, 0x02, 0x03, 0x04 }; byte[] data_b = new byte[] { 0x05, 0x06, 0x07, 0x08 }; byte[] data_c = new byte[] { 0x09, 0xA0, 0xB0, 0xC0 }; byte[] expected_data_d = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0, 0xB0, 0xC0 }; MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data_d = desfire.Concatenate(data_a, data_b, data_c); Assert.AreEqual(expected_data_d, data_d); } [Test] public void Concatenate_Null() { MIFARE_DESFire desfire = new MIFARE_DESFire(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 desfire = new MIFARE_DESFire(null); byte[] data_c = desfire.XOR(data_a, data_b); Assert.AreEqual(expected_data_c, data_c); } [Test] public void XOR_null() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { byte[] lastblock = desfire.XOR(null, null); }); } [Test] public void GenerateSessionKey_DES() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] rndA = HexConverter.ConvertFromHexString("a541a9dc9138df07"); Console.WriteLine(HexConverter.ConvertToHexString(rndA)); byte[] rndB = HexConverter.ConvertFromHexString("cbe55aa893b2da25"); Console.WriteLine(HexConverter.ConvertToHexString(rndB)); byte[] expected_sessionkey = HexConverter.ConvertFromHexString("a541a9dccbe55aa8a541a9dccbe55aa8"); Console.WriteLine(HexConverter.ConvertToHexString(expected_sessionkey)); byte[] sessionkey = desfire.GenerateSesionKey_DES(rndA, rndB); Console.WriteLine(HexConverter.ConvertToHexString(sessionkey)); Assert.AreEqual(expected_sessionkey, sessionkey); } [Test] public void GenerateSessionKey_AES() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] rndA = HexConverter.ConvertFromHexString("bc14dfde20074617e45a8822f06fdd91"); Console.WriteLine(HexConverter.ConvertToHexString(rndA)); byte[] rndB = HexConverter.ConvertFromHexString("482ddc54426e6dee560413b8d95471f5"); Console.WriteLine(HexConverter.ConvertToHexString(rndB)); byte[] expected_sessionkey = HexConverter.ConvertFromHexString("bc14dfde482ddc54f06fdd91d95471f5"); Console.WriteLine(HexConverter.ConvertToHexString(expected_sessionkey)); byte[] sessionkey = desfire.GenerateSesionKey_AES(rndA, rndB); Console.WriteLine(HexConverter.ConvertToHexString(sessionkey)); Assert.AreEqual(expected_sessionkey, sessionkey); } #endregion #region Configuration Generator [Test] public void GenerateKeySetting1() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.AreEqual(0x0B, desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE)); } [Test] public void GenerateKeySetting1_ChangeKey() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.AreEqual(0x1B, desfire.GenerateKeySetting1(0x01, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE)); } [Test] public void GenerateKeySetting1_Wrong_KeyID() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.GenerateKeySetting1(0x10, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE); }); } [Test] public void GenerateKeySetting2() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.AreEqual(0x82, desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 0x02)); } [Test] public void GenerateKeySetting2_Wrong_KeyNumbers() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 0x10); }); } [Test] public void GenerateFileAccessRights() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.AreEqual(0x1234, desfire.GenerateFileAccessRights(0x01, 0x02, 0x03, 0x04)); } [Test] public void GenerateFileAccessRights_OutOfRange() { MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { desfire.GenerateFileAccessRights(0x10, 0x00, 0x00, 0x00); }); } #endregion #region DESFire Commands [Test] public void AuthenticateISO_DES() { ICard card = Substitute.For(); MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response_challenge_request = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF, Body = HexConverter.ConvertFromHexString("5D994CE085F24089") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, Body = HexConverter.ConvertFromHexString("913C6DED84221C41") }; byte[] rndA = HexConverter.ConvertFromHexString("849B36C5F8BF4A09"); byte[] key = HexConverter.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 = HexConverter.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759"); byte[] expected_iv = HexConverter.ConvertFromHexString("0000000000000000"); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); Assert.AreEqual(expected_iv, desfire._IV); } [Test] public void AuthenticateISO_AES() { ICard card = Substitute.For(); MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response_challenge_request = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF, Body = HexConverter.ConvertFromHexString("43a28e28c653df83cd85039714bccb51") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, Body = HexConverter.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f") }; byte[] rndA = HexConverter.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1"); byte[] key = HexConverter.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 = HexConverter.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703"); byte[] expected_iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); Assert.AreEqual(expected_iv, desfire._IV); } [Test] public void ChangeKey_AES() { ICard card = Substitute.For(); MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00 }; byte[] new_key = HexConverter.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530"); byte[] sessionkey = HexConverter.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3"); byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; card.Transmit(null).ReturnsForAnyArgs(response); desfire.ChangeKey_AES(0x00, new_key, 0x10); } [Test] public void ChangeOtherKey_AES() { ICard card = Substitute.For(); MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00 }; byte[] new_key = HexConverter.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12"); byte[] old_key = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); byte[] sessionkey = HexConverter.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b"); byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; card.Transmit(null).ReturnsForAnyArgs(response); desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10); } #endregion } }