Raj Saija
Raj Saija

Reputation: 11

How can I fetch data from a Vigik badge (ISO/IEC 7816-5:2004) using Core NFC?

I'm working on an app that uses Core NFC to detect NFC cards, and everything is working fine with other cards such as MIFARE or ISO 14443 tags. However, I'm having trouble detecting the Vigik badge specifically. I've registered the AID for the Vigik badge correctly in my app's Entitlements.plist, but when I scan the badge, it doesn’t get detected, even though other cards are working as expected.

Here are some details about my implementation:

  1. AID Registration: I have registered the correct AID for the Vigik badge in the entitlements file, and the correct tag type is being polled using NFCTagReaderSession.
  2. Other Cards Detected: NFC cards like ISO 14443 and MIFARE are being detected and read correctly.
//
//  ViewController.swift
//  testNFCCOre
//
//  Created by mind on 12/11/24.
//

import UIKit
import CoreNFC

class ViewController: UIViewController, NFCTagReaderSessionDelegate {
    var nfcSession: NFCReaderSession?

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func onTapScan(_ sender: Any) {
        startScanning()
    }
    
    func startScanning() {
        guard NFCTagReaderSession.readingAvailable else {
            print("NFC is not supported on this device.")
            return
        }
        
        // Create a session for raw tag reading
        nfcSession = NFCTagReaderSession(pollingOption: [.iso14443,.iso18092,.iso15693], delegate: self, queue: DispatchQueue.main)
        
        // Begin the session
        nfcSession?.begin()
    }
    
    // Called when the session becomes active
    func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
        print("NFC session is active.")
        // You can inform the user that the NFC reader is active or show a message
    }
    
    // Called when the session is invalidated (e.g., user cancels or an error occurs)
    func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
        if let error = error as? NFCReaderError {
            switch error.code {
            case .readerSessionInvalidationErrorUserCanceled:
                print("User canceled the session.")
            case .readerSessionInvalidationErrorSessionTimeout:
                print("Session timed out.")
            case .readerSessionInvalidationErrorSystemIsBusy:
                print("System is busy. Please try again.")
            default:
                print("Session invalidated with error: \(error.localizedDescription)")
            }
        } else {
            print("Session invalidated with error: \(error.localizedDescription)")
        }
    }
    
    // Called when the session detects NFC tags
    func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
        let tag = tags.first!
        session.connect(to: tag) { error in
            if let error = error {
                print("Connection failed: \(error.localizedDescription)")
                return
            }
            print("Tag connected successfully!")
            
            // Continue processing the tag depending on its type
            for tag in tags {
                switch tag {
                case .miFare(let mifareTag):
                    print("MIFARE tag detected: \(mifareTag)")
                    self.handleMifareTag(mifareTag)
                    
                case .feliCa(let feliCaTag):
                    print("FeliCa tag detected: \(feliCaTag)")
                    self.handleFeliCaTag(feliCaTag)
                    
                case .iso7816(let iso7816Tag):
                    print("ISO 7816 tag detected: \(iso7816Tag)")
                    
                    let aidData = Data([
                        0xA0, 0x00, 0x00, 0x00, 0x86, 0x32, 0x05, 0x49,
                        0x47, 0x49, 0x4B, 0xAE, 0x5F, 0x33
                    ])

                    // Create APDU SELECT command
                    let command = NFCISO7816APDU(
                        instructionClass: 0x00,
                        instructionCode: 0xA4,
                        p1Parameter: 0x04,
                        p2Parameter: 0x00,
                        data: aidData,
                        expectedResponseLength: -1
                    )

                    // Send the APDU command
                    iso7816Tag.sendCommand(apdu: command) { response, sw1, sw2, error in
                        if let error = error {
                            print("Error sending APDU: \(error.localizedDescription)")
                            return
                        }
                        
                        // Parse the response
                        print("Response: \(response)")
                        print("Status words: SW1=\(sw1), SW2=\(sw2)")
                        
                        // Process specific application template if needed
                        if sw1 == 0x90 && sw2 == 0x00 {
                            print("Application selected successfully!")
                        } else {
                            print("Application selection failed with status words \(sw1), \(sw2)")
                        }
                    }


                    self.handleIso7816Tag(iso7816Tag)
                    
                    
                case .iso15693(let nfcATag):
                    print("ISO 15693 tag detected: \(nfcATag)")
                    self.handleNfcATag(nfcATag)
                    
                default:
                    print("Unknown tag type detected.")
                }
            }
            session.invalidate()
        }
    }
    
    // Handle MIFARE tag
    func handleMifareTag(_ mifareTag: NFCMiFareTag) {
        // Process MIFARE tag data
        print("MIFARE UID: \(mifareTag.identifier)")
    }
    
    // Handle FeliCa tag
    func handleFeliCaTag(_ feliCaTag: NFCFeliCaTag) {
        // Print available information from NFCFeliCaTag
        print("FeliCa tag detected.")
    }
    
    // Handle ISO 7816 tag (smart cards)
    func handleIso7816Tag(_ iso7816Tag: NFCISO7816Tag) {
        // Process ISO 7816 tag data
        print("Tag Identifier: \(iso7816Tag.identifier.hexString())")
        let hexString = "4a6f686e"  // Hex for "John"
        if let decodedText = hexStringToText(hexString: iso7816Tag.identifier.hexString()) {
            print("Decoded text: \(decodedText)")  // Outputs: John
        }
        print("Application Data: \(String(describing: iso7816Tag.applicationData))")
        print("Historical Bytes: \(String(describing: iso7816Tag.historicalBytes))")
        if let historicalBytes = iso7816Tag.historicalBytes {
            let hexString = historicalBytes.map { String(format: "%02hhx", $0) }.joined()
            print("Historical Bytes as Hex: \(hexString)")
        }
        print("Selected AID: \(iso7816Tag.initialSelectedAID)")
    }
    
    // Handle NFC-A tag
    func handleNfcATag(_ nfcATag: NFCISO15693Tag) {
        // Process NFC-A tag data
        print("NFC-A UID: \(nfcATag.identifier)")
    }
    
    // Convert Hex String to Text
    func hexStringToText(hexString: String) -> String? {
        var hex = hexString
        var data = Data()
        while hex.count > 0 {
            let c = hex.prefix(2)
            hex = String(hex.dropFirst(2))
            if let byte = UInt8(c, radix: 16) {
                data.append(byte)
            }
        }
        return String(data: data, encoding: .utf8)
    }
}

// Convert Data to Hex String
extension Data {
    func hexString() -> String {
        return self.map { String(format: "%02hhx", $0) }.joined()
    }
    
    func hexStringToData(hexString: String) -> Data? {
        var data = Data()
        // Ensure the hex string is in valid form (even length)
        let cleanedHexString = hexString.replacingOccurrences(of: " ", with: "").uppercased()
        // Process every pair of characters (each byte)
        var startIndex = cleanedHexString.startIndex
        while startIndex < cleanedHexString.endIndex {
            let endIndex = cleanedHexString.index(startIndex, offsetBy: 2)
            let hexPair = String(cleanedHexString[startIndex..<endIndex])

            if let byte = UInt8(hexPair, radix: 16) {
                data.append(byte)
            } else {
                print("Invalid hex pair: \(hexPair)")
                return nil
            }
            startIndex = endIndex
        }
        return data
    }
}

Upvotes: 1

Views: 78

Answers (0)

Related Questions