【问题标题】:JavaCard: How can an applet's instance call a method in another instance's context?JavaCard:applet 的实例如何在另一个实例的上下文中调用方法?
【发布时间】:2013-01-22 00:50:45
【问题描述】:

考虑一个具有多个实例的 Java Card Classic 小程序,这些实例需要共享 byte[] 变量中的一些数据(例如持久可变,即 EEPROM/Flash),其中包含所有实例共有的信息。

静态 byte[] 变量将是一个完美的选择,但这些恰好被强加给我的验证规则所禁止(我被告知:作为一种全面的方式来证明取消实例化实例可以释放它在实例化时分配)。

如果从属实例可以在主实例的上下文中调用小程序的方法之一(可能最初由 AID 标识,或/和/然后以某种其他方式),则可以解决此问题。如何才能做到这一点?有什么例子吗?


更新:this other question 中的代码是在做我想做的事 共享对象,但似乎没有在另一个实例的上下文中调用方法。

【问题讨论】:

  • 你不能把数组隐藏在Shareable 对象后面吗?我想你可以简单地通过使用master的AID向系统询问可共享接口,然后调用Shareable接口中定义的retrieveByteArray()
  • PS 如果这个问题在明天之前没有得到回答,我会尝试为你制作一个 SSCCE,作为对你在 crypto 工作的感谢:)
  • 啊:您建议实例检索存储在可共享对象中的主数据,而不是在主上下文中调用方法以便它可以使用所有主数据。我担心以这种方式获得的 byte[] 数组无法访问(仅作为参数有效);但如果它们是可读/可写的,那就可以了。我喜欢这样的 SSCCE。
  • 我认为它们应该是,除非它们是 APDU 缓冲区或瞬态CLEAR_ON_DESELECT。也不要让它们成为静态的,尤其是写入静态字节数组肯定会导致灾难。但是对于 JavaCard,有时您只需要尝试一下(如果它不起作用,请阅读公共 RE 规范)。
  • 所以你的计划是:写一个在Shareable接口中定义的retrieveByteArray(),将共享数据从主实例的上下文复制到从实例的上下文,通过RAM,如APDU缓冲区(或也许是瞬态字节[]);我希望通过调用主人的上下文来避免复制。顺便说一句:我理解为什么写入 byte[] 而不是瞬态会导致缓慢和内存磨损,但不知道 static 如何使情况变得更糟。

标签: smartcard javacard


【解决方案1】:

一个经过测试的示例,正​​如承诺的那样:

package nl.owlstead.javacard.sharedarray;

import javacard.framework.*;

/**
 * The master and slave AID should only differ in the last byte; the master should end with the 'm' ASCII character.
 * This applet is for demonstration purposes only.
 * 
 * @author owlstead@stackoverflow
 */
public class SharingApplet extends Applet {

    public interface SharedArray extends Shareable {
        public byte[] getSharedArray();
    }

    public static class SharedArrayImpl implements SharedArray {
        private byte[] sharedArray;

        public SharedArrayImpl(final byte[] arrayToShare) {
            this.sharedArray = arrayToShare;
        }

        public byte[] getSharedArray() {
            return sharedArray;
        }
    }

    private static final short MAX_AID_SIZE = 16;
    private static final short START = 0;
    private static final byte SHARABLE_PARAM = 0;
    private static final byte PARAM_SHARED_ARRAY = 0;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        final byte aidLength = bArray[bOffset++];
        final byte lastAIDByte = bArray[(short) (bOffset + aidLength - 1)];
        final boolean isMaster = lastAIDByte == 'm';
        final SharingApplet applet = new SharingApplet(isMaster);
        applet.register(bArray, bOffset, aidLength);
        applet.setMasterAID();
    }

    // if null, it is not the master
    private final SharedArray sharedArray;
    private AID masterAID;

    public SharingApplet(final boolean isMaster) {
        if (isMaster) {
            final byte[] sa = new byte[] { 'm' };
            sharedArray = new SharedArrayImpl(sa);
        } else {
            sharedArray = null;
        }
    }

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

        byte[] buf = apdu.getBuffer();
        switch (buf[ISO7816.OFFSET_INS]) {
        case (byte) 0x00: {
            final SharedArray theSharedArray;
            if (sharedArray == null) {
                theSharedArray = (SharedArray) JCSystem.getAppletShareableInterfaceObject(masterAID, SHARABLE_PARAM);
            } else {
                theSharedArray = sharedArray;
            }
            final byte[] sa = theSharedArray.getSharedArray();
            Util.arrayCopy(sa, START, buf, START, (short) sa.length);
            apdu.setOutgoingAndSend(START, (short) sa.length);
            break;
        }
        case (byte) 0x02: {
            final SharedArray theSharedArray;
            if (sharedArray == null) {
                theSharedArray = (SharedArray) JCSystem.getAppletShareableInterfaceObject(masterAID, SHARABLE_PARAM);
                final byte[] sa = theSharedArray.getSharedArray();
                sa[START] = 's';
            } else {
                theSharedArray = sharedArray;
                final byte[] sa = theSharedArray.getSharedArray();
                sa[START] = 'm';
            }
            break;
        }
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    private void setMasterAID() {
        final byte[] workspace = new byte[MAX_AID_SIZE];
        final AID slaveOrMasterAID = JCSystem.getAID();
        final byte aidLength = slaveOrMasterAID.getBytes(workspace, START);
        workspace[(short) (aidLength - 1)] = 'm';
        this.masterAID = new AID(workspace, START, aidLength);
    }

    public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
        if (sharedArray == null || parameter != PARAM_SHARED_ARRAY) {
            return null;
        }
        return sharedArray;
    }
}

【讨论】:

  • 非常感谢。我知道它如何解决在从属上下文中获取主控sharedArray 的问题。除非我错了,否则它也会按照我最初的要求执行:theSharedArray.getSharedArray(),当在从属上下文中调用时,实际上是在主上下文中执行并访问其变量,对吧?另外:为什么if (selectingApplet()) { return; }?注意:我会在尝试代码后将此标记为已接受的答案。
  • 是的,它切换到那个上下文。 if (selectingApplet()) { return; } 代码是标准的 Java Card 实践。在SELECT by AID 调用期间,首先执行Applet 的select() 方法(可用于启动会话)。但随后 APDU 也被传递给 process() 方法。这对于返回数据很有用(例如,当 P2 值为 00 时)。但是,通常您至少应该返回一个9000 状态字,因为平台已经选择了Applet ,无论您在process() 方法中做什么。这是通过简单地无异常返回来完成的。
  • 抱歉,还没有。我需要一位同事的帮助才能将 CAP 安装到物理卡中。
  • 用真卡测试过:它有效!再次感谢。创建了 3 个实例,AID 为 ffca11ab1e31,后跟 6d6e6f;然后测试如下:APDU00a4040005ffca11ab1e31选择master,然后8000000000显示当前状态(6D或者73); 00a4040005ffca11ab1e31选择master,然后8002000000设置状态为6D00a4040005ffca11ab1e31 选择主控,然后00a4040205ffca11ab1e31 选择下一个从属,然后8002000000 将状态设置为73。我找不到如何直接通过 AID 选择从站,但我猜这不是小程序的问题。
  • 您是否阅读了我在代码中留下的唯一评论?主 AID 应该以 ASCII 'm' 结尾,从属可以使用任何其他字符,例如's' 或 '1' 或 '2' (当然是 ASCII 编码的二进制)。 AID 的长度不应不同 - 但这只是此示例 Applet 的一个属性,您也可以选择使用 INSTALL for INSTALL APDU 中给出的用户参数,传递给静态 install() 方法。
猜你喜欢
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 2020-10-15
  • 2015-06-10
  • 1970-01-01
  • 2021-07-19
  • 2011-12-30
  • 1970-01-01
相关资源
最近更新 更多