AES Applet在不同的卡上返回不同的结果

时间:2016-01-25 10:04:58

标签: encryption cryptography aes javacard

我编写了以下applet,在CBC和ECB模式下进行AES加密和解密:

package cryptoPack;

import javacard.framework.*;
import javacard.security.AESKey;
import javacard.security.CryptoException;
import javacard.security.KeyBuilder;
import javacardx.crypto.Cipher;

public class CryptoAES extends Applet {

    // Abbreviations
    private static final boolean NO_EXTERNAL_ACCESS = false;

    // AES Cipher AND its required key
    Cipher cipher;
    AESKey AESkey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, NO_EXTERNAL_ACCESS);

    // A fixed Initial vector for AES CBC mode.
    public byte[] IV = { (byte) 0x00, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66,
            (byte) 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE,
            (byte) 0xFF };

    // Defining switch case variables for supported instructions ::: INS in APDU
    // command
    final byte SET_KEY = (byte) 0xC0;
    final byte DO_CRYPTO = (byte) 0xC2;

    // Defining switch case variables for cipher algorithms ::: P1 in APDU
    // command
    final byte AES_BLOCK_128_CBC_NOPAD = (byte) 0x00;
    final byte AES_BLOCK_128_ECB_NOPAD = (byte) 0x01;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new CryptoAES();
    }

    protected CryptoAES() {
        register();
    }

    public void process(APDU apdu) {

        if (selectingApplet()) {
            return;
        }

        byte[] buffer = apdu.getBuffer();

        // Analyzing the command.
        try {

            switch (buffer[ISO7816.OFFSET_INS]) {

            case SET_KEY:
                setKeyAndInit(apdu);
                break;

            case DO_CRYPTO:
                do_crypto(apdu);

                break;

            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

            }

        } catch (CryptoException e) {
            ISOException.throwIt(((CryptoException) e).getReason());
        }
    }



    public void setKeyAndInit(APDU apdu) throws ISOException {
        byte[] buffer = apdu.getBuffer();
        if (buffer[ISO7816.OFFSET_LC] == 16) {
            AESkey.setKey(buffer, (short) ISO7816.OFFSET_CDATA);
        } else {
            ISOException.throwIt(ISO7816.SW_DATA_INVALID);
        }

        switch (buffer[ISO7816.OFFSET_P1]) {
        case AES_BLOCK_128_CBC_NOPAD:
            cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, NO_EXTERNAL_ACCESS);
            break;
        case AES_BLOCK_128_ECB_NOPAD:
            cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, NO_EXTERNAL_ACCESS);
            break;
        }
    }



    public void do_crypto(APDU apdu) throws ISOException {
        byte[] buffer = apdu.getBuffer();

        short datalen = apdu.setIncomingAndReceive();
        if ((datalen % 16) != 0) {
            ISOException.throwIt(ISO7816.SW_DATA_INVALID);
        }

        byte[] out_data = JCSystem.makeTransientByteArray((short) 16, JCSystem.CLEAR_ON_DESELECT);

        switch (buffer[ISO7816.OFFSET_P1]) {

        case AES_BLOCK_128_CBC_NOPAD:
            if(buffer[ISO7816.OFFSET_P2]== 0x00){
                cipher.init(AESkey, Cipher.MODE_DECRYPT, IV, (short) 0x00, (short) 0x10);       
            }else{
                cipher.init(AESkey, Cipher.MODE_ENCRYPT, IV, (short) 0x00, (short) 0x10);       
            }

            break;

        case AES_BLOCK_128_ECB_NOPAD:
            if(buffer[ISO7816.OFFSET_P2]== 0x00){
                cipher.init(AESkey, Cipher.MODE_DECRYPT);       
            }else{
                cipher.init(AESkey, Cipher.MODE_ENCRYPT);       
            }
            break;

        default:
            break;
        }

        short out_data_len = cipher.doFinal(buffer, (short) ISO7816.OFFSET_CDATA, datalen, out_data,
                (short) 0);
        Util.arrayCopyNonAtomic(out_data, (short) 0, buffer, (short) 0, out_data_len);
        apdu.setOutgoingAndSend((short) 0, out_data_len);
    }

}

在三张不同的卡上安装上面的applet后,我得到以下结果:

恩智浦JCOP v2.4.2 r3 - T = 1 TPDU:

Send: 00 A4 04 00 06 01 02 03 04 07 01 00
Recv: 90 00
Time used: 15.000 ms
Send: 00 C0 00 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: 90 00
Time used: 123.000 ms
Send: 00 C2 00 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: C6 11 20 8A 02 37 B4 21 82 80 BC 62 CB 14 6C 46 90 00
Time used: 102.000 ms
Send: 00 C2 00 01 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: BB E0 95 7A 71 0E 04 4B FB 6B 5B 81 04 F6 7A A1 90 00
Time used: 72.000 ms
Send: 00 C2 01 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: C6 00 02 B9 46 62 D2 56 0A 19 16 D9 07 C9 82 B9 90 00
Time used: 73.000 ms
Send: 00 C2 01 01 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: E5 6E 26 F5 60 8B 8D 26 8F 25 56 E1 98 A0 E0 1B 90 00
Time used: 73.000 ms

另外两张牌 - T = 0 TPDU:

Send: 00 A4 04 00 06 01 02 03 04 07 01 00
Recv: 90 00
Time used: 675.000 ms
Send: 00 C0 00 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: 90 00
Time used: 57.000 ms
Send: 00 C2 00 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: A8 03 C8 BC 28 C3 C9 AD EB 56 82 55 9B 7A 68 1E 90 00
Time used: 88.000 ms
Send: 00 C2 00 01 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: 74 3F B8 61 66 76 1C E0 B3 85 A3 AF E7 55 D1 29 90 00
Time used: 80.000 ms
Send: 00 C2 01 00 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: A8 12 EA 8F 6C 96 AF DA 63 CF 28 EE 57 A7 86 E1 90 00
Time used: 86.000 ms
Send: 00 C2 01 01 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 00
Recv: FF A3 C7 ED 04 71 0B 98 06 7D AE 68 15 E2 75 1F 90 00
Time used: 83.000 ms

如上所述,结果不同。我将上述结果与this online tool进行了比较。似乎我的 NXP JCOP 卡工作正常。其他两张卡有什么问题?

1 个答案:

答案 0 :(得分:3)

在访问setIncomingAndReceive的APDU缓冲区之前未调用INS == 0xC0 (setKeyAndInit)方法。

  

applet接收要从Java Card处理的APDU实例   运行时环境在Applet.process(APDU)方法中,第一个   APDU中有五个头字节[CLA,INS,P1,P2,P3]   缓冲液中。

在调用setIncomingAndReceive之前,APDU缓冲区中没有保证数据部分,您不应该访问它。但是,真正的行为通常取决于特定的Java Card实现,这就是为什么您的applet在NXP卡片上正常工作的原因。