简体   繁体   English

使用AES的Java卡加密返回6F00

[英]Java card encryption using AES returns 6F00

I'm new to Java card programming. 我是Java卡编程的新手。 I saw an example regarding AES encryption method for Java cards and was able to create and install the applet. 我看到了有关用于Java卡的AES加密方法的示例,并且能够创建和安装小程序。 When I try to communicate with the applet, it returns a 6F00 error message. 当我尝试与applet通信时,它返回6F00错误消息。 What am I doing wrong? 我究竟做错了什么?

Here's a sample of my code: 这是我的代码示例:

private void SendData(APDU apdu) 
{

    aesKeyTrial= (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
    byte[] outBuffer;
    outBuffer = new byte[16];
    byte[] trialKey;
    trialKey = new byte[16];
    byte[] input = {(byte)0x44,(byte)0x22,(byte)0x33,(byte)0x44,(byte)0x55,(byte)0x66,(byte)0x77,(byte)0x88,(byte)0x99,0x10,(byte)0xA2, 0x35, (byte)0x5E,0x15,0x16,0x14};
    byte[] key = {0x2d, 0x2a, 0x2d, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x41, 0x43, 0x4f, 0x44, 0x45, 0x2d, 0x2a, 0x2d};
    byte[] buffer = apdu.getBuffer();
    short len = (short) input.length;


    aesKeyTrial.setKey(trialKey,(short)0);
    if(len<=0||len%16!=0)
    {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }
    aesCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
    aesCipher.init(aesKeyTrial, Cipher.MODE_ENCRYPT);
    aesCipher.doFinal(input, ISO7816.OFFSET_CDATA, len, outBuffer, (short)0); 
    Util.arrayCopyNonAtomic(input, (short)0, buffer, (short)0, (short)len);
    apdu.setOutgoing();
    apdu.setOutgoingLength(len);
    apdu.sendBytes((short) 0, (short)len);
}

The one I'm trying to encrypt is "input". 我要加密的是“输入”。

As you said in your answer, the problem of your code is that you passed wrong parameters to the doFinal (byte[] inBuff, short inOffset, short inLength,byte[] outBuff, short outOffset) method. 正如您在回答中所说的那样,代码的问题是您将错误的参数传递给doFinal (byte[] inBuff, short inOffset, short inLength,byte[] outBuff, short outOffset)方法。

But, the sample code that you are using seems really bad. 但是,您正在使用的示例代码看起来确实很糟糕。 There are reasons that I call it bad-written: 我把它写得不好是有原因的:

1- It used dynamic variables in a method that is called so many times. 1-它在多次调用的方法中使用了动态变量。 Dynamic variables are those whom created using new keyword. 动态变量是使用new关键字创建的变量。 These variables will allocated in EEPROM. 这些变量将分配在EEPROM中。 Wrting in EEPROM is really slow rather than RAM and it also has a limited erase-write operations before it wear out , so it highly recommended to use RAM instead of EEPROM in cases that you don't need to share the data between different CAD (Card Reader) sessions. EEPROM的写入速度实际上比RAM慢,并且在磨损之前还具有有限的擦除-写入操作,因此,在不需要在不同CAD之间共享数据的情况下,强烈建议使用RAM代替EEPROM(读卡器)会话。 And also because there is no mandatory/automatic garbage collector in Java Card, do not define different dynamic variables repetitive, use one global instead (class variable or instance variable instead of local variables). 另外,由于Java Card中没有强制性/自动垃圾收集器,因此请勿重复定义不同的动态变量,而应使用一个全局变量(类变量或实例变量而不是局部变量)。

2- As int data type is optional in JavaCards, you must try to use short and byte as much as possible and you also need to cast all values to these types to prevent signed/unsigned problems. 2-由于int数据类型在JavaCards中是可选的,因此您必须尽量使用shortbyte ,并且还需要将所有值强制转换为这些类型,以防止出现有符号/无符号问题。

Finally, I provide you an evolved version of your program: 最后,我为您提供了程序的演进版本:

package soQusetion;

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

public class SOQ1 extends Applet {

    Cipher aesCipher;
    AESKey aesKey;

    //Two different types of memory for different usage. each one has 16 (= 0x10) byte capacity.
    private byte[] volatileMem;
    private byte[] nonVolatileMem;

    //INS value for APDU command
    public static final byte INS_SET_KEY = 0x10;
    public static final byte INS_ENCRYPT = 0x20;
    public static final byte INS_DECRYPT = 0x30;

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

    protected SOQ1() {
        volatileMem = JCSystem.makeTransientByteArray((short) 0x10, JCSystem.CLEAR_ON_DESELECT);
        nonVolatileMem = new byte[(short) 0x10];
        aesCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
        aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
        register();
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }
        byte[] buffer = apdu.getBuffer();
        apdu.setIncomingAndReceive();

        if (buffer[ISO7816.OFFSET_LC] != (byte) 0x10) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        switch (buffer[ISO7816.OFFSET_INS]) {
            case INS_SET_KEY:
                aesKey.setKey(buffer, ISO7816.OFFSET_CDATA);
                break;
            case INS_ENCRYPT:
                aesCipher.init(aesKey, Cipher.MODE_ENCRYPT);
                aesCipher.doFinal(buffer, ISO7816.OFFSET_CDATA, (short) 0x10, volatileMem, (short) 0x00);
                Util.arrayCopyNonAtomic(volatileMem, (short) 0x00, buffer, (short) 0x00, (short) 0x10);
                apdu.setOutgoingAndSend((short) 0x00, (short) 0x10);
                break;
            case INS_DECRYPT:
                aesCipher.init(aesKey, Cipher.MODE_DECRYPT);
                aesCipher.doFinal(buffer, ISO7816.OFFSET_CDATA, (short) 0x10, volatileMem, (short) 0x00);
                Util.arrayCopyNonAtomic(volatileMem, (short) 0x00, buffer, (short) 0x00, (short) 0x10);
                apdu.setOutgoingAndSend((short) 0x00, (short) 0x10);
                break;
            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }

    }
}

It works as below: 它的工作原理如下:

Select Applet begin...
Select Applet successful.
//Loading AES Key APDU Command
Send: 00 10 00 00 10 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 00
Recv: 90 00
//Encrypt APDU Command
Send: 00 20 00 00 10 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 00
Recv: 62 F6 79 BE 2B F0 D9 31 64 1E 03 9C A3 40 1B B2 90 00
//Decrypt APDU Command
Send: 00 30 00 00 10 62 F6 79 BE 2B F0 D9 31 64 1E 03 9C A3 40 1B B2 00
Recv: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 90 00

Any suggestion to make the above program more efficient is welcome to me. 欢迎提出任何使上述程序更有效的建议。

Hi I found out what my error was or what is wrong with my code. 嗨,我发现我的错误是什么或我的代码有什么问题。 I misunderstood the function doFinal and it messes up what is to be installed in the card. 我误解了doFinal函数,它弄乱了要安装在卡中的内容。

Here's the new and clean code: 这是新的干净代码:

Cipher aesCipher;
  AESKey aesKeyTrial;
  aesKeyTrial= (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
  byte[] buffer = apdu.getBuffer();
  byte[] aesKey;
  aesKey = new byte[16];
  byte[] input = {(byte)0x11,(byte)0x22,(byte)0x33,(byte)0x44,(byte)0x55,(byte)0x66,(byte)0x77,(byte)0x88,(byte)0x99,0x10,(byte)0xA2, 0x35, (byte)0x5E,0x15,0x16,0x14};
  byte[] key = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26};

  short len = (short) input.length;
  if (len <= 0 || len % 16 != 0)
    {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

  aesKeyTrial.setKey(key,(short)0);
  aesCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
  aesCipher.init(aesKeyTrial, Cipher.MODE_ENCRYPT); 
  aesCipher.doFinal(input, (short)0, len, buffer, (short)0);
  apdu.setOutgoingAndSend((short)0, len);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM