Android System Securing, Hardening, & Privacy

Building a Custom GlobalPlatform Applet for Android Secure Element (UICC/eSE) Integration

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction to Android Secure Element Integration

In the realm of mobile security, the Secure Element (SE) plays a pivotal role in protecting sensitive data and critical applications, especially within payment systems, digital identity, and secure communication. Android devices often incorporate SEs in two primary forms: the Universal Integrated Circuit Card (UICC), commonly known as the SIM card, and the embedded Secure Element (eSE), a dedicated secure chip soldered onto the device motherboard. Both provide a tamper-resistant environment for executing applications and storing cryptographic keys securely.

This article delves into the intricacies of developing and integrating a custom GlobalPlatform applet for Android’s Secure Element. We will cover the foundational concepts, environment setup, applet development, deployment, and high-level Android interaction, focusing on the critical aspects for secure transaction processing.

What is a GlobalPlatform Applet?

GlobalPlatform is a cross-industry, international standard that provides a secure, interoperable infrastructure for managing applications on secure elements. A GlobalPlatform applet is a small application written in Java Card and designed to run on a Java Card-compatible SE. These applets communicate with external devices (like an Android smartphone) using Application Protocol Data Units (APDUs), which are standardized command-response pairs.

Setting Up Your Development Environment

Developing Java Card applets requires a specific toolchain. Ensure you have the following:

  • Java Development Kit (JDK): Version 8 or newer.
  • Java Card Development Kit (JCDK): Download the latest stable version (e.g., JCDK 3.0.5u3 or 3.1.0) from Oracle. This includes the Java Card Runtime Environment (JCRE) simulator and conversion tools.
  • GlobalPlatformPro: A command-line tool for managing GlobalPlatform cards. It simplifies loading, installing, and managing applets. You can find it on GitHub.
  • Smart Card Reader: A PC/SC compliant smart card reader (e.g., ACS ACR122U) is essential for testing with physical UICC or eSE development cards.
  • Integrated Development Environment (IDE): Eclipse or IntelliJ IDEA with Java Card plugins (if available) can streamline development.

Installing GlobalPlatformPro

GlobalPlatformPro is a Java application. Download the `gp.jar` file and place it in a convenient location. Ensure it’s executable via `java -jar gp.jar`.

# Download gp.jar (replace URL with latest release)wget https://github.com/martinpaljak/GlobalPlatformPro/releases/latest/download/gp.jar# Test installationjava -jar gp.jar --version

Designing Your Java Card Applet

Our custom applet will demonstrate basic secure storage and retrieval. For payment systems, this could involve storing payment credentials, processing cryptographic operations, and managing transaction states.

Applet Structure and AID Selection

Every applet requires a unique Application Identifier (AID). This is a sequence of bytes that identifies your applet on the SE. For testing, you can use a private range, but for production, AIDs are often registered.

A typical AID consists of a Registered Application Provider Identifier (RID) and a Proprietary Application Identifier Extension (PIX).

// Example AID for our custom payment appletprivate final static byte[] APPLET_AID = {    (byte)0xA0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x62, // RID (e.g., for testing)    (byte)0x01, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x01 // PIX for our specific applet};

Java Card Applet Code Example

Let’s create a simple applet that stores a byte array and retrieves it.

package com.example.paymentapplet;import javacard.framework.*;public class CustomPaymentApplet extends Applet {    // CLA, INS for custom commands    final static byte CLA_CUSTOM_PAYMENT = (byte)0x80;    final static byte INS_STORE_DATA     = (byte)0x01;    final static byte INS_RETRIEVE_DATA  = (byte)0x02;    final static short SW_DATA_TOO_LONG  = (short)0x6700;    final static short SW_NO_DATA_STORED = (short)0x6A88;    private byte[] storedData;    private short  dataLength = 0;    private CustomPaymentApplet(byte[] bArray, short bOffset, byte bLength) {        register(bArray, (short)(bOffset + 1), bArray[bOffset]);    }    public static void install(byte[] bArray, short bOffset, byte bLength) {        new CustomPaymentApplet(bArray, bOffset, bLength);    }    public void process(APDU apdu) {        if (selectingApplet()) {            return;        }        byte[] buffer = apdu.getBuffer();        byte CLA = buffer[ISO7816.OFFSET_CLA];        byte INS = buffer[ISO7816.OFFSET_INS];        if (CLA != CLA_CUSTOM_PAYMENT) {            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);        }        switch (INS) {            case INS_STORE_DATA:                storeData(apdu);                break;            case INS_RETRIEVE_DATA:                retrieveData(apdu);                break;            default:                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);        }    }    private void storeData(APDU apdu) {        byte[] buffer = apdu.getBuffer();        short bytesRead = apdu.setIncomingAndReceive();        if (bytesRead > buffer.length - ISO7816.OFFSET_CDATA) {            ISOException.throwIt(SW_DATA_TOO_LONG); // Or manage heap allocation        }        // For simplicity, re-allocate each time. In real app, manage efficiently.        storedData = new byte[bytesRead];        Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, storedData, (short)0, bytesRead);        dataLength = bytesRead;        ISOException.throwIt(ISO7816.SW_NO_ERROR);    }    private void retrieveData(APDU apdu) {        byte[] buffer = apdu.getBuffer();        if (dataLength == 0 || storedData == null) {            ISOException.throwIt(SW_NO_DATA_STORED);        }        short le = apdu.setOutgoing();        if (le > dataLength) {            le = dataLength;        }        apdu.setOutgoingLength(le);        Util.arrayCopy(storedData, (short)0, buffer, (short)0, le);        apdu.sendBytes((short)0, le);        ISOException.throwIt(ISO7816.SW_NO_ERROR);    }}

Building and Deploying the Applet

After writing the Java Card applet, you need to compile it and convert it into a CAP (Converted Applet) file, which is the executable format for Java Card platforms. Then, you’ll use GlobalPlatformPro to load and install it onto your Secure Element.

Compilation and CAP File Generation

  1. Compile Java Code: Use the Java compiler from your JCDK.
  2. Convert to CAP: Use the `converter.bat` (Windows) or `converter.sh` (Linux/macOS) script from your JCDK.
# Assume JCDK_HOME is set to your Java Card Development Kit directory# 1. Compile Java Card codejavac -source 1.x -target 1.x -classpath %JCDK_HOME%/api.jar CustomPaymentApplet.java# 2. Create CAP file (package name: com.example.paymentapplet, applet name: CustomPaymentApplet)# AID: A0000000620101000101 (same as APPLET_AID above)java -jar %JCDK_HOME%/bin/converter.jar 	-out CustomPaymentApplet.cap 	-debug 	-verbose 	-applet A0000000620101000101 com.example.paymentapplet.CustomPaymentApplet 	-exportpath %JCDK_HOME%/api_export_files 	-nobanner 	-config %JCDK_HOME%/lib/converter.properties 	com.example.paymentapplet

Loading and Installing with GlobalPlatformPro

Connect your smart card reader with a compatible SE (UICC or eSE development card). Ensure the reader is detected by your system.

# List connected readersjava -jar gp.jar --list-readers# Load the CAP file onto the SEjava -jar gp.jar --load CustomPaymentApplet.cap# Install the applet on the SE. The AID (A0000000620101000101) is for your applet, not the package.java -jar gp.jar --install A0000000620101000101 --default --create A0000000620101000101

Android Integration with Open Mobile API (OMAPI)

Once your applet is installed on the SE, an Android application can interact with it using the Open Mobile API (OMAPI), exposed through the `android.se.omapi` package. This API allows Android apps to establish secure channels and exchange APDUs with applets on different Secure Elements.

Android Code Snippet for SE Interaction

This is a simplified example; robust error handling and background thread management are crucial for production.

import android.se.omapi.Channel;import android.se.omapi.Reader;import android.se.omapi.SecureElement;import android.se.omapi.SEService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class SeAppletConnector implements SEService.On

ServiceConnectedListener { private SEService seService; private ExecutorService executor = Executors.newSingleThreadExecutor(); // Our applet's AID private static final byte[] APPLET_AID = { (byte)0xA0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x62, (byte)0x01, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x01 }; public SeAppletConnector(Context context) { seService = new SEService(context, this); } @Override public void onSEServiceConnected() { // Service is connected, now interact with readers executor.execute(() -> { try { for (Reader reader : seService.getReaders()) { if (reader.isSecureElementPresent()) { // For UICC, reader.getName() might be

Android Mobile Specs & Compare Directory

Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner