为什么我的 Java 卡片小程序 returns 16 字节的零而不是 AES 加密值?

Why my Java Card applet returns 16 bytes of zero instead of AES encrypted value?

编写以下程序来加密传入 APDU 命令数据部分的 16 个字节和 return 加密值:

public class DoAES extends Applet {

    //Required Objects
    static Cipher myCipher;
    static AESKey myAESKey;
    byte[] cipheredData = JCSystem.makeTransientByteArray((short) 0x10, JCSystem.CLEAR_ON_RESET);
    //Supported APDU commands INS byte
    final static byte SET_KEY = (byte) 0x12;
    final static byte WRITE_TEXT = (byte) 0x04;
    final static byte READ_TEXT = (byte) 0xC0;

    private DoAES() {

        try {
            myCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
            myAESKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,
                    KeyBuilder.LENGTH_AES_128, false);
        } catch (CryptoException e) {
            ISOException.throwIt(((CryptoException) e).getReason());
        }
    }

    public static void install(byte bArray[], short bOffset, byte bLength)
            throws ISOException {
        (new DoAES()).register();
    }

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

        byte[] buffer = apdu.getBuffer();

        if ((buffer[ISO7816.OFFSET_CLA] & 0x00FF) != 0x80) {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }

        try {
            switch (buffer[ISO7816.OFFSET_INS]) {

                case SET_KEY:
                    myAESKey.setKey(buffer, (short) ISO7816.OFFSET_CDATA);
                    myCipher.init(myAESKey, Cipher.MODE_ENCRYPT);
                    break;

                case WRITE_TEXT:
                    myCipher.doFinal(buffer, (short) ISO7816.OFFSET_CDATA, (short) 0x10, cipheredData, (short) 0);
                    break;

                case READ_TEXT:
                    Util.arrayCopyNonAtomic(cipheredData, (short) 0, buffer, (short) 0, (short) 0x10);
                    apdu.setOutgoingAndSend((short) 0, (short) 0x10);
                    break;

                default:
                    ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
            }
        } catch (CryptoException e) {
            ISOException.throwIt(((CryptoException) e).getReason());
        }
    }
}

问题是,它只有 return 为零:

OSC:> opensc-tool.exe -s 00a4040006010203040501 -s 801200001000112233445566778899aabbccddeeff -s 80c00000
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 06 01 02 03 04 05 01
Received (SW1=0x90, SW2=0x00)
Sending: 80 12 00 00 10 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
Received (SW1=0x90, SW2=0x00)
Sending: 80 C0 00 00
Received (SW1=0x90, SW2=0x00):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

为了解决这个问题,我更换了

    byte[] cipheredData = JCSystem.makeTransientByteArray((short) 0x10, JCSystem.CLEAR_ON_RESET);

与:

    byte[] cipheredData = JCSystem.makeTransientByteArray((short) 0x10, JCSystem.CLEAR_ON_DESELECT);

还有

    byte[] cipheredData = new byte[16];

但没有任何改变!

请注意,因为我想对卡进行边信道攻击,所以我想尽量少使用 EEPROM,而是想使用 RAM。因此,如果您有任何改进程序的意见,以便我可以减少使用 EEPROM,请告诉我。

还要注意,由于我的侧通道板,我 "must" 对 set_keywrite_textread_text 使用三个不同的命令。我的意思是不要建议混合命令的方法。

您跳过了加密APDU,请发送

80 04 00 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11

其中 11..11 是要加密的数据。

然后尝试通过80 C0 00 00

读取数组

首先这两个是一样的:

To solve this issue, I replace

    byte[] cipheredData = JCSystem.makeTransientByteArray((short) 0x10, JCSystem.CLEAR_ON_RESET);

with:

    byte[] cipheredData = JCSystem.makeTransientByteArray((short) 0x10, JCSystem.CLEAR_ON_RESET);

第二个:

现在 cipheredData 不包含任何内容,它是一个空字节数组,所以在 write_textwrite_text 的情况下都没有任何好处在 read_text.

的情况下

不需要加密APDU吗???

你是不是漏了什么?

更新

既然你问的是保存密钥:

生成密钥:

KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256); 
SecretKey myKey = keyGenerator.generateKey();

保存密钥:

char[] hex = encodeHex(key.getEncoded());
writeKeyToFile(file, String.valueOf(hex));

加载保存的密钥:

String keyHex = new String(readFileToByteArray(file));
byte[] encoded = decodeHex(keyHex.toCharArray());
SecretKey myKey = new SecretKeySpec(encoded, "AES");