using NFC.Helper; using System; using System.Collections.Generic; using System.Linq; namespace NFC { /// /// 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 /// public class APDUCommand { #region Constructors public APDUCommand(IsoCase isoCase, SCardProtocol sCardProtocol = SCardProtocol.ANY) { Case = isoCase; Protocol = sCardProtocol; Data = new byte[0]; } #endregion #region Properties public IsoCase Case { get; set; } 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; } } public byte[] Data { get; set; } public byte LE { get; set; } = 0x00; #endregion #region Methods public byte[] ToArray() { 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.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)); } #endregion } }