public MSRTrackData RetrieveAdditionalData(byte[] trackInformation)
        {
            MSRTrackData trackData = new MSRTrackData()
            {
                PANData           = string.Empty,
                Name              = string.Empty,
                ExpirationDate    = string.Empty,
                ServiceCode       = string.Empty,
                DiscretionaryData = string.Empty
            };

            // avoid encrypted track data errors
            if (trackInformation.Length >= DecryptedTrackDataMinimumLength)
            {
                // clean up track data
                string decryptedTrack = Regex.Replace(ConversionHelper.ByteArrayToAsciiString(trackInformation), @"[^\u0020-\u007E]", string.Empty, RegexOptions.Compiled);
                //Debug.WriteLine($"DECRYPTED _: {decryptedTrack}");

                // expected format: PAN^NAME^ADDITIONAL-DATA^DISCRETIONARY-DATA
                MatchCollection match = Regex.Matches(decryptedTrack, @"([0-9]{1,19})\=([0-9]+)", RegexOptions.Compiled);

                // DISCRETIONARY DATA is optional
                if (match.Count == 1)
                {
                    // ADDITIONAL DATA
                    trackData.ExpirationDate = match[0].Groups[2].Value.Substring(0, 4);
                    trackData.ServiceCode    = match[0].Groups[2].Value.Substring(4, 3);
                }
            }

            return(trackData);
        }
Exemplo n.º 2
0
        static void InternalTesting()
        {
            try
            {
                foreach (var item in trackPayload)
                {
                    MSRTrackDataDecryptor decryptor = new MSRTrackDataDecryptor();

                    // decryptor in action
                    byte[] trackInformation = decryptor.DecryptData(item.KSN, item.EncryptedData);

                    string decryptedTrack = ConversionHelper.ByteArrayToHexString(trackInformation);

                    //1234567890|1234567890|12345
                    Debug.WriteLine($"OUTPUT ____: {decryptedTrack}");
                    Console.WriteLine($"OUTPUT : [{decryptedTrack}]");

                    byte[] expectedValue = ConversionHelper.HexToByteArray(item.DecryptedData);
                    bool   result        = StructuralComparisons.StructuralEqualityComparer.Equals(expectedValue, trackInformation);
                    Console.WriteLine($"EQUAL  : [{result}]");

                    MSRTrackData trackData = decryptor.RetrieveTrackData(trackInformation);
                    Console.WriteLine($"CHOLDER: [{trackData.Name}]");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"EXCEPTION: {e.Message}");
            }
        }
        /// <summary>
        /// Track Data is provided in TLV with DFDB05 and DFDB06 TAGS
        /// </summary>
        /// <param name="trackInformation"></param>
        /// <returns></returns>
        public MSRTrackData RetrieveSREDTrackData(byte[] trackInformation)
        {
            byte[] sREDMagStripTrack1 = new byte[] { 0xDF, 0xDB, 0x05 };
            byte[] sREDMagStripTrack2 = new byte[] { 0xDF, 0xDB, 0x06 };

            MSRTrackData trackData = new MSRTrackData()
            {
                PANData           = string.Empty,
                Name              = string.Empty,
                ExpirationDate    = string.Empty,
                DiscretionaryData = string.Empty
            };

            TLV.TLV        tlv  = new TLV.TLV();
            List <TLV.TLV> tags = tlv.Decode(trackInformation, 0, trackInformation.Length, null);

            string decryptedTrack1Data = "";
            string decryptedTrack2Data = "";

            foreach (var tag in tags)
            {
                if (tag.Tag.SequenceEqual(sREDMagStripTrack1))
                {
                    decryptedTrack1Data = ConversionHelper.ByteArrayCodedHextoString(tag.Data);
                }
                else if (tag.Tag.SequenceEqual(sREDMagStripTrack2))
                {
                    decryptedTrack2Data = ConversionHelper.ByteArrayCodedHextoString(tag.Data);
                }
            }

            // clean up track data
            Debug.WriteLine($"DECRYPTED _: {decryptedTrack1Data}");

            // expected format: PAN^NAME^ADDITIONAL-DATA^DISCRETIONARY-DATA
            MatchCollection match = Regex.Matches(decryptedTrack1Data, @"%B([0-9 ]{1,19})\^([^\^]{2,26})\^([0-9]{4}|\^)([0-9]{3}|\^)([^\?]+)\?", RegexOptions.Compiled);

            // DISCRETIONARY DATA is optional
            if (match.Count == 1 && match[0].Groups.Count >= 5)
            {
                // PAN DATA
                trackData.PANData = match[0].Groups[1].Value;

                // NAME
                trackData.Name = match[0].Groups[2].Value;

                // ADDITIONAL DATA
                trackData.ExpirationDate = match[0].Groups[3].Value;
                trackData.ServiceCode    = match[0].Groups[4].Value;

                // DISCRETIONARY DATA
                if (match[0].Groups.Count > 5)
                {
                    trackData.DiscretionaryData = match[0].Groups[5].Value;
                }
            }

            return(trackData);
        }
        //[InlineData("23B281E8E126E1EA3630353137373131313131383D3235313231303130373130383036393930303030303F33DFDB053525423337393630353137373131313131385E49534F2F414D455854455354202020205E323531323130313037313038303639393F3F800000", "", "ISO/AMEXTEST    ", "071080699")]
        //[InlineData("2542343831353838313030323836313839365E444F452F4C204A4F484E2020202020202020202020205E3232313231303233353638353820202020202030303939383030303030303F", "", "DOE/L JOHN            ", "")]
        //[InlineData("7846D845D274861F32343138303030313233343536335E4644435320544553542043415244202F4D4153544552434152445E32353132313031303030313131313132333435363738393031323F438000", "", "FDCS TEST CARD /MASTERCARD", "")]
        //[InlineData("19143D2F3491E8AA3935333139323335313030343D323530323135303331323334353F3BDFDB053E254233373339203533313932332035313030345E414D45582054455354204341524420414E5349202020202020205E323030383130303831323334353F5D8000", "", "AMEX TEST CARD ANSI       ", "")]
        public void RetrieveTrackData_ShouldProcessTrackData_WhenCalled(string decryptedTrack, string panData, string cardholderName, string discretionaryData)
        {
            byte[] trackInformation = ConversionHelper.HexToByteArray(decryptedTrack);

            MSRTrackData trackData = subject.RetrieveTrackData(trackInformation);

            Assert.NotNull(trackData.PANData);
            Assert.NotNull(trackData.Name);
            Assert.NotNull(trackData.ExpirationDate);
            Assert.Equal(panData, trackData.PANData);
            Assert.Equal(cardholderName, trackData.Name);
            Assert.Equal(discretionaryData, trackData.DiscretionaryData);
        }
        /*public MSRTrackData RetrieveTrackData(byte[] trackInformation)
         * {
         *  MSRTrackData trackData = new MSRTrackData()
         *  {
         *      PANData = string.Empty,
         *      Name = string.Empty,
         *      ExpirationDate = string.Empty,
         *      DiscretionaryData = string.Empty
         *  };
         *
         *  // xF�E�t�24180001234563^FDCS TEST CARD /MASTERCARD^25121010001111123456789012?C�
         *  //string decryptedTrack = ConversionHelper.ByteArrayToUTF8String(trackInformation);
         *  //string decryptedTrack = ConversionHelper.ByteArrayToAsciiString(trackInformation);
         *
         *  // xF?E?t?24180001234563^FDCS TEST CARD /MASTERCARD^25121010001111123456789012?C?
         *  string decryptedTrack = Regex.Replace(ConversionHelper.ByteArrayToAsciiString(trackInformation), @"[^\u0020-\u007E]", string.Empty);
         *
         *  // expected format: PAN^NAME^ADDITIONAL DATA^DISCRETIONARY DATA
         *  //MatchCollection match = Regex.Matches(decryptedTrack, "(?:[^^^?]+)", RegexOptions.Compiled);
         *  MatchCollection match = Regex.Matches(decryptedTrack, "([^^^]+)", RegexOptions.Compiled);
         *
         *  if (match.Count >= 3)
         *  {
         *      // PAN DATA
         *      MatchCollection pan = Regex.Matches(match[0].Value, "(?:[^^^?]+)", RegexOptions.Compiled);
         *
         *      if (pan.Count >= 4)
         *      {
         *          trackData.PANData = Regex.Replace(pan[3].Value, @"[^\u0020-\u007E]", string.Empty);
         *      }
         *
         *      // NAME
         *      trackData.Name = match[1].Value;
         *
         *      // ADDITIONAL DATA
         *      MatchCollection track1 = Regex.Matches(match[2].Value, "(?:[^^^?]+)", RegexOptions.Compiled);
         *
         *      if (track1.Count >= 1)
         *      {
         *          trackData.ExpirationDate = track1[0].Value.Substring(0, 4);
         *          trackData.ServiceCode = track1[0].Value.Substring(4, 3);
         *
         *          if (track1.Count >= 2)
         *          {
         *              MatchCollection discretionary = Regex.Matches(track1[1].Value, "^[[:ascii:]]+");
         *              if (discretionary.Count > 0)
         *              {
         *                  trackData.DiscretionaryData = discretionary[0].Value;
         *              }
         *          }
         *      }
         *  }
         *
         *  return trackData;
         * }*/

        /// <summary>
        /// The Track 1 structure is specified as:
        ///     STX : Start sentinel "%"
        ///     FC : Format code "B" (The format described here.Format "A" is reserved for proprietary use.)
        ///     PAN : Payment card number 4400664987366029, up to 19 digits
        ///     FS : Separator "^"
        ///     NM : Name, 2 to 26 characters(including separators, where appropriate, between surname, first name etc.)
        ///     FS : Separator "^"
        ///     ED : Expiration data, 4 digits or "^"
        ///     SC : Service code, 3 digits or "^"
        ///     DD : Discretionary data, balance of characters
        ///     ETX : End sentinel "?"
        ///     LRC : Longitudinal redundancy check, calculated according to ISO/IEC 7811-2
        ///
        /// REGULAR EXPRESSION
        /// ^%B([0-9]{1,19})\^([^\^]{2,26})\^([0-9]{4}|\^)([0-9]{3}|\^)([^\?]+)\?$
        ///
        /// </summary>
        /// <param name="trackInformation"></param>
        /// <returns></returns>
        public MSRTrackData RetrieveTrackData(byte[] trackInformation)
        {
            MSRTrackData trackData = new MSRTrackData()
            {
                PANData           = string.Empty,
                Name              = string.Empty,
                ExpirationDate    = string.Empty,
                DiscretionaryData = string.Empty
            };

            // avoid encrypted track data errors
            if (trackInformation.Length >= DecryptedTrackDataMinimumLength)
            {
                // clean up track data
                string decryptedTrack = Regex.Replace(ConversionHelper.ByteArrayToAsciiString(trackInformation), @"[^\u0020-\u007E]", string.Empty, RegexOptions.Compiled);
                Debug.WriteLine($"DECRYPTED _: {decryptedTrack}");

                // expected format: PAN^NAME^ADDITIONAL-DATA^DISCRETIONARY-DATA
                MatchCollection match = Regex.Matches(decryptedTrack, @"%B([0-9 ]{1,19})\^([^\^]{2,26})\^([0-9]{4}|\^)([0-9]{3}|\^)([^\?]+)\?", RegexOptions.Compiled);

                // DISCRETIONARY DATA is optional
                if (match.Count == 1 && match[0].Groups.Count >= 5)
                {
                    // PAN DATA
                    trackData.PANData = match[0].Groups[1].Value;

                    // NAME
                    trackData.Name = match[0].Groups[2].Value;

                    // ADDITIONAL DATA
                    trackData.ExpirationDate = match[0].Groups[3].Value;
                    trackData.ServiceCode    = match[0].Groups[4].Value;

                    // DISCRETIONARY DATA
                    if (match[0].Groups.Count > 5)
                    {
                        trackData.DiscretionaryData = match[0].Groups[5].Value;
                    }
                }
            }

            return(trackData);
        }
Exemplo n.º 6
0
        static void MsrTrackDecryption(IConfiguration configuration, int index)
        {
            var trackData = configuration.GetSection("MSRTrackDataGroup:MSRTrackData")
                            .GetChildren()
                            .ToList()
                            .Select(x => new
            {
                msrTrackKsn           = x.GetValue <string>("KSN"),
                msrTrackIV            = x.GetValue <string>("IV"),
                msrEncryptedTrackData = x.GetValue <string>("EncryptedTrackData"),
                msrDecryptedTrackData = x.GetValue <string>("DecryptedTrackData")
            });

            // Is there a matching item?
            if (trackData.Count() > index)
            {
                string msrTrackKsn           = trackData.ElementAt(index).msrTrackKsn;
                string msrTrackIV            = trackData.ElementAt(index).msrTrackIV;
                string msrEncryptedTrackData = trackData.ElementAt(index).msrEncryptedTrackData;
                string msrDecryptedTrackData = trackData.ElementAt(index).msrDecryptedTrackData;

                try
                {
                    //1234567890|1234567890|12345
                    Console.WriteLine($"\r\n==== [ MSR TRACK DECRYPTION ] ====");

                    MSRTrackDataDecryptor decryptor = new MSRTrackDataDecryptor();

                    Debug.WriteLine($"KSN _______: {msrTrackKsn}");
                    Console.WriteLine($"KSN      : {msrTrackKsn}");
                    //Console.WriteLine($"DATA     : {msrEncryptedTrackData}");

                    // decryptor in action
                    byte[] trackInformation = decryptor.DecryptData(msrTrackKsn, msrEncryptedTrackData);

                    string decryptedTrack = ConversionHelper.ByteArrayToHexString(trackInformation);

                    //1234567890|1234567890|12345
                    //Console.WriteLine($"OUTPUT   : {decryptedTrack}");
                    Debug.WriteLine($"OUTPUT ____: {decryptedTrack}");

                    //MSRTrackData trackInfo = decryptor.RetrieveAdditionalData(trackInformation);
                    MSRTrackData trackInfo = decryptor.RetrieveTrackData(trackInformation);

                    string expirationDate = "";

                    if (trackInfo.ExpirationDate.Length >= 4)
                    {
                        expirationDate = trackInfo.ExpirationDate.Substring(0, 2) + "/" + trackInfo.ExpirationDate.Substring(2, 2);
                    }

                    //1234567890|1234567890|12345
                    Debug.WriteLine($"PAN DATA     : {trackInfo.PANData}");
                    Debug.WriteLine($"EXPIR (YY/MM): {expirationDate}");
                    Debug.WriteLine($"SERVICE CODE : {trackInfo.ServiceCode}");
                    Debug.WriteLine($"DISCRETIONARY: {trackInfo.DiscretionaryData}");

                    Console.WriteLine($"EXPIRATE : {trackInfo.ExpirationDate}");
                    Console.WriteLine($"SERV CODE: {trackInfo.ServiceCode}");

                    byte[] expectedValue = ConversionHelper.HexToByteArray(msrDecryptedTrackData);
                    bool   result        = StructuralComparisons.StructuralEqualityComparer.Equals(expectedValue, trackInformation);
                    Console.WriteLine($"EQUAL  : [{result}]");

                    //MSRTrackData trackData = decryptor.RetrieveTrackData(trackInformation);
                    //Console.WriteLine($"CHOLDER: [{trackData.Name}]");
                }
                catch (Exception e)
                {
                    Console.WriteLine($"EXCEPTION: {e.Message}");
                }
            }
        }