mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-03-13 15:21:45 +01:00
552 lines
14 KiB
C#
552 lines
14 KiB
C#
|
using NFC;
|
|||
|
using NFC.ISO7816_4;
|
|||
|
using NFC.Mifare_DESFire;
|
|||
|
using NFC.NXP_MIFARE_DESFire.Exceptions;
|
|||
|
using NSubstitute;
|
|||
|
using NUnit.Framework;
|
|||
|
using System;
|
|||
|
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<ArgumentNullException>(
|
|||
|
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<Exception>(
|
|||
|
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<IllegalCommandCodeException>(
|
|||
|
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<IntegrityErrorException>(
|
|||
|
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<NoSuchKeyException>(
|
|||
|
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<LengthErrorException>(
|
|||
|
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<PermissionDeniedException>(
|
|||
|
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<ParameterErrorException>(
|
|||
|
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<AuthenticationDelayException>(
|
|||
|
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<AuthenticationErrorException>(
|
|||
|
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<BoundaryErrorException>(
|
|||
|
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<CommandAbortedException>(
|
|||
|
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<DuplicateErrorException>(
|
|||
|
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<FileNotFoundException>(
|
|||
|
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<ArgumentException>(
|
|||
|
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<ArgumentNullException>(
|
|||
|
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<ArgumentNullException>(
|
|||
|
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<ArgumentNullException>(
|
|||
|
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<ArgumentNullException>(
|
|||
|
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<ArgumentNullException>(
|
|||
|
delegate
|
|||
|
{
|
|||
|
byte[] lastblock = desfire.XOR(null, null);
|
|||
|
});
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region DESFire Commands
|
|||
|
[Test]
|
|||
|
public void AuthenticateISO_DES()
|
|||
|
{
|
|||
|
ICard card = Substitute.For<ICard>();
|
|||
|
|
|||
|
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<APDUCommand>(x => x.INS == 0x1A)).Returns(response_challenge_request);
|
|||
|
card.Transmit(Arg.Is<APDUCommand>(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);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|