Java 智能卡开发主要围绕 Java Card 技术展开,Java Card 是一个专门为资源极度受限的设备(如智能卡、SIM卡)设计的 Java 平台子集,它允许在智能卡上运行安全的、可移植的应用程序(称为 Applet)。

核心概念
在深入技术细节前,必须理解几个核心概念:
-
Java Card 虚拟机:
- 与标准的 JVM 不同,JCVM 被设计得非常精简,占用极小的内存(通常只有几 KB 的 RAM 和几 KB 的 ROM)。
- 它是解释执行的,指令集经过优化,适合智能卡的微控制器。
- 关键特性: 持久性,JCVM 的状态(包括对象实例、类定义等)在断电后不会丢失,这由智能卡的 EEPROM 硬件特性保证。
-
Applet (小应用程序):
- 这是运行在智能卡上的应用程序,一个 Java Card 文件(
.cap文件)可以包含一个或多个 Applet。 - 每个 Applet 必须继承自
javacard.framework.Applet类,并实现其生命周期方法。
- 这是运行在智能卡上的应用程序,一个 Java Card 文件(
-
Applet Life Cycle (生命周期):
(图片来源网络,侵删)install(byte[] bArray, short bOffset, byte bLength): Applet 的入口点,由卡片首次安装时调用,通常在这里注册 Applet。process(APDU apdu): 核心方法,卡片接收到的所有 APDU 命令都会由这个方法处理,这是你实现业务逻辑的地方。select(): 当外部终端(如读卡器)选择该 Applet 时调用,通常用于初始化 Applet 的状态,使其准备好接收命令。deselect(): 当外部终端选择另一个 Applet 或从卡片上移除时调用,用于清理资源。
-
APDU (Application Protocol Data Unit):
- 智能卡与终端之间通信的基本数据单元,它包含一个头(命令或响应)和数据体。
- Command APDU: 终端 -> 卡片,格式为
[CLA, INS, P1, P2, Lc, Data, Le]。 - Response APDU: 卡片 -> 终端,格式为
[Data, Sw1, Sw2]。Sw1和Sw2是状态字,用于表示命令执行结果(如成功0x6900,无数据0x6A82等)。
-
防火墙:
- Java Card 平台的核心安全机制,它确保一个 Applet 无法访问另一个 Applet 的数据和资源,除非被明确授权。
- 每个Applet都有自己的上下文,内存和对象都是隔离的。
关键技术详解
开发环境搭建
- Java Card Development Kit (JCDK): 提供了编译、转换、打包工具链。
jc: Java Card 编译器,将.java文件编译成.class文件。converter: Java Card 转换器,将.class文件和资源文件转换成符合 GlobalPlatform 规范的.cap文件。
- 集成开发环境: Eclipse + Java Card Development Tools (JCDE) 插件是主流选择,它集成了编译、转换和调试功能。
- 模拟器: 用于在 PC 上测试 Applet,如
JCIDE自带的模拟器,或更专业的JCWDE(Java Card Workstation Development Environment)。 - 物理卡与读卡器: 最终测试阶段需要使用真实的 Java Card 和 PC/SC 读卡器。
核心编程技术
a. 内存管理与对象持久化
-
javacard.framework.ISO7816类: 定义了 APDU 状态字等常量,是开发中最常用的类。 -
javacard.framework.Util类: 提供字节数组操作工具方法,如arrayCopy(),arrayFill(),setShort(),getShort()。这是性能关键点,应优先使用这些工具方法而不是循环。 -
对象持久化: Java Card 中,所有需要跨会话保存的对象都必须创建在
EEPROM或Persistent内存中。-
关键字
transient: 标记一个字段,表示它不会被持久化,它只存在于当前会话的RAM中,Appletdeselect或复位后会丢失。 -
示例:
public class MyApplet extends Applet { // 持久化字段,存储在EEPROM中,断电不丢失 byte[] persistentData; // 非持久化字段,存储在RAM中,会话结束后丢失 transient byte sessionData; // ... 其他代码 }
-
b. 安全与加密
Java Card 提供了强大的密码学 API (javacardx.crypto)。
-
密钥: 密钥对象本身是持久化的,创建和管理密钥是安全的核心。
KeyBuilder: 用于构建不同类型的密钥对象(如AES_KEY,DES_KEY,RSA_CRT_PRIVATE_KEY)。Key: 密钥接口。
-
密码算法:
- 对称加密:
Cipher类,支持AES,DES/3DES。 - 公钥加密:
Cipher类,支持RSA。 - 哈希:
MessageDigest类,支持SHA-256。 - 随机数:
RandomData类,用于生成安全的随机数。
- 对称加密:
-
示例: 初始化一个 AES 密钥。
import javacardx.crypto.*; // ... Key aesKey; Cipher cipher; // 在install或select方法中初始化 aesKey = KeyBuilder.buildKey(Key.TYPE_AES, Key.LENGTH_AES_128, false); cipher = Cipher.getInstance(Cipher.ALGORITHM_AES_ECB_NOPAD, false);
c. Applet 交互与防火墙
- 共享接口: 一个 Applet 可以定义一个公共接口,另一个 Applet 可以通过
JCSystem.getAppletShareInterfaceObject()获取该接口的引用,从而进行有限制的通信。 - AID (Application IDentifier): 每个 Applet 都有一个唯一的 AID,由注册时指定,终端通过选择 AID 来选择特定的 Applet。
完整实例:一个简单的 PIN 验证 Applet
这个 Applet 实现了最常见的安全功能:用户需要输入正确的 PIN 码才能访问受保护的功能。
Applet 代码 (PinProtectApplet.java)
import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.*;
/**
* 一个简单的PIN验证Applet。
* 功能:
* 1. 安装时设置一个默认PIN码 (如 "123456")。
* 2. 支持验证PIN码。
* 3. 支持修改PIN码(需要先验证旧PIN)。
* 4. 支持查询剩余尝试次数。
*/
public class PinProtectApplet extends Applet {
// 定义APDU指令的INS码
final static byte VERIFY_PIN = (byte) 0x20;
final static byte CHANGE_PIN = (byte) 0x24;
final static byte GET_RETRIES = (byte) 0x30;
// PIN码相关常量
final static byte PIN_LENGTH = (byte) 6;
final static byte MAX_PIN_RETRIES = (byte) 3;
// 持久化字段
private byte[] pinCode; // 存储PIN码
private byte pinRetryCounter; // 剩余尝试次数
// 非持久化字段,用于处理APDU
private byte[] apduBuffer;
/**
* Applet的入口点,由卡片安装时调用。
* @param bArray 安装参数
* @param bOffset 参数偏移量
* @param bLength 参数长度
*/
public static void install(byte[] bArray, short bOffset, byte bLength) {
new PinProtectApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
}
/**
* 私有构造函数。
*/
private PinProtectApplet() {
// 在EEPROM中为PIN码分配空间
pinCode = JCSystem.makeTransientArray((byte) PIN_LENGTH, JCSystem.MEMORY_TYPE_PERSISTENT);
// 设置默认PIN码 "123456"
pinCode[0] = (byte) 0x12;
pinCode[1] = (byte) 0x34;
pinCode 