mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-04-20 18:36:31 +02:00
Added: Create STD File, ReadData, WriteData
This commit is contained in:
parent
2c0db72f55
commit
2049e7eba3
@ -62,6 +62,5 @@ namespace Borepin.iOS.CNFC
|
|||||||
// TODO: decide what to do
|
// TODO: decide what to do
|
||||||
Console.WriteLine("reader session invalidated");
|
Console.WriteLine("reader session invalidated");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,26 +2,14 @@
|
|||||||
|
|
||||||
namespace NFC.Crypto
|
namespace NFC.Crypto
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CRC16 for DESFire Card
|
||||||
|
/// </summary>
|
||||||
public class CRC16
|
public class CRC16
|
||||||
{
|
{
|
||||||
public byte[] Calculate(byte[] data)
|
public UInt16 Polynomial { get; } = 0x8408;
|
||||||
{
|
|
||||||
UInt16 crc16 = 0x6363;
|
|
||||||
|
|
||||||
crc16 = Calculate(data, crc16);
|
public UInt16 InitValue { get; } = 0x6363;
|
||||||
|
|
||||||
return BitConverter.GetBytes(crc16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Calculate(byte[] cmd, byte[] data)
|
|
||||||
{
|
|
||||||
UInt16 crc16 = 0x6363;
|
|
||||||
|
|
||||||
crc16 = Calculate(cmd, crc16);
|
|
||||||
crc16 = Calculate(data, crc16);
|
|
||||||
|
|
||||||
return BitConverter.GetBytes(crc16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UInt16 Calculate(byte[] data, UInt16 crc16)
|
public UInt16 Calculate(byte[] data, UInt16 crc16)
|
||||||
{
|
{
|
||||||
@ -34,11 +22,23 @@ namespace NFC.Crypto
|
|||||||
crc16 >>= 1;
|
crc16 >>= 1;
|
||||||
if (b_Bit)
|
if (b_Bit)
|
||||||
{
|
{
|
||||||
crc16 ^= 0x8408;
|
crc16 ^= Polynomial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return crc16;
|
return crc16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] Calculate(params byte[][] data)
|
||||||
|
{
|
||||||
|
UInt16 crc16 = InitValue;
|
||||||
|
|
||||||
|
foreach(byte[] d in data)
|
||||||
|
{
|
||||||
|
crc16 = Calculate(d, crc16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BitConverter.GetBytes(crc16);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,28 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace NFC.Crypto
|
namespace NFC.Crypto
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CRC32 for DESFire Card
|
||||||
|
/// </summary>
|
||||||
public class CRC32
|
public class CRC32
|
||||||
{
|
{
|
||||||
public byte[] Calculate(byte[] data)
|
public UInt32 Polynomial { get; } = 0xEDB88320;
|
||||||
{
|
|
||||||
UInt32 crc32 = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
crc32 = Calculate(data, crc32);
|
public UInt32 InitValue { get; } = 0xFFFFFFFF;
|
||||||
|
|
||||||
return BitConverter.GetBytes(crc32);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Calculate(byte[] cmd, byte[] data)
|
|
||||||
{
|
|
||||||
UInt32 crc32 = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
crc32 = Calculate(cmd, crc32);
|
|
||||||
crc32 = Calculate(data, crc32);
|
|
||||||
|
|
||||||
return BitConverter.GetBytes(crc32);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UInt32 Calculate(byte[] data, UInt32 crc32)
|
public UInt32 Calculate(byte[] data, UInt32 crc32)
|
||||||
{
|
{
|
||||||
@ -35,11 +22,23 @@ namespace NFC.Crypto
|
|||||||
crc32 >>= 1;
|
crc32 >>= 1;
|
||||||
if (b_Bit)
|
if (b_Bit)
|
||||||
{
|
{
|
||||||
crc32 ^= 0xEDB88320;
|
crc32 ^= Polynomial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return crc32;
|
return crc32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] Calculate(params byte[][] data)
|
||||||
|
{
|
||||||
|
UInt32 crc32 = InitValue;
|
||||||
|
|
||||||
|
foreach(byte[] d in data)
|
||||||
|
{
|
||||||
|
crc32 = Calculate(d, crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BitConverter.GetBytes(crc32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,16 @@
|
|||||||
using Org.BouncyCastle.Crypto;
|
using Org.BouncyCastle.Crypto;
|
||||||
using Org.BouncyCastle.Crypto.Engines;
|
using Org.BouncyCastle.Crypto.Engines;
|
||||||
using Org.BouncyCastle.Crypto.Modes;
|
using Org.BouncyCastle.Crypto.Modes;
|
||||||
using Org.BouncyCastle.Crypto.Paddings;
|
|
||||||
using Org.BouncyCastle.Crypto.Parameters;
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
|
||||||
namespace NFC.Crypto
|
namespace NFC.Crypto
|
||||||
{
|
{
|
||||||
public class AES
|
public class AES : ICipher
|
||||||
{
|
{
|
||||||
|
public uint BlockSize { get; } = 16;
|
||||||
|
|
||||||
|
public uint KeySize { get; } = 16;
|
||||||
|
|
||||||
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
||||||
{
|
{
|
||||||
AesEngine engine = new AesEngine();
|
AesEngine engine = new AesEngine();
|
49
NFC/Crypto/Cipher/TDES.cs
Normal file
49
NFC/Crypto/Cipher/TDES.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using Org.BouncyCastle.Crypto;
|
||||||
|
using Org.BouncyCastle.Crypto.Engines;
|
||||||
|
using Org.BouncyCastle.Crypto.Modes;
|
||||||
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
|
||||||
|
namespace NFC.Crypto
|
||||||
|
{
|
||||||
|
public class TDES : ICipher
|
||||||
|
{
|
||||||
|
public uint BlockSize { get; } = 8;
|
||||||
|
|
||||||
|
// Two times the DES Key
|
||||||
|
public uint KeySize { get; } = 16;
|
||||||
|
|
||||||
|
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
DesEngine engine = new DesEdeEngine();
|
||||||
|
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
|
||||||
|
BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher);
|
||||||
|
KeyParameter keyParam = new KeyParameter(key);
|
||||||
|
ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv);
|
||||||
|
|
||||||
|
// Encrypt
|
||||||
|
cipher.Init(true, keyParamWithIV);
|
||||||
|
byte[] outputBytes = new byte[cipher.GetOutputSize(data.Length)];
|
||||||
|
int length = cipher.ProcessBytes(data, outputBytes, 0);
|
||||||
|
cipher.DoFinal(outputBytes, length);
|
||||||
|
|
||||||
|
return outputBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
DesEngine engine = new DesEdeEngine();
|
||||||
|
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
|
||||||
|
BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher);
|
||||||
|
KeyParameter keyParam = new KeyParameter(key);
|
||||||
|
ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv);
|
||||||
|
|
||||||
|
// Decrypt
|
||||||
|
cipher.Init(false, keyParamWithIV);
|
||||||
|
byte[] outputBytes = new byte[cipher.GetOutputSize(data.Length)];
|
||||||
|
int length = cipher.ProcessBytes(data, outputBytes, 0);
|
||||||
|
cipher.DoFinal(outputBytes, length);
|
||||||
|
|
||||||
|
return outputBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,16 @@
|
|||||||
using Org.BouncyCastle.Crypto;
|
using Org.BouncyCastle.Crypto;
|
||||||
using Org.BouncyCastle.Crypto.Engines;
|
using Org.BouncyCastle.Crypto.Engines;
|
||||||
using Org.BouncyCastle.Crypto.Modes;
|
using Org.BouncyCastle.Crypto.Modes;
|
||||||
using Org.BouncyCastle.Crypto.Paddings;
|
|
||||||
using Org.BouncyCastle.Crypto.Parameters;
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
|
||||||
namespace NFC.Crypto
|
namespace NFC.Crypto
|
||||||
{
|
{
|
||||||
public class TripleDES
|
public class TDES_2K : ICipher
|
||||||
{
|
{
|
||||||
|
public uint BlockSize { get; } = 8;
|
||||||
|
|
||||||
|
public uint KeySize { get; } = 16;
|
||||||
|
|
||||||
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
||||||
{
|
{
|
||||||
DesEngine engine = new DesEdeEngine();
|
DesEngine engine = new DesEdeEngine();
|
@ -1,16 +1,19 @@
|
|||||||
using Org.BouncyCastle.Crypto;
|
using Org.BouncyCastle.Crypto;
|
||||||
using Org.BouncyCastle.Crypto.Engines;
|
using Org.BouncyCastle.Crypto.Engines;
|
||||||
using Org.BouncyCastle.Crypto.Modes;
|
using Org.BouncyCastle.Crypto.Modes;
|
||||||
using Org.BouncyCastle.Crypto.Paddings;
|
|
||||||
using Org.BouncyCastle.Crypto.Parameters;
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
|
||||||
namespace NFC.Crypto
|
namespace NFC.Crypto
|
||||||
{
|
{
|
||||||
public class DES
|
public class TDES_3K : ICipher
|
||||||
{
|
{
|
||||||
|
public uint BlockSize { get; } = 8;
|
||||||
|
|
||||||
|
public uint KeySize { get; } = 24;
|
||||||
|
|
||||||
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
||||||
{
|
{
|
||||||
DesEngine engine = new DesEngine();
|
DesEngine engine = new DesEdeEngine();
|
||||||
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
|
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
|
||||||
BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher);
|
BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher);
|
||||||
KeyParameter keyParam = new KeyParameter(key);
|
KeyParameter keyParam = new KeyParameter(key);
|
||||||
@ -27,7 +30,7 @@ namespace NFC.Crypto
|
|||||||
|
|
||||||
public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
|
public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
|
||||||
{
|
{
|
||||||
DesEngine engine = new DesEngine();
|
DesEngine engine = new DesEdeEngine();
|
||||||
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
|
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
|
||||||
BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher);
|
BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher);
|
||||||
KeyParameter keyParam = new KeyParameter(key);
|
KeyParameter keyParam = new KeyParameter(key);
|
171
NFC/Crypto/CipherKey.cs
Normal file
171
NFC/Crypto/CipherKey.cs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NFC.Crypto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Key for DESFire Card
|
||||||
|
/// </summary>
|
||||||
|
public class CipherKey
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
/// <summary>
|
||||||
|
/// Creates Key from Array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Key</param>
|
||||||
|
/// <param name="cipher">Cipher for Key</param>
|
||||||
|
/// <param name="keyVersion">Version of Key</param>
|
||||||
|
public CipherKey(byte[] key, CipherType cipher, byte keyVersion)
|
||||||
|
{
|
||||||
|
_Cipher = cipher;
|
||||||
|
|
||||||
|
if (cipher == CipherType.AES && keyVersion < 0x10)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("KeyVersion is to low for AES Key (Minimum = 0x10)");
|
||||||
|
}
|
||||||
|
_KeyVersion = keyVersion;
|
||||||
|
|
||||||
|
if (!CheckKey(key, cipher))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Key is not vaild for CipherType");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher == CipherType.TDES || cipher == CipherType.TDES_2K || cipher == CipherType.TDES_3K)
|
||||||
|
{
|
||||||
|
_Key = SetKeyVersion(key, keyVersion);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_Key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates Empty Key
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipher">Cipher for Key</param>
|
||||||
|
/// <param name="keyVerion"></param>
|
||||||
|
public CipherKey(CipherType cipher)
|
||||||
|
{
|
||||||
|
_Cipher = cipher;
|
||||||
|
_Key = GenerateEmptyKey(cipher);
|
||||||
|
|
||||||
|
if (cipher == CipherType.AES)
|
||||||
|
{
|
||||||
|
_KeyVersion = 0x10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_KeyVersion = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
/// <summary>
|
||||||
|
/// Key as Array
|
||||||
|
/// </summary>
|
||||||
|
public byte[] _Key { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CipherType of Key
|
||||||
|
/// </summary>
|
||||||
|
public CipherType _Cipher { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// KeyVersion of Key
|
||||||
|
/// For AES 0x10 is minimum
|
||||||
|
/// </summary>
|
||||||
|
public byte _KeyVersion { get; private set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
/// <summary>
|
||||||
|
/// Generate Empty Key for CipherType
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipher">Type of Cipher</param>
|
||||||
|
public byte[] GenerateEmptyKey(CipherType cipher)
|
||||||
|
{
|
||||||
|
uint size = GetKeySize(cipher);
|
||||||
|
|
||||||
|
byte[] key = new byte[size];
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
key[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check Key Array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Key</param>
|
||||||
|
/// <param name="cipher">Cipher Type of Key</param>
|
||||||
|
public bool CheckKey(byte[] key, CipherType cipher)
|
||||||
|
{
|
||||||
|
if (key.Length != GetKeySize(cipher))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get KeySize for CipherType
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipher">Type of Cipher</param>
|
||||||
|
public uint GetKeySize(CipherType cipher)
|
||||||
|
{
|
||||||
|
switch (cipher)
|
||||||
|
{
|
||||||
|
case CipherType.TDES:
|
||||||
|
return 8;
|
||||||
|
case CipherType.TDES_2K:
|
||||||
|
return 16;
|
||||||
|
case CipherType.TDES_3K:
|
||||||
|
return 24;
|
||||||
|
case CipherType.AES:
|
||||||
|
return 16;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException("Unknown CipherType.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set Key Version for DES/TDES Keys
|
||||||
|
/// KeyVersion is stored in the LSBits of the first 8 Bytes
|
||||||
|
/// Parity Bits are not used from DESFire Cars
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="version"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public byte[] SetKeyVersion(byte[] key, byte version)
|
||||||
|
{
|
||||||
|
byte[] pow2 = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] new_key = new byte[key.Length];
|
||||||
|
key.CopyTo(new_key, 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if ((version & pow2[i]) > 0)
|
||||||
|
{
|
||||||
|
new_key[i] = (byte)(new_key[5] | 0x01);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_key[i] = (byte)(new_key[5] & 0x7F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_key;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
25
NFC/Crypto/CipherType.cs
Normal file
25
NFC/Crypto/CipherType.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace NFC.Crypto
|
||||||
|
{
|
||||||
|
public enum CipherType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DES / Triple DES
|
||||||
|
/// </summary>
|
||||||
|
TDES,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triple DES with 2 DES Keys
|
||||||
|
/// </summary>
|
||||||
|
TDES_2K,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triple DES with 3 DES Keys
|
||||||
|
/// </summary>
|
||||||
|
TDES_3K,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AES
|
||||||
|
/// </summary>
|
||||||
|
AES
|
||||||
|
}
|
||||||
|
}
|
32
NFC/Crypto/ICipher.cs
Normal file
32
NFC/Crypto/ICipher.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
namespace NFC.Crypto
|
||||||
|
{
|
||||||
|
public interface ICipher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Size of Cipher Block in Byte
|
||||||
|
/// </summary>
|
||||||
|
public uint BlockSize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of Key in Byte
|
||||||
|
/// </summary>
|
||||||
|
public uint KeySize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt Data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">Data in BlockSize</param>
|
||||||
|
/// <param name="key">Key</param>
|
||||||
|
/// <param name="IV">Initialisation Vector</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public byte[] Encrypt(byte[] data, byte[] key, byte[] IV);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt Data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">Data in BlockSize</param>
|
||||||
|
/// <param name="key">Key</param>
|
||||||
|
/// <param name="IV">Initialisation Vector</param>
|
||||||
|
public byte[] Decrypt(byte[] data, byte[] key, byte[] IV);
|
||||||
|
}
|
||||||
|
}
|
51
NFC/HexConverter.cs
Normal file
51
NFC/HexConverter.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NFC
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts to and from Byte Array from and to String
|
||||||
|
/// </summary>
|
||||||
|
public static class HexConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts byte[] to string with HEX Code
|
||||||
|
/// No 0x is created
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">Data</param>
|
||||||
|
public static string ConvertToHexString(byte[] data)
|
||||||
|
{
|
||||||
|
return BitConverter.ToString(data).Replace("-", "").ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts string with HEX Code to byte[]
|
||||||
|
/// No 0x is requiered
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">Data</param>
|
||||||
|
public static byte[] ConvertFromHexString(string data)
|
||||||
|
{
|
||||||
|
if (data.Length % 2 == 1)
|
||||||
|
throw new Exception("Data Length is uneven.");
|
||||||
|
|
||||||
|
byte[] arr = new byte[data.Length >> 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Length >> 1; ++i)
|
||||||
|
{
|
||||||
|
arr[i] = (byte)((GetHexVal(data[i << 1]) << 4) + (GetHexVal(data[(i << 1) + 1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetHexVal(char hex)
|
||||||
|
{
|
||||||
|
int val = (int)hex;
|
||||||
|
//For uppercase A-F letters:
|
||||||
|
//return val - (val < 58 ? 48 : 55);
|
||||||
|
//For lowercase a-f letters:
|
||||||
|
//return val - (val < 58 ? 48 : 87);
|
||||||
|
//Or the two combined, but a bit slower:
|
||||||
|
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using PCSC;
|
using PCSC;
|
||||||
using PCSC.Iso7816;
|
using PCSC.Iso7816;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
|
|
||||||
namespace NFC.ISO7816_4
|
namespace NFC.ISO7816_4
|
||||||
{
|
{
|
||||||
@ -21,7 +21,8 @@ namespace NFC.ISO7816_4
|
|||||||
INS == command.INS &&
|
INS == command.INS &&
|
||||||
P1 == command.P1 &&
|
P1 == command.P1 &&
|
||||||
P2 == command.P2 &&
|
P2 == command.P2 &&
|
||||||
EqualityComparer<byte[]>.Default.Equals(Data, command.Data);
|
Data.SequenceEqual(command.Data) &&
|
||||||
|
Le == command.Le;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
@ -43,5 +44,40 @@ namespace NFC.ISO7816_4
|
|||||||
hash.Add(IsValid);
|
hash.Add(IsValid);
|
||||||
return hash.ToHashCode();
|
return hash.ToHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(APDUCommand obj1, APDUCommand obj2)
|
||||||
|
{
|
||||||
|
return obj1.Equals(obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(APDUCommand obj1, APDUCommand obj2)
|
||||||
|
{
|
||||||
|
return !(obj1.Equals(obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string pattern_case1 = "(CASE: 1) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x}";
|
||||||
|
string pattern_case2 = "(CASE: 2) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LE: 0x{4:x} |";
|
||||||
|
string pattern_case3 = "(CASE: 3) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LC: 0x{4:x} | Data: {5:x}";
|
||||||
|
string pattern_case4 = "(CASE: 4) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LC: 0x{4:x} | Data: {5:x} | LE: 0x{6:x} |";
|
||||||
|
|
||||||
|
switch (Case)
|
||||||
|
{
|
||||||
|
case IsoCase.Case1:
|
||||||
|
return string.Format(pattern_case1, CLA, INS, P1, P2);
|
||||||
|
case IsoCase.Case2Short:
|
||||||
|
case IsoCase.Case2Extended:
|
||||||
|
return string.Format(pattern_case2, CLA, INS, P1, P2, Le);
|
||||||
|
case IsoCase.Case3Short:
|
||||||
|
case IsoCase.Case3Extended:
|
||||||
|
return string.Format(pattern_case3, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "));
|
||||||
|
case IsoCase.Case4Short:
|
||||||
|
case IsoCase.Case4Extended:
|
||||||
|
return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "), Le);
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown IsoCase");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
CREATE_CYCLIC_RECORD_FILE = 0xC0,
|
CREATE_CYCLIC_RECORD_FILE = 0xC0,
|
||||||
DELETE_FILE = 0xDF,
|
DELETE_FILE = 0xDF,
|
||||||
GET_ISO_FILE_IDS = 0x61,
|
GET_ISO_FILE_IDS = 0x61,
|
||||||
READ_DATA = 0x8D,
|
READ_DATA = 0xBD,
|
||||||
WRITE_DATA = 0x3D,
|
WRITE_DATA = 0x3D,
|
||||||
GET_VALUE = 0x6C,
|
GET_VALUE = 0x6C,
|
||||||
CREDIT = 0x0C,
|
CREDIT = 0x0C,
|
||||||
|
106
NFC/NXP MIFARE DESFire/CMAC.cs
Normal file
106
NFC/NXP MIFARE DESFire/CMAC.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
using NFC.Crypto;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NFC.NXP_MIFARE_DESFire
|
||||||
|
{
|
||||||
|
public class CMAC
|
||||||
|
{
|
||||||
|
#region Contructors
|
||||||
|
public CMAC(CipherType cipher)
|
||||||
|
{
|
||||||
|
switch(cipher)
|
||||||
|
{
|
||||||
|
case(CipherType.TDES):
|
||||||
|
_Cipher = new TDES();
|
||||||
|
break;
|
||||||
|
case(CipherType.TDES_2K):
|
||||||
|
_Cipher = new TDES_2K();
|
||||||
|
break;
|
||||||
|
case(CipherType.TDES_3K):
|
||||||
|
_Cipher = new TDES_3K();
|
||||||
|
break;
|
||||||
|
case (CipherType.AES):
|
||||||
|
_Cipher = new AES();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unkown Cipher Type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CMAC(ICipher cipher)
|
||||||
|
{
|
||||||
|
_Cipher = cipher ?? throw new ArgumentNullException();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
private ICipher _Cipher;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
/// <summary>
|
||||||
|
/// Generate Key with all Zeros, in KeySize
|
||||||
|
/// </summary>
|
||||||
|
public byte[] GenerateEmpytKey()
|
||||||
|
{
|
||||||
|
byte[] key = new byte[_Cipher.KeySize];
|
||||||
|
for (int i = 0; i < _Cipher.KeySize; i++)
|
||||||
|
{
|
||||||
|
key[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate IV with all Zeros, in KeySize
|
||||||
|
/// </summary>
|
||||||
|
public byte[] GenerateEmpytIV()
|
||||||
|
{
|
||||||
|
byte[] key = new byte[_Cipher.BlockSize];
|
||||||
|
for (int i = 0; i < _Cipher.BlockSize; i++)
|
||||||
|
{
|
||||||
|
key[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt Data
|
||||||
|
/// </summary>
|
||||||
|
public byte[] Encrypt(byte[] data)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt Data
|
||||||
|
/// </summary>
|
||||||
|
public byte[] Decrypt(byte[] data)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Two Keys</returns>
|
||||||
|
public byte[][] GenerateSubKey()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public byte[] Digest(byte[] data)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
namespace NFC.Mifare_DESFire.Enums
|
namespace NFC.Mifare_DESFire.Enums
|
||||||
{
|
{
|
||||||
public enum AccessRights : byte
|
public enum FileAccessRights : byte
|
||||||
{
|
{
|
||||||
FREE = 0x0E,
|
FREE = 0x0E,
|
||||||
NEVER = 0x0F
|
NEVER = 0x0F
|
@ -1,4 +1,4 @@
|
|||||||
namespace NFC.Mifare_DESFire
|
namespace NFC.Mifare_DESFire.Enums
|
||||||
{
|
{
|
||||||
enum FileTypes : byte
|
enum FileTypes : byte
|
||||||
{
|
{
|
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NFC.NXP_MIFARE_DESFire.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current authentication status does not allow there- quested command.
|
||||||
|
/// 0x91AE
|
||||||
|
/// </summary>
|
||||||
|
public class AuthenticationMissingException : Exception
|
||||||
|
{
|
||||||
|
public AuthenticationMissingException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationMissingException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationMissingException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,844 +0,0 @@
|
|||||||
using log4net.Repository.Hierarchy;
|
|
||||||
using NFC.Crypto;
|
|
||||||
using NFC.ISO7816_4;
|
|
||||||
using NFC.Mifare_DESFire.Enums;
|
|
||||||
using NFC.NXP_MIFARE_DESFire.Exceptions;
|
|
||||||
using PCSC.Iso7816;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace NFC.Mifare_DESFire
|
|
||||||
{
|
|
||||||
public class MIFARE_DESFire_V2
|
|
||||||
{
|
|
||||||
// Docs https://hackmd.io/qATu8uYdRnOC40aFrB9afg
|
|
||||||
|
|
||||||
#region Log
|
|
||||||
private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Contructors
|
|
||||||
/// <summary>
|
|
||||||
/// Construct MIFRARE_DESFire Object with ICard Interface
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="card">Implementation of ICard, only transmit is used</param>
|
|
||||||
public MIFARE_DESFire_V2(ICard card)
|
|
||||||
{
|
|
||||||
_Card = card;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
/// <summary>
|
|
||||||
/// ICard Implementation used to transmit APDUCommands and recive APDUResponses
|
|
||||||
/// </summary>
|
|
||||||
private ICard _Card;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SessionKey, is set after Successfull Authentication
|
|
||||||
/// </summary>
|
|
||||||
public byte[] _SessionKey;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialation Vector for CBC Encryption
|
|
||||||
/// Is 0 bytes after Successfull Authentication
|
|
||||||
/// </summary>
|
|
||||||
public byte[] _IV;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
#region Helper Methods
|
|
||||||
/// <summary>
|
|
||||||
/// Generate Byte Array filled with 0
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="size">Size of Array</param>
|
|
||||||
public byte[] GenerateEmptyKey(uint size)
|
|
||||||
{
|
|
||||||
byte[] key = new byte[size];
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
key[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts byte[] to string with HEX Code
|
|
||||||
/// No 0x is created
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data</param>
|
|
||||||
public string ConvertToHexString(byte[] data)
|
|
||||||
{
|
|
||||||
return BitConverter.ToString(data).Replace("-", "").ToLower();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts string with HEX Code to byte[]
|
|
||||||
/// No 0x is requiered
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data</param>
|
|
||||||
public byte[] ConvertFromHexString(string data)
|
|
||||||
{
|
|
||||||
if (data.Length % 2 == 1)
|
|
||||||
throw new Exception("Data Length is uneven.");
|
|
||||||
|
|
||||||
byte[] arr = new byte[data.Length >> 1];
|
|
||||||
|
|
||||||
for (int i = 0; i < data.Length >> 1; ++i)
|
|
||||||
{
|
|
||||||
arr[i] = (byte)((GetHexVal(data[i << 1]) << 4) + (GetHexVal(data[(i << 1) + 1])));
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetHexVal(char hex)
|
|
||||||
{
|
|
||||||
int val = (int)hex;
|
|
||||||
//For uppercase A-F letters:
|
|
||||||
//return val - (val < 58 ? 48 : 55);
|
|
||||||
//For lowercase a-f letters:
|
|
||||||
//return val - (val < 58 ? 48 : 87);
|
|
||||||
//Or the two combined, but a bit slower:
|
|
||||||
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check APDU Response for DESFire Error Codes
|
|
||||||
/// https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf
|
|
||||||
/// Section: 11.3
|
|
||||||
/// </summary>
|
|
||||||
public void CheckAPDUResponse(APDUResponse response)
|
|
||||||
{
|
|
||||||
if (response == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Response cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.SW1 == 0x91)
|
|
||||||
{
|
|
||||||
switch (response.SW2)
|
|
||||||
{
|
|
||||||
case 0x00: // OPERATION_OK
|
|
||||||
return;
|
|
||||||
case 0x0C: // NO_CHANGES
|
|
||||||
return;
|
|
||||||
case 0x1C: // ILLEGAL_COMMAND_CODE
|
|
||||||
throw new IllegalCommandCodeException();
|
|
||||||
case 0x1E: // INTEGRITY_ERROR
|
|
||||||
throw new IntegrityErrorException();
|
|
||||||
case 0x40: // NO_SUCH_KEY
|
|
||||||
throw new NoSuchKeyException();
|
|
||||||
case 0x7E: // LENGTH_ERROR
|
|
||||||
throw new LengthErrorException();
|
|
||||||
case 0x9D: // PERMISSION_DENIED
|
|
||||||
throw new PermissionDeniedException();
|
|
||||||
case 0x9E: // PARAMETER_ERROR
|
|
||||||
throw new ParameterErrorException();
|
|
||||||
case 0xAD: // AUTHENTICATION_DELAY
|
|
||||||
throw new AuthenticationDelayException();
|
|
||||||
case 0xAE: // AUTHENTICATION_ERROR
|
|
||||||
throw new AuthenticationErrorException();
|
|
||||||
case 0xAF: // ADDITIONAL_FRAME
|
|
||||||
return;
|
|
||||||
case 0xBE: // BOUNDARY_ERROR
|
|
||||||
throw new BoundaryErrorException();
|
|
||||||
case 0xCA: // COMMAND_ABORTED
|
|
||||||
throw new CommandAbortedException();
|
|
||||||
case 0xDE: // DUPLICATE_ERROR
|
|
||||||
throw new DuplicateErrorException();
|
|
||||||
case 0xF0: // FILE_NOT_FOUND
|
|
||||||
throw new FileNotFoundException();
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception(string.Format("Unknown Response Code: 0x{0}.", BitConverter.ToString(new byte[] { response.SW1, response.SW2 }).Replace("-", string.Empty)));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Crypto Operation
|
|
||||||
/// <summary>
|
|
||||||
/// Return a copy of the last Block of data
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data compatible to blocksize</param>
|
|
||||||
/// <param name="blocksize">in byte</param>
|
|
||||||
public byte[] ExtractLastBlock(byte[] data, uint blocksize)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Data cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.Length % blocksize != 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(string.Format("Data is not compatible with blocksize(data(length):{0}, blocksize:{1}.", data.Length, blocksize));
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] lastblock = new byte[blocksize];
|
|
||||||
|
|
||||||
for (int i = 0; i < blocksize; i++)
|
|
||||||
{
|
|
||||||
lastblock[i] = data[data.Length - blocksize + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastblock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rotates Array to the left
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data</param>
|
|
||||||
/// <returns>Copy of data</returns>
|
|
||||||
public byte[] RotateLeft(byte[] data)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Data cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] rotate = new byte[data.Length];
|
|
||||||
data.CopyTo(rotate, 0);
|
|
||||||
|
|
||||||
byte tmp = rotate[0];
|
|
||||||
for (var i = 0; i < rotate.Length - 1; i++)
|
|
||||||
{
|
|
||||||
rotate[i] = rotate[i + 1];
|
|
||||||
}
|
|
||||||
rotate[rotate.Length - 1] = tmp;
|
|
||||||
|
|
||||||
return rotate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rotates Array to the right
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data</param>
|
|
||||||
/// <returns>Copy of data</returns>
|
|
||||||
public byte[] RotateRight(byte[] data)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Data cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] rotate = new byte[data.Length];
|
|
||||||
data.CopyTo(rotate, 0);
|
|
||||||
|
|
||||||
byte tmp = rotate[rotate.Length - 1];
|
|
||||||
for (var i = rotate.Length - 1; i > 0; i--)
|
|
||||||
{
|
|
||||||
rotate[i] = rotate[i - 1];
|
|
||||||
}
|
|
||||||
rotate[0] = tmp;
|
|
||||||
|
|
||||||
return rotate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Concatenates two Arrays, Array A start at index 0
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">Array A</param>
|
|
||||||
/// <param name="b">Array B</param>
|
|
||||||
/// <returns>Copy of Data (a.Size + b.Size)</returns>
|
|
||||||
public byte[] Concatenate(byte[] a, byte[] b)
|
|
||||||
{
|
|
||||||
if (a == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Array A cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Array B cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] c = new byte[a.Length + b.Length];
|
|
||||||
a.CopyTo(c, 0);
|
|
||||||
b.CopyTo(c, a.Length);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Boolean Operation XOR on all Bytes
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">Array A</param>
|
|
||||||
/// <param name="b">Array B</param>
|
|
||||||
/// <returns>Copy of Data</returns>
|
|
||||||
public byte[] XOR(byte[] a, byte[] b)
|
|
||||||
{
|
|
||||||
if (a == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Array A cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("Array B cannot be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.Length != b.Length)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(string.Format("Arrays are not same Length(Length A:{0}, Lenght B:{1})", a.Length, b.Length));
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] c = new byte[a.Length];
|
|
||||||
|
|
||||||
for(int i = 0; i < a.Length; i++)
|
|
||||||
{
|
|
||||||
c[i] = (byte)(a[i] ^ b[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates SessionKey for DES Authentification
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>16Byte SessionKey</returns>
|
|
||||||
public byte[] GenerateSesionKey_DES(byte[] rndA, byte[] rndB)
|
|
||||||
{
|
|
||||||
byte[] sesssionkey = new byte[8];
|
|
||||||
|
|
||||||
for (int i = 0; i < sesssionkey.Length; i++)
|
|
||||||
{
|
|
||||||
if (i < 4)
|
|
||||||
{
|
|
||||||
sesssionkey[i] = rndA[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sesssionkey[i] = rndB[i - 4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DES SessionKey is a double DES Key
|
|
||||||
return Concatenate(sesssionkey, sesssionkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates SessionKey for AES Authentification
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>16Byte SessionKey</returns>
|
|
||||||
public byte[] GenerateSesionKey_AES(byte[] rndA, byte[] rndB)
|
|
||||||
{
|
|
||||||
byte[] sesssionkey = new byte[16];
|
|
||||||
|
|
||||||
for (int i = 0; i < sesssionkey.Length; i++)
|
|
||||||
{
|
|
||||||
if (i < 4)
|
|
||||||
{
|
|
||||||
sesssionkey[i] = rndA[i];
|
|
||||||
}
|
|
||||||
else if(i >= 4 && i < 8)
|
|
||||||
{
|
|
||||||
sesssionkey[i] = rndB[i - 4];
|
|
||||||
}
|
|
||||||
else if (i >= 8 && i < 12)
|
|
||||||
{
|
|
||||||
sesssionkey[i] = rndA[i + 4];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sesssionkey[i] = rndB[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sesssionkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set KeyVersion in DES Key
|
|
||||||
/// KeyVersion is stored in LSB of the first 8 Bytes of the DES Key
|
|
||||||
/// </summary>
|
|
||||||
public byte[] SetKeyVersion(byte[] key, byte keyversion)
|
|
||||||
{
|
|
||||||
byte[] pow2 = new byte[]
|
|
||||||
{
|
|
||||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] new_key = new byte[key.Length];
|
|
||||||
key.CopyTo(new_key, 0);
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((keyversion & pow2[i]) > 0)
|
|
||||||
{
|
|
||||||
new_key[i] = (byte)(new_key[5] | 0x01);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
new_key[i] = (byte)(new_key[5] & 0x7F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Expand Array to Block Size, fill with 0x00
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
public byte[] ExpandToBlockSize(byte[] data, uint bocksize)
|
|
||||||
{
|
|
||||||
int diff = data.Length % (int)bocksize;
|
|
||||||
if (diff == 0)
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] expand = new byte[data.Length + bocksize - diff];
|
|
||||||
|
|
||||||
data.CopyTo(expand, 0);
|
|
||||||
|
|
||||||
for (int i = expand.Length - 1; i > data.Length - 1; i--)
|
|
||||||
{
|
|
||||||
expand[i] = 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
return expand;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region DESFire Commands
|
|
||||||
/// <summary>
|
|
||||||
/// Authenticate to PICC, with ISO Authenticate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key_id">0x01 - 0x0D</param>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <param name="rndA">!!! WARNING For Testing only !!!</param>
|
|
||||||
/// <exception cref="AuthenticationDelayException">Retry after short Time</exception>
|
|
||||||
public void AuthenticateISO_DES(byte key_id, byte[] key, byte[] rndA = null)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start AuthenticateISO_DES");
|
|
||||||
|
|
||||||
// Sepearte InitialisationVector for Authentication
|
|
||||||
byte[] iv = new byte[8];
|
|
||||||
|
|
||||||
APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0x1A,
|
|
||||||
Data = new byte[]
|
|
||||||
{
|
|
||||||
key_id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_challange_request);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
byte[] rndB_enc = response.Body;
|
|
||||||
_Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc));
|
|
||||||
|
|
||||||
DES des = new DES();
|
|
||||||
byte[] rndB = des.Decrypt(rndB_enc, key, GenerateEmptyKey(8));
|
|
||||||
_Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB));
|
|
||||||
|
|
||||||
rndB.CopyTo(iv, 0);
|
|
||||||
|
|
||||||
byte[] rndB_rl = RotateLeft(rndB);
|
|
||||||
_Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl));
|
|
||||||
|
|
||||||
if(rndA == null)
|
|
||||||
{
|
|
||||||
Random rnd = new Random();
|
|
||||||
rndA = new byte[8];
|
|
||||||
rnd.NextBytes(rndA);
|
|
||||||
}
|
|
||||||
_Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA));
|
|
||||||
|
|
||||||
byte[] rndAB = Concatenate(rndA, rndB_rl);
|
|
||||||
_Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB));
|
|
||||||
|
|
||||||
byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc);
|
|
||||||
_Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc));
|
|
||||||
iv = ExtractLastBlock(rndAB_enc, 8);
|
|
||||||
|
|
||||||
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xAF,
|
|
||||||
Data = rndAB_enc
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray()));
|
|
||||||
|
|
||||||
response = _Card.Transmit(cmd_challange_response);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
byte[] encryptedRndAFromCard = response.Body;
|
|
||||||
_Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard));
|
|
||||||
|
|
||||||
byte[] rotatedRndAFromCard = des.Decrypt(encryptedRndAFromCard, key, iv);
|
|
||||||
_Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard));
|
|
||||||
|
|
||||||
byte[] rndAFromCard = RotateRight(rotatedRndAFromCard);
|
|
||||||
_Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard));
|
|
||||||
|
|
||||||
if (!rndA.SequenceEqual(rndAFromCard))
|
|
||||||
{
|
|
||||||
throw new Exception("Authentication failed, PICC Challenge is not corret");
|
|
||||||
}
|
|
||||||
|
|
||||||
_SessionKey = GenerateSesionKey_DES(rndA, rndB);
|
|
||||||
_Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey));
|
|
||||||
|
|
||||||
_IV = GenerateEmptyKey(8);
|
|
||||||
_Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV));
|
|
||||||
|
|
||||||
_Log.Debug("End AuthenticateISO_DES");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Format PICC
|
|
||||||
/// </summary>
|
|
||||||
public void Format()
|
|
||||||
{
|
|
||||||
_Log.Debug("Start Format");
|
|
||||||
|
|
||||||
APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xFC,
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_format): {0}", ConvertToHexString(cmd_format.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_format);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_format): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End Format");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create Application for ID
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="aid">3 Byte ID</param>
|
|
||||||
public void CreateApplication(UInt32 aid, byte keysetting1, byte keysetting2)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start CreateApplication");
|
|
||||||
|
|
||||||
byte[] id_byte = BitConverter.GetBytes(aid);
|
|
||||||
_Log.DebugFormat("AID: {0}", ConvertToHexString(id_byte.ToArray()));
|
|
||||||
|
|
||||||
APDUCommand cmd_CreateApplication = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xCA,
|
|
||||||
Data = new byte[]
|
|
||||||
{
|
|
||||||
id_byte[0],
|
|
||||||
id_byte[1],
|
|
||||||
id_byte[2],
|
|
||||||
keysetting1,
|
|
||||||
keysetting2
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_CreateApplication): {0}", ConvertToHexString(cmd_CreateApplication.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_CreateApplication);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_CreateApplication): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End CreateApplication");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Select Application by AID
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="aid">3 Byte AID</param>
|
|
||||||
public void SelectApplication(UInt32 aid)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start SelectApplication");
|
|
||||||
|
|
||||||
byte[] id_byte = BitConverter.GetBytes(aid);
|
|
||||||
_Log.DebugFormat("AID: {0}", ConvertToHexString(id_byte.ToArray()));
|
|
||||||
|
|
||||||
APDUCommand cmd_SelectApplication = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = (byte)APDUInstructions.SELECT_APPLICATION,
|
|
||||||
Data = new byte[]
|
|
||||||
{
|
|
||||||
id_byte[0],
|
|
||||||
id_byte[1],
|
|
||||||
id_byte[2]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_SelectApplication): {0}", ConvertToHexString(cmd_SelectApplication.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_SelectApplication);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_SelectApplication): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End SelectApplication");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Authenticate to PICC, with ISO Authenticate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key_id">0x01 - 0x0D</param>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <param name="rndA">!!! WARNING For Testing only !!!</param>
|
|
||||||
/// <exception cref="AuthenticationDelayException">Retry after short Time</exception>
|
|
||||||
public void AuthenticateISO_AES(byte key_id, byte[] key, byte[] rndA = null)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start AuthenticateISO_AES");
|
|
||||||
|
|
||||||
// Sepearte InitialisationVector for Authentication
|
|
||||||
byte[] iv = new byte[16];
|
|
||||||
|
|
||||||
APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xAA,
|
|
||||||
Data = new byte[]
|
|
||||||
{
|
|
||||||
key_id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_challange_request);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
byte[] rndB_enc = response.Body;
|
|
||||||
_Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc));
|
|
||||||
|
|
||||||
AES aes = new AES();
|
|
||||||
byte[] rndB = aes.Decrypt(rndB_enc, key, GenerateEmptyKey(16));
|
|
||||||
_Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB));
|
|
||||||
|
|
||||||
rndB.CopyTo(iv, 0);
|
|
||||||
|
|
||||||
byte[] rndB_rl = RotateLeft(rndB);
|
|
||||||
_Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl));
|
|
||||||
|
|
||||||
if (rndA == null)
|
|
||||||
{
|
|
||||||
Random rnd = new Random();
|
|
||||||
rndA = new byte[16];
|
|
||||||
rnd.NextBytes(rndA);
|
|
||||||
}
|
|
||||||
_Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA));
|
|
||||||
|
|
||||||
byte[] rndAB = Concatenate(rndA, rndB_rl);
|
|
||||||
_Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB));
|
|
||||||
|
|
||||||
byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc);
|
|
||||||
_Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc));
|
|
||||||
iv = ExtractLastBlock(rndAB_enc, 16);
|
|
||||||
|
|
||||||
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xAF,
|
|
||||||
Data = rndAB_enc
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray()));
|
|
||||||
|
|
||||||
response = _Card.Transmit(cmd_challange_response);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
byte[] encryptedRndAFromCard = response.Body;
|
|
||||||
_Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard));
|
|
||||||
|
|
||||||
byte[] rotatedRndAFromCard = aes.Decrypt(encryptedRndAFromCard, key, iv);
|
|
||||||
_Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard));
|
|
||||||
|
|
||||||
byte[] rndAFromCard = RotateRight(rotatedRndAFromCard);
|
|
||||||
_Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard));
|
|
||||||
|
|
||||||
if (!rndA.SequenceEqual(rndAFromCard))
|
|
||||||
{
|
|
||||||
throw new Exception("Authentication failed, PICC Challenge is not corret");
|
|
||||||
}
|
|
||||||
|
|
||||||
_SessionKey = GenerateSesionKey_AES(rndA, rndB);
|
|
||||||
_Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey));
|
|
||||||
|
|
||||||
_IV = GenerateEmptyKey(16);
|
|
||||||
_Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV));
|
|
||||||
|
|
||||||
_Log.Debug("End AuthenticateISO_DES");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change Same AES key as Authenticated
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key_id"></param>
|
|
||||||
/// <param name="new_key"></param>
|
|
||||||
/// <param name="key_version"></param>
|
|
||||||
public void ChangeKey_AES(byte key_id, byte[] new_key, byte key_version)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start ChangeKey_AES");
|
|
||||||
|
|
||||||
byte[] header = new byte[]
|
|
||||||
{
|
|
||||||
0xC4, key_id
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("header: {0}", ConvertToHexString(header));
|
|
||||||
|
|
||||||
// AES Key Version is Append to Key
|
|
||||||
byte[] key_and_version = Concatenate(new_key, new byte[] { key_version });
|
|
||||||
byte[] command = Concatenate(header, key_and_version);
|
|
||||||
_Log.DebugFormat("command: {0}", ConvertToHexString(command));
|
|
||||||
|
|
||||||
CRC32 crc32 = new CRC32();
|
|
||||||
byte[] crc = crc32.Calculate(command);
|
|
||||||
_Log.DebugFormat("crc: {0}", ConvertToHexString(crc));
|
|
||||||
|
|
||||||
byte[] cryptogram = Concatenate(key_and_version, crc);
|
|
||||||
_Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram));
|
|
||||||
|
|
||||||
byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16);
|
|
||||||
_Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block));
|
|
||||||
|
|
||||||
AES aes = new AES();
|
|
||||||
byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV);
|
|
||||||
_Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc));
|
|
||||||
|
|
||||||
_IV = ExtractLastBlock(cryptogram_enc, 16);
|
|
||||||
_Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV));
|
|
||||||
|
|
||||||
byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc);
|
|
||||||
_Log.DebugFormat("data: {0}", ConvertToHexString(data));
|
|
||||||
|
|
||||||
APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xC4,
|
|
||||||
Data = data
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End ChangeKey_AES");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change other AES key as Authenticated
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key_id"></param>
|
|
||||||
/// <param name="new_key"></param>
|
|
||||||
/// <param name="key_version"></param>
|
|
||||||
public void ChangeOtherKey_AES(byte key_id, byte[] new_key, byte[] old_key, byte key_version)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start ChangeOtherKey_AES");
|
|
||||||
|
|
||||||
byte[] header = new byte[]
|
|
||||||
{
|
|
||||||
0xC4, key_id
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("header: {0}", ConvertToHexString(header));
|
|
||||||
|
|
||||||
byte[] key_xor = XOR(new_key, old_key);
|
|
||||||
|
|
||||||
// AES Key Version is Append to Key
|
|
||||||
byte[] key_and_version = Concatenate(key_xor, new byte[] { key_version });
|
|
||||||
byte[] command = Concatenate(header, key_and_version);
|
|
||||||
_Log.DebugFormat("command: {0}", ConvertToHexString(command));
|
|
||||||
|
|
||||||
CRC32 crc32 = new CRC32();
|
|
||||||
byte[] crc_cmd = crc32.Calculate(command);
|
|
||||||
_Log.DebugFormat("crc_cmd: {0}", ConvertToHexString(crc_cmd));
|
|
||||||
byte[] crc_key = crc32.Calculate(new_key);
|
|
||||||
_Log.DebugFormat("crc_key: {0}", ConvertToHexString(crc_key));
|
|
||||||
|
|
||||||
byte[] cryptogram = Concatenate(key_and_version, crc_cmd);
|
|
||||||
cryptogram = Concatenate(cryptogram, crc_key);
|
|
||||||
_Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram));
|
|
||||||
|
|
||||||
byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16);
|
|
||||||
_Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block));
|
|
||||||
|
|
||||||
AES aes = new AES();
|
|
||||||
byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV);
|
|
||||||
_Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc));
|
|
||||||
|
|
||||||
_IV = ExtractLastBlock(cryptogram_enc, 16);
|
|
||||||
_Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV));
|
|
||||||
|
|
||||||
byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc);
|
|
||||||
_Log.DebugFormat("data: {0}", ConvertToHexString(data));
|
|
||||||
|
|
||||||
APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xC4,
|
|
||||||
Data = data
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End ChangeOtherKey_AES");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateFile_STD()
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Configuration Generator
|
|
||||||
/// <summary>
|
|
||||||
/// Genearte KeySetting1 for Application Settings or PICC Setting
|
|
||||||
/// </summary>
|
|
||||||
public byte GenerateKeySetting1(ChangeApplicationKey changeKey, ChangeMasterKeySettings changeMasterKeySettings, CreateDeleteFile createDeleteFile, FileDirectoryAccess fileDirectoryAccess, ChangeMasterKey changeMasterKey)
|
|
||||||
{
|
|
||||||
return (byte)(((byte)changeKey << 4) | (byte)changeMasterKeySettings | (byte)createDeleteFile | (byte)fileDirectoryAccess | (byte)changeMasterKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Genearte KeySetting1 for Application Settings or PICC Setting
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="changeKey">ID of Key for changing Application Keys</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public byte GenerateKeySetting1(byte changeKey, ChangeMasterKeySettings changeMasterKeySettings, CreateDeleteFile createDeleteFile, FileDirectoryAccess fileDirectoryAccess, ChangeMasterKey changeMasterKey)
|
|
||||||
{
|
|
||||||
if (changeKey < 0x01 || changeKey >= 0x0E)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
return GenerateKeySetting1(changeKey, changeMasterKeySettings, createDeleteFile, fileDirectoryAccess, changeMasterKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Genearte KeySetting2 for Application Creation
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="numberOfKeys">Number of keys that can be stored within the application (0x01-0x0D)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public byte GenerateKeySetting2(CryptoOperationsType cryptoOperations, FileIdentifies fileIdentifies, byte numberOfKeys)
|
|
||||||
{
|
|
||||||
if (numberOfKeys < 0x01 || numberOfKeys >= 0x0D)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (byte)((byte)cryptoOperations | (byte)fileIdentifies | numberOfKeys);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,211 +0,0 @@
|
|||||||
using NFC;
|
|
||||||
using NFC.Crypto;
|
|
||||||
using NFC.ISO7816_4;
|
|
||||||
using NFC.Mifare_DESFire;
|
|
||||||
using NSubstitute;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using PCSC.Iso7816;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NFC_Test
|
|
||||||
{
|
|
||||||
public class AuthCrypto_Test
|
|
||||||
{
|
|
||||||
public byte[] GenerateDefaultKey(int size)
|
|
||||||
{
|
|
||||||
List<byte> key = new List<byte>();
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
key.Add(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
// https://www.linkedin.com/pulse/mifare-desfire-introduction-david-coelho
|
|
||||||
public void AuthExample()
|
|
||||||
{
|
|
||||||
DES des = new DES();
|
|
||||||
|
|
||||||
byte[] challenge = new byte[]
|
|
||||||
{
|
|
||||||
0x93 ,0x9d ,0x2c ,0x2e ,0xa1 ,0x65 ,0x75 ,0xd5
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] key = GenerateDefaultKey(8);
|
|
||||||
byte[] iv = GenerateDefaultKey(8);
|
|
||||||
|
|
||||||
byte[] rndA = new byte[]
|
|
||||||
{
|
|
||||||
0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] rndB = des.Decrypt(challenge, key, iv);
|
|
||||||
|
|
||||||
byte[] rndB_expected = new byte[]
|
|
||||||
{
|
|
||||||
0xea ,0x48 ,0x50 ,0x13 ,0xd8 ,0x0a ,0x05 ,0x67
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.AreEqual(rndB_expected, rndB);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void concatenate()
|
|
||||||
{
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(null);
|
|
||||||
|
|
||||||
byte[] rndA = new byte[]
|
|
||||||
{
|
|
||||||
0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] rndB = new byte[]
|
|
||||||
{
|
|
||||||
0x48 ,0x50 ,0x13 ,0xd8 ,0x0a ,0x05 ,0x67 ,0xea
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] rndA_rndB_expected = new byte[]
|
|
||||||
{
|
|
||||||
0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07, 0x48 ,0x50 ,0x13 ,0xd8 ,0x0a ,0x05 ,0x67 ,0xea
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] rndA_rndB = mifareDESFire.concatenate(rndA, rndB);
|
|
||||||
|
|
||||||
Assert.AreEqual(rndA_rndB_expected, rndA_rndB);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Auth()
|
|
||||||
{
|
|
||||||
APDUCommand cmd_getchallange = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = (byte)0x1A,
|
|
||||||
Data = new byte[]
|
|
||||||
{
|
|
||||||
0x00
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
APDUCommand cmd_answerchallange = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = (byte)0xAF,
|
|
||||||
Data = new byte[]
|
|
||||||
{
|
|
||||||
0x69, 0x17, 0x8b, 0x93, 0x8c, 0x03, 0xed, 0xf1, 0x86, 0xd3, 0x05, 0x6b, 0xed, 0xc8, 0xd6, 0xcf
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
APDUResponse response = new APDUResponse()
|
|
||||||
{
|
|
||||||
Body = new byte[]
|
|
||||||
{
|
|
||||||
0xB8, 0x90, 0x04, 0x7F, 0x2D, 0xC8, 0xD6, 0x8B
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
APDUResponse response2 = new APDUResponse()
|
|
||||||
{
|
|
||||||
Body = new byte[]
|
|
||||||
{
|
|
||||||
0x04, 0x79, 0xed, 0x6c, 0x4f, 0x74, 0xda, 0x4a
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ICard card = Substitute.For<ICard>();
|
|
||||||
|
|
||||||
card.Transmit(cmd_getchallange).ReturnsForAnyArgs(response);
|
|
||||||
card.Transmit(cmd_answerchallange).Returns(response2);
|
|
||||||
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
mifareDESFire.AuthenticateDES(0x00, mifareDESFire.GenerateDefaultKey(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void ChangeKey()
|
|
||||||
{
|
|
||||||
ICard card = Substitute.For<ICard>();
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
mifareDESFire._SessionKey = new byte[]
|
|
||||||
{
|
|
||||||
0xDC, 0xB0, 0x96, 0xC2, 0xA4, 0x0E, 0x78, 0xE0, 0xA0, 0xE4, 0x7A, 0x96, 0xF4, 0x2E, 0x62, 0xAE
|
|
||||||
};
|
|
||||||
mifareDESFire._IV = new byte[]
|
|
||||||
{
|
|
||||||
0x33, 0x45 , 0xAA , 0x95 , 0xF2 , 0xD9 , 0x56 , 0xCF
|
|
||||||
};
|
|
||||||
|
|
||||||
mifareDESFire.ChangeKeyDES(0x00, GenerateDefaultKey(16), GenerateDefaultKey(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void CRC()
|
|
||||||
{
|
|
||||||
byte[] data = StringToByteArrayFastest("c40045eeb8338ae8f49a032e85bb1114353010");
|
|
||||||
|
|
||||||
CRC32 crc32 = new CRC32();
|
|
||||||
|
|
||||||
byte[] crc = crc32.Calculate(data);
|
|
||||||
|
|
||||||
MIFARE_DESFire dESFire = new MIFARE_DESFire(null);
|
|
||||||
|
|
||||||
Console.WriteLine("data: {0}", dESFire.ConvertToHexString(data));
|
|
||||||
Console.WriteLine("crc: {0}", dESFire.ConvertToHexString(crc));
|
|
||||||
|
|
||||||
byte[] data_crc = dESFire.concatenate(data, crc);
|
|
||||||
Console.WriteLine("data_crc: {0}", dESFire.ConvertToHexString(data_crc));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] StringToByteArrayFastest(string hex)
|
|
||||||
{
|
|
||||||
if (hex.Length % 2 == 1)
|
|
||||||
throw new Exception("The binary key cannot have an odd number of digits");
|
|
||||||
|
|
||||||
byte[] arr = new byte[hex.Length >> 1];
|
|
||||||
|
|
||||||
for (int i = 0; i < hex.Length >> 1; ++i)
|
|
||||||
{
|
|
||||||
arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetHexVal(char hex)
|
|
||||||
{
|
|
||||||
int val = (int)hex;
|
|
||||||
//For uppercase A-F letters:
|
|
||||||
//return val - (val < 58 ? 48 : 55);
|
|
||||||
//For lowercase a-f letters:
|
|
||||||
//return val - (val < 58 ? 48 : 87);
|
|
||||||
//Or the two combined, but a bit slower:
|
|
||||||
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AES()
|
|
||||||
{
|
|
||||||
byte[] data = StringToByteArrayFastest("45eeb8338ae8f49a032e85bb111435301095c3894b0000000000000000000000");
|
|
||||||
byte[] key = StringToByteArrayFastest("d99aca2b5b4de3a949fa2cf12b0eb673");
|
|
||||||
byte[] iv = StringToByteArrayFastest("00000000000000000000000000000000");
|
|
||||||
|
|
||||||
MIFARE_DESFire dESFire = new MIFARE_DESFire(null);
|
|
||||||
|
|
||||||
Console.WriteLine("data: {0}", dESFire.ConvertToHexString(data));
|
|
||||||
Console.WriteLine("key: {0}", dESFire.ConvertToHexString(key));
|
|
||||||
Console.WriteLine("iv: {0}", dESFire.ConvertToHexString(iv));
|
|
||||||
|
|
||||||
AES aes = new AES();
|
|
||||||
|
|
||||||
byte[] data_enc = aes.Encrypt(data, key, iv);
|
|
||||||
Console.WriteLine("data_enc: {0}", dESFire.ConvertToHexString(data_enc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
using NFC.Mifare_DESFire;
|
using NFC.Mifare_DESFire;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace NFC_Test
|
namespace NFC_Test.Crypto
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class AES_Test
|
public class AES_Test
|
||||||
@ -10,7 +10,7 @@ namespace NFC_Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void Encrypt()
|
public void Encrypt()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] data = desfire.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12104a3b07e8eb77a7ac00000000000000");
|
byte[] data = desfire.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12104a3b07e8eb77a7ac00000000000000");
|
||||||
byte[] key = desfire.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b");
|
byte[] key = desfire.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b");
|
23
NFC_Test/Crypto/CRC16_Test.cs
Normal file
23
NFC_Test/Crypto/CRC16_Test.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using NFC;
|
||||||
|
using NFC.Crypto;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace NFC_Test.Crypto
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CRC16_Test
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[Ignore("Unknown Expected Data")]
|
||||||
|
public void Caluclate()
|
||||||
|
{
|
||||||
|
byte[] data = HexConverter.ConvertFromHexString("");
|
||||||
|
byte[] crc_expected = HexConverter.ConvertFromHexString("");
|
||||||
|
|
||||||
|
CRC16 crc16 = new CRC16();
|
||||||
|
byte[] crc = crc16.Calculate(data);
|
||||||
|
|
||||||
|
Assert.AreEqual(crc_expected, crc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
NFC_Test/Crypto/CRC32_Test.cs
Normal file
22
NFC_Test/Crypto/CRC32_Test.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using NFC;
|
||||||
|
using NFC.Crypto;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace NFC_Test.Crypto
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CRC32_Test
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Caluclate()
|
||||||
|
{
|
||||||
|
byte[] data = HexConverter.ConvertFromHexString("c40045eeb8338ae8f49a032e85bb1114353010");
|
||||||
|
byte[] crc_expected = HexConverter.ConvertFromHexString("95c3894b");
|
||||||
|
|
||||||
|
CRC32 crc32 = new CRC32();
|
||||||
|
byte[] crc = crc32.Calculate(data);
|
||||||
|
|
||||||
|
Assert.AreEqual(crc_expected, crc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
NFC_Test/Crypto/TDES_Test.cs
Normal file
61
NFC_Test/Crypto/TDES_Test.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using NFC.Crypto;
|
||||||
|
using NFC.Mifare_DESFire;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace NFC_Test.Crypto
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TDES_Test
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[Ignore("Unknown Expected Data")]
|
||||||
|
public void Encrypt_TDES()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
byte[] data = desfire.ConvertFromHexString("");
|
||||||
|
byte[] key = desfire.ConvertFromHexString("");
|
||||||
|
byte[] iv = desfire.ConvertFromHexString("0000000000000000");
|
||||||
|
|
||||||
|
TDES des = new TDES();
|
||||||
|
byte[] data_enc = des.Encrypt(data, key, iv);
|
||||||
|
|
||||||
|
byte[] data_enc_expected = desfire.ConvertFromHexString("");
|
||||||
|
Assert.AreEqual(data_enc_expected, data_enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Ignore("Unknown Expected Data")]
|
||||||
|
public void Encrypt_TDES_2K()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
byte[] data = desfire.ConvertFromHexString("");
|
||||||
|
byte[] key = desfire.ConvertFromHexString("");
|
||||||
|
byte[] iv = desfire.ConvertFromHexString("0000000000000000");
|
||||||
|
|
||||||
|
TDES_2K des = new TDES_2K();
|
||||||
|
byte[] data_enc = des.Encrypt(data, key, iv);
|
||||||
|
|
||||||
|
byte[] data_enc_expected = desfire.ConvertFromHexString("");
|
||||||
|
Assert.AreEqual(data_enc_expected, data_enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Ignore("Unknown Expected Data")]
|
||||||
|
public void Encrypt_TDES_3K()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
byte[] data = desfire.ConvertFromHexString("");
|
||||||
|
byte[] key = desfire.ConvertFromHexString("");
|
||||||
|
byte[] iv = desfire.ConvertFromHexString("0000000000000000");
|
||||||
|
|
||||||
|
TDES_3K des = new TDES_3K();
|
||||||
|
byte[] data_enc = des.Encrypt(data, key, iv);
|
||||||
|
|
||||||
|
byte[] data_enc_expected = desfire.ConvertFromHexString("");
|
||||||
|
Assert.AreEqual(data_enc_expected, data_enc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
NFC_Test/ISO7816-4/APDUCommand_Test.cs
Normal file
119
NFC_Test/ISO7816-4/APDUCommand_Test.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using NFC.ISO7816_4;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using PCSC.Iso7816;
|
||||||
|
|
||||||
|
namespace NFC_Test.ISO7816_4
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class APDUCommand_Test
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Compare()
|
||||||
|
{
|
||||||
|
APDUCommand command1 = new APDUCommand(IsoCase.Case4Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0xAA,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x03
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
APDUCommand command2 = new APDUCommand(IsoCase.Case4Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0xAA,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x03
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.IsTrue(command1 == command2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Compare_Diff()
|
||||||
|
{
|
||||||
|
APDUCommand command1 = new APDUCommand(IsoCase.Case4Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0xAA,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x03
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
APDUCommand command2 = new APDUCommand(IsoCase.Case4Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0x1A,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x03
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.IsFalse(command1 == command2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ToString_Case1()
|
||||||
|
{
|
||||||
|
APDUCommand command = new APDUCommand(IsoCase.Case1)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0x1A
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine(command.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ToString_Case2()
|
||||||
|
{
|
||||||
|
APDUCommand command = new APDUCommand(IsoCase.Case2Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0x1A
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine(command.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ToString_Case3()
|
||||||
|
{
|
||||||
|
APDUCommand command = new APDUCommand(IsoCase.Case3Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0x1A,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x03
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine(command.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ToString_Case4()
|
||||||
|
{
|
||||||
|
APDUCommand command = new APDUCommand(IsoCase.Case4Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0x1A,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
0x01, 0x02, 0x03
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine(command.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
using NFC;
|
|
||||||
using NFC.Mifare_DESFire;
|
|
||||||
using NFC.Mifare_DESFire.Enums;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NFC_Test
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class MifareDESFire_Commands
|
|
||||||
{
|
|
||||||
private MIFARE_DESFire _MifareDESFire;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void SetUp()
|
|
||||||
{
|
|
||||||
//_MifareDESFire = new MifareDESFire();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetApplicationIDs()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GenerateKeySetting1()
|
|
||||||
{
|
|
||||||
Assert.AreEqual(0xEF, _MifareDESFire.GenerateKeySetting1(ChangeApplicationKey.SAMEKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
@ -3,17 +3,13 @@ using NFC.ISO7816_4;
|
|||||||
using NFC.Mifare_DESFire;
|
using NFC.Mifare_DESFire;
|
||||||
using NFC.NXP_MIFARE_DESFire.Exceptions;
|
using NFC.NXP_MIFARE_DESFire.Exceptions;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using NSubstitute.Core;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using PCSC.Iso7816;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace NFC_Test
|
namespace NFC_Test.NXP_MIFARE_DESFire
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class MIFARE_DESFire_V2_Test
|
public class MIFARE_DESFire_Test
|
||||||
{
|
{
|
||||||
#region Helper Methods
|
#region Helper Methods
|
||||||
[Test]
|
[Test]
|
||||||
@ -21,7 +17,7 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
uint i = 16;
|
uint i = 16;
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] data = desfire.GenerateEmptyKey(i);
|
byte[] data = desfire.GenerateEmptyKey(i);
|
||||||
|
|
||||||
@ -37,7 +33,7 @@ namespace NFC_Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void CheckAPDUResponse__NULL()
|
public void CheckAPDUResponse__NULL()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
Assert.Throws<ArgumentNullException>(
|
Assert.Throws<ArgumentNullException>(
|
||||||
delegate
|
delegate
|
||||||
{
|
{
|
||||||
@ -54,7 +50,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x00
|
SW2 = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
Assert.Throws<Exception>(
|
Assert.Throws<Exception>(
|
||||||
delegate
|
delegate
|
||||||
{
|
{
|
||||||
@ -71,7 +67,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x00
|
SW2 = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
desfire.CheckAPDUResponse(response);
|
desfire.CheckAPDUResponse(response);
|
||||||
}
|
}
|
||||||
@ -85,7 +81,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x0C
|
SW2 = 0x0C
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
desfire.CheckAPDUResponse(response);
|
desfire.CheckAPDUResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +94,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x1C
|
SW2 = 0x1C
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<IllegalCommandCodeException>(
|
Assert.Throws<IllegalCommandCodeException>(
|
||||||
delegate
|
delegate
|
||||||
@ -116,7 +112,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x1E
|
SW2 = 0x1E
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<IntegrityErrorException>(
|
Assert.Throws<IntegrityErrorException>(
|
||||||
delegate
|
delegate
|
||||||
@ -134,7 +130,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x40
|
SW2 = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<NoSuchKeyException>(
|
Assert.Throws<NoSuchKeyException>(
|
||||||
delegate
|
delegate
|
||||||
@ -152,7 +148,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x7E
|
SW2 = 0x7E
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<LengthErrorException>(
|
Assert.Throws<LengthErrorException>(
|
||||||
delegate
|
delegate
|
||||||
@ -170,7 +166,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x9D
|
SW2 = 0x9D
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<PermissionDeniedException>(
|
Assert.Throws<PermissionDeniedException>(
|
||||||
delegate
|
delegate
|
||||||
@ -189,7 +185,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0x9E
|
SW2 = 0x9E
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ParameterErrorException>(
|
Assert.Throws<ParameterErrorException>(
|
||||||
delegate
|
delegate
|
||||||
@ -208,7 +204,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xAD
|
SW2 = 0xAD
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<AuthenticationDelayException>(
|
Assert.Throws<AuthenticationDelayException>(
|
||||||
delegate
|
delegate
|
||||||
@ -226,7 +222,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xAE
|
SW2 = 0xAE
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<AuthenticationErrorException>(
|
Assert.Throws<AuthenticationErrorException>(
|
||||||
delegate
|
delegate
|
||||||
@ -244,7 +240,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xAF
|
SW2 = 0xAF
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
desfire.CheckAPDUResponse(response);
|
desfire.CheckAPDUResponse(response);
|
||||||
}
|
}
|
||||||
@ -258,7 +254,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xBE
|
SW2 = 0xBE
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<BoundaryErrorException>(
|
Assert.Throws<BoundaryErrorException>(
|
||||||
delegate
|
delegate
|
||||||
@ -276,7 +272,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xCA
|
SW2 = 0xCA
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<CommandAbortedException>(
|
Assert.Throws<CommandAbortedException>(
|
||||||
delegate
|
delegate
|
||||||
@ -294,7 +290,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xDE
|
SW2 = 0xDE
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<DuplicateErrorException>(
|
Assert.Throws<DuplicateErrorException>(
|
||||||
delegate
|
delegate
|
||||||
@ -312,7 +308,7 @@ namespace NFC_Test
|
|||||||
SW2 = 0xF0
|
SW2 = 0xF0
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<FileNotFoundException>(
|
Assert.Throws<FileNotFoundException>(
|
||||||
delegate
|
delegate
|
||||||
@ -336,7 +332,7 @@ namespace NFC_Test
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] lastblock = desfire.ExtractLastBlock(data, 8);
|
byte[] lastblock = desfire.ExtractLastBlock(data, 8);
|
||||||
|
|
||||||
@ -351,7 +347,7 @@ namespace NFC_Test
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
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);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ArgumentException>(
|
Assert.Throws<ArgumentException>(
|
||||||
delegate
|
delegate
|
||||||
@ -365,7 +361,7 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ArgumentNullException>(
|
Assert.Throws<ArgumentNullException>(
|
||||||
delegate
|
delegate
|
||||||
@ -387,7 +383,7 @@ namespace NFC_Test
|
|||||||
0x02, 0x03, 0x04, 0x01
|
0x02, 0x03, 0x04, 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] data_left = desfire.RotateLeft(data);
|
byte[] data_left = desfire.RotateLeft(data);
|
||||||
|
|
||||||
@ -397,7 +393,7 @@ namespace NFC_Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void RotateLeft_Null()
|
public void RotateLeft_Null()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ArgumentNullException>(
|
Assert.Throws<ArgumentNullException>(
|
||||||
delegate
|
delegate
|
||||||
@ -419,7 +415,7 @@ namespace NFC_Test
|
|||||||
0x04, 0x01, 0x02, 0x03
|
0x04, 0x01, 0x02, 0x03
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] data_left = desfire.RotateRight(data);
|
byte[] data_left = desfire.RotateRight(data);
|
||||||
|
|
||||||
@ -429,7 +425,7 @@ namespace NFC_Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void RotateRight_Null()
|
public void RotateRight_Null()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ArgumentNullException>(
|
Assert.Throws<ArgumentNullException>(
|
||||||
delegate
|
delegate
|
||||||
@ -456,17 +452,47 @@ namespace NFC_Test
|
|||||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] data_c = desfire.Concatenate(data_a, data_b);
|
byte[] data_c = desfire.Concatenate(data_a, data_b);
|
||||||
|
|
||||||
Assert.AreEqual(expected_data_c, data_c);
|
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]
|
[Test]
|
||||||
public void Concatenate_Null()
|
public void Concatenate_Null()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ArgumentNullException>(
|
Assert.Throws<ArgumentNullException>(
|
||||||
delegate
|
delegate
|
||||||
@ -493,7 +519,7 @@ namespace NFC_Test
|
|||||||
0x0F, 0xF0, 0x0F, 0xF0
|
0x0F, 0xF0, 0x0F, 0xF0
|
||||||
};
|
};
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] data_c = desfire.XOR(data_a, data_b);
|
byte[] data_c = desfire.XOR(data_a, data_b);
|
||||||
|
|
||||||
@ -503,7 +529,7 @@ namespace NFC_Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void XOR_null()
|
public void XOR_null()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
Assert.Throws<ArgumentNullException>(
|
Assert.Throws<ArgumentNullException>(
|
||||||
delegate
|
delegate
|
||||||
@ -515,7 +541,7 @@ namespace NFC_Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void GenerateSessionKey_AES()
|
public void GenerateSessionKey_AES()
|
||||||
{
|
{
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
byte[] rndA = desfire.ConvertFromHexString("bc14dfde20074617e45a8822f06fdd91");
|
byte[] rndA = desfire.ConvertFromHexString("bc14dfde20074617e45a8822f06fdd91");
|
||||||
Console.WriteLine(desfire.ConvertToHexString(rndA));
|
Console.WriteLine(desfire.ConvertToHexString(rndA));
|
||||||
@ -537,31 +563,31 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
ICard card = Substitute.For<ICard>();
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
APDUResponse response_challenge_request = new APDUResponse()
|
APDUResponse response_challenge_request = new APDUResponse()
|
||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0xAF,
|
SW2 = 0xAF,
|
||||||
Body = desfire.ConvertFromHexString("5D994CE085F24089")
|
Body = HexConverter.ConvertFromHexString("5D994CE085F24089")
|
||||||
};
|
};
|
||||||
|
|
||||||
APDUResponse response_challenge_response = new APDUResponse()
|
APDUResponse response_challenge_response = new APDUResponse()
|
||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0x00,
|
SW2 = 0x00,
|
||||||
Body = desfire.ConvertFromHexString("913C6DED84221C41")
|
Body = HexConverter.ConvertFromHexString("913C6DED84221C41")
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] rndA = desfire.ConvertFromHexString("849B36C5F8BF4A09");
|
byte[] rndA = HexConverter.ConvertFromHexString("849B36C5F8BF4A09");
|
||||||
byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] key = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0x1A)).Returns(response_challenge_request);
|
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);
|
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAF)).Returns(response_challenge_response);
|
||||||
|
|
||||||
desfire.AuthenticateISO_DES(0x00, key, rndA);
|
desfire.AuthenticateISO_DES(0x00, key, rndA);
|
||||||
|
|
||||||
byte[] expected_sessionkey = desfire.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759");
|
byte[] expected_sessionkey = HexConverter.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759");
|
||||||
byte[] expected_iv = desfire.GenerateEmptyKey(8);
|
byte[] expected_iv = desfire.GenerateEmptyKey(8);
|
||||||
|
|
||||||
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
||||||
@ -573,31 +599,31 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
ICard card = Substitute.For<ICard>();
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
APDUResponse response_challenge_request = new APDUResponse()
|
APDUResponse response_challenge_request = new APDUResponse()
|
||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0xAF,
|
SW2 = 0xAF,
|
||||||
Body = desfire.ConvertFromHexString("43a28e28c653df83cd85039714bccb51")
|
Body = HexConverter.ConvertFromHexString("43a28e28c653df83cd85039714bccb51")
|
||||||
};
|
};
|
||||||
|
|
||||||
APDUResponse response_challenge_response = new APDUResponse()
|
APDUResponse response_challenge_response = new APDUResponse()
|
||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0x00,
|
SW2 = 0x00,
|
||||||
Body = desfire.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f")
|
Body = HexConverter.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f")
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] rndA = desfire.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1");
|
byte[] rndA = HexConverter.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1");
|
||||||
byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] key = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAA)).Returns(response_challenge_request);
|
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAA)).Returns(response_challenge_request);
|
||||||
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAF)).Returns(response_challenge_response);
|
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAF)).Returns(response_challenge_response);
|
||||||
|
|
||||||
desfire.AuthenticateISO_AES(0x00, key, rndA);
|
desfire.AuthenticateISO_AES(0x00, key, rndA);
|
||||||
|
|
||||||
byte[] expected_sessionkey = desfire.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703");
|
byte[] expected_sessionkey = HexConverter.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703");
|
||||||
byte[] expected_iv = desfire.GenerateEmptyKey(16);
|
byte[] expected_iv = desfire.GenerateEmptyKey(16);
|
||||||
|
|
||||||
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
||||||
@ -609,7 +635,7 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
ICard card = Substitute.For<ICard>();
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
APDUResponse response = new APDUResponse()
|
APDUResponse response = new APDUResponse()
|
||||||
{
|
{
|
||||||
@ -617,10 +643,10 @@ namespace NFC_Test
|
|||||||
SW2 = 0x00
|
SW2 = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] new_key = desfire.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530");
|
byte[] new_key = HexConverter.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530");
|
||||||
|
|
||||||
byte[] sessionkey = desfire.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3");
|
byte[] sessionkey = HexConverter.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3");
|
||||||
byte[] iv = desfire.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
desfire._SessionKey = sessionkey;
|
desfire._SessionKey = sessionkey;
|
||||||
desfire._IV = iv;
|
desfire._IV = iv;
|
||||||
@ -635,7 +661,7 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
ICard card = Substitute.For<ICard>();
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
APDUResponse response = new APDUResponse()
|
APDUResponse response = new APDUResponse()
|
||||||
{
|
{
|
||||||
@ -643,11 +669,11 @@ namespace NFC_Test
|
|||||||
SW2 = 0x00
|
SW2 = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] new_key = desfire.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12");
|
byte[] new_key = HexConverter.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12");
|
||||||
byte[] old_key = desfire.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] old_key = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
byte[] sessionkey = desfire.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b");
|
byte[] sessionkey = HexConverter.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b");
|
||||||
byte[] iv = desfire.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
desfire._SessionKey = sessionkey;
|
desfire._SessionKey = sessionkey;
|
||||||
desfire._IV = iv;
|
desfire._IV = iv;
|
||||||
@ -657,5 +683,27 @@ namespace NFC_Test
|
|||||||
desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10);
|
desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Configuration Generator
|
||||||
|
[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<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.GenerateFileAccessRights(0x10, 0x00, 0x00, 0x00);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,14 +1,11 @@
|
|||||||
using log4net;
|
using log4net.Config;
|
||||||
using log4net.Config;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace NFC_Test
|
namespace NFC_Test
|
||||||
{
|
{
|
||||||
[SetUpFixture]
|
[SetUpFixture]
|
||||||
public class NamespaceSetUp
|
public class NamespaceSetUp
|
||||||
{
|
{
|
||||||
private static readonly ILog log = LogManager.GetLogger(typeof(NamespaceSetUp));
|
|
||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public void OneTimeSetUp()
|
public void OneTimeSetUp()
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,8 @@ using NFC;
|
|||||||
using NFC.Readers.PCSC;
|
using NFC.Readers.PCSC;
|
||||||
using NFC.Mifare_DESFire;
|
using NFC.Mifare_DESFire;
|
||||||
using NFC.Mifare_DESFire.Enums;
|
using NFC.Mifare_DESFire.Enums;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace NFC_Test
|
namespace NFC_Test
|
||||||
{
|
{
|
||||||
@ -23,7 +25,7 @@ namespace NFC_Test
|
|||||||
{
|
{
|
||||||
card.Connect();
|
card.Connect();
|
||||||
|
|
||||||
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
desfire.SelectApplication(0x000000);
|
desfire.SelectApplication(0x000000);
|
||||||
desfire.AuthenticateISO_DES(0x00, desfire.GenerateEmptyKey(16));
|
desfire.AuthenticateISO_DES(0x00, desfire.GenerateEmptyKey(16));
|
||||||
@ -49,6 +51,15 @@ namespace NFC_Test
|
|||||||
desfire.AuthenticateISO_AES(0x00, key_master);
|
desfire.AuthenticateISO_AES(0x00, key_master);
|
||||||
desfire.ChangeOtherKey_AES(0x02, key_2, desfire.GenerateEmptyKey(16), 0x10);
|
desfire.ChangeOtherKey_AES(0x02, key_2, desfire.GenerateEmptyKey(16), 0x10);
|
||||||
|
|
||||||
|
UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00);
|
||||||
|
desfire.CreateFile_Standard(0x01, FileCommunication.PLAIN, accesRights, 0x100);
|
||||||
|
|
||||||
|
desfire.WriteData(0x01, 0, Encoding.ASCII.GetBytes("user@domain.org"));
|
||||||
|
|
||||||
|
byte[] data = desfire.ReadData(0x01, 0, 32);
|
||||||
|
|
||||||
|
Console.WriteLine(Encoding.ASCII.GetString(data));
|
||||||
|
|
||||||
transmit_successfully = true;
|
transmit_successfully = true;
|
||||||
|
|
||||||
card.Disconnect();
|
card.Disconnect();
|
||||||
|
@ -58,275 +58,5 @@ namespace NFC_Test
|
|||||||
reader.Stop();
|
reader.Stop();
|
||||||
reader.CardDiscovered -= handler;
|
reader.CardDiscovered -= handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0")]
|
|
||||||
public void GetApplicationIDs(string readerID)
|
|
||||||
{
|
|
||||||
IHardware hardware = new Hardware();
|
|
||||||
IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
bool transmit_successfully = false;
|
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
|
||||||
{
|
|
||||||
card.Connect();
|
|
||||||
|
|
||||||
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
//APDUCommand cmd = desfire.GetApplicationIDs();
|
|
||||||
|
|
||||||
//APDUResponse response = card.Transmit(cmd);
|
|
||||||
|
|
||||||
//if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK)
|
|
||||||
//{
|
|
||||||
// UInt32[] ApplicationIDs = desfire.ConvertApplicationIDs(response);
|
|
||||||
|
|
||||||
// foreach(UInt32 id in ApplicationIDs)
|
|
||||||
// {
|
|
||||||
// Console.WriteLine("0x{0:X3}", id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// transmit_successfully = true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
card.Disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
|
||||||
reader.Start();
|
|
||||||
|
|
||||||
Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
reader.Stop();
|
|
||||||
reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xC0FFEE)]
|
|
||||||
public void SelectApplication(string readerID, UInt32 applicationID)
|
|
||||||
{
|
|
||||||
IHardware hardware = new Hardware();
|
|
||||||
IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
bool transmit_successfully = false;
|
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
|
||||||
{
|
|
||||||
card.Connect();
|
|
||||||
|
|
||||||
//MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
//APDUCommand cmd = desfire.SelectApplication(applicationID);
|
|
||||||
|
|
||||||
//cmd.ToArray();
|
|
||||||
|
|
||||||
//APDUResponse response = card.Transmit(cmd);
|
|
||||||
|
|
||||||
//if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK)
|
|
||||||
//{
|
|
||||||
// transmit_successfully = true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
card.Disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
|
||||||
reader.Start();
|
|
||||||
|
|
||||||
Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
reader.Stop();
|
|
||||||
reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xAAFFEE)]
|
|
||||||
public void CreateApplication(string readerID, UInt32 applicationID)
|
|
||||||
{
|
|
||||||
//IHardware hardware = new Hardware();
|
|
||||||
//IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
//bool transmit_successfully = false;
|
|
||||||
|
|
||||||
//ReaderEventHandler handler = (sender, card) =>
|
|
||||||
//{
|
|
||||||
// card.Connect();
|
|
||||||
|
|
||||||
// MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
// byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
|
|
||||||
// byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.TDES, FileIdentifies.NOTUSED, 0x03);
|
|
||||||
|
|
||||||
// APDUCommand cmd = desfire.CreateApplication(applicationID, keysetting1, keysetting2);
|
|
||||||
|
|
||||||
// Console.WriteLine(cmd.ToArray());
|
|
||||||
|
|
||||||
// APDUResponse response = card.Transmit(cmd);
|
|
||||||
|
|
||||||
// if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK)
|
|
||||||
// {
|
|
||||||
// transmit_successfully = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// card.Disconnect();
|
|
||||||
//};
|
|
||||||
|
|
||||||
//reader.CardDiscovered += handler;
|
|
||||||
//reader.Start();
|
|
||||||
|
|
||||||
//Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
//reader.Stop();
|
|
||||||
//reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xAAFFEE)]
|
|
||||||
public void DeleteApplication(string readerID, UInt32 applicationID)
|
|
||||||
{
|
|
||||||
IHardware hardware = new Hardware();
|
|
||||||
IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
bool transmit_successfully = false;
|
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
|
||||||
{
|
|
||||||
card.Connect();
|
|
||||||
|
|
||||||
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
desfire.SelectApplication(0x000000);
|
|
||||||
desfire.AuthenticateDES(0x00, GenerateDefaultKey(8));
|
|
||||||
desfire.DeleteApplication(applicationID);
|
|
||||||
|
|
||||||
transmit_successfully = true;
|
|
||||||
|
|
||||||
card.Disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
|
||||||
reader.Start();
|
|
||||||
|
|
||||||
Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
reader.Stop();
|
|
||||||
reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] GenerateDefaultKey(int size)
|
|
||||||
{
|
|
||||||
List<byte> key = new List<byte>();
|
|
||||||
for(int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
key.Add(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used Default PICC Key with PICC authenticate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="readerID"></param>
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0")]
|
|
||||||
public void Authenticate(string readerID)
|
|
||||||
{
|
|
||||||
IHardware hardware = new Hardware();
|
|
||||||
IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
bool transmit_successfully = false;
|
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
|
||||||
{
|
|
||||||
card.Connect();
|
|
||||||
|
|
||||||
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
desfire.SelectApplication(0x000000);
|
|
||||||
desfire.AuthenticateDES(0x00, GenerateDefaultKey(8));
|
|
||||||
|
|
||||||
transmit_successfully = true;
|
|
||||||
|
|
||||||
card.Disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
|
||||||
reader.Start();
|
|
||||||
|
|
||||||
Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
reader.Stop();
|
|
||||||
reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0")]
|
|
||||||
public void ChangeKey(string readerID)
|
|
||||||
{
|
|
||||||
IHardware hardware = new Hardware();
|
|
||||||
IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
bool transmit_successfully = false;
|
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
|
||||||
{
|
|
||||||
card.Connect();
|
|
||||||
|
|
||||||
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
desfire.SelectApplication(0xAAFFEE);
|
|
||||||
desfire.AuthenticateDES(0x00, GenerateDefaultKey(8));
|
|
||||||
desfire.ChangeKeyDES(0x00, GenerateDefaultKey(8), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF });
|
|
||||||
|
|
||||||
transmit_successfully = true;
|
|
||||||
|
|
||||||
card.Disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
|
||||||
reader.Start();
|
|
||||||
|
|
||||||
Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
reader.Stop();
|
|
||||||
reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("ACS ACR122U PICC Interface 0")]
|
|
||||||
public void ChangeKey_Test(string readerID)
|
|
||||||
{
|
|
||||||
IHardware hardware = new Hardware();
|
|
||||||
IReader reader = hardware.OpenReader(readerID);
|
|
||||||
|
|
||||||
bool transmit_successfully = false;
|
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
|
||||||
{
|
|
||||||
card.Connect();
|
|
||||||
|
|
||||||
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
|
||||||
|
|
||||||
desfire.SelectApplication(0xAAFFEE);
|
|
||||||
desfire.AuthenticateDES(0x00, GenerateDefaultKey(8));
|
|
||||||
|
|
||||||
APDUCommand cmd = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xC4,
|
|
||||||
Data = GenerateDefaultKey(1 + 16 + 4 + 4)
|
|
||||||
// KEY_NO, KEY, CRC32, PADDING
|
|
||||||
};
|
|
||||||
|
|
||||||
card.Transmit(cmd);
|
|
||||||
|
|
||||||
transmit_successfully = true;
|
|
||||||
|
|
||||||
card.Disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
|
||||||
reader.Start();
|
|
||||||
|
|
||||||
Assert.AreEqual(true, transmit_successfully);
|
|
||||||
|
|
||||||
reader.Stop();
|
|
||||||
reader.CardDiscovered -= handler;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,183 +9,183 @@ using System.Text;
|
|||||||
|
|
||||||
namespace NFC_Test
|
namespace NFC_Test
|
||||||
{
|
{
|
||||||
[TestFixture]
|
//[TestFixture]
|
||||||
public class REAL_Windows_CardSetUp
|
//public class REAL_Windows_CardSetUp
|
||||||
{
|
//{
|
||||||
public static UInt32 FabAccessAID = 0x001100;
|
// public static UInt32 FabAccessAID = 0x001100;
|
||||||
public static string CardReaderID = "ACS ACR122U PICC Interface 0";
|
// public static string CardReaderID = "ACS ACR122U PICC Interface 0";
|
||||||
public static byte[] PICC_MasterKey = new byte[]
|
// public static byte[] PICC_MasterKey = new byte[]
|
||||||
{
|
// {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
// };
|
||||||
|
|
||||||
public static byte[] APP_MasterKey = new byte[]
|
// public static byte[] APP_MasterKey = new byte[]
|
||||||
{
|
// {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
// };
|
||||||
|
|
||||||
public static byte[] APP_Key_1 = new byte[]
|
// public static byte[] APP_Key_1 = new byte[]
|
||||||
{
|
// {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
// };
|
||||||
|
|
||||||
public static byte[] APP_Key_2 = new byte[]
|
// public static byte[] APP_Key_2 = new byte[]
|
||||||
{
|
// {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
// };
|
||||||
|
|
||||||
public static byte[] Empty_Key = new byte[]
|
// public static byte[] Empty_Key = new byte[]
|
||||||
{
|
// {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
// };
|
||||||
|
|
||||||
public static byte FabAccessIdentFileID = 0x01;
|
// public static byte FabAccessIdentFileID = 0x01;
|
||||||
public static string UserDomain = "user1@fabaccess.org";
|
// public static string UserDomain = "user1@fabaccess.org";
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void ResetCard()
|
// public void ResetCard()
|
||||||
{
|
// {
|
||||||
IHardware hardware = new Hardware();
|
// IHardware hardware = new Hardware();
|
||||||
IReader reader = hardware.OpenReader(CardReaderID);
|
// IReader reader = hardware.OpenReader(CardReaderID);
|
||||||
|
|
||||||
bool connected_successfully = false;
|
// bool connected_successfully = false;
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
// ReaderEventHandler handler = (sender, card) =>
|
||||||
{
|
// {
|
||||||
card.Connect();
|
// card.Connect();
|
||||||
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
// MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
mifareDESFire.AuthenticateDES(0x01, PICC_MasterKey);
|
// mifareDESFire.AuthenticateISO_DES(0x01, PICC_MasterKey);
|
||||||
|
|
||||||
mifareDESFire.Format();
|
// mifareDESFire.Format();
|
||||||
|
|
||||||
connected_successfully = true;
|
// connected_successfully = true;
|
||||||
|
|
||||||
card.Disconnect();
|
// card.Disconnect();
|
||||||
};
|
// };
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
// reader.CardDiscovered += handler;
|
||||||
reader.Start();
|
// reader.Start();
|
||||||
|
|
||||||
Assert.AreEqual(true, connected_successfully);
|
// Assert.AreEqual(true, connected_successfully);
|
||||||
|
|
||||||
reader.Stop();
|
// reader.Stop();
|
||||||
reader.CardDiscovered -= handler;
|
// reader.CardDiscovered -= handler;
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void ProvisionCard()
|
// public void ProvisionCard()
|
||||||
{
|
// {
|
||||||
IHardware hardware = new Hardware();
|
// IHardware hardware = new Hardware();
|
||||||
IReader reader = hardware.OpenReader(CardReaderID);
|
// IReader reader = hardware.OpenReader(CardReaderID);
|
||||||
|
|
||||||
bool connected_successfully = false;
|
// bool connected_successfully = false;
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
// ReaderEventHandler handler = (sender, card) =>
|
||||||
{
|
// {
|
||||||
card.Connect();
|
// card.Connect();
|
||||||
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
// MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
mifareDESFire.AuthenticateDES(0x01, APP_MasterKey);
|
// mifareDESFire.AuthenticateISO_DES(0x01, APP_MasterKey);
|
||||||
mifareDESFire.CreateApplication(FabAccessAID);
|
// mifareDESFire.CreateApplication(FabAccessAID);
|
||||||
mifareDESFire.SelectApplication(FabAccessAID);
|
// mifareDESFire.SelectApplication(FabAccessAID);
|
||||||
|
|
||||||
mifareDESFire.AuthenticateDES(0x00, Empty_Key);
|
// mifareDESFire.AuthenticateDES(0x00, Empty_Key);
|
||||||
mifareDESFire.ChangeApplicationMasterKey(APP_MasterKey);
|
// mifareDESFire.ChangeApplicationMasterKey(APP_MasterKey);
|
||||||
|
|
||||||
mifareDESFire.AuthenticateDES(0x00, APP_MasterKey);
|
// mifareDESFire.AuthenticateDES(0x00, APP_MasterKey);
|
||||||
mifareDESFire.ChangeApplicationKey(0x01, APP_Key_1);
|
// mifareDESFire.ChangeApplicationKey(0x01, APP_Key_1);
|
||||||
|
|
||||||
connected_successfully = true;
|
// connected_successfully = true;
|
||||||
|
|
||||||
card.Disconnect();
|
// card.Disconnect();
|
||||||
};
|
// };
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
// reader.CardDiscovered += handler;
|
||||||
reader.Start();
|
// reader.Start();
|
||||||
|
|
||||||
Assert.AreEqual(true, connected_successfully);
|
// Assert.AreEqual(true, connected_successfully);
|
||||||
|
|
||||||
reader.Stop();
|
// reader.Stop();
|
||||||
reader.CardDiscovered -= handler;
|
// reader.CardDiscovered -= handler;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void SetUpUserCard()
|
// public void SetUpUserCard()
|
||||||
{
|
// {
|
||||||
IHardware hardware = new Hardware();
|
// IHardware hardware = new Hardware();
|
||||||
IReader reader = hardware.OpenReader(CardReaderID);
|
// IReader reader = hardware.OpenReader(CardReaderID);
|
||||||
|
|
||||||
bool connected_successfully = false;
|
// bool connected_successfully = false;
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
// ReaderEventHandler handler = (sender, card) =>
|
||||||
{
|
// {
|
||||||
card.Connect();
|
// card.Connect();
|
||||||
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
// MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
mifareDESFire.SelectApplication(FabAccessAID);
|
// mifareDESFire.SelectApplication(FabAccessAID);
|
||||||
mifareDESFire.AuthenticateDES(0x00, Empty_Key);
|
// mifareDESFire.AuthenticateDES(0x00, Empty_Key);
|
||||||
UInt16 fileAccessRight = mifareDESFire.GenerateFileAccessRight(AccessRights.FREE, 0x00, 0x00, 0x00);
|
// UInt16 fileAccessRight = mifareDESFire.GenerateFileAccessRight(AccessRights.FREE, 0x00, 0x00, 0x00);
|
||||||
mifareDESFire.CreateFile(FabAccessIdentFileID, FileCommunication.PLAIN, fileAccessRight, (UInt32)0x90);
|
// mifareDESFire.CreateFile(FabAccessIdentFileID, FileCommunication.PLAIN, fileAccessRight, (UInt32)0x90);
|
||||||
|
|
||||||
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
|
// System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
|
||||||
|
|
||||||
mifareDESFire.WirteData(FabAccessIdentFileID, 0x00000000, 0x00000000, enc.GetBytes(UserDomain));
|
// mifareDESFire.WirteData(FabAccessIdentFileID, 0x00000000, 0x00000000, enc.GetBytes(UserDomain));
|
||||||
|
|
||||||
connected_successfully = true;
|
// connected_successfully = true;
|
||||||
|
|
||||||
card.Disconnect();
|
// card.Disconnect();
|
||||||
};
|
// };
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
// reader.CardDiscovered += handler;
|
||||||
reader.Start();
|
// reader.Start();
|
||||||
|
|
||||||
Assert.AreEqual(true, connected_successfully);
|
// Assert.AreEqual(true, connected_successfully);
|
||||||
|
|
||||||
reader.Stop();
|
// reader.Stop();
|
||||||
reader.CardDiscovered -= handler;
|
// reader.CardDiscovered -= handler;
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void AuthenticateCard()
|
// public void AuthenticateCard()
|
||||||
{
|
// {
|
||||||
IHardware hardware = new Hardware();
|
// IHardware hardware = new Hardware();
|
||||||
IReader reader = hardware.OpenReader(CardReaderID);
|
// IReader reader = hardware.OpenReader(CardReaderID);
|
||||||
|
|
||||||
bool connected_successfully = false;
|
// bool connected_successfully = false;
|
||||||
|
|
||||||
ReaderEventHandler handler = (sender, card) =>
|
// ReaderEventHandler handler = (sender, card) =>
|
||||||
{
|
// {
|
||||||
card.Connect();
|
// card.Connect();
|
||||||
|
|
||||||
MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
// MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
mifareDESFire.SelectApplication(FabAccessAID);
|
// mifareDESFire.SelectApplication(FabAccessAID);
|
||||||
byte[] filedata = mifareDESFire.ReadData(FabAccessIdentFileID, 0x00000000, 0x00000000);
|
// byte[] filedata = mifareDESFire.ReadData(FabAccessIdentFileID, 0x00000000, 0x00000000);
|
||||||
|
|
||||||
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
|
// System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
|
||||||
string userdomain = enc.GetString(filedata);
|
// string userdomain = enc.GetString(filedata);
|
||||||
|
|
||||||
Console.WriteLine(userdomain);
|
// Console.WriteLine(userdomain);
|
||||||
|
|
||||||
mifareDESFire.AuthenticateDES(0x01, APP_Key_1);
|
// mifareDESFire.AuthenticateDES(0x01, APP_Key_1);
|
||||||
|
|
||||||
connected_successfully = true;
|
// connected_successfully = true;
|
||||||
|
|
||||||
card.Disconnect();
|
// card.Disconnect();
|
||||||
};
|
// };
|
||||||
|
|
||||||
reader.CardDiscovered += handler;
|
// reader.CardDiscovered += handler;
|
||||||
reader.Start();
|
// reader.Start();
|
||||||
|
|
||||||
Assert.AreEqual(true, connected_successfully);
|
// Assert.AreEqual(true, connected_successfully);
|
||||||
|
|
||||||
reader.Stop();
|
// reader.Stop();
|
||||||
reader.CardDiscovered -= handler;
|
// reader.CardDiscovered -= handler;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user