开发Javacard Applet时如何访问智能卡读卡器的集成Pinpad
Javacard读卡器集成Pinpad调用方案
实现原理
ReinerSCT cyberJack RFID standard读卡器原生支持PC/SC 2.0 Part 10的Pinpad硬件扩展规范,你不需要修改现有卡端的PIN校验逻辑,只需要在主机侧通过PC/SC Escape指令唤起读卡器内置的PIN采集流程,读卡器会自动将采集到的PIN填充到你指定的APDU数据域并发送给卡片,全程主机侧不会接触PIN明文。
具体实现步骤
基于javax.smartcardio原生实现
- 首先调用
TerminalFactory获取目标读卡器实例,连接卡片后获取CardChannel对象 - 构造ReinerSCT专用的Pinpad唤起指令,指令中需要指定PIN长度范围、显示模式、以及你卡端已实现的PIN校验APDU头(
0x80 0x04 0x00 0x00) - 调用
channel.transmit()发送指令,读卡器会自动弹出PIN输入提示,用户输入完成后自动拼接完整APDU发送给卡片,返回卡片的响应结果 - 直接判断响应状态码即可获取PIN校验结果
示例代码:
import javax.smartcardio.*; public class PinpadTest { public static void main(String[] args) throws Exception { // 获取读卡器 TerminalFactory factory = TerminalFactory.getDefault(); CardTerminal terminal = factory.terminals().list() .stream() .filter(t -> t.getName().contains("cyberJack")) .findFirst() .orElseThrow(() -> new RuntimeException("未找到读卡器")); // 连接卡片 Card card = terminal.connect("*"); CardChannel channel = card.getBasicChannel(); // 构造Pinpad唤起指令 byte[] pinpadCommand = new byte[]{ 0x62, 0x00, 0x00, 0x00, // ReinerSCT读卡器固定Escape指令头 0x04, // 最小PIN长度,根据你的业务调整 0x08, // 最大PIN长度,根据你的业务调整 0x02, // 输入显示模式:0x02=输入时显示*掩码,0x00=完全不显示输入内容 0x80, 0x04, 0x00, 0x00 // 卡端PIN校验APDU的CLA/INS/P1/P2 }; // 发送指令,读卡器自动完成PIN采集、APDU拼接、发送、返回结果 ResponseAPDU response = channel.transmit(new CommandAPDU(pinpadCommand)); // 处理响应 if (response.getSW() == 0x9000) { System.out.println("PIN校验成功"); } else if ((response.getSW() & 0xFFF0) == 0x63C0) { int retryCount = response.getSW() & 0x0F; System.out.println("PIN校验失败,剩余重试次数:" + retryCount); } else { System.out.printf("操作失败,状态码:0x%04X%n", response.getSW()); } card.disconnect(false); } }
基于apdu4j实现
apdu4j已经封装了主流读卡器的Pinpad适配逻辑,不需要自己拼厂商专用指令,代码更简洁:
import com.github.apdu4j.*; import com.github.apdu4j.pinpad.*; // 初始化读卡器 CardTerminal terminal = TerminalFactory.getDefault().terminals().list().get(0); PinPadTerminal pinPadTerminal = new PinPadTerminal(terminal); // 配置PIN校验参数 PinpadSettings settings = PinpadSettings.builder() .minPinLength(4) .maxPinLength(8) .promptText("请输入PIN码") .verifyCommand(new CommandAPDU(0x80, 0x04, 0x00, 0x00)) .build(); // 自动唤起Pinpad并执行校验 ResponseAPDU response = pinPadTerminal.verifyPin(settings); // 后续处理逻辑和原生实现一致
注意事项
- 上面给出的
0x62开头的Escape指令头仅适用于ReinerSCT系列读卡器,其他品牌读卡器需要使用对应厂商的指令头 - 读卡器Pinpad功能同时支持接触式(ISO7816)和非接触式(ISO14443)卡片,不需要额外配置
- 你可以根据业务需求调整PIN长度、输入超时时间、提示文本等参数,具体可参考ReinerSCT官方的开发者手册
内容的提问来源于stack exchange,提问作者Johann Zapf
相关产品推荐
相关产品推荐

