This commit is contained in:
TheJoKlLa 2020-10-06 15:59:53 +02:00
parent d601e9afb3
commit f5dffcec5b
5 changed files with 338 additions and 67 deletions

View File

@ -3,6 +3,7 @@ using System.Threading;
using CoreNFC; using CoreNFC;
using Foundation; using Foundation;
using NFC; using NFC;
using NFC.ISO7816_4;
namespace Borepin.iOS.CNFC namespace Borepin.iOS.CNFC
{ {

44
NFC/Crypto/CRC32.cs Normal file
View File

@ -0,0 +1,44 @@
using System;
namespace NFC.Crypto
{
public class CRC32
{
public byte[] Calculate(byte[] data)
{
UInt32 crc32 = 0xFFFFFFFF;
crc32 = Calculate(data, crc32);
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)
{
for (int i = 0; i < data.Length; i++)
{
crc32 ^= data[i];
for (int b = 0; b < 8; b++)
{
bool b_Bit = (crc32 & 0x01) > 0;
crc32 >>= 1;
if (b_Bit)
{
crc32 ^= 0xEDB88320;
}
}
}
return crc32;
}
}
}

View File

@ -1,16 +1,13 @@
using NFC.Crypto; using NFC.Crypto;
using NFC.ISO7816_4; using NFC.ISO7816_4;
using NFC.Mifare_DESFire.Enums; using NFC.Mifare_DESFire.Enums;
using Org.BouncyCastle.Asn1.Crmf;
using PCSC.Iso7816; using PCSC.Iso7816;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data;
using System.Linq; using System.Linq;
namespace NFC.Mifare_DESFire namespace NFC.Mifare_DESFire
{ {
public class MIFARE_DESFire public class MIFARE_DESFire
{ {
// Docs https://hackmd.io/qATu8uYdRnOC40aFrB9afg // Docs https://hackmd.io/qATu8uYdRnOC40aFrB9afg
@ -31,6 +28,9 @@ namespace NFC.Mifare_DESFire
/// ICard Implementation used to transmit APDUCommands and recive APDUResponses /// ICard Implementation used to transmit APDUCommands and recive APDUResponses
/// </summary> /// </summary>
private ICard _Card; private ICard _Card;
public byte[] _SessionKey;
public byte[] _IV;
#endregion #endregion
#region Methods #region Methods
@ -43,7 +43,7 @@ namespace NFC.Mifare_DESFire
byte[] key = new byte[size]; byte[] key = new byte[size];
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
key.[i] = 0; key[i] = 0;
} }
return key; return key;
@ -64,6 +64,63 @@ namespace NFC.Mifare_DESFire
} }
public bool CheckKey(byte[] key)
{
try
{
GetKeyTypeDES(key);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// Key Types used for DESFire Cards
/// </summary>
public enum KeyType
{
/// <summary>
/// DES Key - 8 Byte - 64 Bit
/// </summary>
DES,
/// <summary>
/// Triple DES Key with two DES Keys - 16 Byte - 128 Bit
/// </summary>
TDES_2K,
/// <summary>
/// Triple DES Key with three DES Keys - 24 Byte - 192 Bit
/// </summary>
TDES_3K,
/// <summary>
/// AES Key - 16 Byte - 128 Bit
/// </summary>
AES
}
/// <summary>
/// Check the Key Length to get Type of DES/3DES Key
/// </summary>
public KeyType GetKeyTypeDES(byte[] key)
{
switch(key.Length)
{
case 8:
return KeyType.DES;
case 16:
return KeyType.TDES_2K;
case 24:
return KeyType.TDES_3K;
default:
throw new ArgumentException(string.Format("No valid DES/3DES Key Size({0})", key.Length));
}
}
#region Methods for Crypto Operation #region Methods for Crypto Operation
/// <summary> /// <summary>
/// Return a copy of the last Block of data /// Return a copy of the last Block of data
@ -141,6 +198,23 @@ namespace NFC.Mifare_DESFire
return c; return c;
} }
public byte[] xor(byte[] a, byte[] b)
{
if(a.Length != b.Length)
{
throw new ArgumentException("Array are not same Length");
}
byte[] c = new byte[a.Length];
for(int i = 0; i < a.Length; i++)
{
c[i] = (byte)(a[i] ^ b[i]);
}
return c;
}
#endregion #endregion
#endregion #endregion
@ -192,7 +266,7 @@ namespace NFC.Mifare_DESFire
{ {
byte[] id_byte = BitConverter.GetBytes(aid); byte[] id_byte = BitConverter.GetBytes(aid);
APDUCommand cmd = new APDUCommand(IsoCase.Case3Short) APDUCommand cmd = new APDUCommand(IsoCase.Case4Short)
{ {
CLA = 0x90, CLA = 0x90,
INS = (byte)APDUInstructions.SELECT_APPLICATION, INS = (byte)APDUInstructions.SELECT_APPLICATION,
@ -201,8 +275,7 @@ namespace NFC.Mifare_DESFire
id_byte[0], id_byte[0],
id_byte[1], id_byte[1],
id_byte[2] id_byte[2]
}, }
Le = 0x00
}; };
APDUResponse response = _Card.Transmit(cmd); APDUResponse response = _Card.Transmit(cmd);
@ -211,7 +284,76 @@ namespace NFC.Mifare_DESFire
} }
#endregion #endregion
/// <summary>
/// Expand Array to Block Size
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public byte[] expandToBlockSize(byte[] data, int bocksize)
{
int diff = data.Length % bocksize;
if (diff == 0)
{
return data;
}
byte[] expand = new byte[data.Length + diff];
data.CopyTo(expand, 0);
for(int i = expand.Length - 1; i > data.Length - 1; i--)
{
expand[i] = 0x00;
}
return expand;
}
public void ChangeKeyDES(byte key_no, byte[] key_new, byte[] key_current)
{
if(!CheckKey(key_new))
{
throw new ArgumentException("key_new is invalid");
}
if (!CheckKey(key_current))
{
throw new ArgumentException("key_new is invalid");
}
if(GetKeyTypeDES(key_new) != GetKeyTypeDES(key_current))
{
throw new ArgumentException("key_new and key_current are not same KeyType");
}
byte[] keys_xor = xor(key_new, key_current);
keys_xor = concatenate(keys_xor, keys_xor);
CRC32 crc32 = new CRC32();
byte[] crc = crc32.Calculate(new byte[] { (byte)APDUInstructions.CHANGE_KEY, key_no }, keys_xor);
byte[] key_xor_crc = concatenate(keys_xor, crc);
byte[] key_xor_crc_block = expandToBlockSize(key_xor_crc, 8);
DES des = new DES();
byte[] key_xor_crc_block_enc = des.Encrypt(key_xor_crc_block, _SessionKey, _IV);
APDUCommand cmd = new APDUCommand(IsoCase.Case4Short)
{
CLA = 0x90,
INS = (byte)APDUInstructions.CHANGE_KEY,
Data = key_xor_crc_block_enc,
Le = 0x00
};
APDUResponse response = _Card.Transmit(cmd);
CheckAPDUResponse(response);
}
@ -302,6 +444,58 @@ namespace NFC.Mifare_DESFire
{ {
throw new Exception("PICC Challenge is not correct answered."); throw new Exception("PICC Challenge is not correct answered.");
} }
_SessionKey = GenerateDESSesionKey(rndA, rndB);
_IV = GenerateDefaultKey(8);
}
private byte[] GenerateDESSesionKey(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];
}
}
// Set Key Verion of Key to 0x55 to LSB
// TODO
byte[] key_version = SetKeyVersion(sesssionkey, 0x55);
return concatenate(key_version, key_version);
}
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;
} }
public void ChangeApplicationMasterKey(byte[] aPP_MasterKey) public void ChangeApplicationMasterKey(byte[] aPP_MasterKey)
@ -313,7 +507,7 @@ namespace NFC.Mifare_DESFire
/// Delete Application by ID /// Delete Application by ID
/// </summary> /// </summary>
/// <param name="id">3 Byte ID</param> /// <param name="id">3 Byte ID</param>
public APDUCommand DeleteApplication(UInt32 id) public void DeleteApplication(UInt32 id)
{ {
byte[] id_byte = BitConverter.GetBytes(id); byte[] id_byte = BitConverter.GetBytes(id);
@ -330,7 +524,8 @@ namespace NFC.Mifare_DESFire
Le = 0x00 Le = 0x00
}; };
return cmd; APDUResponse response = _Card.Transmit(cmd);
CheckAPDUResponse(response);
} }
public void ChangeApplicationKey(int v, byte[] aPP_Key_1) public void ChangeApplicationKey(int v, byte[] aPP_Key_1)

View File

@ -1,5 +1,6 @@
using NFC; using NFC;
using NFC.Crypto; using NFC.Crypto;
using NFC.ISO7816_4;
using NFC.Mifare_DESFire; using NFC.Mifare_DESFire;
using NSubstitute; using NSubstitute;
using NUnit.Framework; using NUnit.Framework;

View File

@ -7,6 +7,7 @@ using NFC.Readers.PCSC;
using System.Threading; using System.Threading;
using NFC.Mifare_DESFire; using NFC.Mifare_DESFire;
using NFC.Mifare_DESFire.Enums; using NFC.Mifare_DESFire.Enums;
using NFC.ISO7816_4;
namespace NFC_Test namespace NFC_Test
{ {
@ -71,21 +72,21 @@ namespace NFC_Test
MIFARE_DESFire desfire = new MIFARE_DESFire(card); MIFARE_DESFire desfire = new MIFARE_DESFire(card);
APDUCommand cmd = desfire.GetApplicationIDs(); //APDUCommand cmd = desfire.GetApplicationIDs();
APDUResponse response = card.Transmit(cmd); //APDUResponse response = card.Transmit(cmd);
if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK) //if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK)
{ //{
UInt32[] ApplicationIDs = desfire.ConvertApplicationIDs(response); // UInt32[] ApplicationIDs = desfire.ConvertApplicationIDs(response);
foreach(UInt32 id in ApplicationIDs) // foreach(UInt32 id in ApplicationIDs)
{ // {
Console.WriteLine("0x{0:X3}", id); // Console.WriteLine("0x{0:X3}", id);
} // }
transmit_successfully = true; // transmit_successfully = true;
} //}
card.Disconnect(); card.Disconnect();
}; };
@ -111,18 +112,18 @@ namespace NFC_Test
{ {
card.Connect(); card.Connect();
MIFARE_DESFire desfire = new MIFARE_DESFire(card); //MIFARE_DESFire desfire = new MIFARE_DESFire(card);
APDUCommand cmd = desfire.SelectApplication(applicationID); //APDUCommand cmd = desfire.SelectApplication(applicationID);
cmd.ToArray(); //cmd.ToArray();
APDUResponse response = card.Transmit(cmd); //APDUResponse response = card.Transmit(cmd);
if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK) //if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK)
{ //{
transmit_successfully = true; // transmit_successfully = true;
} //}
card.Disconnect(); card.Disconnect();
}; };
@ -136,44 +137,7 @@ namespace NFC_Test
reader.CardDiscovered -= handler; reader.CardDiscovered -= handler;
} }
[TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xC0FFEE)] [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);
APDUCommand cmd = desfire.DeleteApplication(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)0xC0FFEE)]
public void CreateApplication(string readerID, UInt32 applicationID) public void CreateApplication(string readerID, UInt32 applicationID)
{ {
IHardware hardware = new Hardware(); IHardware hardware = new Hardware();
@ -188,7 +152,7 @@ namespace NFC_Test
MIFARE_DESFire desfire = new MIFARE_DESFire(card); MIFARE_DESFire desfire = new MIFARE_DESFire(card);
byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.SAMEKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE); byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.SAMEKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 0x01); byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.TDES, FileIdentifies.NOTUSED, 0x03);
APDUCommand cmd = desfire.CreateApplication(applicationID, keysetting1, keysetting2); APDUCommand cmd = desfire.CreateApplication(applicationID, keysetting1, keysetting2);
@ -213,6 +177,38 @@ namespace NFC_Test
reader.CardDiscovered -= handler; 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) public byte[] GenerateDefaultKey(int size)
{ {
List<byte> key = new List<byte>(); List<byte> key = new List<byte>();
@ -223,6 +219,7 @@ namespace NFC_Test
return key.ToArray(); return key.ToArray();
} }
/// <summary> /// <summary>
/// Used Default PICC Key with PICC authenticate /// Used Default PICC Key with PICC authenticate
/// </summary> /// </summary>
@ -241,6 +238,7 @@ namespace NFC_Test
MIFARE_DESFire desfire = new MIFARE_DESFire(card); MIFARE_DESFire desfire = new MIFARE_DESFire(card);
desfire.SelectApplication(0x000000);
desfire.AuthenticateDES(0x00, GenerateDefaultKey(8)); desfire.AuthenticateDES(0x00, GenerateDefaultKey(8));
transmit_successfully = true; transmit_successfully = true;
@ -256,5 +254,37 @@ namespace NFC_Test
reader.Stop(); reader.Stop();
reader.CardDiscovered -= handler; 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(0x01, 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;
}
} }
} }