java - Java Card 中的加密/解密输出 + 相应的 APDU

标签 java javacard apdu

我是 Java Card 整个主题的新手,并尝试查看一些代码示例以更好地理解。 我在 oracle forum 中找到了 AES 使用示例但以下部分存在一些问题:

     private void doAES(APDU apdu)
     {

          byte b[] = apdu.getBuffer();

          short incomingLength = (short) (apdu.setIncomingAndReceive());
          if (incomingLength != 24) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

          //perform encryption and append results in APDU Buffer a[] automatically 

          cipherAES.init(aesKey, Cipher.MODE_ENCRYPT);
          cipherAES.doFinal(b, (short) dataOffset, incomingLength, a, (short) (dataOffset + 24));
          cipherAES.init(aesKey, Cipher.MODE_DECRYPT);
          cipherAES.doFinal(b, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48));

          // Send results
          apdu.setOutgoing();
          apdu.setOutgoingLength((short) 72);
          apdu.sendBytesLong(b, (short) dataOffset, (short) 72);
     }

根据我的理解,这段代码从传入的 APDU 中获取前 24 个数据字节,对它们进行加密并将它们放入字节数组 a 中。 然后它获取接下来的 24 个数据字节,对它们进行解密并将它们放入一个 too 中。

但是下面的命令不使用这些输出数据,因为

apdu.sendBytesLong(b, (short) dataOffset, (short) 72);

将 b 用于输出数据...这可能不正确,所以请帮助我了解哪里出错了。

另外:用这个和相应的答案加密小文本的简单命令 APDU 看起来像什么?

最佳答案

Oracle 论坛的代码实际上不是很好。它不遵循内存使用的基本规则,根本不是真实世界的例子。而且,它会很慢,如果经常使用它甚至会损坏您的智能卡。

我认为您应该首先通读 Java Card 教程并了解什么是 APDU 及其结构,请参阅以下问题:

How to get started with Java Cards?

然后就可以进行Java Card加密/解密了。像这样的东西可能对你有帮助:

public class MiniApplet extends Applet {
     public static void install(byte[] bArray, short bOffset, byte bLength) {
        // GP-compliant JavaCard applet registration
        new MiniApplet().register(bArray, (short) (bOffset + 1),
                bArray[bOffset]);
     }

    private final AESKey aesKey = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
    private final Cipher aes = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);

    public void process(APDU apdu) {
    // Good practice: Return 9000 on SELECT
    if (selectingApplet()) {
        return;
    }

    final byte[] buf = apdu.getBuffer();
    final short dataLen = apdu.setIncomingAndReceive(); 
    final byte ins = buf[ISO7816.OFFSET_INS];

    switch (ins) {
    case (byte) 0x00: //KEY VALUE INIT FROM APDU
        if (dataLen != 16) //checking key value length
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH)
        aesKey.setKey(buf, ISO7816.OFFSET_CDATA);
        break;
    case (byte) 0x01: //DECRYPTION
    case (byte) 0x02: //ENCRYPTION
        if ((dataLen & 0x000F) != 0) //checking if input data is block-aligned
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH)

        if (!aesKey.isInitialized())
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
        aes.init(aesKey, (ins == 0x02) ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT);
        aes.doFinal(buf, ISO7816.OFFSET_CDATA, dataLen, buf, ISO7816.OFFSET_CDATA);
        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, dataLen);
        break;
    default:
        // good practice: If you don't know the INStruction, say so:
        ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }
}

}

注意:在我的示例中,我从输入命令初始化键值。我的 key 存储在 RAM 中,这意味着每次重置卡或选择另一个小程序后,该值都会消失。这不一定适合您的业务案例,更明智的做法是只在卡上生成一次 key 并将其存储在持久性内存中。如果是这样,您必须使用不同的 key 类型:KeyBuilder.TYPE_AES 而不是 KeyBuilder.TYPE_AES_TRANSIENT_DESELECT

关于java - Java Card 中的加密/解密输出 + 相应的 APDU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32395400/

相关文章:

java - 从命令行将 clojure 源代码编译为类 (AOT)(不使用 lein)

java - 如何将 war 文件部署到 Glassfish?

javacard - 发送扩展 APDU 失败

android - 使用外部 NFC 阅读器 ACR1252 读取 NDEF 消息

smartcard - DESFire 写入数据命令失败,出现 917E(长度错误)

java - 将 JFrame 大小调整为 JLayeredPane 内的 JPanel

Java 卡小程序转换为 .cap 文件

JavaCard 获取卡上的数据

nfc - ACR122U 的 MIFARE Classic 1K 加载身份验证 key 失败

java - 这是否被视为递归?