public static TrackData ParseIdtFormat(byte[] bytes) { var test = ByteArrayToHexString(bytes); var testdata = HexStringToByteArray(test); //get length data var lenData = BitConverter.ToInt16(new byte[] { bytes[osLenDataL], bytes[osLenDataH] }, 0); var hexlenData = bytes.Length - 6; //validate data var data = SubArray <byte>(bytes, 3, lenData); if (bytes[lenData + 3] != GetLrc(data) || bytes[lenData + 4] != GetChecksumAdd(data) || bytes[osStx] != StxValid || bytes[lenData + 5] != EtxValid) { throw new Exception("invalid card read"); } // get the actual idtech data string idtData = test.Substring(0, (lenData + 6) * 2); //// get the actual idtech data //string idtData = test.Substring(0, (lenData +6)*2); //get card encode type and manual var cardEncodeType = (CardEncodeType)bytes[osCardEncodeType]; var isEnhancedFormat = cardEncodeType == CardEncodeType.AAMVA_Enhanced || cardEncodeType == CardEncodeType.ISOABA_Enhanced || cardEncodeType == CardEncodeType.manual_Enhanced || cardEncodeType == CardEncodeType.Other_Enhanced || cardEncodeType == CardEncodeType.Raw_Enhanced; //isEnhancedFormat==true var isManual = cardEncodeType == CardEncodeType.manual || cardEncodeType == CardEncodeType.manual_Enhanced; TrackData trackData; if (cardEncodeType == CardEncodeType.manual) { var trackStatus = bytes[8]; //should be 04 var lenUnEncryptData = bytes[9]; //length of unencrypted data (PAN=EXP= from the status bits) - 16 (22 dec) int lenEncryptData = lenUnEncryptData % 8 > 0 ? (lenUnEncryptData / 8 + 1) * 8 : lenUnEncryptData; //Note: encrypted data length is len of unencrypted data rounded up to a multiple of 8 bytes(64 - bits) – I think (please test with other lengths of PAN data) var encryptedData = ByteArrayToHexString(SubArray <byte>(bytes, 10, lenEncryptData)); var hashData = ByteArrayToHexString(SubArray <byte>(bytes, 10 + lenEncryptData, 20)); var expLenStr = ByteArrayToHexString(SubArray <byte>(bytes, 10 + lenEncryptData + 20, 1)); int expLen = Int32.Parse(expLenStr.TrimStart('0')); var exp = Encoding.ASCII.GetString(SubArray <byte>(bytes, 10 + lenEncryptData + 20 + 1, expLen)); var ksn = ByteArrayToHexString(SubArray <byte>(bytes, 10 + lenEncryptData + 20 + 1 + expLen, 10)); string track2Data = new string('*', lenUnEncryptData - expLen - 3); track2Data = $";{track2Data}={exp}="; trackData = new TrackData() { T1Data = "", T2Data = "", T3Data = "", T1Crypto = "", T2Crypto = "", T3Crypto = "", T1Hash = "", T2Hash = "", T3Hash = "", SerialNumber = "", Ksn = ksn, //EncryptedTracks = ConvertIDTByteArrayToString(bytes), EncryptedTracks = idtData, IsSwipe = !isManual }; trackData.PAN = ""; trackData.Name = ""; trackData.ExpDate = exp; trackData.T3Data = encryptedData; } else if (isEnhancedFormat) { var trackStatus = (TrackStatus)bytes[osTrackStatus]; var maskStatus = (MaskStatus)bytes[osMaskStatus]; var dataStatus = (CryptoStatus)bytes[osDataStatus]; var isAesCrypto = maskStatus.HasFlag(MaskStatus.AesEncryption); var cryptoMultiple = (isAesCrypto ? 16 : 8); var serialNumberLen = maskStatus.HasFlag(MaskStatus.SerialNumberPresent) ? lenSerialNumber : 0; var ksnLen = dataStatus.HasFlag(CryptoStatus.KsnPresent) ? lenKsn : 0; var lenT1 = bytes[osLenT1]; var lenT2 = bytes[osLenT2]; var lenT3 = bytes[osLenT3]; var t1DataLen = trackStatus.HasFlag(TrackStatus.T1Sampling) ? lenT1 : 0; var t2DataLen = trackStatus.HasFlag(TrackStatus.T2Sampling) ? lenT2 : 0; var t3DataLen = trackStatus.HasFlag(TrackStatus.T3Sampling) ? lenT3 : 0; var lenT1CryptoPad = ((lenT1 % cryptoMultiple) > 0 ? cryptoMultiple : 0) - (lenT1 % cryptoMultiple); var lenT2CryptoPad = ((lenT2 % cryptoMultiple) > 0 ? cryptoMultiple : 0) - (lenT2 % cryptoMultiple); var lenT3CryptoPad = ((lenT3 % cryptoMultiple) > 0 ? cryptoMultiple : 0) - -(lenT3 % cryptoMultiple); var t1CryptoLen = dataStatus.HasFlag(CryptoStatus.T1Encrypted) ? lenT1 + lenT1CryptoPad : 0; var t2CryptoLen = dataStatus.HasFlag(CryptoStatus.T2Encrypted) ? lenT2 + lenT2CryptoPad : 0; var t3CryptoLen = dataStatus.HasFlag(CryptoStatus.T3Encrypted) ? lenT3 + lenT3CryptoPad : 0; var t1HashLen = dataStatus.HasFlag(CryptoStatus.T1Hash) ? lenHash : 0; var t2HashLen = dataStatus.HasFlag(CryptoStatus.T2Hash) ? lenHash : 0; var t3HashLen = dataStatus.HasFlag(CryptoStatus.T3Hash) ? lenHash : 0; var osT1Data = 10; var osT2Data = osT1Data + t1DataLen; var osT3Data = osT2Data + t2DataLen; var osT1Crypto = osT3Data + t3DataLen; var osT2Crypto = osT1Crypto + t1CryptoLen; var osT3Crypto = osT2Crypto + t2CryptoLen; var osT1Hash = osT3Crypto + t3CryptoLen; var osT2Hash = osT1Hash + t1HashLen; var osT3Hash = osT2Hash + t2HashLen; var osSerialNumber = osT3Hash + t3HashLen; var osKsn = osSerialNumber + serialNumberLen; var osLrc = osKsn + ksnLen; var osCheckSum = osLrc + 1; var osEtx = osCheckSum + 1; trackData = new TrackData() { T1Data = Encoding.ASCII.GetString(SubArray <byte>(bytes, osT1Data, t1DataLen)), T2Data = Encoding.ASCII.GetString(SubArray <byte>(bytes, osT2Data, t2DataLen)), T3Data = Encoding.ASCII.GetString(SubArray <byte>(bytes, osT3Data, t3DataLen)), T1Crypto = ByteArrayToHexString(SubArray <byte>(bytes, osT1Crypto, t1CryptoLen)), T2Crypto = ByteArrayToHexString(SubArray <byte>(bytes, osT2Crypto, t2CryptoLen)), T3Crypto = ByteArrayToHexString(SubArray <byte>(bytes, osT3Crypto, t3CryptoLen)), T1Hash = ByteArrayToHexString(SubArray <byte>(bytes, osT1Hash, t1HashLen)), T2Hash = ByteArrayToHexString(SubArray <byte>(bytes, osT2Hash, t2HashLen)), T3Hash = ByteArrayToHexString(SubArray <byte>(bytes, osT3Hash, t3HashLen)), SerialNumber = ByteArrayToHexString(SubArray <byte>(bytes, osSerialNumber, serialNumberLen)), Ksn = ByteArrayToHexString(SubArray <byte>(bytes, osKsn, ksnLen)), EncryptedTracks = ConvertIDTByteArrayToString(bytes), IsSwipe = !isManual }; var track1Values = GetTrack1(trackData.T1Data); trackData.PAN = track1Values.PAN; trackData.Name = track1Values.Name ?? track1Values.Name; trackData.ExpDate = track1Values.ExpDate; //debit card has not track1 data if (trackData.T1Data == string.Empty) { string track1 = trackData.T2Data; track1 = track1.Replace(";", "%%"); track1 = track1.Replace('*', '0'); track1 = track1.Replace('?', '0'); track1 = track1.Replace("=", "^MANUALLY/ENTERED^"); track1Values = GetTrack1(track1); trackData.PAN = track1Values.PAN; trackData.Name = ""; trackData.ExpDate = track1Values.ExpDate; } //Matthew: use ingenigo format for IDT data if (String.IsNullOrWhiteSpace(trackData.T2Data) && String.IsNullOrWhiteSpace(trackData.T3Data)) { trackData.T3Data = $"{trackData.Ksn}:1:{trackData.T1Crypto.Length / 2:D4}:{trackData.T1Crypto}"; } else if (String.IsNullOrWhiteSpace(trackData.T3Data) && !String.IsNullOrWhiteSpace(trackData.T2Crypto)) { trackData.T3Data = $"{trackData.Ksn}:2:{trackData.T2Crypto.Length / 2:D4}:{trackData.T2Crypto}"; trackData.T1Data = string.Empty; } if (isManual) { string firstHalf = ByteArrayToHexString(SubArray <byte>(bytes, 3, osT2Data - 3)) + Encoding.ASCII.GetString(SubArray <byte>(bytes, osT2Data, t2DataLen)); string newData = firstHalf + idtData.Substring(firstHalf.Length + t2DataLen + 6); int dataLength = newData.Length - 6; string dataLengthHex = dataLength.ToString("X"); newData = newData.Substring(0, dataLength); //var newDataHex =HexStringToByteArray(newData); long LRC = 0; long ChkSum = 0; for (int i = 0; i < newData.Length; i++) { long l = Convert.ToInt64(newData[i]); LRC ^= l; ChkSum += l; } byte[] LRCArray = BitConverter.GetBytes(LRC); byte[] ChkSumArray = BitConverter.GetBytes(ChkSum); byte[] ending = new byte[3]; ending[0] = LRCArray[0]; ending[1] = ChkSumArray[0]; ending[2] = EtxValid; newData = "02" + dataLengthHex + "00" + newData + ByteArrayToHexString(ending); trackData.EncryptedTracks = newData; } else { trackData.EncryptedTracks = $"{trackData.T1Data}|{trackData.T2Data}|{trackData.T3Data}"; } } else if (cardEncodeType == CardEncodeType.ISOABA) //original format { var trackStatus = bytes[4]; //should be 04 var lenUnEncryptTrack1 = bytes[5]; //length of unencrypted data (PAN=EXP= from the status bits) - 16 (22 dec) var lenUnEncryptTrack2 = bytes[6]; var lenUnEncryptTrack3 = bytes[7]; int indexUnEcryptTrack1 = 8; int indexUnEcryptTrack2 = indexUnEcryptTrack1 + lenUnEncryptTrack1; int indexUnEcryptTrack3 = indexUnEcryptTrack2 + lenUnEncryptTrack2; int lenEncryptTrack = (lenUnEncryptTrack1 + lenUnEncryptTrack2 + lenUnEncryptTrack3) % 8 > 0 ? ((lenUnEncryptTrack1 + lenUnEncryptTrack2 + lenUnEncryptTrack3) / 8 + 1) * 8 : (lenUnEncryptTrack1 + lenUnEncryptTrack2 + lenUnEncryptTrack3); int indexEncryptTrack = indexUnEcryptTrack3 + lenUnEncryptTrack3; int lenHash = 20; int lenHashTrack1 = 0; int lenHashTrack2 = 0; int indexHashTrack1 = indexEncryptTrack + lenEncryptTrack; if (lenUnEncryptTrack1 > 0)//we have track1, we have track1 hash. { lenHashTrack1 = lenHash; } int indexHashTrack2 = indexHashTrack1 + lenHashTrack1; if (lenUnEncryptTrack2 > 0)//we have track2, we have track2 hash. { lenHashTrack2 = lenHash; } int indexKsn = indexHashTrack2 + lenHashTrack2; int lenKsn = 10; trackData = new TrackData() { T1Data = Encoding.ASCII.GetString(SubArray <byte>(bytes, indexUnEcryptTrack1, lenUnEncryptTrack1)), T2Data = Encoding.ASCII.GetString(SubArray <byte>(bytes, indexUnEcryptTrack2, lenUnEncryptTrack2)), T3Data = Encoding.ASCII.GetString(SubArray <byte>(bytes, indexUnEcryptTrack3, lenUnEncryptTrack3)), T1Crypto = ByteArrayToHexString(SubArray <byte>(bytes, indexEncryptTrack, lenEncryptTrack)), T2Crypto = "", T3Crypto = "", T1Hash = ByteArrayToHexString(SubArray <byte>(bytes, indexHashTrack1, lenHashTrack1)), T2Hash = ByteArrayToHexString(SubArray <byte>(bytes, indexHashTrack2, lenHashTrack2)), T3Hash = "", SerialNumber = "", Ksn = ByteArrayToHexString(SubArray <byte>(bytes, indexKsn, lenKsn)), EncryptedTracks = "", IsSwipe = !isManual }; var track1Values = GetTrack1(trackData.T1Data); trackData.PAN = track1Values.PAN; trackData.Name = track1Values.Name ?? track1Values.Name; trackData.ExpDate = track1Values.ExpDate; //debit card has not track1 data if (trackData.T1Data == string.Empty) { string track1 = trackData.T2Data; track1 = track1.Replace(";", "%%"); track1 = track1.Replace('*', '0'); track1 = track1.Replace('?', '0'); track1 = track1.Replace("=", "^MANUALLY/ENTERED^"); track1Values = GetTrack1(track1); trackData.PAN = track1Values.PAN; trackData.Name = ""; trackData.ExpDate = track1Values.ExpDate; } if (lenUnEncryptTrack2 > 0)//if we do not have track2, it means it is an invalid swipe or card. { trackData.T3Data = $"{trackData.Ksn}:4:{(trackData.T1Crypto.Length) / 2:D4}:{trackData.T1Crypto}"; } else { trackData.T3Data = string.Empty; } trackData.EncryptedTracks = $"{trackData.T1Data}|{trackData.T2Data}|{trackData.T3Data}"; } else { trackData = null; } if (String.IsNullOrWhiteSpace(trackData?.Ksn) || String.IsNullOrWhiteSpace(trackData?.T3Data)) { trackData = null; } return(trackData); }
public static TrackData ParseXmlFormat(byte[] bytes) { var test = Encoding.ASCII.GetString(bytes); var testdata = Encoding.ASCII.GetBytes(test); var osDvcMsgEnd = search(bytes, Encoding.ASCII.GetBytes("</DvcMsg>"), 0); var osCard = search(bytes, Encoding.ASCII.GetBytes("<Card "), 0); var osCardEnd = search(bytes, Encoding.ASCII.GetBytes("></Card"), osCard); int osETrk1 = 0; int osETrk1End = 0; int osETrk2 = 0; int osETrk2End = 0; int osECData = 0; int osECDataEnd = 0; int cardEntry = search(bytes, Encoding.ASCII.GetBytes("Entry=\"MANUAL\""), 0); if (cardEntry > 0)//manual { osECData = search(bytes, Encoding.ASCII.GetBytes("ECData=\""), osCard); if (osECData < 0) { osECData = 0; } osECDataEnd = search(bytes, Encoding.ASCII.GetBytes("\" CDataKSN=\""), osECData); } else { try { osETrk1 = search(bytes, Encoding.ASCII.GetBytes("ETrk1=\""), osCard); if (osETrk1 < 0) { osETrk1 = 0; } osETrk1End = search(bytes, Encoding.ASCII.GetBytes("\" ETrk2=\""), osETrk1); } catch (Exception ex) { } osETrk2 = search(bytes, Encoding.ASCII.GetBytes("ETrk2=\""), osETrk1End); osETrk2End = search(bytes, Encoding.ASCII.GetBytes("\" CDataKSN=\""), osETrk2); } var osKsn = search(bytes, Encoding.ASCII.GetBytes("CDataKSN=\""), osETrk2); var osKsnEnd = search(bytes, Encoding.ASCII.GetBytes("\" Exp=\""), osKsn); const int MaxResponseLength = 666; var data = new StringBuilder(MaxResponseLength); if (osETrk1 > 0) { data.Append(Encoding.ASCII.GetString(SubArray <byte>(bytes, 0, osETrk1 + 7))); data.Append(ByteArrayToHexString(((SubArray <byte>(bytes, osETrk1 + 7, osETrk1End - osETrk1 - 7))))); data.Append(Encoding.ASCII.GetString(SubArray <byte>(bytes, osETrk1End, osETrk2 - osETrk1End + 7))); } if (osETrk2 > 0) { data.Append(ByteArrayToHexString(SubArray <byte>(bytes, osETrk2 + 7, osETrk2End - osETrk2 - 7))); data.Append(Encoding.ASCII.GetString(SubArray <byte>(bytes, osETrk2End, osKsn - osETrk2End + 10))); } if (osECData > 0) //manual input { data.Append(Encoding.ASCII.GetString(SubArray <byte>(bytes, 0, osECData + 8))); data.Append(ByteArrayToHexString(((SubArray <byte>(bytes, osECData + 8, osECDataEnd - osECData - 8))))); data.Append(Encoding.ASCII.GetString(SubArray <byte>(bytes, osECDataEnd, osKsn - osECDataEnd + 10))); } data.Append(ByteArrayToHexString(SubArray <byte>(bytes, osKsn + 10, osKsnEnd - osKsn - 10))); data.Append(Encoding.ASCII.GetString(SubArray <byte>(bytes, osKsnEnd, osDvcMsgEnd - osKsnEnd + 9))); var dvcMsg = data.ToString(); dvcMsg = dvcMsg.Replace("\0", " ");//remove the "\0" null value. XmlSerializer serializer = new XmlSerializer(typeof(DvcMsg)); StringReader rdr = new StringReader(dvcMsg); var obj = (DvcMsg)serializer.Deserialize(rdr); var trackData = new TrackData() { IsDebit = false, T1Data = obj.Card.ETrk1, T2Data = obj.Card.ETrk2, Name = obj.Card.CHolder ?? string.Empty, ExpDate = obj.Card.Exp.ToString(), PAN = obj.Card.MskPAN, EncryptedTracks = "", T1Crypto = obj.Card.ETrk1, T2Crypto = obj.Card.ETrk2, Ksn = obj.Card.CDataKSN }; //trackData.SerialNumber = obj.Dvc.DvcSN.ToString(); trackData.IsSwipe = true; //Matthew: use ingenigo format for IDT data if (String.IsNullOrWhiteSpace(trackData.T1Crypto) && String.IsNullOrWhiteSpace(trackData.T2Crypto)) { trackData.IsSwipe = false; trackData.PAN = trackData.PAN.Replace('*', '0'); trackData.T1Data = $""; trackData.T2Data = $""; trackData.T3Data = $""; } else if (String.IsNullOrWhiteSpace(trackData.T2Data)) { trackData.T3Data = $"{trackData.Ksn}:1:{trackData.T1Crypto.Length / 2:D4}:{trackData.T1Crypto}"; } else { trackData.T3Data = $"{trackData.Ksn}:2:{trackData.T2Crypto.Length / 2:D4}:{trackData.T2Crypto}"; trackData.T1Data = string.Empty; } if (trackData.IsSwipe) { trackData.EncryptedTracks = $"{trackData.T1Data}|{trackData.T2Data}|{trackData.T3Data}"; } else { trackData.EncryptedTracks = dvcMsg; } return(trackData); }