1

Okay - I have this hex data and I have a list of tags:

the raw data may look like this:

5F201A54444320424C41434B20554E4C494D49544544205649534120204F07A00000000310105F24

Because I have a list of tags I can see there are multiple values here Tags [5f20, 4f, 5f24]

Ex: 5F201A54444320424C41434B20554E4C494D49544544205649534120204F07A00000000310105F24…ETC

So - I know that I have this tag [5f20] and its value is all the other stuff in between [5f20] and [4f]. —

I can take this other stuff:

1A54444320424C41434B20554E4C494D4954454420564953412020 and create a string from it which becomes: ("TDC BLACK UNLIMITED VISA“)

I can parse through a small section of it like using:

    let string2 = 
    "5F201A54444320424C41434B20554E4C494D49544544205649534120204F"
    var string3: String = ""
    if let startRange2 = string2.range(of: "5F20"),
    let endRange2 = string2.range(of: "4F")
    {
    let contents2 = String(string2[startRange2.upperBound..
    <endRange2.lowerBound])
    print(string3)
    string3 = contents2
    }

What Im not sure about is: How do I scale this up to work with data where I wont know what tag will be first or second or how many there are? Im seriously stumped and I don't know where to go from here.

Overall my goal is to get create readable data like this: Clean formatted Tags and value

look something like this:

5F201A54444320424C41434B20554E4C494D49544544205649534120204F07A00000000310105F24032307319F160F4243544553542031323334353637389F21031826509A031406179F02060000000000019F03060000000000009F34030203009F120C56495341204352454449544F9F0607A00000000310105F300202019F4E0F616263640000000000000000000000C408491573FFFFFF1097C00A09117101800165E0000AC2820168D9DE289AAD770BE408F6B1D4E0A2576CEA7F03CD479CE3A1827375D6C4D4959ACDB5D3B6F84CD83430F4346C35E48A77A0D5F36FBEA444C2D8701C07FFC7AF06C0485D68F7A83FC30840D3C0766EC4EE669BE5A42BAD4C7459680FAAAE9C4EFEFFEB5A590E53B3E91B3CD28A415C2C9484E26DA5A15592BBCD1F45CF49D27A9D480B031957DF8C790C55FF60DB192CCD070FA4F7BCDC99E7F7567C2F991B5536F9336BA66D68115D54BC3642A9CA47FDD162FCDC33E455AAC283975DACC98CBE9A6611E996F0740072CF8E32D3D9F39F4BB25568F5CC3E7F5DE158E4D62BF4E7185CF13BD068C4F062C26A3BBF88E056F249130E89AA29E52A1EBB6BAD98296822F10949F0C825D1449DA7EF4431AB846D0DDB916F2901359DD9A3B3395BAC9F9BE4D24657F65B030DDADA53577A14D9F5F776B6FF7EAB99D8C4BB08BEF2016C72D94B1DB91BCF0238405B7857646DCE5F79871D96B6A6652090FD8CFCC59973433919A6D0533DFE

Puneet
  • 615
  • 2
  • 7
  • 17
Pfister
  • 11
  • 1
  • 4
  • You might want to have a look [here](https://stackoverflow.com/q/11473974/5128464) and [here](https://stackoverflow.com/a/36644826/5128464)..Good luck! – vlp Mar 14 '18 at 01:26

3 Answers3

3

So you can have three arrays. One array contains all your short tag, one array contains all your long tag, and one array contains all your proprietary tags.

You can loop through your long string with the three tag arrays you created.

First check the long string with your short tag array, which is the first 2 characters, if they are not in your short tag list, then take the first 4 characters to check to see if it's a long tag, if it's not in the long tag list either then it's a proprietary tags.

For example your string,

5F201A54444320424C41434B20554E4C494D49544544205649534120204F07A00000000310105F24032307319F160F4243544553542031323334353637389F21031826509A031406179F02060000000000019F03060000000000009F34030203009F120C56495341204352454449544F9F0607A00000000310105F300202019F4E0F616263640000000000000000000000C408491573FFFFFF1097C00A09117101800165E0000AC2820168D9DE289AAD770BE408F6B1D4E0A2576CEA7F03CD479CE3A1827375D6C4D4959ACDB5D3B6F84CD83430F4346C35E48A77A0D5F36FBEA444C2D8701C07FFC7AF06C0485D68F7A83FC30840D3C0766EC4EE669BE5A42BAD4C7459680FAAAE9C4EFEFFEB5A590E53B3E91B3CD28A415C2C9484E26DA5A15592BBCD1F45CF49D27A9D480B031957DF8C790C55FF60DB192CCD070FA4F7BCDC99E7F7567C2F991B5536F9336BA66D68115D54BC3642A9CA47FDD162FCDC33E455AAC283975DACC98CBE9A6611E996F0740072CF8E32D3D9F39F4BB25568F5CC3E7F5DE158E4D62BF4E7185CF13BD068C4F062C26A3BBF88E056F249130E89AA29E52A1EBB6BAD98296822F10949F0C825D1449DA7EF4431AB846D0DDB916F2901359DD9A3B3395BAC9F9BE4D24657F65B030DDADA53577A14D9F5F776B6FF7EAB99D8C4BB08BEF2016C72D94B1DB91BCF0238405B7857646DCE5F79871D96B6A6652090FD8CFCC59973433919A6D0533DFE

you will take the first two characters 5F, use it to loop through your short tag array to see if there is a match, there is no match.

Since there is no match, you then start over to check if it's a long tag, so long tag is always 4 characters, so you take the first four characters which is 5F20.

Loop through your long tag to see if there is 5F20. Yes there is, so the two characters after 5F20 will be your length. So 1A is your length. I know 1A is more length because the standard format is always

Tag | Length | Value

Now you know what your length is, use that length to determine how many characters are in your value. 1A convert to int is 26, you always multiply your length by 2. So your value will contains 26 x 2 = 52 characters starting from the character after 1A.

so this will be your value 54444320424C41434B20554E4C494D4954454420564953412020

Convert that hex to string you get: TDC BLACK UNLIMITED VISA

Follow that structure will get your all the Tag, length and value.

jjlei
  • 109
  • 7
2

Any EMV tag follows the below standards for Tag Length and its value. It is taken from EMV Book 3. Download it from EMVCo website, specifications sections.

enter image description here

enter image description here enter image description here

Adarsh Nanu
  • 2,133
  • 1
  • 13
  • 18
0

I would encourage you to use the built-in decoder that comes with CryptoTokenKit.framework. Specifically, the TKBERTLVRecord class which uses the BER-TLV format aka EMV.

Using the built-in decoder, we can convert our TLV string to a dictionary keyed by the tags of the TLV. This makes it super easy to read-through all the data.

class EMVDecoder {
    func decode(_ inputTLV: String) -> [String: String] {
        var result: [String: String] = [:]
        if let records = TKBERTLVRecord.sequenceOfRecords(from: hexStringToData(inputTLV)) {
            for record in records {
                let hexTag = String(record.tag, radix: 16).uppercased()
                result["0x\(hexTag)"] = hexEncodedString(from: record.value)
            }
        }
        return result
    }
    
    private func hexEncodedString(from data: Data) -> String {
        return data.map { String(format: "%02X", $0) }.joined()
    }
    
    private func hexStringToData(_ hexString: String) -> Data {
        let hexString = hexString.replacingOccurrences(of: " ", with: "")
        var data = Data(capacity: hexString.count / 2)
        
        var index = hexString.startIndex
        while index < hexString.endIndex {
            let nextIndex = hexString.index(index, offsetBy: 2)
            let byteString = hexString[index..<nextIndex]
            if var byte = UInt8(byteString, radix: 16) {
                data.append(&byte, count: 1)
            }
            index = nextIndex
        }
        
        return data
    }
}

// usage

let inputString = "5F201A54444320424C41434B20554E4C494D49544544205649534120204F07A00000000310105F24032307319F160F4243544553542031323334353637389F21031826509A031406179F02060000000000019F03060000000000009F34030203009F120C56495341204352454449544F9F0607A00000000310105F300202019F4E0F616263640000000000000000000000C408491573FFFFFF1097C00A09117101800165E0000AC2820168D9DE289AAD770BE408F6B1D4E0A2576CEA7F03CD479CE3A1827375D6C4D4959ACDB5D3B6F84CD83430F4346C35E48A77A0D5F36FBEA444C2D8701C07FFC7AF06C0485D68F7A83FC30840D3C0766EC4EE669BE5A42BAD4C7459680FAAAE9C4EFEFFEB5A590E53B3E91B3CD28A415C2C9484E26DA5A15592BBCD1F45CF49D27A9D480B031957DF8C790C55FF60DB192CCD070FA4F7BCDC99E7F7567C2F991B5536F9336BA66D68115D54BC3642A9CA47FDD162FCDC33E455AAC283975DACC98CBE9A6611E996F0740072CF8E32D3D9F39F4BB25568F5CC3E7F5DE158E4D62BF4E7185CF13BD068C4F062C26A3BBF88E056F249130E89AA29E52A1EBB6BAD98296822F10949F0C825D1449DA7EF4431AB846D0DDB916F2901359DD9A3B3395BAC9F9BE4D24657F65B030DDADA53577A14D9F5F776B6FF7EAB99D8C4BB08BEF2016C72D94B1DB91BCF0238405B7857646DCE5F79871D96B6A6652090FD8CFCC59973433919A6D0533DFE"

let decodedEMV = EMVDecoder().decode(inputString)
print(decodedEMV)

/**
Outputs this dictionary:

["0xC4": "491573FFFFFF1097", "0x9F12": "56495341204352454449544F", "0x9F16": "424354455354203132333435363738", "0x9F02": "000000000001", "0x4F": "A0000000031010", "0x9F4E": "616263640000000000000000000000", "0x9F21": "182650", "0x5F30": "0201", "0x9F03": "000000000000", "0x9A": "140617", "0x9F06": "A0000000031010", "0x9F34": "020300", "0xC0": "09117101800165E0000A", "0x5F20": "54444320424C41434B20554E4C494D4954454420564953412020", "0xC2": "D9DE289AAD770BE408F6B1D4E0A2576CEA7F03CD479CE3A1827375D6C4D4959ACDB5D3B6F84CD83430F4346C35E48A77A0D5F36FBEA444C2D8701C07FFC7AF06C0485D68F7A83FC30840D3C0766EC4EE669BE5A42BAD4C7459680FAAAE9C4EFEFFEB5A590E53B3E91B3CD28A415C2C9484E26DA5A15592BBCD1F45CF49D27A9D480B031957DF8C790C55FF60DB192CCD070FA4F7BCDC99E7F7567C2F991B5536F9336BA66D68115D54BC3642A9CA47FDD162FCDC33E455AAC283975DACC98CBE9A6611E996F0740072CF8E32D3D9F39F4BB25568F5CC3E7F5DE158E4D62BF4E7185CF13BD068C4F062C26A3BBF88E056F249130E89AA29E52A1EBB6BAD98296822F10949F0C825D1449DA7EF4431AB846D0DDB916F2901359DD9A3B3395BAC9F9BE4D24657F65B030DDADA53577A14D9F5F776B6FF7EAB99D8C4BB08BEF2016C72D94B1DB91BCF0238405B7857646DCE5F79871D96B6A6652090FD8CFCC59973433919A6D0533DFE", "0x5F24": "230731"]
*/
Daniel Galasko
  • 23,617
  • 8
  • 77
  • 97