2020-09-15 15:27:01 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using NFC.Mifare_DESFire;
|
|
|
|
|
|
2020-10-05 18:39:45 +02:00
|
|
|
|
namespace NFC.ISO7816_4
|
2020-09-15 15:27:01 +02:00
|
|
|
|
{
|
|
|
|
|
public class APDUResponse
|
|
|
|
|
{
|
2020-10-05 18:39:45 +02:00
|
|
|
|
#region constructor
|
|
|
|
|
public APDUResponse()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-15 15:27:01 +02:00
|
|
|
|
/// <summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
/// Creates a new APDUResponse from the raw received data.
|
2020-09-15 15:27:01 +02:00
|
|
|
|
/// </summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
public APDUResponse(byte[] raw)
|
|
|
|
|
{
|
|
|
|
|
Body = raw.Take(raw.Length - 1).ToArray();
|
|
|
|
|
SW1 = raw[raw.Length - 2];
|
|
|
|
|
SW2 = raw[raw.Length - 3];
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2020-09-15 15:27:01 +02:00
|
|
|
|
|
2020-10-05 18:39:45 +02:00
|
|
|
|
#region Properties
|
2020-09-15 15:27:01 +02:00
|
|
|
|
/// <summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
/// ISO 7816-4-4 - Body - Body
|
2020-09-15 15:27:01 +02:00
|
|
|
|
/// </summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
public byte[] Body { get; set; }
|
2020-09-15 15:27:01 +02:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
/// ISO 7816-4 - SW1 - Status Word 1
|
2020-09-15 15:27:01 +02:00
|
|
|
|
/// </summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
public byte SW1 { get; set; }
|
2020-09-15 15:27:01 +02:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
/// ISO 7816-4 - SW2 - Status Word 2
|
2020-09-15 15:27:01 +02:00
|
|
|
|
/// </summary>
|
2020-10-05 18:39:45 +02:00
|
|
|
|
public byte SW2 { get; set; }
|
2020-09-15 15:27:01 +02:00
|
|
|
|
|
|
|
|
|
public APDUStatusWords StatusWord
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
// Some status words only require a specific first byte
|
|
|
|
|
// and in some cases SW2 contains additional information.
|
|
|
|
|
// This will filter out those errors. When there is more information separate methods for getting those are available.
|
|
|
|
|
switch(SW1) {
|
|
|
|
|
case 0x61:
|
|
|
|
|
// Kommando erfolgreich ausgeführt. xx Datenbytes können mit dem ‚GET RESPONSE‘-Kommando abgeholt werden. Statuswort zur Steuerung des T=0-Protokolls
|
|
|
|
|
return APDUStatusWords.DATA_READY;
|
|
|
|
|
case 0x62:
|
|
|
|
|
// Warnung; Zustand des nichtflüchtigen Speichers nicht verändert
|
|
|
|
|
return APDUStatusWords.STORAGE_NOT_CHANGED;
|
|
|
|
|
case 0x63:
|
|
|
|
|
if((SW2 & 0xF0) == 0xC0) {
|
|
|
|
|
// Zähler hat den Wert x erreicht (die genaue Bedeutung ist vom Kommando abhängig)
|
|
|
|
|
return APDUStatusWords.COUNTER_REACHED;
|
|
|
|
|
}
|
|
|
|
|
// Warnung; Zustand des nichtflüchtigen Speichers verändert
|
|
|
|
|
return APDUStatusWords.STORAGE_CHANGED;
|
|
|
|
|
case 0x64:
|
|
|
|
|
// Ausführungsfehler; Zustand des nichtflüchtigen Speichers nicht verändert
|
|
|
|
|
return APDUStatusWords.EXECUTION_ERROR_WITHOUT_CHANGE;
|
|
|
|
|
case 0x65:
|
|
|
|
|
// Ausführungsfehler; Zustand des nichtflüchtigen Speichers verändert
|
|
|
|
|
return APDUStatusWords.EXECUTION_ERROR_WITH_CHANGE;
|
|
|
|
|
case 0x6C:
|
|
|
|
|
// Falsche Länge Le; xx gibt die korrekte Länge an Statuswort zur Steuerung des T=0-Protokolls
|
|
|
|
|
return APDUStatusWords.INVALID_LE;
|
|
|
|
|
}
|
|
|
|
|
return (APDUStatusWords) (((UInt16) SW1) << 8 | ((UInt16) SW2));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If the reponse status is DATA_READY this method can be used to get the amount of data that can be read from the card.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public byte DataLength
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return SW2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If the reponse status is COUNTER_REACHED this method can be used to get the value that the counter reached.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public byte Counter
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (byte)(SW2 & 0x0F);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// If the reponse status is INVALID_LE this method can be used to get the correct LE.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public byte CorrectLE
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return SW2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-05 18:39:45 +02:00
|
|
|
|
#endregion
|
2020-09-15 15:27:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|