睿诚科技协会

Java智能卡开发关键技术有哪些?

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

Java智能卡开发关键技术有哪些?-图1
(图片来源网络,侵删)

核心概念

在深入技术细节前,必须理解几个核心概念:

  1. Java Card 虚拟机:

    • 与标准的 JVM 不同,JCVM 被设计得非常精简,占用极小的内存(通常只有几 KB 的 RAM 和几 KB 的 ROM)。
    • 它是解释执行的,指令集经过优化,适合智能卡的微控制器。
    • 关键特性: 持久性,JCVM 的状态(包括对象实例、类定义等)在断电后不会丢失,这由智能卡的 EEPROM 硬件特性保证。
  2. Applet (小应用程序):

    • 这是运行在智能卡上的应用程序,一个 Java Card 文件(.cap 文件)可以包含一个或多个 Applet。
    • 每个 Applet 必须继承自 javacard.framework.Applet 类,并实现其生命周期方法。
  3. Applet Life Cycle (生命周期):

    Java智能卡开发关键技术有哪些?-图2
    (图片来源网络,侵删)
    • install(byte[] bArray, short bOffset, byte bLength): Applet 的入口点,由卡片首次安装时调用,通常在这里注册 Applet。
    • process(APDU apdu): 核心方法,卡片接收到的所有 APDU 命令都会由这个方法处理,这是你实现业务逻辑的地方。
    • select(): 当外部终端(如读卡器)选择该 Applet 时调用,通常用于初始化 Applet 的状态,使其准备好接收命令。
    • deselect(): 当外部终端选择另一个 Applet 或从卡片上移除时调用,用于清理资源。
  4. APDU (Application Protocol Data Unit):

    • 智能卡与终端之间通信的基本数据单元,它包含一个头(命令或响应)和数据体。
    • Command APDU: 终端 -> 卡片,格式为 [CLA, INS, P1, P2, Lc, Data, Le]
    • Response APDU: 卡片 -> 终端,格式为 [Data, Sw1, Sw2]Sw1Sw2 是状态字,用于表示命令执行结果(如成功 0x6900,无数据 0x6A82 等)。
  5. 防火墙:

    • 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 中,所有需要跨会话保存的对象都必须创建在 EEPROMPersistent 内存中。

    • 关键字 transient: 标记一个字段,表示它不会被持久化,它只存在于当前会话的 RAM 中,Applet deselect 或复位后会丢失。

    • 示例:

      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
分享:
扫描分享到社交APP
上一篇
下一篇