6

我想编写我的小程序,使其 APDU 命令和状态字在我的卡和读卡器之间的传输通道中不清晰。我的意思是我不想将 APDU 命令和响应发送为第三方的纯文本。

我想我有两个选择:

  1. 在卡上选择我的小程序后,对于所有其他命令,对 APDU 命令的数据部分执行加密功能并在卡上对其进行解密,然后对其进行分析。请注意,我无法使用此方法对整个命令进行加密,因为结果可能与另一个 APDU 命令冲突,并且卡的 SD 将其错误地SELECT识别为命令。SELECT那正确吗?

其示意图:

在此处输入图像描述

  1. 使用 SD 安全通道:据我所知,安全通道意味着:整个APDU 命令响应以加密形式传输(即它们在源(安全域/读卡器)中加密并在目标(安全域/卡)中解密读者). 对吗?据我所知,SD 在这个机制中扮演着密码学方法的角色,我的小程序和 SD 之间的通信很简单(下图),对吧?

其示意图: 在此处输入图像描述

还有其他方法吗?

似乎第一个解决方案还不够好,因为:

  1. 我必须自己实现!:)
  2. 我们无法对第三方隐藏命令和响应的所有部分。(我们只能隐藏数据)

我对吗?

现在,假设我想确保我的小程序仅适用于使用安全通道传输的 APDU 命令。我想我又有两个选择:

  1. 将卡片置于SECURED状态。由于在这种状态下用户无法使用纯文本 APDU 命令与卡进行通信(对吗?),因此他必须使用安全通道将命令发送到我的小程序。正确的?如果不正确,有什么方法可以强制 SD 仅使用安全通道?

  2. 将卡保持在任何生命周期中(例如 OP_READY),但是,在接收到任何 APDU 命令时,检查CLA部分以查看它是否是安全传输的!(有可能吗?CLA来自安全通道的部分 APDU 命令和其他命令之间有什么区别吗?我说的对吗?)

还有其他方法吗?

最后是主要问题:

如何使用 SD 与我的小程序进行安全通信?由于我认为我必须使用 GlobalPlatform 类(我是吗?),所以我查看了它的 API-s。我getSecureChannel在一个名为org.globalplatform.GPSystem. 我的方式正确吗?我必须使用这种方法吗?

我知道这可能太长无法回答,但我相信它不仅为我澄清了很多问题,也为其他未来的观众澄清了很多问题。

我感谢任何机构为我阐明这个问题。

并且一个示例小程序更可观。

4

4 回答 4

4

不用担心通过小程序进行安全通道通信。如果您在小程序中使用 Global Platform API,这非常简单。

您不需要考虑很多问题,只需尝试编写一个安全通道小程序,它就会按照命令数据中定义的安全级别处理您的小程序。

参考 GP 安全通道 API: http: //www.win.tue.nl/pinpasjc/docs/apis/gp22/

并且您应该将卡保持在 SECURED 状态。

这是安全通道 scp02 的示例小程序:

package secureChannel;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;

import org.globalplatform.GPSystem;
import org.globalplatform.SecureChannel;

public class Scp02 extends Applet
{
    final static byte INIT_UPDATE       = (byte) 0x50;

    final static byte EXT_AUTHENTICATE  = (byte) 0x82;

    final static byte STORE_DATA        = (byte) 0xE2;

    public static void install(byte[] bArray, short sOffset, byte bLength)
    {
        new Scp02().register(bArray, sOffset, bLength);
    }

    public void process(APDU apdu) throws ISOException
    { 
        SecureChannel sc = GPSystem.getSecureChannel();

        byte[] buffer = apdu.getBuffer();

        short inlength = 0;

        switch (ISO7816.OFFSET_INS)
        {
            case INIT_UPDATE:
            case EXT_AUTHENTICATE:
                inlength = apdu.setIncomingAndReceive();
                sc.processSecurity(apdu);
            break;

            case STORE_DATA:
                //Receive command data
                inlength = apdu.setIncomingAndReceive();
                inlength = sc.unwrap(buffer, (short) 0, inlength);

                apdu.setOutgoingAndSend((short)0, inlength);

                //Process data
                break;
        }
    }
}
于 2015-06-15T07:17:57.930 回答
3

我按顺序回答:

  1. 是的,对于 ISO/IEC 7816-4,只有数据部分是加密的。标头仅受身份验证标签的保护。
  2. 不,全球平台安全通道也只是(可选地)加密数据。不过,完整性在于标头和命令数据。
  3. 不,安全状态仅适用于全球平台,您必须使用卡上 GP API 自行编程。GP API 具有执行身份验证、请求安全通道和检索当前状态的访问方法。
  4. 正确,CLA 字节确定 APDU 是否已加密(但不是加密方式)。如果 CLA 的第一位为零,那么您的安全通道必须符合 ISO/IEC 7816-4。
于 2015-04-16T10:34:14.930 回答
1

为了 Google 搜索,Anurag Bajpai 的代码在没有稍作修改的情况下无法运行,因为如 GP 安全通道 API 中所述,小程序应输出最终响应数据:

如果存在响应数据,该数据将被放置在偏移量 ISO7816.OFFSET_CDATA 的 APDU 缓冲区中。返回值表示长度,必要时小程序负责输出此数据。

因此,修正后的代码是:

package secureChannel;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import org.globalplatform.GPSystem;
import org.globalplatform.SecureChannel;


public class Scp02 extends Applet
{
    final static byte INIT_UPDATE       = (byte) 0x50;

    final static byte EXT_AUTHENTICATE  = (byte) 0x82;

    final static byte STORE_DATA        = (byte) 0xE2;

    public static void install(byte[] bArray, short sOffset, byte bLength)
    {
        new Scp02().register(bArray, sOffset, bLength);
    }

    public void process(APDU apdu) throws ISOException
    { 
        SecureChannel sc = GPSystem.getSecureChannel();

        byte[] buffer = apdu.getBuffer();

        short inlength = 0;

        switch (ISO7816.OFFSET_INS)
        {
            case INIT_UPDATE:
            case EXT_AUTHENTICATE:
                inlength = apdu.setIncomingAndReceive();
                short respLen = sc.processSecurity(apdu);
                apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, respLen);
            break;

            case STORE_DATA:
                //Receive command data
                inlength = apdu.setIncomingAndReceive();
                inlength = sc.unwrap(buffer, (short) 0, inlength);

                apdu.setOutgoingAndSend((short)0, inlength);

                //Process data
            break;
    }
}

}

于 2019-01-04T11:21:58.070 回答
0

请注意,在调用apdu.setIncomingAndReceive()之前调用是不正确的sc.processSecurity(apdu),因为 processSecurity() “负责接收可识别的命令的数据字段”。

于 2021-11-03T13:48:14.120 回答