2021-03-31 14:11:57 +02:00
|
|
|
|
using NFC.Helper;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2021-03-30 22:51:02 +02:00
|
|
|
|
|
|
|
|
|
namespace NFC
|
|
|
|
|
{
|
2021-03-31 14:11:57 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Application Protocol Data Unit
|
|
|
|
|
/// https://de.wikipedia.org/wiki/Application_Protocol_Data_Unit
|
|
|
|
|
/// https://github.com/danm-de/pcsc-sharp/blob/246fc4303190184d6acd98a2d66f48cb7ffd7094/src/PCSC.Iso7816/CommandApdu.cs
|
|
|
|
|
/// </summary>
|
2021-03-30 22:51:02 +02:00
|
|
|
|
public class APDUCommand
|
|
|
|
|
{
|
2021-03-31 14:11:57 +02:00
|
|
|
|
#region Constructors
|
|
|
|
|
public APDUCommand(IsoCase isoCase, SCardProtocol sCardProtocol = SCardProtocol.ANY)
|
2021-03-30 22:51:02 +02:00
|
|
|
|
{
|
2021-03-30 23:27:12 +02:00
|
|
|
|
Case = isoCase;
|
2021-03-31 14:11:57 +02:00
|
|
|
|
Protocol = sCardProtocol;
|
|
|
|
|
Data = new byte[0];
|
2021-03-30 22:51:02 +02:00
|
|
|
|
}
|
2021-03-31 14:11:57 +02:00
|
|
|
|
#endregion
|
2021-03-30 22:51:02 +02:00
|
|
|
|
|
2021-03-31 14:11:57 +02:00
|
|
|
|
#region Properties
|
2021-03-30 23:27:12 +02:00
|
|
|
|
public IsoCase Case { get; set; }
|
2021-03-31 14:11:57 +02:00
|
|
|
|
public SCardProtocol Protocol { get; set; }
|
|
|
|
|
|
|
|
|
|
public byte CLA { get; set; } = 0x00;
|
|
|
|
|
public byte INS { get; set; } = 0x00;
|
|
|
|
|
public byte P1 { get; set; } = 0x00;
|
|
|
|
|
public byte P2 { get; set; } = 0x00;
|
|
|
|
|
public byte LC
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (byte)Data.Length;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-30 23:27:12 +02:00
|
|
|
|
public byte[] Data { get; set; }
|
2021-03-31 14:11:57 +02:00
|
|
|
|
public byte LE { get; set; } = 0x00;
|
|
|
|
|
#endregion
|
2021-03-30 22:51:02 +02:00
|
|
|
|
|
2021-03-31 14:11:57 +02:00
|
|
|
|
#region Methods
|
2021-03-30 23:27:12 +02:00
|
|
|
|
public byte[] ToArray()
|
2021-03-30 22:51:02 +02:00
|
|
|
|
{
|
2021-03-31 14:11:57 +02:00
|
|
|
|
byte[] header = ByteOperation.Concatenate(new byte[] { CLA }, new byte[] { INS }, new byte[] { P1 }, new byte[] { P2 });
|
|
|
|
|
switch (Case)
|
|
|
|
|
{
|
|
|
|
|
case IsoCase.Case1:
|
|
|
|
|
/* Regarding to OpenSC: T0 needs one additional
|
|
|
|
|
* byte containing 0x00. */
|
|
|
|
|
if (Protocol == SCardProtocol.T0)
|
|
|
|
|
{
|
|
|
|
|
return ByteOperation.Concatenate(header, new byte[] { 0x00 });
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return header;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case IsoCase.Case2Short:
|
|
|
|
|
return ByteOperation.Concatenate(header, new byte[] { LE });
|
|
|
|
|
|
|
|
|
|
case IsoCase.Case3Short:
|
|
|
|
|
return ByteOperation.Concatenate(header, new byte[] { LC }, Data);
|
|
|
|
|
|
|
|
|
|
case IsoCase.Case4Short:
|
|
|
|
|
/* Regarding to OpenSC: T0 has no Le */
|
|
|
|
|
if (Protocol == SCardProtocol.T0)
|
|
|
|
|
{
|
|
|
|
|
return ByteOperation.Concatenate(header, new byte[] { LC }, Data, new byte[] { 0x00 });
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return ByteOperation.Concatenate(header, new byte[] { LC }, Data, new byte[] { LE });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new NotSupportedException(string.Format("IsoCase {0} is not supported.", Case));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
|
|
|
|
return obj is APDUCommand command &&
|
|
|
|
|
Case == command.Case &&
|
|
|
|
|
Protocol == command.Protocol &&
|
|
|
|
|
CLA == command.CLA &&
|
|
|
|
|
INS == command.INS &&
|
|
|
|
|
P1 == command.P1 &&
|
|
|
|
|
P2 == command.P2 &&
|
|
|
|
|
Data.SequenceEqual(command.Data) &&
|
|
|
|
|
LE == command.LE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
int hashCode = -98047210;
|
|
|
|
|
hashCode = hashCode * -1521134295 + Case.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + Protocol.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + CLA.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + INS.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + P1.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + P2.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + LC.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + EqualityComparer<byte[]>.Default.GetHashCode(Data);
|
|
|
|
|
hashCode = hashCode * -1521134295 + LE.GetHashCode();
|
|
|
|
|
return hashCode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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("-", "").ToLower());
|
|
|
|
|
case IsoCase.Case4Short:
|
|
|
|
|
case IsoCase.Case4Extended:
|
|
|
|
|
return string.Format(pattern_case4, CLA, INS, P1, P2, LC, BitConverter.ToString(Data).Replace("-", "").ToLower(), LE);
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception("Unknown IsoCase");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Operator Overloading
|
|
|
|
|
public static bool operator ==(APDUCommand obj1, APDUCommand obj2)
|
|
|
|
|
{
|
|
|
|
|
return obj1.Equals(obj2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool operator !=(APDUCommand obj1, APDUCommand obj2)
|
|
|
|
|
{
|
|
|
|
|
return !(obj1.Equals(obj2));
|
2021-03-30 22:51:02 +02:00
|
|
|
|
}
|
2021-03-31 14:11:57 +02:00
|
|
|
|
#endregion
|
2021-03-30 22:51:02 +02:00
|
|
|
|
}
|
|
|
|
|
}
|