为什么我的Java Card小程序返回16个字节的零而不是AES加密值?

时间:2015-08-21 08:44:50

标签: java cryptography javacard

编写以下程序是为了加密16字节的传入APDU命令数据部分并返回该加密值:

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());
        }
    }
}

问题是,它只返回零:

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的方式有任何改进程序的评论,请告诉我。

同时请注意,由于我的侧面频道板,我“必须”对set_keywrite_textread_text使用三种不同的命令。我的意思是不建议混合命令的方法。

2 个答案:

答案 0 :(得分:1)

您跳过加密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

读取数组

答案 1 :(得分:1)

首先,这两个是相同的:

  

要解决此问题,请替换

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

使用:

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

第二

现在 cipheredData 不包含任何内容,它是一个空的字节数组,所以在write_text和{read_text的情况下都不会有任何好处。 1}}。

您是否需要加密 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");