Kalan's Blog

Software Engineer / Taiwanese / Life in Fukuoka

Current Theme light

Preface

iOS 11.0 can read and write NFC Tags through CoreNFC, but it cannot read information from IC cards. IC cards can only be read by iOS devices after iOS 13.

I have been interested in NFC for a long time, and I also want to read the information from Suica (Japanese transportation IC card) on my own so that I can directly check the balance with my mobile phone (I know there are already several apps doing this, but I want to do it for study purposes).

There are relatively few Chinese and English resources on the Internet about Suica, so I spent a few days researching the FeliCa documentation and implemented it with CoreNFC.

This article will start with the NFC protocol, then discuss FeliCa, which is widely used in Japanese transportation IC cards, and finally, the implementation in Swift.

While I have just started learning Swift, there may be some places that are not well-written. Feel free to reach out to me on Twitter.

What is NFC?

NFC (Near Field Communication) is a communication protocol, also known as RFID wireless communication technology.

This protocol mainly defines:

  • Communication agreement: how to communicate between the sender and receiver
  • Data exchange: how to exchange data between the sender and receiver

While it is possible to write data into a card (if you have the key), this article will only focus on how to read the data in FeliCa.

The Problems Solved by NFC

In wireless communication, we can use Bluetooth, WiFi, etc. to communicate, but the biggest problems are related to security and pairing.

Bluetooth requires devices to be paired before communicating with each other. Pairing might take time and the communication process is more complicated.

If a reader can detect card information from 20 meters and directly request payment, there will be significant problems.

Therefore, in NFC, the detection distance is usually within a few centimeters. This not only ensures security but also reduces noise interference.

FeliCa

FeliCa is an IC card technology developed by Sony in 2001. Compared to NFC Type-A and Type-B, it is faster. The reason for its speed might be the terrible commute traffic in Japan.

Youyou card in Taiwan is an IC card made by Mifare, designed by Philips. At the same time, Mifare is also a non-contact IC card widely used around the world.

Currently, only FeliCa is widely used in Japan.

FeliCa is really fast. If you use public transportation in Japan, you should notice that you don't have to stop when entering the platform.

It is currently widely used in transportation IC cards such as Suica, ICOCA, はやかけん, etc. All of these cards use FeliCa technology.

Not only in transportation, but you can also use your transportation IC card to make payments at convenience stores.

Data Security

In NFC, some data can be read, some cannot, and some cards need to be decrypted with the correct key to read and write data.

Although Android and iOS can now read NFC cards, if you want to modify the balance and other data, you must have the correct key.

FeliCa Architecture

In FeliCa's architecture, it can be divided into two major parts: private domain (プライベート) and common domain.

The common domain stores some information that can be read, while the private domain stores some information such as personal data or control balances, which must be encrypted and decrypted to operate.

In the common field, it can be divided into several parts:

  • System: indicates the unit of the card. Each card will have a system code (2 bytes). According to the law of JIS 6319-4, this value will be between FE00 ~ AA00. Cards like Suica have a system code of 0003 (this value is important, we'll use it later).
  • Area: Contains information such as storage space, the number of blocks stored by each service, and so on.
  • Service: Stores data in blocks for external access. Each service will have a service code (2 bytes), such as the service code of the entry record 090f. Services can be divided into random service, cyclic service, and pass service.
  • Block: Where data is stored, each block is 16 bytes, and the number of blocks required will vary depending on the service.

If you only want to read the information inside the card, you will encounter two parts: service and block.

Service Type

As mentioned earlier, services are divided into random, cyclic, and pass, mainly distinguished by data access.

  • Random Service: data that can be freely read and written, determined by the manufacturer.
  • Cyclic Service: A place where you can store records like historical data.
  • Pass Service: A place to manage things like balances and deductions.

Command

There are many types of instructions in [FeliCa](http://www.proxmark.org/files/Documents/13.56 MHz - Felica/card_usersmanual_2.0.pdf), which can be found in the [FeliCa document](http://www.proxmark.org/files/Documents/13.56 MHz - Felica/card_usersmanual_2.0.pdf). To read FeliCa data, you need several commands:

  • Polling
  • Request Service
  • Read without encryption

Each command has a corresponding request packet, which specifies what should be in the request. This part already provides corresponding functions in CoreNFC, so we don't have to worry about that.

Communication Process in FeliCa

  1. Capture cards with the polling command.
  2. Use the Request Service command and pass in the service code list. The card will confirm whether the service code is correct or readable. If the service does not exist or there is an error, it will return 0xFFFF.
  3. Use the Read without encryption command and pass in the service code to return the corresponding data in blocks (up to 16 services).
    1. This command will return status1 and status2. If both are 0, it means there is no problem.
    2. If they are not 0, it means there is an error. You can find the error code status in the FeliCa documentation.

iOS Implementation

You can refer to the examples on the Apple Developer website to find out how to read NFC Tags. Here, we are focusing on how to read FeliCaTag.

To implement NFC, you must first have a physical iPhone. There is no way to read NFC in the simulator.

You can use NFCTagReaderSession.isReadingAvailable to determine if NFC data is readable on your device.

5]) >> 5 & 0b1111 // get month bit let date = data[5] & 0b11111 // get date bit

let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" formatter.locale = Locale(identifier: "en_US_POSIX") return formatter.date(from: "20(year)-(month)-(date)")!


## Demo

You can see the source code on [GitHub](https://github.com/kjj6198/nfc-reader).

## Thought

Although the information was successfully read, some numbers are different from what I expected.

For example, the station code has not been found even after searching for a long time on the Internet. I don't even know if I parsed the station code correctly.

Although it is said that the history record can get 20 blocks, some cards will fail to read because of this. The safer range is 10 (still testing).

Looking at the records inside (my card is a regular ticket), it seems that not every entry and exit will be recorded. If you want to use cards to collect your own inbound and outbound information, I'm afraid it is not so easy to use (such as visualization).

Regarding FeliCa reading, on iOS, Japanese developers have written a library called [TRETJapanNFCReader](https://github.com/treastrain/TRETJapanNFCReader) which is quite easy to use. If you want to use it directly, you can refer to it. In addition to SUICA, it also supports quite a few types of IC cards. Even the driver's license can be read.

When I saw the CoreNFC SDK, I wanted to try reading FeliCa information, but there are not many Chinese resources on the Internet.

There are quite a lot of Japanese implementations, but I can only see the service code, blockList, etc. without knowing their meaning. So it took a day to read the FeliCa documentation and try to implement it myself.

Also, quite troublesome on the Swift conversion of another type, such as the Data converted into UInt, etc. I found this code on the Internet, but I don't really understand what it is doing XD. I only know the way of conversion using `UInt(bytes: Data)`.

```swift
import Foundation

extension FixedWidthInteger {
    init(bytes: UInt8...) {
        self.init(bytes: bytes)
    }

    init<T: DataProtocol>(bytes: T) {
        let count = bytes.count - 1
        self = bytes.enumerated().reduce(into: 0) { (result, item) in
            result += Self(item.element) << (8 * (count - item.offset))
        }
    }
}

It was a long journey to read all of this, isn't it? I hope you can understand how NFC works, what FeliCa is, and more importantly, how to use it in combination with CoreNFC in Swift!

Prev

Reading experience: Lateral Leadership

Next

2019 Review

If you found this article helpful, please consider buy me a drink ☕️ It'll make my ordinary day shine✨

Buy me a coffee

作者

Kalan 頭像照片,在淡水拍攝,淺藍背景

愷開 | Kalan

Hi, I'm Kai. I'm Taiwanese and moved to Japan in 2019 for work. Currently settled in Fukuoka. In addition to being familiar with frontend development, I also have experience in IoT, app development, backend, and electronics. Recently, I started playing electric guitar! Feel free to contact me via email for consultations or collaborations or music! I hope to connect with more people through this blog.