SIM Card Programming

Understanding how to develop applications and manage data on SIM cards

SIM Card Programming Environments

Modern SIM cards support several programming environments and technologies that enable the development of secure applications:

JavaCard

JavaCard is the most widely used programming environment for SIM cards. It's a subset of Java designed specifically for smart cards and other devices with limited memory and processing capabilities.

Key features of JavaCard include:

  • Object-oriented programming model
  • Applet-based architecture
  • Strong security features
  • Interoperability across different card platforms
  • Support for post-issuance application loading

JavaCard applications are called "applets" and follow a specific lifecycle model defined by the JavaCard Runtime Environment (JCRE).

JavaCard Versions

  • JavaCard 2.1: Basic functionality
  • JavaCard 2.2: Added logical channels, enhanced crypto
  • JavaCard 3.0: Added web applications, extended memory
  • JavaCard 3.1: Enhanced security, biometric support

JavaCard Architecture

  • JavaCard Virtual Machine (JCVM)
  • JavaCard Runtime Environment (JCRE)
  • JavaCard API
  • Applet Framework

JavaCard Programming

JavaCard is the most widely used programming environment for SIM cards. Let's explore the basics of JavaCard development:

JavaCard Applet Structure

A typical JavaCard applet has the following structure:

java
1package com.example.simapplet;
2
3import javacard.framework.*;
4
5public class ExampleApplet extends Applet {
6 // Constants
7 private static final byte CLA_EXAMPLE = (byte) 0x80;
8 private static final byte INS_GET_DATA = (byte) 0x01;
9 private static final byte INS_SET_DATA = (byte) 0x02;
10
11 // Data
12 private byte[] data;
13
14 // Constructor
15 private ExampleApplet() {
16 data = new byte[10];
17 register();
18 }
19
20 // Installation method
21 public static void install(byte[] bArray, short bOffset, byte bLength) {
22 new ExampleApplet();
23 }
24
25 // Process method - handles incoming APDUs
26 public void process(APDU apdu) throws ISOException {
27 // Get the APDU buffer
28 byte[] buffer = apdu.getBuffer();
29
30 // Check for SELECT command
31 if (selectingApplet()) {
32 return;
33 }
34
35 // Check the CLA byte
36 if (buffer[ISO7816.OFFSET_CLA] != CLA_EXAMPLE) {
37 ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
38 }
39
40 // Process the instruction
41 switch (buffer[ISO7816.OFFSET_INS]) {
42 case INS_GET_DATA:
43 getData(apdu);
44 break;
45 case INS_SET_DATA:
46 setData(apdu);
47 break;
48 default:
49 ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
50 }
51 }
52
53 // Method to get data
54 private void getData(APDU apdu) {
55 byte[] buffer = apdu.getBuffer();
56 short length = (short) data.length;
57
58 // Send the data
59 Util.arrayCopy(data, (short) 0, buffer, (short) 0, length);
60 apdu.setOutgoingAndSend((short) 0, length);
61 }
62
63 // Method to set data
64 private void setData(APDU apdu) {
65 byte[] buffer = apdu.getBuffer();
66
67 // Receive data
68 short dataLength = apdu.setIncomingAndReceive();
69
70 // Copy the received data
71 Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, data, (short) 0, dataLength);
72 }
73}

JavaCard Lifecycle

JavaCard applets follow a specific lifecycle:

  1. Loading: The applet's CAP file is loaded onto the card
  2. Installation: The install() method is called
  3. Registration: The applet calls register() to register with the JCRE
  4. Selection: The applet is selected by an APDU command
  5. Processing: The applet processes APDU commands via process()
  6. Deselection: Another applet is selected
  7. Uninstallation: The applet is removed from the card

JavaCard API

JavaCard provides a limited subset of Java APIs, plus specialized packages:

  • javacard.framework: Core functionality
  • javacard.security: Cryptographic services
  • javacardx.crypto: Extended cryptography
  • javacard.biometry: Biometric services (3.1+)
  • javacard.framework.service: Service framework

JavaCard supports only a subset of Java language features and data types, with limitations on inheritance, objects, and dynamic memory allocation.

SIM Toolkit Programming

The SIM Application Toolkit (STK) allows SIM cards to initiate commands and interact with the mobile device [^7]. Programming STK applications involves:

Proactive Commands

STK applications use proactive commands to interact with the mobile device [^7]. These include:

  • DISPLAY TEXT: Show text on the device screen
  • GET INPUT: Request text input from the user
  • SELECT ITEM: Display a menu for user selection
  • SEND SMS: Send an SMS message
  • SET UP CALL: Initiate a voice call
  • LAUNCH BROWSER: Open a web browser

Event Handling

STK applications can register for various events from the mobile device [^7]:

  • Menu Selection: User selects an STK menu item
  • Call Control: Outgoing call is initiated
  • SMS Control: Outgoing SMS is sent
  • Timer Expiration: A timer set by the SIM expires
  • Location Status: Device's network location changes
  • Browser Termination: Browser session ends

STK Menu Example

Here's an example of a JavaCard applet that implements a simple STK menu:

java
1package com.example.stk;
2
3import javacard.framework.*;
4import sim.toolkit.*;
5
6public class MenuApplet extends Applet implements ToolkitInterface, ToolkitConstants {
7 // Menu items
8 private static final byte ITEM_BALANCE = (byte) 1;
9 private static final byte ITEM_TRANSFER = (byte) 2;
10 private static final byte ITEM_SETTINGS = (byte) 3;
11
12 // Menu text
13 private static final String MENU_TITLE = "Banking Menu";
14 private static final String[] MENU_ITEMS = {
15 "Check Balance",
16 "Transfer Money",
17 "Settings"
18 };
19
20 // ToolkitRegistry reference
21 private ToolkitRegistry reg;
22
23 private MenuApplet() {
24 // Register with the applet
25 register();
26
27 // Get the toolkit registry
28 reg = ToolkitRegistry.getEntry();
29
30 // Register for the MENU event
31 reg.setEvent(EVENT_MENU_SELECTION);
32
33 // Initialize the menu
34 initializeMenu();
35 }
36
37 public static void install(byte[] bArray, short bOffset, byte bLength) {
38 new MenuApplet();
39 }
40
41 private void initializeMenu() {
42 // Create the main menu
43 Menu menu = new Menu(MENU_TITLE, (short) 0, (short) MENU_TITLE.length(), (byte) 0);
44
45 // Add menu items
46 for (byte i = 0; i < MENU_ITEMS.length; i++) {
47 menu.appendItem(MENU_ITEMS[i], (short) 0, (short) MENU_ITEMS[i].length(), (byte) (i + 1), false);
48 }
49
50 // Register the menu
51 reg.registerMenu(menu);
52 }
53
54 public void process(APDU apdu) throws ISOException {
55 // Process regular APDUs if needed
56 if (selectingApplet()) {
57 return;
58 }
59
60 // Other APDU processing...
61 }
62
63 public void processToolkit(byte event) throws ToolkitException {
64 // Handle menu selection event
65 if (event == EVENT_MENU_SELECTION) {
66 // Get the selected item
67 byte selectedItem = reg.getMenuItemIdentifier();
68
69 // Handle the selection
70 switch (selectedItem) {
71 case ITEM_BALANCE:
72 showBalance();
73 break;
74 case ITEM_TRANSFER:
75 showTransferMenu();
76 break;
77 case ITEM_SETTINGS:
78 showSettings();
79 break;
80 }
81 }
82 }
83
84 private void showBalance() {
85 // Create a display text proactive command
86 ProactiveHandler handler = ProactiveHandler.getTheHandler();
87 handler.init(PRO_CMD_DISPLAY_TEXT, (byte) 0x81, DEV_ID_DISPLAY);
88 handler.appendTLV(TAG_TEXT_STRING, (byte) 0x04, "Your balance: $1,250.75");
89 handler.send();
90 }
91
92 private void showTransferMenu() {
93 // Implementation for transfer menu
94 // ...
95 }
96
97 private void showSettings() {
98 // Implementation for settings
99 // ...
100 }
101}

APDU Communication

Application Protocol Data Units (APDUs) are the communication format used between a SIM card and a terminal (mobile device or card reader) [^5]. Understanding APDU structure is essential for SIM card programming:

Command APDU Structure

FieldSizeDescription
CLA1 byteClass byte - Indicates the command type
INS1 byteInstruction byte - Specifies the particular command
P1, P22 bytesParameter bytes - Additional parameters for the command
Lc0-3 bytesOptional - Length of data to be sent
DataVariableOptional - Data to be sent to the card
Le0-3 bytesOptional - Expected length of response data

Response APDU Structure

FieldSizeDescription
DataVariableOptional - Response data from the card
SW1, SW22 bytesStatus Words - Indicate the result of the command

Common Status Words

  • 90 00: Success
  • 61 XX: Success, XX bytes available
  • 6A 82: File not found
  • 6A 86: Incorrect P1/P2 parameters
  • 6D 00: Instruction not supported
  • 6E 00: Class not supported
  • 67 00: Wrong length
  • 69 82: Security status not satisfied
  • 69 85: Conditions of use not satisfied

APDU Examples

SELECT Command

plaintext
1// Select the MF (Master File)
200 A4 00 00 02 3F 00
3
4// Command breakdown:
5// CLA: 00 - ISO/IEC 7816-4 compliant command
6// INS: A4 - SELECT command
7// P1: 00 - Select by file ID
8// P2: 00 - First or only occurrence
9// Lc: 02 - 2 bytes of data follow
10// Data: 3F 00 - File ID of the MF
11// Le: (absent) - No response data expected

READ BINARY Command

plaintext
1// Read 10 bytes from transparent EF at offset 0
200 B0 00 00 0A
3
4// Command breakdown:
5// CLA: 00 - ISO/IEC 7816-4 compliant command
6// INS: B0 - READ BINARY command
7// P1: 00 - High byte of offset (0)
8// P2: 00 - Low byte of offset (0)
9// Le: 0A - Request 10 bytes of data

UPDATE BINARY Command

plaintext
1// Write 5 bytes to transparent EF at offset 0
200 D6 00 00 05 01 02 03 04 05
3
4// Command breakdown:
5// CLA: 00 - ISO/IEC 7816-4 compliant command
6// INS: D6 - UPDATE BINARY command
7// P1: 00 - High byte of offset (0)
8// P2: 00 - Low byte of offset (0)
9// Lc: 05 - 5 bytes of data follow
10// Data: 01 02 03 04 05 - Data to write

Over-The-Air (OTA) Programming

Over-The-Air (OTA) programming allows remote management of SIM cards after they have been deployed in the field. This is a critical capability for mobile operators and service providers:

OTA Architecture

OTA updates use a client-server architecture:

  • OTA Server: Managed by the operator or service provider
  • SMS Gateway: Converts server commands to SMS format
  • Mobile Network: Delivers the SMS to the device
  • SIM Card: Processes the OTA commands

The communication typically uses encrypted SMS messages with a special format defined in the GSM 03.48 (later 3GPP TS 23.048) specification.

OTA Operations

Common OTA operations include:

  • Remote File Management: Read/write files on the SIM
  • Applet Installation: Deploy new applications
  • Applet Deletion: Remove applications
  • Applet Personalization: Configure applications
  • Key Management: Update cryptographic keys
  • Profile Management: For eSIM, manage operator profiles

OTA Security

OTA operations involve sensitive operations on the SIM card, so security is paramount:

  • Encryption: OTA messages are encrypted to prevent eavesdropping
  • Authentication: Messages are signed to verify the sender's identity
  • Integrity Protection: Ensures messages aren't tampered with in transit
  • Replay Protection: Prevents reuse of previously captured messages
  • Access Control: Only authorized entities can perform OTA operations

OTA Message Structure

OTA messages follow the structure defined in 3GPP TS 23.048:

plaintext
1// OTA Message Structure
2+------------------+
3| SMS Header | Standard SMS header
4+------------------+
5| Command Packet | Contains the actual OTA command
6| |
7| +---------------+|
8| | Security Header|| Contains security parameters
9| +---------------+|
10| | Command Header || Identifies the command type
11| +---------------+|
12| | Command Data || The actual command data
13| +---------------+|
14+------------------+
15
16// Example of a Remote File Management command
17// (Simplified representation)
18D0 // Command Packet Tag
1981 // Length
2002 // Command Header: Remote File Management
21A4 00 00 02 3F 00 // SELECT command for MF
22B0 00 00 0A // READ BINARY command for 10 bytes

SIM Card Development Tools

Several tools are available for SIM card development and testing:

Development Environments

  • Eclipse with JCIDE: Popular IDE for JavaCard development
  • NetBeans with JavaCard plugin: Alternative IDE
  • Ant-JavaCard: Build tool for JavaCard projects
  • Maven JavaCard Plugin: Maven integration for JavaCard
  • GlobalPlatform Pro: Command-line tool for card management

Simulators and Emulators

  • jCardSim: JavaCard simulator in pure Java
  • Oracle JavaCard Simulator: Official simulator
  • JCOP Tools: Simulator for NXP JCOP cards
  • Gemalto Developer Suite: Comprehensive development environment
  • pySim: Python tools for SIM card programming

Card Readers and Interfaces

  • PC/SC Readers: Standard smart card readers
  • PCSC-Lite: Linux implementation of PC/SC
  • APDU Scanner: Analyze and debug APDU communication
  • SIMTrace: Hardware for SIM card protocol analysis
  • Osmocom SIMtrace: Open-source SIM tracing tools

SIM Programming Best Practices

Developing for SIM cards requires special considerations due to their constrained environment and security requirements:

Memory Management

  • Minimize Object Creation: Create objects during installation, not during normal operation
  • Reuse Arrays: Reuse existing arrays instead of creating new ones
  • Avoid Recursion: Recursion can quickly exhaust the limited stack space
  • Use Transient Objects: For temporary data that doesn't need to persist
  • Be Aware of EEPROM Write Limitations: EEPROM has limited write cycles

Security Considerations

  • Validate All Input: Never trust data received from outside the card
  • Implement Secure Messaging: Encrypt sensitive communication
  • Use Secure Random Numbers: For cryptographic operations
  • Clear Sensitive Data: Zero out buffers containing sensitive information after use
  • Implement Access Control: Restrict access to sensitive functions
  • Protect Against Side-Channel Attacks: Consider timing attacks, power analysis, etc.

Performance Optimization

  • Minimize EEPROM Writes: Group writes to reduce wear and improve performance
  • Use RAM for Temporary Data: RAM operations are much faster than EEPROM
  • Optimize Loops: Unroll small loops, minimize loop overhead
  • Use Native Methods: For performance-critical operations
  • Batch Operations: Process multiple items in a single command when possible

Testing and Debugging

  • Test on Simulators First: Easier to debug than physical cards
  • Implement Logging: Use available debug features or create your own logging mechanism
  • Test Edge Cases: Buffer boundaries, maximum data sizes, etc.
  • Test Security Features: Verify that security mechanisms work as expected
  • Test with Different Card Readers: Ensure compatibility
Online