Skip to content
Muhammed Ali
Kocabey

Reading an eID chip on Android: NFC, APDU and data groups

For a long time, identity verification in banking apps was a box you bought: you integrated a library and waited for a result. I replaced that box in the onboarding flow with an Android SDK we built in-house. The goal was not just something that worked. It was an SDK whose behaviour we understood line by line, one where we knew exactly where to look when it failed. You can find a technical summary of this work in the NFC section of my work page.

This post does not describe internal source code. What it describes is public: how an eID chip is read over NFC on Android, which standards are involved, and which decisions hold up when you design a production SDK. The world of identity chips looks closed, but it is in fact a well-documented standard. The difficulty is not in the theory. It is in device reality.

What an eID chip holds

Chip-based ID cards and passports follow the ICAO Doc 9303 standard. Inside the chip is a small file system called the LDS (Logical Data Structure). A few files matter to us:

  • DG1: the MRZ data, the digital form of the machine-readable lines printed on the document (name, document number, date of birth, expiry).
  • DG2: the facial image, the source for face matching.
  • EF.SOD: the Document Security Object. It carries the hashes of every data group and the certificate that signs them. This is the heart of verification.
  • Other groups (fingerprints, public keys) come into play depending on the scenario.

The key point: reading the data and trusting it are two separate jobs. Pulling DG1 off the chip does not prove that the identity is genuine. The proof comes from a separate verification step.

The flow: from reading to verifying

There are four stages on the Android side. Each depends on the previous one; skip one and the next becomes meaningless.

1. NFC discovery and reader mode

Communication with the chip runs over ISO/IEC 14443 (contactless). Android gives you two paths: the old foreground dispatch and the modern enableReaderMode. Reader mode is the production choice because it stops the system from interfering during the scan (for example another NFC app waking up) and puts timing under your control. You open an IsoDep connection and exchange raw APDU commands with transceive.

2. Access control: BAC and PACE

The chip does not let just anyone read it. First you have to prove you are allowed to read its data. There are two mechanisms:

  • BAC (Basic Access Control): establishes a secure channel using keys derived from the MRZ (document number, date of birth, expiry). Older, but widespread.
  • PACE (Password Authenticated Connection Establishment): the choice for modern documents. It does the same job more robustly with stronger, password-based cryptography.

In practice an SDK should support both and pick the right one based on the chip's capability. Not a single data group can be read before access control is set up.

3. Reading data groups with APDU

Once the secure channel is up, communication proceeds through APDU commands: select a file (SELECT), read its contents (READ BINARY). Data groups arrive in small chunks; the SDK reassembles and parses them. Open-source libraries like jMRTD are a good reference for this parsing; they are worth reading to see how raw bytes are turned into the LDS structure.

4. Passive Authentication: trusting the data

The most critical step. The signature inside EF.SOD is verified against the country's certificate chain (CSCA and Document Signer). Then the hash of each data group you read is compared against the hash in the SOD. If both pass, the data really came from that document and was not altered during reading.

Passive Authentication proves the integrity and origin of the data. It does not prove the chip was not cloned. For that, Active Authentication (a challenge-response with the DG15 public key) or Chip Authentication steps in. Which one you implement depends on your security requirement, but none of them mean anything without Passive Authentication.

Architecture: separating reading, verification and integration

I split the eID SDK into three responsibilities and kept those boundaries strict:

  • Reading: chip communication, access control, APDU, turning data groups from bytes into a model.
  • Verification: signature and hash checks, the certificate chain, trust decisions.
  • Integration: wiring the SDK into the app flow, callbacks, progress and error reporting.

This split is not theoretical elegance, it is a maintenance decision. The reading layer wrestles with device quirks; the verification layer with cryptography. Mix them and you risk breaking signature logic while fixing an NFC timeout. Keep them apart and you can test each layer independently and let feature teams see only a clean API.

There is also a layer that is easy to overlook: diagnostics and telemetry. Identity reading fails in the field, and if you do not know why it failed you are blind. Which stage broke (discovery, access, or verification), on which device, in how long. Designing this from the start is far cheaper than adding it later.

The real difficulty: device reality

The standards are clear. What is hard is reading the same chip reliably across hundreds of different Android devices. Lessons from the field:

  • The antenna sits in a different place on every device. The user does not know where on the phone to hold the chip. A good scanning UX (where to hold it, how long to wait, do not move it) directly affects the success rate.
  • Timeouts and retries are unavoidable. The connection drops mid-read. The SDK should wait for this and recover gracefully rather than telling the user to start over.
  • The error message is a feature. "Read failed" is useless. "Chip found but verification did not pass" and "could not reach the chip at all" are entirely different problems with different fixes.

What bringing it in-house changed

The third-party solution worked, but it was a black box. Building it in-house changed three things: we could see exactly which stage broke when it failed, we could shape the flow around the product's needs, and when new device issues appeared we did not have to wait for a vendor's roadmap. Thanks to the modular structure, chip communication, verification and integration could each mature on their own.

Reading an eID looks like magic from the outside. It is not. It is the combination of a well-defined standard, an honest verification step, and respect for device reality. Most of the difficulty is not in the cryptography. It is in running that cryptography reliably in millions of hands.

WORK TOGETHER

Let’s start with a good problem.

Looking for an Android engineer for your team, or someone to think through a technical problem with? Let’s talk.

Book a 30-minute conversationAll contact and podcast links