/// <summary> /// Initializes a new <see cref="DataObjectList"/> instance. /// </summary> /// <param name="dolData">Raw DOL data.</param> public DataObjectList(byte[] dolData) : this() { Tlv = new TlvData { Value = dolData }; }
private TlvData BuildTlv(TagModel tagModel) { var tlv = new TlvData { Tag = Convert.ToUInt32(tagModel.Tag, 16) }; if (tagModel.Fields == null) { tlv.Value = tagModel.Tag switch { // Language Preference "5F2D" => _data.UnmanagedAttributes[tagModel.Tag] .ToObject <string[]>() .Aggregate(String.Empty, (c, l) => c + l) .FromString(), _ => _data.UnmanagedAttributes[tagModel.Tag] .ToObject <string>() .FromHexa() }; } else { tlv.InnerTlvs = tagModel.Fields.Select(BuildTlv).ToList(); } return(tlv); }
/// <summary> /// Constructor /// </summary> /// <param name="tlvLogEntry">Raw Log Entry tag</param> public LogEntry(TlvData tlvLogEntry) { if (tlvLogEntry.Length < 2) { throw new Exception(String.Format("LogEntry: TLV data length < 2, can't parse [{0}]", tlvLogEntry)); } Tlv = tlvLogEntry; }
/// <inheritdoc /> public override string ToString() { var tlv = new TlvData { Tag = Tag, Length = Length }; return(String.Format("({0:T}/{0:L})", tlv)); }
/// <summary> /// MasterCard cAPDU. /// Process the COMPUTE CRYPTOGRAPHIC CHECKSUM phase of a MasterCard transaction. /// </summary> /// <returns>Last status word.</returns> public UInt16 ComputeCryptographicChecksum() { BeforeComputeCryptographicChecksumEvent.Raise(this, new EmvEventArgs()); // If UDOL 9F69 is not supplied in records, then use default UDOL = 9F6A04 byte[] udolDataValue = null; var tlvAll = new List <TlvData>(); foreach (var record in _tlvRecords) { tlvAll.Add(record); if (record.HasTag(0x9F69)) { var udol = new DataObjectList(record.GetTag(0x9F69).Value); tlvAll.AddRange(TlvTerminalData); udolDataValue = udol.BuildData(tlvAll); } } if (udolDataValue == null) { var tmp = ""; var seed = new Random(10000).Next(); var rndNumbers = new Random(seed); for (var i = 0; i < 8; i++) { var rndNumber = rndNumbers.Next(10); tmp += rndNumber.ToString(CultureInfo.InvariantCulture); } udolDataValue = tmp.FromHexa(); } // Execute COMPUTE CRYPTOGRAPHIC CHECKSUM var cAPDU = new CommandAPDU(0x80, 0x2A, 0x8E, 0x80, (uint)udolDataValue.Length, udolDataValue, 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { _tlvCryptographicChecksum = new TlvData(); crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _tlvCryptographicChecksum = new TlvData(crp.RApdu.Udr); } AfterComputeCryptographicChecksumEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
/// <summary> /// Initializes a new <see cref="EmvApplication"/> instance. /// </summary> /// <param name="cardChannel"><see cref="ICardChannel">ICardChannel</see> object to use</param> /// <param name="tlvFromPSE"><see cref="TlvData">TLVData</see> object coming from PSE records for this application</param> public EmvApplication(ICardChannel cardChannel, TlvData tlvFromPSE) : this(cardChannel) { _tlvFromPSE = tlvFromPSE; if (_tlvFromPSE.HasTag(0x4F)) { Aid = _tlvFromPSE.GetTag(0x4F).Value.ToHexa(); } }
/// <summary> /// /// </summary> /// <param name="tagId"></param> /// <param name="tlv"></param> /// <param name="tagsManager"></param> private static void WriteTlv(UInt32 tagId, TlvData tlv, TlvDictionary tagsManager) { Console.WriteLine(" >> Contains tag {0:X2}: {1} [ {2} ]", tagId, tlv.HasTag(tagId), tlv.GetTag(tagId)); if (tlv.HasTag(tagId) && (tagsManager.CreateInstance(tlv.GetTag(tagId)) != null)) { Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine(" >> {0:N}: {0}", tagsManager.CreateInstance(tlv.GetTag(tagId))); Console.ForegroundColor = ConsoleColor.Gray; } }
/// <inheritdoc /> public string ToString(string format, IFormatProvider formatProvider) { if (!String.IsNullOrEmpty(format)) { var tlv = new TlvData { Tag = Tag, Length = Length }; return(tlv.ToString(format, formatProvider)); } return(ToString()); }
/// <summary> /// Enumerates DO. /// </summary> /// <returns><see cref="DataObjectList.DataObjectDefinition"/> instances.</returns> public IEnumerable <DataObjectDefinition> GetDataObjectDefinitions() { UInt32 offset = 0; var tlvParser = new TlvData(); while (offset < Tlv.Value.Length) { offset = tlvParser.ParseT(Tlv.Value, offset); offset = tlvParser.ParseL(Tlv.Value, offset); yield return(new DataObjectDefinition(tlvParser.Tag, tlvParser.Length)); } }
/// <summary> /// Process the INTERNAL AUTHENTICATION of an EMV transaction. /// </summary> /// <param name="unpredictableNumber">Unpredictable number.</param> /// <returns>Last status word.</returns> public UInt16 InternalAuthenticate(byte[] unpredictableNumber) { BeforeInternalAuthenticateEvent.Raise(this, new EmvEventArgs()); _tlvInternalAuthenticateUnpredictableNumber = new TlvData(0x9F37, 0x04, unpredictableNumber); // Build DDOL data byte[] ddolDataValue; if (Ddol != null) { // Use DDOL to build data var tlvAll = new List <TlvData> { TlvFci, TlvProcessingOptions, _tlvInternalAuthenticateUnpredictableNumber }; tlvAll.AddRange(TlvRecords); tlvAll.AddRange(TlvTerminalData); ddolDataValue = Ddol.BuildData(tlvAll); } else { ddolDataValue = new byte[0]; } // Execute GET PROCESSING OPTIONS var cAPDU = new CommandAPDU(0x00, 0x88, 0x00, 0x00, (uint)ddolDataValue.Length, ddolDataValue, 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { _tlvSignedDynamicApplicationResponse = new TlvData(); crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _tlvSignedDynamicApplicationResponse = new TlvData(crp.RApdu.Udr); } AfterInternalAuthenticateEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
/// <summary> /// /// </summary> /// <param name="tagId"></param> /// <param name="tlv"></param> /// <param name="tagsManager"></param> private void WriteTlv(UInt32 tagId, TlvData tlv, TlvDictionary tagsManager) { gui.guiDetailedLogs.AppendText(String.Format(" >> TLV {0:X2}: [ {1} ]\n", tagId, tlv.GetTag(tagId))); if (!tlv.HasTag(tagId) || (tagsManager.CreateInstance(tlv.GetTag(tagId)) == null)) { return; } gui.guiDetailedLogs.SelectionColor = highlightColor; gui.guiDetailedLogs.AppendText(String.Format(" >> {0:N}: {0}\n", tagsManager.CreateInstance(tlv.GetTag(tagId)))); gui.guiDetailedLogs.SelectionColor = standardColor; }
/// <summary> /// Process the GET PROCESSING OPTIONS phase of an EMV transaction. /// </summary> /// <returns>Last status word.</returns> public UInt16 GetProcessingOptions() { BeforeGetProcessingOptionsEvent.Raise(this, new EmvEventArgs()); // If PDOL 9F38 is not supplied in FCI, then used 8300 as UDC; if supplied: build the PDOL in tag 83 L V byte[] pdolDataValue; if (TlvFci.HasTag(0x9F38)) { // Use PDOL to build tag 83 value var pdol = new DataObjectList(TlvFci.GetTag(0x9F38).Value); var tlvAll = new List <TlvData> { TlvFci }; tlvAll.AddRange(TlvTerminalData); pdolDataValue = pdol.BuildData(tlvAll); } else { pdolDataValue = new byte[0]; } // Build tag 83 with computed value var tlvPdolData = new TlvData(0x83, (uint)pdolDataValue.Length, pdolDataValue); // Execute GET PROCESSING OPTIONS var cAPDU = new CommandAPDU(0x80, 0xA8, 0x00, 0x00, tlvPdolData.Length + 2, tlvPdolData.ToByteArray(), 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { _tlvProcessingOptions = new TlvData(); crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _tlvProcessingOptions = new TlvData(crp.RApdu.Udr); } AfterGetProcessingOptionsEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
private void buttonXmlToTlv_Click(object sender, EventArgs e) { TlvData tlv = null; var isDone = TryAndOutput(() => { var serializer = new XmlSerializer(typeof(TlvData)); tlv = (TlvData)serializer.Deserialize(new StringReader(textSource.Text)); }); if (!isDone) { return; } ConvertAndOutput(() => tlv.ToByteArray().ToHexa()); }
/// <summary> /// Builds DGI to be used with STORE DATA command for given records having the same index. /// </summary> /// <param name="sfi"></param> /// <param name="index"></param> /// <param name="records"></param> /// <returns></returns> public string BuildDgi(byte sfi, byte index, IEnumerable <PseRecord> records) { var tlv70 = new TlvData(0x70, new List <TlvData>()); foreach (var record in records) { var tlvs = new List <TlvData> { new TlvData { Tag = 0x4F, Value = record.AdfName.FromHexa() }, new TlvData { Tag = 0x50, Value = record.ApplicationLabel.FromString() } }; if (!String.IsNullOrWhiteSpace(record.PreferredName)) { tlvs.Add(new TlvData { Tag = 0x9F12, Value = record.PreferredName.FromString() }); } if (record.PriorityIndicator.HasValue) { tlvs.Add(new TlvData { Tag = 0x87, Value = record.PriorityIndicator.Value.ToByteArray() }); } if (!String.IsNullOrWhiteSpace(record.DiscretionaryData)) { tlvs.Add(new TlvData { Tag = 0x73, Value = record.DiscretionaryData.FromHexa() }); } var tlv61 = new TlvData(0x61, tlvs); tlv70.InnerTlvs.Add(tlv61); } var dgiLength = TlvDataHelper.ToBerEncodedL((uint)tlv70.Length / 2); return($"{sfi:X2}{index:X2}{dgiLength.ToHexa('\0')}{tlv70.ToByteArray().ToHexa()}"); }
/// <summary> /// Parses an array of Bytes as a sequence of value, using the format defined by the <see cref="DataObjectList"/>. /// </summary> /// <param name="data">Array of Bytes to be parsed.</param> /// <returns>The list of <see cref="TlvData"/> objects obtained after parsing.</returns> public List <TlvData> ParseRawData(byte[] data) { var tlvDataList = new List <TlvData>(); var offset = 0; foreach (var dod in GetDataObjectDefinitions()) { var tlvData = new TlvData { Tag = dod.Tag, Length = dod.Length, Value = new byte[dod.Length] }; Array.Copy(data, offset, tlvData.Value, 0, (int)dod.Length); tlvDataList.Add(tlvData); offset += (int)dod.Length; } return(tlvDataList); }
/// <summary> /// Reads the file pointed by the SFI found in the FCI of the application. /// </summary> /// <returns>Last status word.</returns> public UInt16 ReadDataFile(AflEntry file) { for (var recordNumber = file.FirstRecord; recordNumber <= file.LastRecord; recordNumber++) { CommandAPDU cAPDU = new EMVReadRecordCommand(recordNumber, file.Sfi, 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); if (crp.RApdu.StatusWord == 0x9000) { var tlv = new TlvData(crp.RApdu.Udr); if (tlv.Tag != 0x70) { throw new Exception(String.Format("EMVApplication.readData(): record is not TLV-coded with tag 70 [{0}]", tlv)); } // Store data in list _tlvRecords.Add(tlv); // If used for offline, store it in dedicated list if (recordNumber - file.FirstRecord < file.OfflineNumberOfRecords) { // For files with SFI in the range 1 to 10, the record tag ('70') and the record length are excluded from the offline data authentication process. if (file.Sfi <= 10) { foreach (var tlvData in tlv.InnerTlvs) { _tlvOfflineRecords.Add(tlvData); } } //For files with SFI in the range 11 to 30, the record tag ('70') and the record length are not excluded from the offline data authentication process. else { _tlvOfflineRecords.Add(tlv); } } } _lastStatusWord = crp.RApdu.StatusWord; } return(_lastStatusWord); }
private static TreeNode ConvertTlvDataToTreeNode(TlvData tlv, TlvDictionary tlvManager) { TreeNode tlvNode; if (tlvManager != null && tlvManager.Get(String.Format("{0:T}", tlv)) != null) { var tlvObject = tlvManager.CreateInstance(tlv); tlvObject.Tlv = tlv; tlvNode = new TreeNode(String.Format("{0:N}: {0}", tlvObject)); } else { tlvNode = new TreeNode(String.Format("T:{0:T} L:{0:L} V:{0:Vh}", tlv)); } foreach (var subTLV in tlv.InnerTlvs) { tlvNode.Nodes.Add(ConvertTlvDataToTreeNode(subTLV, tlvManager)); } return(tlvNode); }
/// <summary> /// Selects the DF by its DF Name or AID. /// </summary> /// <returns>Last status word</returns> public UInt16 Select() { BeforeSelectEvent.Raise(this, new EmvEventArgs()); // Execute the SELECT var crp = new CommandResponsePair(new EMVSelectByNameCommand(_adfName, 0)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // Finally, store FCI if (crp.RApdu.StatusWord == 0x9000) { TlvFci = new TlvData(crp.RApdu.Udr); } AfterSelectEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
/// <summary> /// Process a GET DATA to retrieve one EMV information. /// </summary> /// <param name="tag"> /// <list type="bullet"> /// <item><c>0x9F36</c> for ATC</item> /// <item><c>0x9F13</c> for Last Online ATC Register</item> /// <item><c>0x9F17</c> for PIN Try Counter</item> /// <item><c>0x9F4F</c> for Log Format</item> /// </list> /// </param> /// <param name="tlv"></param> /// <returns>Last status word.</returns> protected UInt16 GetData(UInt32 tag, ref TlvData tlv) { // Execute GET DATA instruction var cAPDU = new GetDataCommand(tag, 0) { Cla = 0x80 }; var crp = new CommandResponsePair(cAPDU); if (crp.Transmit(_cardChannel) != ErrorCode.Success) { return(_lastStatusWord); } _lastStatusWord = crp.RApdu.StatusWord; // Finally store rAPDU if (crp.RApdu.StatusWord == 0x9000) { tlv = new TlvData(crp.RApdu.Udr); } return(_lastStatusWord); }
/// <summary> /// Initializes a new <see cref="CertificationAuthorityPublicKeyIndex"/> instance. /// </summary> /// <param name="tlvCaPublicKeyIndex">TLVData defining the Certification Authority Public Key Index tag.</param> public CertificationAuthorityPublicKeyIndex(TlvData tlvCaPublicKeyIndex) { Tlv = tlvCaPublicKeyIndex; }
/// <summary> /// Creates a new <see cref="EmvDefinitionFile"/> instance. /// </summary> /// <param name="cardChannel"><see cref="ICardChannel">ICardChannel</see> object to use</param> public EmvDefinitionFile(ICardChannel cardChannel) { _cardChannel = new CardChannelIso7816(new CardChannelTerminalTransportLayer(cardChannel)); TlvFci = null; }
/// <summary> /// Initializes a new <see cref="ShortFileIdentifier"/> instance. /// </summary> /// <param name="tlvSfi">TLVData defining the SFI tag</param> public ShortFileIdentifier(TlvData tlvSfi) { Tlv = tlvSfi; }
/// <summary> /// Initializes a new <see cref="CryptogramInformationData"/> instance. /// </summary> /// <param name="tlvCid">TLV CID data.</param> public CryptogramInformationData(TlvData tlvCid) : this() { Tlv = tlvCid; }
/// <summary> /// Initializes a new <see cref="CryptogramInformationData"/> instance. /// </summary> public CryptogramInformationData() { Tlv = new TlvData(); }
/// <summary> /// Initializes a new <see cref="TerminalVerificationResult"/> instance. /// </summary> /// <param name="tlvTvr">TLV TVR data.</param> public TerminalVerificationResult(TlvData tlvTvr) : this() { Tlv = tlvTvr; }
/// <summary> /// Initializes a new <see cref="TerminalVerificationResult"/> instance. /// </summary> public TerminalVerificationResult() { Tlv = new TlvData(); }
/// <summary> /// Initializes a new <see cref="ApplicationIdentifier"/> instance. /// </summary> /// <param name="sAid">string AID.</param> public ApplicationIdentifier(string sAid) { var value = sAid.FromHexa(); Tlv = new TlvData(0x4F, (UInt32)value.Length, value); }
/// <summary> /// Initializes a new <see cref="ApplicationIdentifier"/> instance. /// Constructor /// </summary> /// <param name="tlvAid">TLVData containing AID.</param> public ApplicationIdentifier(TlvData tlvAid) { Tlv = tlvAid; }
/// <summary> /// Initializes a new <see cref="ApplicationIdentifier"/> instance. /// </summary> public ApplicationIdentifier() { Tlv = new TlvData { Tag = 0x4F }; }
/// <summary> /// Initializes a new <see cref="ApplicationFileLocator"/> instance. /// </summary> public ApplicationFileLocator() { Tlv = new TlvData { Tag = 0x94 }; }