chenpengcong / blog

14 stars 3 forks source link

JavaCard-Programming Large Applications and Libraries实践 #30

Open chenpengcong opened 4 years ago

chenpengcong commented 4 years ago

Java Card Development Kit 2.2.2的User Guide中说道

The most important limitation on a package is the 64KB limitation on the maximum component size. . . . You can overcome the component size limitation by dividing the application into separate application and library components.

. . .

Keep in mind that there are important differences between library packages and applet packages:

  • In a library package, all public fields are available to other packages for linking.
  • In an applet package, only interactions through a shareable interface are allowed by the firewall.

简单来说就是我们可以将应用的部分功能分离到另外的库(library)或者应用(applet)中, 以达到减少应用大小的目的

本文接下来对library package和applet package两种方式进行实践

library package

我们编写一个库C, 对外提供一个两数相加的功能

package com.example.javacard.libPackageC;
public class C {
    public static short add(short a, short b) {
        return (short)(a + b);
    }
}

applet package

接下来创建一个applet B, 该applet作为shareable interface object供其他applet访问, 与库C一样对外提供两数相加的接口

先编写加法器接口AdderInterface, 继承自Shareable

package com.example.javacard.appPackageB;
import javacard.framework.Shareable;
public interface AdderInterface extends Shareable {
    public short add(short a, short b);
}

然后编写Applet B, 实现AdderInterface

package com.example.javacard.appPackageB;
import javacard.framework.*;
public class B extends Applet implements AdderInterface {
    public B() {
        register();
    }

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new B();
    }

    public short add(short a, short b) {
        return (short)(a + b);
    }

    public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
        return this;
    }

    public void process(APDU apdu) {
        return;
    }
}

Test Applet

接下来编写应用Applet A, 该应用接受INS为0x52和0x54的APDU指令, 并分别调用库C和Applet B的add方法对APDU的P1和P2进行相加, 并将结果返回

package com.example.javacard.appPackageA;
import javacard.framework.*;
import com.example.javacard.appPackageB.AdderInterface;
import com.example.javacard.libPackageC.C;

public class A extends Applet {
    private static byte[] bAppAIDBytes = {(byte)0xA0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x01};    
    private static short ERROR_APPLET_AID_NOT_FOUND = (short)0x910D;
    private static short ERROR_SHAREABLE_NOT_FOUND = (short)0x910E;

    protected A() {
        register();
    }

    public static void install(byte[] bArray, short offset, byte length) {
        new A();
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }
        byte[] buffer = apdu.getBuffer();
        byte ins = buffer[ISO7816.OFFSET_INS];
        short p1 = (short)(buffer[ISO7816.OFFSET_P1] & 0xFF);
        short p2 = (short)(buffer[ISO7816.OFFSET_P2] & 0XFF);
        short sum = 0;
        switch (ins) {
            case (byte)0x52:
                sum = C.add(p1, p2);
                Util.setShort(buffer, (short)0, sum);
                apdu.setOutgoing();
                apdu.setOutgoingLength((short)2);
                apdu.sendBytes((short)0, (short)2);
                break;
            case (byte)0x54:
                AID bAppAID = JCSystem.lookupAID(bAppAIDBytes, (short)0, (byte)bAppAIDBytes.length);
                if (bAppAID == null) {
                    ISOException.throwIt(ERROR_APPLET_AID_NOT_FOUND);
                }
                AdderInterface adder = (AdderInterface)(JCSystem.getAppletShareableInterfaceObject(bAppAID,(byte)0));
                if (adder == null) {
                    ISOException.throwIt(ERROR_SHAREABLE_NOT_FOUND);
                }
                sum = adder.add(p1, p2);
                Util.setShort(buffer, (short)0, sum);
                apdu.setOutgoing();
                apdu.setOutgoingLength((short)2);
                apdu.sendBytes((short)0, (short)2);
                break;
            default:
                break;
        }
    }
}

编译, 安装及测试

开发环境

关于如何使用JCDK中的converter, scriptgen, apdutool, CREF工具完成代码的编译, 转换, 安装及运行这里不详细介绍, 在JCDK中的Users Guide手册中有很详细的讲解.

下面列出一些开发过程需要注意的点

APDU指令测试结果如下

CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 00, 00, 00, 00, 01, 01, Le: 00, SW1: 90, SW2: 00 # SELECT APPLET A
CLA: 00, INS: 52, P1: 01, P2: 02, Lc: 00, Le: 02, 00, 03, SW1: 90, SW2: 00 # 0x01 + 0x02 = 03
CLA: 00, INS: 54, P1: 01, P2: 02, Lc: 00, Le: 02, 00, 03, SW1: 90, SW2: 00 # 0x01 + 0x02 = 03
CLA: 00, INS: 52, P1: 80, P2: a0, Lc: 00, Le: 02, 01, 20, SW1: 90, SW2: 00 # 0x80 + 0xA0 = 0x0120
CLA: 00, INS: 54, P1: 80, P2: a0, Lc: 00, Le: 02, 01, 20, SW1: 90, SW2: 00 # 0x80 + 0xA0 = 0x0120

结果符合预期

参考