无法在我的智能卡上安装 Java 卡小程序
Can't install Java Card applets on my Smart Card
我从一个简单的 HelloWorld 程序生成了一个 .cap 文件,如下所示:
package com.oracle.jcclassic.samples.helloworld;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;
public class HelloWorld extends Applet {
private byte[] echoBytes;
private static final short LENGTH_ECHO_BYTES = 256;
protected HelloWorld() {
echoBytes = new byte[LENGTH_ECHO_BYTES];
register();
}
public static void install(byte[] bArray, short bOffset, byte bLength) {
new HelloWorld();
}
@Override
public void process(APDU apdu) {
byte buffer[] = apdu.getBuffer();
if ((buffer[ISO7816.OFFSET_CLA] == 0) &&
(buffer[ISO7816.OFFSET_INS] == (byte) (0xA4))) {
return;
}
short bytesRead = apdu.setIncomingAndReceive();
short echoOffset = (short) 0;
while (bytesRead > 0) {
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, echoBytes, echoOffset, bytesRead);
echoOffset += bytesRead;
bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
}
apdu.setOutgoing();
apdu.setOutgoingLength((short) (echoOffset + 5));
apdu.sendBytes((short) 0, (short) 5);
apdu.sendBytesLong(echoBytes, (short) 0, echoOffset);
}
}
我已经使用 Eclipse IDE 及其提供的 HelloWorld 经典小程序示例来执行此操作。然后我有一张 NXP J3H145 智能卡,我想在上面安装我的小程序。为此,我使用了 Global Platform Pro 工具并编写了命令:
gp.exe -d -v -install helloworld.cap
我得到以下结果:
gp.exe -d -v -install helloworld.cap
# gp -d -v -install helloworld.cap
# GlobalPlatformPro v21.12.31-3-g903416f
# Running on Windows 10 10.0 amd64, Java 18.0.1.1 by Oracle Corporation
[DEBUG] TerminalManager - Processing 3 readers with null as preferred and null as ignored
[DEBUG] TerminalManager - Preferred reader: Optional.empty
SCardConnect("Broadcom Corp Contacted SmartCard 0", T=*) -> T=1, 3BDC18FF8191FE1FC38073C821136605036351000250
A>> T=1 (4+0000) 00A40400 00
A<< (0018+2) (26ms) 6F108408A000000151000000A5049F6501FF 9000
[DEBUG] GPSession - Auto-detected ISD: A000000151000000
# Warning: no keys given, defaulting to 404142434445464748494A4B4C4D4E4F
[INFO] GPSession - Using card master keys with version 0 for setting up session with MAC
A>> T=1 (4+0008) 80500000 08 4E2AF49D3EFDF13F 00
A<< (0029+2) (99ms) 00008048009426073469FF03001B999689BD191E08DBB58A4F31BE3D4A 9000
[DEBUG] GPSession - KDD: 00008048009426073469
[DEBUG] GPSession - Host challenge: 4E2AF49D3EFDF13F
[DEBUG] GPSession - Card challenge: 1B999689BD191E08
[DEBUG] GPSession - Card reports SCP03 with key version 255 (0xFF)
[INFO] GPSession - Diversified card keys: ENC=404142434445464748494A4B4C4D4E4F (KCV: 504A77) MAC=404142434445464748494A4B4C4D4E4F (KCV: 504A77) DEK=404142434445464748494A4B4C4D4E4F (KCV: 504A77) for SCP03
[INFO] GPSession - Session keys: ENC=196540E4A67650882195BF1BCEB78B36 MAC=09B4554BBA83417A61728B9AE76DECF7 RMAC=CB8F3FC5C52BE5A9C83A49622B195C01
[DEBUG] GPSession - Verified card cryptogram: DBB58A4F31BE3D4A
[DEBUG] GPSession - Calculated host cryptogram: 89F0CD854C3725AD
A>> T=1 (4+0016) 84820100 10 89F0CD854C3725AD58C4B201E2C601FE
A<< (0000+2) (148ms) 9000
A>> T=1 (4+0010) 84F28002 0A 4F002740B169D9F9CC3A 00
A<< (0044+2) (111ms) E32A4F08A0000001510000009F700107C5039EFE80C407A0000000620001CE020100CC08A000000151000000 9000
A>> T=1 (4+0010) 84F24002 0A 4F009CDA12BDBB4AD370 00
A<< (0000+2) (99ms) 6A88
A>> T=1 (4+0010) 84F21002 0A 4F00467F8B0AF8DAC1AE 00
A<< (0025+2) (102ms) E3174F07A00000015153509F7001018408A000000151535041 9000
A>> T=1 (4+0010) 84F22002 0A 4F00510E1124D76D25E7 00
A<< (0015+2) (99ms) E30D4F07A00000015153509F700101 9000
CAP file (v2.3), contains: applets for JavaCard 3.1.0
Package: com.oracle.jcclassic.samples.helloworld A00000006203010C01 v1.0
Applet: com.oracle.jcclassic.samples.helloworld.HelloWorld A00000006203010C0101
Import: A0000000620101 v1.8 javacard.framework
Import: A0000000620001 v1.0 java.lang
Generated by Oracle Corporation converter [v3.1.0]
On Thu May 26 14:58:30 EEST 2022 with JDK 18.0.1.1 (Oracle Corporation)
Code size 339 bytes (1149 with debug)
SHA-256 96aaaaa6510a3bc106babdec45790831c3ea62c2e05d274e05a4999255bdc3e1
SHA-1 8afd2bd6d08fff180d6949189399928ff41a7371
A>> T=1 (4+0030) 84E60200 1E 09A00000006203010C0108A000000151000000000000268DB924E83229B2
A<< (0001+2) (113ms) 00 9000
A>> T=1 (4+0255) 84E80000 FF C4820153010014DECAFFED030204000109A00000006203010C010002002500140025000E0015003600170072000A00130000006C02B80000000000000000000002010004001502080107A0000000620101000107A000000062000103000E010AA00000006203010C01010014060017000000800301000107010000001D000102030405060708070072000210188C000118110100900B8700188B00027A01308F00038C00047A0523198B00052D1A0325610A1A042510A46B037A198B00063203290470191A08AD0016041F8D000B3B16041F41290419088B000C321F64E8198B00073B19160408418B00081903088B000919AD00031604728F17ECFC6DA47C
A<< (0000+2) (698ms) 6403
Error: LOAD failed: 0x6403
SCardDisconnect("Broadcom Corp Contacted SmartCard 0", true) tx:399/rx:150 in 1s663ms
因此,该过程以错误 6403 结束,我的小程序未安装。我发现 APDU 响应代码 6403 表示“CAP MINOR”,但我不知道它是什么意思。 CAP 文件次要版本?我可以在以下行上方的打印输出中看到:
CAP file (v2.3), contains: applets for JavaCard 3.1.0
这是否意味着不同版本存在一些问题?但是我在我的智能卡规范(https://www.cardlogix.com/product/nxp-jcop3-j3h145-java-card-3-0-4-dual-interface)中发现它支持 JavaCard 版本 v3.
我还尝试使用 PyApduTool (http://javacardos.com/javacardforum/viewtopic.php?t=38) 将我的小程序下载到我的卡中。我收到以下错误消息:
Download Cap error: GP init update failed. recv: 67 00
有没有人知道我的代码或我的操作有什么问题,以及为什么我不能在我的卡上安装任何小程序?
请使用准确的版本进行编译。 NormalJava在小版本差异的时候相对比较灵活。动态 linking 仅通过方法签名发生,即 class 文件中的名称和参数。
但是,CAP 文件在转换期间是 pre-linked。这意味着 class 中的所有方法都被枚举,字节码只是按值引用成员,而不是按名称。
如果 API 发生变化,则枚举也会发生变化,字节码将 link 指向 class 中的错误成员。因此,次要版本也正确非常重要。
我从一个简单的 HelloWorld 程序生成了一个 .cap 文件,如下所示:
package com.oracle.jcclassic.samples.helloworld;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;
public class HelloWorld extends Applet {
private byte[] echoBytes;
private static final short LENGTH_ECHO_BYTES = 256;
protected HelloWorld() {
echoBytes = new byte[LENGTH_ECHO_BYTES];
register();
}
public static void install(byte[] bArray, short bOffset, byte bLength) {
new HelloWorld();
}
@Override
public void process(APDU apdu) {
byte buffer[] = apdu.getBuffer();
if ((buffer[ISO7816.OFFSET_CLA] == 0) &&
(buffer[ISO7816.OFFSET_INS] == (byte) (0xA4))) {
return;
}
short bytesRead = apdu.setIncomingAndReceive();
short echoOffset = (short) 0;
while (bytesRead > 0) {
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, echoBytes, echoOffset, bytesRead);
echoOffset += bytesRead;
bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
}
apdu.setOutgoing();
apdu.setOutgoingLength((short) (echoOffset + 5));
apdu.sendBytes((short) 0, (short) 5);
apdu.sendBytesLong(echoBytes, (short) 0, echoOffset);
}
}
我已经使用 Eclipse IDE 及其提供的 HelloWorld 经典小程序示例来执行此操作。然后我有一张 NXP J3H145 智能卡,我想在上面安装我的小程序。为此,我使用了 Global Platform Pro 工具并编写了命令:
gp.exe -d -v -install helloworld.cap
我得到以下结果:
gp.exe -d -v -install helloworld.cap
# gp -d -v -install helloworld.cap
# GlobalPlatformPro v21.12.31-3-g903416f
# Running on Windows 10 10.0 amd64, Java 18.0.1.1 by Oracle Corporation
[DEBUG] TerminalManager - Processing 3 readers with null as preferred and null as ignored
[DEBUG] TerminalManager - Preferred reader: Optional.empty
SCardConnect("Broadcom Corp Contacted SmartCard 0", T=*) -> T=1, 3BDC18FF8191FE1FC38073C821136605036351000250
A>> T=1 (4+0000) 00A40400 00
A<< (0018+2) (26ms) 6F108408A000000151000000A5049F6501FF 9000
[DEBUG] GPSession - Auto-detected ISD: A000000151000000
# Warning: no keys given, defaulting to 404142434445464748494A4B4C4D4E4F
[INFO] GPSession - Using card master keys with version 0 for setting up session with MAC
A>> T=1 (4+0008) 80500000 08 4E2AF49D3EFDF13F 00
A<< (0029+2) (99ms) 00008048009426073469FF03001B999689BD191E08DBB58A4F31BE3D4A 9000
[DEBUG] GPSession - KDD: 00008048009426073469
[DEBUG] GPSession - Host challenge: 4E2AF49D3EFDF13F
[DEBUG] GPSession - Card challenge: 1B999689BD191E08
[DEBUG] GPSession - Card reports SCP03 with key version 255 (0xFF)
[INFO] GPSession - Diversified card keys: ENC=404142434445464748494A4B4C4D4E4F (KCV: 504A77) MAC=404142434445464748494A4B4C4D4E4F (KCV: 504A77) DEK=404142434445464748494A4B4C4D4E4F (KCV: 504A77) for SCP03
[INFO] GPSession - Session keys: ENC=196540E4A67650882195BF1BCEB78B36 MAC=09B4554BBA83417A61728B9AE76DECF7 RMAC=CB8F3FC5C52BE5A9C83A49622B195C01
[DEBUG] GPSession - Verified card cryptogram: DBB58A4F31BE3D4A
[DEBUG] GPSession - Calculated host cryptogram: 89F0CD854C3725AD
A>> T=1 (4+0016) 84820100 10 89F0CD854C3725AD58C4B201E2C601FE
A<< (0000+2) (148ms) 9000
A>> T=1 (4+0010) 84F28002 0A 4F002740B169D9F9CC3A 00
A<< (0044+2) (111ms) E32A4F08A0000001510000009F700107C5039EFE80C407A0000000620001CE020100CC08A000000151000000 9000
A>> T=1 (4+0010) 84F24002 0A 4F009CDA12BDBB4AD370 00
A<< (0000+2) (99ms) 6A88
A>> T=1 (4+0010) 84F21002 0A 4F00467F8B0AF8DAC1AE 00
A<< (0025+2) (102ms) E3174F07A00000015153509F7001018408A000000151535041 9000
A>> T=1 (4+0010) 84F22002 0A 4F00510E1124D76D25E7 00
A<< (0015+2) (99ms) E30D4F07A00000015153509F700101 9000
CAP file (v2.3), contains: applets for JavaCard 3.1.0
Package: com.oracle.jcclassic.samples.helloworld A00000006203010C01 v1.0
Applet: com.oracle.jcclassic.samples.helloworld.HelloWorld A00000006203010C0101
Import: A0000000620101 v1.8 javacard.framework
Import: A0000000620001 v1.0 java.lang
Generated by Oracle Corporation converter [v3.1.0]
On Thu May 26 14:58:30 EEST 2022 with JDK 18.0.1.1 (Oracle Corporation)
Code size 339 bytes (1149 with debug)
SHA-256 96aaaaa6510a3bc106babdec45790831c3ea62c2e05d274e05a4999255bdc3e1
SHA-1 8afd2bd6d08fff180d6949189399928ff41a7371
A>> T=1 (4+0030) 84E60200 1E 09A00000006203010C0108A000000151000000000000268DB924E83229B2
A<< (0001+2) (113ms) 00 9000
A>> T=1 (4+0255) 84E80000 FF C4820153010014DECAFFED030204000109A00000006203010C010002002500140025000E0015003600170072000A00130000006C02B80000000000000000000002010004001502080107A0000000620101000107A000000062000103000E010AA00000006203010C01010014060017000000800301000107010000001D000102030405060708070072000210188C000118110100900B8700188B00027A01308F00038C00047A0523198B00052D1A0325610A1A042510A46B037A198B00063203290470191A08AD0016041F8D000B3B16041F41290419088B000C321F64E8198B00073B19160408418B00081903088B000919AD00031604728F17ECFC6DA47C
A<< (0000+2) (698ms) 6403
Error: LOAD failed: 0x6403
SCardDisconnect("Broadcom Corp Contacted SmartCard 0", true) tx:399/rx:150 in 1s663ms
因此,该过程以错误 6403 结束,我的小程序未安装。我发现 APDU 响应代码 6403 表示“CAP MINOR”,但我不知道它是什么意思。 CAP 文件次要版本?我可以在以下行上方的打印输出中看到:
CAP file (v2.3), contains: applets for JavaCard 3.1.0
这是否意味着不同版本存在一些问题?但是我在我的智能卡规范(https://www.cardlogix.com/product/nxp-jcop3-j3h145-java-card-3-0-4-dual-interface)中发现它支持 JavaCard 版本 v3.
我还尝试使用 PyApduTool (http://javacardos.com/javacardforum/viewtopic.php?t=38) 将我的小程序下载到我的卡中。我收到以下错误消息:
Download Cap error: GP init update failed. recv: 67 00
有没有人知道我的代码或我的操作有什么问题,以及为什么我不能在我的卡上安装任何小程序?
请使用准确的版本进行编译。 NormalJava在小版本差异的时候相对比较灵活。动态 linking 仅通过方法签名发生,即 class 文件中的名称和参数。
但是,CAP 文件在转换期间是 pre-linked。这意味着 class 中的所有方法都被枚举,字节码只是按值引用成员,而不是按名称。
如果 API 发生变化,则枚举也会发生变化,字节码将 link 指向 class 中的错误成员。因此,次要版本也正确非常重要。