mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-04-20 18:36:31 +02:00
Finished: NFC Lib v0.9, TODO: CMAC check, Change PICC Key
This commit is contained in:
parent
6c51e40891
commit
e4cc1348b8
@ -71,10 +71,10 @@ namespace NFC.ISO7816_4
|
|||||||
return string.Format(pattern_case2, CLA, INS, P1, P2, Le);
|
return string.Format(pattern_case2, CLA, INS, P1, P2, Le);
|
||||||
case IsoCase.Case3Short:
|
case IsoCase.Case3Short:
|
||||||
case IsoCase.Case3Extended:
|
case IsoCase.Case3Extended:
|
||||||
return string.Format(pattern_case3, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "));
|
return string.Format(pattern_case3, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", "").ToLower());
|
||||||
case IsoCase.Case4Short:
|
case IsoCase.Case4Short:
|
||||||
case IsoCase.Case4Extended:
|
case IsoCase.Case4Extended:
|
||||||
return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "), Le);
|
return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", "").ToLower(), Le);
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown IsoCase");
|
throw new Exception("Unknown IsoCase");
|
||||||
}
|
}
|
||||||
|
@ -146,8 +146,15 @@ namespace NFC.ISO7816_4
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
string pattern = "SW1: 0x{0:x} | SW2: 0x{1:x} | Body: 0x{2:x}";
|
if(Body == null)
|
||||||
return string.Format(pattern, SW1, SW2, Body);
|
{
|
||||||
|
return string.Format("SW1: 0x{0:x} | SW2: 0x{1:x}", SW1, SW2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Format("SW1: 0x{0:x} | SW2: 0x{1:x} | Body: {2:x}", SW1, SW2, BitConverter.ToString(Body).Replace("-", "").ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -412,40 +412,54 @@ namespace NFC.Mifare_DESFire
|
|||||||
|
|
||||||
#region DESFire Commands
|
#region DESFire Commands
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Format PICC
|
/// Select Application by ApplicationID (AID)
|
||||||
/// Works after PICC Authentication
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Format()
|
/// <param name="aid">3 Byte AID</param>
|
||||||
|
public void SelectApplication(UInt32 aid)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start Format");
|
if(aid > 0xFFFFFF)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("AID is too large");
|
||||||
|
}
|
||||||
|
|
||||||
APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short)
|
byte[] id_byte = BitConverter.GetBytes(aid);
|
||||||
|
_Log.InfoFormat("Select Application: {0}", HexConverter.ConvertToHexString(id_byte.ToArray()));
|
||||||
|
|
||||||
|
APDUCommand cmd_SelectApplication = new APDUCommand(IsoCase.Case4Short)
|
||||||
{
|
{
|
||||||
CLA = 0x90,
|
CLA = 0x90,
|
||||||
INS = 0xFC,
|
INS = (byte)APDUInstructions.SELECT_APPLICATION,
|
||||||
|
Data = new byte[]
|
||||||
|
{
|
||||||
|
id_byte[0],
|
||||||
|
id_byte[1],
|
||||||
|
id_byte[2]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_format): {0}", HexConverter.ConvertToHexString(cmd_format.ToArray()));
|
_Log.Debug(cmd_SelectApplication.ToString());
|
||||||
|
HexConverter.ConvertToHexString(cmd_SelectApplication.ToArray());
|
||||||
APDUResponse response = _Card.Transmit(cmd_format);
|
APDUResponse response = _Card.Transmit(cmd_SelectApplication);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_format): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.DebugFormat(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
_Log.Debug("End Format");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authenticate to PICC, with ISO Authenticate
|
/// Authenticate to PICC, with ISO Authenticate for DES Key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key_id">0x01 - 0x0D</param>
|
/// <param name="key_id">0x01 - 0x0D</param>
|
||||||
/// <param name="key"></param>
|
/// <param name="key">Array of 8/16 Bytes</param>
|
||||||
/// <param name="rndA">!!! WARNING For Testing only !!!</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)
|
public void AuthenticateISO_DES(byte key_id, byte[] key, byte[] rndA = null)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start AuthenticateISO_DES");
|
if(key_id >= 0x0E)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("KeyID is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
// Sepearte InitialisationVector for Authentication
|
_Log.InfoFormat("Authenticate with DES Key No: 0x{0:x}", key_id);
|
||||||
|
|
||||||
|
// Sepearte Initialisation Vector for Authentication Process
|
||||||
byte[] iv = new byte[8];
|
byte[] iv = new byte[8];
|
||||||
|
|
||||||
APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short)
|
APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short)
|
||||||
@ -457,10 +471,10 @@ namespace NFC.Mifare_DESFire
|
|||||||
key_id
|
key_id
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", HexConverter.ConvertToHexString(cmd_challange_request.ToArray()));
|
_Log.Debug(cmd_challange_request.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_challange_request);
|
APDUResponse response = _Card.Transmit(cmd_challange_request);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
@ -476,7 +490,7 @@ namespace NFC.Mifare_DESFire
|
|||||||
byte[] rndB_rl = RotateLeft(rndB);
|
byte[] rndB_rl = RotateLeft(rndB);
|
||||||
_Log.DebugFormat("rndB_enc: {0}", HexConverter.ConvertToHexString(rndB_rl));
|
_Log.DebugFormat("rndB_enc: {0}", HexConverter.ConvertToHexString(rndB_rl));
|
||||||
|
|
||||||
if(rndA == null)
|
if (rndA == null)
|
||||||
{
|
{
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
rndA = new byte[8];
|
rndA = new byte[8];
|
||||||
@ -488,7 +502,7 @@ namespace NFC.Mifare_DESFire
|
|||||||
_Log.DebugFormat("rndAB: {0}", HexConverter.ConvertToHexString(rndAB));
|
_Log.DebugFormat("rndAB: {0}", HexConverter.ConvertToHexString(rndAB));
|
||||||
|
|
||||||
byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc);
|
byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc);
|
||||||
_Log.DebugFormat("rndA_rndB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc));
|
_Log.DebugFormat("rndAB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc));
|
||||||
iv = ExtractLastBlock(rndAB_enc, 8);
|
iv = ExtractLastBlock(rndAB_enc, 8);
|
||||||
|
|
||||||
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
|
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
|
||||||
@ -497,10 +511,10 @@ namespace NFC.Mifare_DESFire
|
|||||||
INS = 0xAF,
|
INS = 0xAF,
|
||||||
Data = rndAB_enc
|
Data = rndAB_enc
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray()));
|
_Log.Debug(cmd_challange_response.ToString());
|
||||||
|
|
||||||
response = _Card.Transmit(cmd_challange_response);
|
response = _Card.Transmit(cmd_challange_response);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
@ -515,28 +529,52 @@ namespace NFC.Mifare_DESFire
|
|||||||
|
|
||||||
if (!rndA.SequenceEqual(rndAFromCard))
|
if (!rndA.SequenceEqual(rndAFromCard))
|
||||||
{
|
{
|
||||||
throw new Exception("Authentication failed, PICC Challenge is not corret");
|
throw new Exception("Authentication failed, PICC Challenge is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_Log.Info("Authenticated");
|
||||||
|
|
||||||
_SessionKey = GenerateSesionKey_DES(rndA, rndB);
|
_SessionKey = GenerateSesionKey_DES(rndA, rndB);
|
||||||
_Log.DebugFormat("_SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey));
|
_Log.DebugFormat("SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey));
|
||||||
|
|
||||||
_IV = GenerateEmptyArray(8);
|
_IV = GenerateEmptyArray(8);
|
||||||
_Log.DebugFormat("_IV: {0}", HexConverter.ConvertToHexString(_IV));
|
_Log.DebugFormat("IV: {0}", HexConverter.ConvertToHexString(_IV));
|
||||||
|
|
||||||
_Log.Debug("End AuthenticateISO_DES");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create Application for ID
|
/// Format PICC
|
||||||
|
/// Need Authentication for PICC / Application 0x000000
|
||||||
|
/// </summary>
|
||||||
|
public void Format()
|
||||||
|
{
|
||||||
|
_Log.Info("Format PICC");
|
||||||
|
|
||||||
|
APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = 0xFC,
|
||||||
|
};
|
||||||
|
_Log.Debug(cmd_format.ToString());
|
||||||
|
|
||||||
|
APDUResponse response = _Card.Transmit(cmd_format);
|
||||||
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
|
CheckAPDUResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Application for ApplicationID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="aid">3 Byte ID</param>
|
/// <param name="aid">3 Byte ID</param>
|
||||||
public void CreateApplication(UInt32 aid, byte keysetting1, byte keysetting2)
|
public void CreateApplication(UInt32 aid, byte keysetting1, byte keysetting2)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start CreateApplication");
|
if (aid > 0xFFFFFF)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("AID is too large");
|
||||||
|
}
|
||||||
|
|
||||||
byte[] id_byte = BitConverter.GetBytes(aid);
|
byte[] id_byte = BitConverter.GetBytes(aid);
|
||||||
_Log.DebugFormat("AID: {0}", HexConverter.ConvertToHexString(id_byte.ToArray()));
|
_Log.InfoFormat("Create Application: {0}", HexConverter.ConvertToHexString(id_byte.ToArray()));
|
||||||
|
|
||||||
APDUCommand cmd_CreateApplication = new APDUCommand(IsoCase.Case4Short)
|
APDUCommand cmd_CreateApplication = new APDUCommand(IsoCase.Case4Short)
|
||||||
{
|
{
|
||||||
@ -551,58 +589,28 @@ namespace NFC.Mifare_DESFire
|
|||||||
keysetting2
|
keysetting2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_CreateApplication): {0}", HexConverter.ConvertToHexString(cmd_CreateApplication.ToArray()));
|
_Log.Debug(cmd_CreateApplication.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_CreateApplication);
|
APDUResponse response = _Card.Transmit(cmd_CreateApplication);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_CreateApplication): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
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}", HexConverter.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}", HexConverter.ConvertToHexString(cmd_SelectApplication.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_SelectApplication);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_SelectApplication): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End SelectApplication");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authenticate to PICC, with ISO Authenticate
|
/// Authenticate to PICC, with ISO Authenticate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key_id">0x01 - 0x0D</param>
|
/// <param name="key_id">0x01 - 0x0D</param>
|
||||||
/// <param name="key"></param>
|
/// <param name="key">Array of 16 Bytes</param>
|
||||||
/// <param name="rndA">!!! WARNING For Testing only !!!</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)
|
public void AuthenticateISO_AES(byte key_id, byte[] key, byte[] rndA = null)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start AuthenticateISO_AES");
|
if (key_id >= 0x0E)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("KeyID is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
_Log.InfoFormat("Authenticate with AES Key No: 0x{0:x}", key_id);
|
||||||
|
|
||||||
// Sepearte InitialisationVector for Authentication
|
// Sepearte InitialisationVector for Authentication
|
||||||
byte[] iv = new byte[16];
|
byte[] iv = new byte[16];
|
||||||
@ -616,10 +624,10 @@ namespace NFC.Mifare_DESFire
|
|||||||
key_id
|
key_id
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", HexConverter.ConvertToHexString(cmd_challange_request.ToArray()));
|
_Log.Debug(cmd_challange_request.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_challange_request);
|
APDUResponse response = _Card.Transmit(cmd_challange_request);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
@ -647,7 +655,7 @@ namespace NFC.Mifare_DESFire
|
|||||||
_Log.DebugFormat("rndAB: {0}", HexConverter.ConvertToHexString(rndAB));
|
_Log.DebugFormat("rndAB: {0}", HexConverter.ConvertToHexString(rndAB));
|
||||||
|
|
||||||
byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc);
|
byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc);
|
||||||
_Log.DebugFormat("rndA_rndB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc));
|
_Log.DebugFormat("rndAB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc));
|
||||||
iv = ExtractLastBlock(rndAB_enc, 16);
|
iv = ExtractLastBlock(rndAB_enc, 16);
|
||||||
|
|
||||||
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
|
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
|
||||||
@ -656,10 +664,10 @@ namespace NFC.Mifare_DESFire
|
|||||||
INS = 0xAF,
|
INS = 0xAF,
|
||||||
Data = rndAB_enc
|
Data = rndAB_enc
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray()));
|
_Log.Debug(cmd_challange_response.ToString());
|
||||||
|
|
||||||
response = _Card.Transmit(cmd_challange_response);
|
response = _Card.Transmit(cmd_challange_response);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
@ -674,83 +682,30 @@ namespace NFC.Mifare_DESFire
|
|||||||
|
|
||||||
if (!rndA.SequenceEqual(rndAFromCard))
|
if (!rndA.SequenceEqual(rndAFromCard))
|
||||||
{
|
{
|
||||||
throw new Exception("Authentication failed, PICC Challenge is not corret");
|
throw new Exception("Authentication failed, PICC Challenge is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_SessionKey = GenerateSesionKey_AES(rndA, rndB);
|
_SessionKey = GenerateSesionKey_AES(rndA, rndB);
|
||||||
_Log.DebugFormat("_SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey));
|
_Log.DebugFormat("SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey));
|
||||||
|
|
||||||
_IV = GenerateEmptyArray(16);
|
_IV = GenerateEmptyArray(16);
|
||||||
_Log.DebugFormat("_IV: {0}", HexConverter.ConvertToHexString(_IV));
|
_Log.DebugFormat("IV: {0}", HexConverter.ConvertToHexString(_IV));
|
||||||
|
|
||||||
_Log.Debug("End AuthenticateISO_DES");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change Same DES key as Authenticated
|
/// Change AES key, the same as Authenticated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key_id"></param>
|
/// <param name="key_id">0x01 - 0x0D</param>
|
||||||
/// <param name="new_key"></param>
|
/// <param name="new_key">Array of 16 Bytes</param>
|
||||||
/// <param name="key_version"></param>
|
/// <param name="key_version">Version of Key(min. 0x10)</param>
|
||||||
public void ChangeKey_DES(byte key_id, byte[] new_key, byte key_version)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start ChangeKey_DES");
|
|
||||||
|
|
||||||
byte[] header = new byte[]
|
|
||||||
{
|
|
||||||
0xC4, key_id
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("header: {0}", HexConverter.ConvertToHexString(header));
|
|
||||||
|
|
||||||
byte[] key_and_version = new_key;
|
|
||||||
byte[] command = Concatenate(header, key_and_version);
|
|
||||||
_Log.DebugFormat("command: {0}", HexConverter.ConvertToHexString(command));
|
|
||||||
|
|
||||||
CRC32 crc32 = new CRC32();
|
|
||||||
byte[] crc = crc32.Calculate(command);
|
|
||||||
_Log.DebugFormat("crc: {0}", HexConverter.ConvertToHexString(crc));
|
|
||||||
|
|
||||||
byte[] cryptogram = Concatenate(key_and_version, crc);
|
|
||||||
_Log.DebugFormat("cryptogram: {0}", HexConverter.ConvertToHexString(cryptogram));
|
|
||||||
|
|
||||||
byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16);
|
|
||||||
_Log.DebugFormat("cryptogram_block: {0}", HexConverter.ConvertToHexString(cryptogram_block));
|
|
||||||
|
|
||||||
TDES des = new TDES();
|
|
||||||
byte[] cryptogram_enc = des.Encrypt(cryptogram_block, _SessionKey, _IV);
|
|
||||||
_Log.DebugFormat("cryptogram_enc: {0}", HexConverter.ConvertToHexString(cryptogram_enc));
|
|
||||||
|
|
||||||
_IV = ExtractLastBlock(cryptogram_enc, 8);
|
|
||||||
_Log.DebugFormat("_IV: {0}", HexConverter.ConvertToHexString(_IV));
|
|
||||||
|
|
||||||
byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc);
|
|
||||||
_Log.DebugFormat("data: {0}", HexConverter.ConvertToHexString(data));
|
|
||||||
|
|
||||||
APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = 0xC4,
|
|
||||||
Data = data
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(cmd_ChangeKey.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
|
|
||||||
_Log.Debug("End ChangeKey_AES");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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)
|
public void ChangeKey_AES(byte key_id, byte[] new_key, byte key_version)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start ChangeKey_AES");
|
if (key_id >= 0x0E)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("KeyID is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
_Log.InfoFormat("Change AES Key No: 0x{0:x}", key_id);
|
||||||
|
|
||||||
byte[] header = new byte[]
|
byte[] header = new byte[]
|
||||||
{
|
{
|
||||||
@ -789,25 +744,28 @@ namespace NFC.Mifare_DESFire
|
|||||||
INS = 0xC4,
|
INS = 0xC4,
|
||||||
Data = data
|
Data = data
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(cmd_ChangeKey.ToArray()));
|
_Log.Debug(cmd_ChangeKey.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
_Log.Debug("End ChangeKey_AES");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change other AES key as Authenticated
|
/// Change AES key, other than Authenticated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key_id"></param>
|
/// <param name="key_id">0x01 - 0x0D</param>
|
||||||
/// <param name="new_key"></param>
|
/// <param name="new_key">Array of 16 Bytes</param>
|
||||||
/// <param name="key_version"></param>
|
/// <param name="key_version">Version of Key(min. 0x10)</param>
|
||||||
public void ChangeOtherKey_AES(byte key_id, byte[] new_key, byte[] old_key, byte key_version)
|
public void ChangeOtherKey_AES(byte key_id, byte[] new_key, byte[] old_key, byte key_version)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start ChangeOtherKey_AES");
|
if (key_id >= 0x0E)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("KeyID is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
_Log.InfoFormat("Change AES Key No: 0x{0:x}", key_id);
|
||||||
|
|
||||||
byte[] header = new byte[]
|
byte[] header = new byte[]
|
||||||
{
|
{
|
||||||
@ -851,28 +809,28 @@ namespace NFC.Mifare_DESFire
|
|||||||
INS = 0xC4,
|
INS = 0xC4,
|
||||||
Data = data
|
Data = data
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(cmd_ChangeKey.ToArray()));
|
_Log.Debug(cmd_ChangeKey.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
_Log.Debug("End ChangeOtherKey_AES");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create Standard Data File
|
/// Create Standard Data File
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="file_id">ID of File (0x01 - 0x10)</param>
|
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
|
||||||
/// <param name="communication">Type of File Communicaton</param>
|
/// <param name="communication">Type of File Communicaton</param>
|
||||||
/// <param name="accessRights">Access Rights for File</param>
|
/// <param name="accessRights">Access Rights for File</param>
|
||||||
/// <param name="size">Size of File in Bytes</param>
|
/// <param name="size">Size of File in Bytes</param>
|
||||||
public void CreateFile_Standard(byte file_id, FileCommunication communication, UInt16 accessRights, UInt32 size)
|
public void CreateFile_Standard(byte file_id, FileCommunication communication, UInt16 accessRights, UInt32 size)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start CreateFile_Standard");
|
if (file_id >= 0x20)
|
||||||
|
{
|
||||||
_Log.DebugFormat("FID: {0}", file_id);
|
throw new ArgumentOutOfRangeException("FileID is to large");
|
||||||
|
}
|
||||||
|
_Log.DebugFormat("Create STD File: {0}", file_id);
|
||||||
|
|
||||||
byte[] accessRights_byte = BitConverter.GetBytes(accessRights);
|
byte[] accessRights_byte = BitConverter.GetBytes(accessRights);
|
||||||
byte[] size_byte_tolong = BitConverter.GetBytes(size);
|
byte[] size_byte_tolong = BitConverter.GetBytes(size);
|
||||||
@ -896,97 +854,27 @@ namespace NFC.Mifare_DESFire
|
|||||||
INS = (byte)APDUInstructions.CREATE_STDDATAFILE,
|
INS = (byte)APDUInstructions.CREATE_STDDATAFILE,
|
||||||
Data = Concatenate(data, accessRights_byte, size_byte)
|
Data = Concatenate(data, accessRights_byte, size_byte)
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_CreateFile_Standard): {0}", HexConverter.ConvertToHexString(cmd_CreateFile_Standard.ToArray()));
|
_Log.Debug(cmd_CreateFile_Standard.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_CreateFile_Standard);
|
APDUResponse response = _Card.Transmit(cmd_CreateFile_Standard);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_CreateFile_Standard): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.DebugFormat(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
_Log.Debug("End CreateFile_Standard");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read Data from File
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="file_id">ID of File (0x01 - 0x10)</param>
|
|
||||||
/// <param name="offset">Offset for File</param>
|
|
||||||
/// <param name="length">Lenght of Data</param>
|
|
||||||
public byte[] ReadData(byte file_id, UInt32 offset, UInt32 length)
|
|
||||||
{
|
|
||||||
_Log.Debug("Start ReadData");
|
|
||||||
|
|
||||||
int max_read_bytes_pre_transaction = 47;
|
|
||||||
long bytes_readed = 0;
|
|
||||||
|
|
||||||
List<byte> read_data = new List<byte>();
|
|
||||||
|
|
||||||
while (bytes_readed != length)
|
|
||||||
{
|
|
||||||
byte[] data = new byte[]
|
|
||||||
{
|
|
||||||
file_id
|
|
||||||
};
|
|
||||||
|
|
||||||
byte[] offset_byte_tolong = BitConverter.GetBytes(offset + bytes_readed);
|
|
||||||
// Use only 3 Bytes
|
|
||||||
byte[] offset_byte = new byte[]
|
|
||||||
{
|
|
||||||
offset_byte_tolong[0],
|
|
||||||
offset_byte_tolong[1],
|
|
||||||
offset_byte_tolong[2],
|
|
||||||
};
|
|
||||||
|
|
||||||
long bytes_toread = 0;
|
|
||||||
|
|
||||||
if (length - bytes_readed < max_read_bytes_pre_transaction)
|
|
||||||
{
|
|
||||||
bytes_toread = length - bytes_readed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bytes_toread = max_read_bytes_pre_transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] length_byte_tolong = BitConverter.GetBytes(bytes_toread);
|
|
||||||
bytes_readed += bytes_toread;
|
|
||||||
|
|
||||||
// Use only 3 Bytes
|
|
||||||
byte[] length_byte = new byte[]
|
|
||||||
{
|
|
||||||
length_byte_tolong[0],
|
|
||||||
length_byte_tolong[1],
|
|
||||||
length_byte_tolong[2],
|
|
||||||
};
|
|
||||||
|
|
||||||
APDUCommand cmd_ReadData = new APDUCommand(IsoCase.Case4Short)
|
|
||||||
{
|
|
||||||
CLA = 0x90,
|
|
||||||
INS = (byte)APDUInstructions.READ_DATA,
|
|
||||||
Data = Concatenate(data, offset_byte, length_byte)
|
|
||||||
};
|
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_ReadData): {0}", HexConverter.ConvertToHexString(cmd_ReadData.ToArray()));
|
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_ReadData);
|
|
||||||
_Log.DebugFormat("APDU_RES(cmd_ReadData): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
|
||||||
read_data.AddRange(response.Body);
|
|
||||||
}
|
|
||||||
_Log.Debug("End ReadData");
|
|
||||||
|
|
||||||
return read_data.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write Data to File
|
/// Write Data to File
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="file_id">ID of File (0x01 - 0x10)</param>
|
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
|
||||||
/// <param name="offset">Offset for File</param>
|
/// <param name="offset">Offset for File</param>
|
||||||
/// <param name="data">Data to write</param>
|
/// <param name="data">Data to write</param>
|
||||||
public void WriteData(byte file_id, UInt32 offset, byte[] data)
|
public void WriteData(byte file_id, UInt32 offset, byte[] data)
|
||||||
{
|
{
|
||||||
_Log.Debug("Start WriteData");
|
if (file_id >= 0x20)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("FileID is to large");
|
||||||
|
}
|
||||||
|
_Log.DebugFormat("Write Data to File: {0}", file_id);
|
||||||
|
|
||||||
int max_write_bytes_pre_transaction = 47;
|
int max_write_bytes_pre_transaction = 47;
|
||||||
byte[] write_buffer;
|
byte[] write_buffer;
|
||||||
@ -1040,15 +928,91 @@ namespace NFC.Mifare_DESFire
|
|||||||
INS = (byte)APDUInstructions.WRITE_DATA,
|
INS = (byte)APDUInstructions.WRITE_DATA,
|
||||||
Data = Concatenate(file_id_array, offset_byte, length_byte, write_buffer)
|
Data = Concatenate(file_id_array, offset_byte, length_byte, write_buffer)
|
||||||
};
|
};
|
||||||
_Log.DebugFormat("APDU_CMD(cmd_WriteData): {0}", HexConverter.ConvertToHexString(cmd_WriteData.ToArray()));
|
_Log.Debug(cmd_WriteData.ToString());
|
||||||
|
|
||||||
APDUResponse response = _Card.Transmit(cmd_WriteData);
|
APDUResponse response = _Card.Transmit(cmd_WriteData);
|
||||||
_Log.DebugFormat("APDU_RES(cmd_WriteData): {0}", HexConverter.ConvertToHexString(response.ToArray()));
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
CheckAPDUResponse(response);
|
CheckAPDUResponse(response);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_Log.Debug("End WriteData");
|
/// <summary>
|
||||||
|
/// Read Data from File
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
|
||||||
|
/// <param name="offset">Offset for File</param>
|
||||||
|
/// <param name="length">Lenght of Data</param>
|
||||||
|
public byte[] ReadData(byte file_id, UInt32 offset, UInt32 length)
|
||||||
|
{
|
||||||
|
if (file_id >= 0x20)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("FileID is to large");
|
||||||
|
}
|
||||||
|
_Log.DebugFormat("Read Data from File: {0}", file_id);
|
||||||
|
|
||||||
|
int max_read_bytes_pre_transaction = 47;
|
||||||
|
long bytes_readed = 0;
|
||||||
|
byte[] readbuffer = new byte[47];
|
||||||
|
|
||||||
|
List<byte> read_data = new List<byte>();
|
||||||
|
|
||||||
|
while (bytes_readed != length)
|
||||||
|
{
|
||||||
|
byte[] data = new byte[]
|
||||||
|
{
|
||||||
|
file_id
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] offset_byte_tolong = BitConverter.GetBytes(offset + bytes_readed);
|
||||||
|
// Use only 3 Bytes
|
||||||
|
byte[] offset_byte = new byte[]
|
||||||
|
{
|
||||||
|
offset_byte_tolong[0],
|
||||||
|
offset_byte_tolong[1],
|
||||||
|
offset_byte_tolong[2],
|
||||||
|
};
|
||||||
|
|
||||||
|
long bytes_toread = 0;
|
||||||
|
|
||||||
|
if (length - bytes_readed < max_read_bytes_pre_transaction)
|
||||||
|
{
|
||||||
|
bytes_toread = length - bytes_readed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes_toread = max_read_bytes_pre_transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] length_byte_tolong = BitConverter.GetBytes(bytes_toread);
|
||||||
|
bytes_readed += bytes_toread;
|
||||||
|
|
||||||
|
// Use only 3 Bytes
|
||||||
|
byte[] length_byte = new byte[]
|
||||||
|
{
|
||||||
|
length_byte_tolong[0],
|
||||||
|
length_byte_tolong[1],
|
||||||
|
length_byte_tolong[2],
|
||||||
|
};
|
||||||
|
|
||||||
|
APDUCommand cmd_ReadData = new APDUCommand(IsoCase.Case4Short)
|
||||||
|
{
|
||||||
|
CLA = 0x90,
|
||||||
|
INS = (byte)APDUInstructions.READ_DATA,
|
||||||
|
Data = Concatenate(data, offset_byte, length_byte)
|
||||||
|
};
|
||||||
|
_Log.Debug(cmd_ReadData.ToString());
|
||||||
|
|
||||||
|
APDUResponse response = _Card.Transmit(cmd_ReadData);
|
||||||
|
_Log.Debug(response.ToString());
|
||||||
|
|
||||||
|
CheckAPDUResponse(response);
|
||||||
|
|
||||||
|
// Remove CMAC from Body
|
||||||
|
read_data.AddRange(GetSubArray(response.Body, 0, bytes_toread));
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_data.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -6,6 +6,7 @@ using NFC.NXP_MIFARE_DESFire.Exceptions;
|
|||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
||||||
{
|
{
|
||||||
@ -697,6 +698,38 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region DESFire Commands
|
#region DESFire Commands
|
||||||
|
[Test]
|
||||||
|
public void SelectApplication()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "905a00000333221100")).Returns(response);
|
||||||
|
|
||||||
|
desfire.SelectApplication(0x112233);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SelectApplication_InvalidAID()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.SelectApplication(0xFF000000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void AuthenticateISO_DES()
|
public void AuthenticateISO_DES()
|
||||||
{
|
{
|
||||||
@ -708,31 +741,93 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
|||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0xAF,
|
SW2 = 0xAF,
|
||||||
Body = HexConverter.ConvertFromHexString("5D994CE085F24089")
|
Body = HexConverter.ConvertFromHexString("2bf9a938ecca02e2")
|
||||||
};
|
};
|
||||||
|
|
||||||
APDUResponse response_challenge_response = new APDUResponse()
|
APDUResponse response_challenge_response = new APDUResponse()
|
||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0x00,
|
SW2 = 0x00,
|
||||||
Body = HexConverter.ConvertFromHexString("913C6DED84221C41")
|
Body = HexConverter.ConvertFromHexString("07d825607a552e2e")
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] rndA = HexConverter.ConvertFromHexString("849B36C5F8BF4A09");
|
byte[] rndA = HexConverter.ConvertFromHexString("5f7d1dd12d979173");
|
||||||
byte[] key = HexConverter.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 => HexConverter.ConvertToHexString(x.ToArray()) == "901a0000010000")).Returns(response_challenge_request);
|
||||||
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAF)).Returns(response_challenge_response);
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90af000010f8cdb2eaa42a3167dfcb53852ce267fd00")).Returns(response_challenge_response);
|
||||||
|
|
||||||
desfire.AuthenticateISO_DES(0x00, key, rndA);
|
desfire.AuthenticateISO_DES(0x00, key, rndA);
|
||||||
|
|
||||||
byte[] expected_sessionkey = HexConverter.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759");
|
byte[] expected_sessionkey = HexConverter.ConvertFromHexString("5f7d1dd1f449db5c5f7d1dd1f449db5c");
|
||||||
byte[] expected_iv = HexConverter.ConvertFromHexString("0000000000000000");
|
byte[] expected_iv = HexConverter.ConvertFromHexString("0000000000000000");
|
||||||
|
|
||||||
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
||||||
Assert.AreEqual(expected_iv, desfire._IV);
|
Assert.AreEqual(expected_iv, desfire._IV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AuthenticateISO_DES_InvalidKeyNo()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.AuthenticateISO_DES(0x0F, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Format()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90fc000000")).Returns(response);
|
||||||
|
|
||||||
|
desfire.Format();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateApplication()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90ca000005eeffaa0b8200")).Returns(response);
|
||||||
|
|
||||||
|
desfire.CreateApplication(0xAAFFEE, 0x0b, 0x82);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateApplication_InvalidAID()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.CreateApplication(0xFF000000, 0x00, 0x00);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void AuthenticateISO_AES()
|
public void AuthenticateISO_AES()
|
||||||
{
|
{
|
||||||
@ -744,31 +839,43 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
|||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0xAF,
|
SW2 = 0xAF,
|
||||||
Body = HexConverter.ConvertFromHexString("43a28e28c653df83cd85039714bccb51")
|
Body = HexConverter.ConvertFromHexString("a33856932308775cf464610c2b17a558")
|
||||||
};
|
};
|
||||||
|
|
||||||
APDUResponse response_challenge_response = new APDUResponse()
|
APDUResponse response_challenge_response = new APDUResponse()
|
||||||
{
|
{
|
||||||
SW1 = 0x91,
|
SW1 = 0x91,
|
||||||
SW2 = 0x00,
|
SW2 = 0x00,
|
||||||
Body = HexConverter.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f")
|
Body = HexConverter.ConvertFromHexString("8fdc476f6bac44fe9150e285abd68d48")
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] rndA = HexConverter.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1");
|
byte[] rndA = HexConverter.ConvertFromHexString("2176770e7a6eb4bef00d5e4b201d1e57");
|
||||||
byte[] key = HexConverter.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 => HexConverter.ConvertToHexString(x.ToArray()) == "90aa0000010000")).Returns(response_challenge_request);
|
||||||
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAF)).Returns(response_challenge_response);
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90af000020cbe9726faf54bc76b2055d0b9700e7dc97ecad5627f1d1702a16e8408d2a0ada00")).Returns(response_challenge_response);
|
||||||
|
|
||||||
desfire.AuthenticateISO_AES(0x00, key, rndA);
|
desfire.AuthenticateISO_AES(0x00, key, rndA);
|
||||||
|
|
||||||
byte[] expected_sessionkey = HexConverter.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703");
|
byte[] expected_sessionkey = HexConverter.ConvertFromHexString("2176770e11c512ca201d1e57fde6e15a");
|
||||||
byte[] expected_iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] expected_iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
||||||
Assert.AreEqual(expected_iv, desfire._IV);
|
Assert.AreEqual(expected_iv, desfire._IV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AuthenticateISO_AES_InvalidKeyNo()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.AuthenticateISO_AES(0x0F, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ChangeKey_AES()
|
public void ChangeKey_AES()
|
||||||
{
|
{
|
||||||
@ -782,19 +889,31 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
|||||||
SW2 = 0x00
|
SW2 = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] new_key = HexConverter.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530");
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90c400002100c2b54a718d0251845653199909bb32e8e38bd6719e8dc21799c29c922a0984fc00")).Returns(response);
|
||||||
|
|
||||||
byte[] sessionkey = HexConverter.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3");
|
byte[] new_key = HexConverter.ConvertFromHexString("25432a462d4a614e645267556b587032");
|
||||||
|
|
||||||
|
byte[] sessionkey = HexConverter.ConvertFromHexString("a8514dd0350f3dfbc86e80744bcc9b57");
|
||||||
byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
desfire._SessionKey = sessionkey;
|
desfire._SessionKey = sessionkey;
|
||||||
desfire._IV = iv;
|
desfire._IV = iv;
|
||||||
|
|
||||||
card.Transmit(null).ReturnsForAnyArgs(response);
|
|
||||||
|
|
||||||
desfire.ChangeKey_AES(0x00, new_key, 0x10);
|
desfire.ChangeKey_AES(0x00, new_key, 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ChangeKey_AES_InvalidKeyNo()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.ChangeKey_AES(0x0F, null, 0x10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ChangeOtherKey_AES()
|
public void ChangeOtherKey_AES()
|
||||||
{
|
{
|
||||||
@ -808,19 +927,209 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire
|
|||||||
SW2 = 0x00
|
SW2 = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] new_key = HexConverter.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12");
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90c400002101a8c5a61a06f56f38dc91266fed2e87dc00a5ad72a634ff0e62c8d6d80707dd6000")).Returns(response);
|
||||||
|
|
||||||
|
byte[] new_key = HexConverter.ConvertFromHexString("25432a462d4a614e645267556b587032");
|
||||||
byte[] old_key = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] old_key = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
byte[] sessionkey = HexConverter.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b");
|
byte[] sessionkey = HexConverter.ConvertFromHexString("1677623e1e158a62dc3d128db55f947d");
|
||||||
byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000");
|
||||||
|
|
||||||
desfire._SessionKey = sessionkey;
|
desfire._SessionKey = sessionkey;
|
||||||
desfire._IV = iv;
|
desfire._IV = iv;
|
||||||
|
|
||||||
card.Transmit(null).ReturnsForAnyArgs(response);
|
|
||||||
|
|
||||||
desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10);
|
desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ChangeOtherKey_AES_InvalidKeyNo()
|
||||||
|
{
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(null);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.ChangeKey_AES(0x0F, null, 0x10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateFile_Standard()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90cd000007010000e0f0000000")).Returns(response);
|
||||||
|
|
||||||
|
UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00);
|
||||||
|
desfire.CreateFile_Standard(0x01, FileCommunication.PLAIN, accesRights, 0xF0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateFile_Standard_InvalidFID()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.CreateFile_Standard(0x21, FileCommunication.PLAIN, 0x0000, 0xF0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void WriteData()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d00000f01000000080000546573743132333400")).Returns(response);
|
||||||
|
|
||||||
|
desfire.WriteData(0x01, 0, Encoding.ASCII.GetBytes("Test1234"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void WriteData_Long()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d000036010000002f0000546573743132333454657374313233345465737431323334546573743132333454657374313233345465737431323300")).Returns(response);
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d000036012f00002f0000345465737431323334546573743132333454657374313233345465737431323334546573743132333454657374313200")).Returns(response);
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d000019015e000012000033345465737431323334546573743132333400")).Returns(response);
|
||||||
|
|
||||||
|
desfire.WriteData(0x01, 0, Encoding.ASCII.GetBytes("Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void WriteData_InvalidFileID()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.WriteData(0x21, 0x00, Encoding.ASCII.GetBytes("Test1234"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReadData()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00,
|
||||||
|
Body = HexConverter.ConvertFromHexString("54657374313233340000000000000000000000000000000000000000000000009100")
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd0000070100000020000000")).Returns(response);
|
||||||
|
|
||||||
|
byte[] data = desfire.ReadData(0x01, 0x00, 0x20);
|
||||||
|
|
||||||
|
Assert.AreEqual("Test1234", Encoding.ASCII.GetString(data).Replace("\u0000", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReadData_CMAC()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00,
|
||||||
|
Body = HexConverter.ConvertFromHexString("5465737431323334000000000000000000000000000000000000000000000000809a9bedbc559a5b9100")
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd0000070100000020000000")).Returns(response);
|
||||||
|
|
||||||
|
byte[] data = desfire.ReadData(0x01, 0x00, 0x20);
|
||||||
|
|
||||||
|
Assert.AreEqual("Test1234", Encoding.ASCII.GetString(data).Replace("\u0000", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReadData_Long()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
APDUResponse response_1 = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00,
|
||||||
|
Body = HexConverter.ConvertFromHexString("54657374313233340000000000000000000000000000000000000000000000000000000000000000000000000000009100")
|
||||||
|
};
|
||||||
|
|
||||||
|
APDUResponse response_2 = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00,
|
||||||
|
Body = HexConverter.ConvertFromHexString("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009100")
|
||||||
|
};
|
||||||
|
|
||||||
|
APDUResponse response_3 = new APDUResponse()
|
||||||
|
{
|
||||||
|
SW1 = 0x91,
|
||||||
|
SW2 = 0x00,
|
||||||
|
Body = HexConverter.ConvertFromHexString("00009100")
|
||||||
|
};
|
||||||
|
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd000007010000002f000000")).Returns(response_1);
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd000007012f00002f000000")).Returns(response_2);
|
||||||
|
card.Transmit(Arg.Is<APDUCommand>(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd000007015e000002000000")).Returns(response_3);
|
||||||
|
|
||||||
|
byte[] data = desfire.ReadData(0x01, 0x00, 0x60);
|
||||||
|
|
||||||
|
Assert.AreEqual("Test1234", Encoding.ASCII.GetString(data).Replace("\u0000", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReadData_InvalidFileID()
|
||||||
|
{
|
||||||
|
ICard card = Substitute.For<ICard>();
|
||||||
|
|
||||||
|
MIFARE_DESFire desfire = new MIFARE_DESFire(card);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
desfire.ReadData(0x21, 0x00, 0x20);
|
||||||
|
});
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ namespace NFC_Real_Test
|
|||||||
desfire.AuthenticateISO_AES(0x00, key_aes._Key);
|
desfire.AuthenticateISO_AES(0x00, key_aes._Key);
|
||||||
|
|
||||||
CipherKey key_aes_new = new CipherKey(ApplicationMasterKey, CipherType.AES, 0x10);
|
CipherKey key_aes_new = new CipherKey(ApplicationMasterKey, CipherType.AES, 0x10);
|
||||||
desfire.ChangeKey_AES(0x00, key._Key, key._KeyVersion);
|
desfire.ChangeKey_AES(0x00, key_aes_new._Key, key_aes_new._KeyVersion);
|
||||||
|
|
||||||
test_successfully = true;
|
test_successfully = true;
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ namespace NFC_Real_Test
|
|||||||
private byte _FabAccess_FID = 0x01;
|
private byte _FabAccess_FID = 0x01;
|
||||||
private UInt32 _FabAccess_FSize = 0xF0;
|
private UInt32 _FabAccess_FSize = 0xF0;
|
||||||
|
|
||||||
private CipherKey _FabAccess_Card_MasterKey = new CipherKey("294A404E635266556A576E5A72347537", CipherType.AES, 0x10);
|
// Change of PICC Key is not implementet yet
|
||||||
|
// private CipherKey _FabAccess_Card_MasterKey = new CipherKey("294A404E635266556A576E5A72347537", CipherType.AES, 0x10);
|
||||||
|
|
||||||
private CipherKey _FabAccess_Application_MasterKey = new CipherKey("50645367566B59703273357638792F42", CipherType.AES, 0x10);
|
private CipherKey _FabAccess_Application_MasterKey = new CipherKey("50645367566B59703273357638792F42", CipherType.AES, 0x10);
|
||||||
private CipherKey _FabAccess_Application_AuthKey = new CipherKey("6D5A7134743677397A24432646294A40", CipherType.AES, 0x10);
|
private CipherKey _FabAccess_Application_AuthKey = new CipherKey("6D5A7134743677397A24432646294A40", CipherType.AES, 0x10);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user