JavaCard小程序签名挑战返回错误28416,求问题排查方案
问题排查:JavaCard签名返回0x6F00(28416)错误
首先,你看到的错误码28416转成十六进制是0x6F00,这是JavaCard的通用未处理异常,说明你的小程序在执行sign方法时抛出了未被捕获的错误,我们来一步步拆解问题:
1. 卡端代码最明显的问题:未定义的offset变量
你的卡端代码里直接使用了offset参数,但这个变量从来没有被初始化过:
short sigLength = signature.sign(buffer, offset, length, output, x);
在JavaCard中,未初始化的局部变量会直接导致运行时异常,触发0x6F00错误。你需要从APDU缓冲区中获取输入数据的起始偏移量——对于常规APDU命令,输入数据的起始位置是ISO7816.OFFSET_CDATA(也就是偏移量5),同时你还需要获取实际接收的数据长度,而不是硬写20。
2. 签名输出缓冲区长度严重不足
你定义的output数组只有20字节:
byte [] output = new byte [20];
但Signature.ALG_RSA_SHA_PKCS1的签名长度是和你的RSA私钥长度对应的——比如2048位RSA的签名长度是256字节,1024位是128字节,20字节远远不够,这会导致signature.sign()方法抛出ArrayIndexOutOfBoundsException,同样触发0x6F00。
3. 未正确处理APDU输入数据的接收
你的代码直接调用apdu.getBuffer(),但没有先执行输入数据的接收操作。正确的流程应该是先调用apdu.setIncomingAndReceive()来获取实际接收的数据长度,确保你拿到了主机发送的完整挑战值。
修复后的卡端sign方法示例
private void sign(APDU apdu) { if (!pin.isValidated()) { ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED); } byte[] buffer = apdu.getBuffer(); // 接收APDU输入数据,获取实际长度 short dataLen = apdu.setIncomingAndReceive(); // 输入数据的起始偏移量是ISO7816.OFFSET_CDATA(固定为5) short offset = ISO7816.OFFSET_CDATA; // 根据私钥长度初始化足够大的输出缓冲区(私钥位数/8就是字节数) byte[] output = new byte[privKey.getSize() / 8]; short x = 0; Signature signature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false); signature.init(privKey, Signature.MODE_SIGN); // 使用实际接收的数据长度进行签名,避免硬写值 short sigLength = signature.sign(buffer, offset, dataLen, output, x); // 发送签名结果时,用实际生成的签名长度而非数组总长度 apdu.setOutgoing(); apdu.setOutgoingLength(sigLength); apdu.sendBytesLong(output, (short)0, sigLength); }
主机端的小问题
你的主机代码里有个变量名错误:
card_signature = resp2.getData();
这里应该用resp3.getData(),因为你接收响应的变量是resp3,不过这个不是导致卡端错误的原因,但会导致主机端获取不到正确的签名数据。
内容的提问来源于stack exchange,提问作者Gakuo
相关产品推荐
相关产品推荐

