2016-05-29 97 views
1

我写了下面的小程序在我的恩智浦JCOP办卡RSA密码操作“ILLEGAL_USE”:RSA加密返回Java卡小程序

package testPack; 

import javacard.framework.*; 
import javacard.security.CryptoException; 
import javacard.security.KeyBuilder; 
import javacard.security.KeyPair; 
import javacard.security.RSAPrivateKey; 
import javacard.security.RSAPublicKey; 
import javacardx.crypto.Cipher; 

public class Test extends Applet { 

    RSAPrivateKey myRSAPriKey; 
    RSAPublicKey myRSAPubKey; 
    Cipher myCipher; 
    KeyPair myKeyPair; 
    byte[] input; 
    byte[] result; 

    private static final byte INS_GEN_KEYPAIR = (byte) 0x10; 
    private static final byte INS_INIT_CIPHER_ENC = (byte) 0x20; 
    private static final byte INS_ENC = 0x21; 
    private static final byte INS_INIT_CIPHER_DEC = (byte) 0x30; 
    private static final byte INS_DEC = (byte) 0x31; 

    private static final byte P1_CHAIN_APDU = (byte) 0x00; 
    private static final byte P1_LAST_APDU = (byte) 0x01; 

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

    protected Test() { 
     myRSAPriKey = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_2048, false); 
     myRSAPubKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_2048, false); 
     myKeyPair = new KeyPair(myRSAPubKey, myRSAPriKey); 
     myCipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); 
     input = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_RESET); 
     result = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_RESET); 
     register(); 
    } 

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

     byte[] buff = apdu.getBuffer(); 
     byte ins = buff[ISO7816.OFFSET_INS]; 
     byte p1 = buff[ISO7816.OFFSET_P1]; 
     short lc = (short) (buff[ISO7816.OFFSET_LC] & 0x00FF); 
     short dataOffset = ISO7816.OFFSET_CDATA; 

     switch (ins) { 
      case INS_GEN_KEYPAIR: 
       myKeyPair.genKeyPair(); 
       break; 

      case INS_INIT_CIPHER_ENC: 
       myCipher.init(myRSAPubKey, Cipher.MODE_ENCRYPT); 
       break; 
      case INS_ENC: 
       apdu.setIncomingAndReceive(); 
       if (p1 == P1_CHAIN_APDU) { 
        Util.arrayCopyNonAtomic(buff, dataOffset, input, (short) 0x00, lc); 
       } else if (p1 == P1_LAST_APDU) { 
        Util.arrayCopyNonAtomic(buff, dataOffset, input, (short) 128, lc); 
        try { 
         myCipher.doFinal(input, (short) 0x00, (short) 256, result, (short) 0x00); 
        } catch (CryptoException e) { 
         short reason = e.getReason(); 
         ISOException.throwIt((short) ((short) 0x6B00 | reason)); 
        } 
        apdu.setOutgoing(); 
        apdu.setOutgoingLength((short) 256); 
        apdu.sendBytesLong(result, (short) 0x00, (short) 256); 
       } 
       break; 
      case INS_INIT_CIPHER_DEC: 
       myCipher.init(myRSAPriKey, Cipher.MODE_DECRYPT); 
       break; 
      case INS_DEC: 
       apdu.setIncomingAndReceive(); 
       if (p1 == P1_CHAIN_APDU) { 
        Util.arrayCopyNonAtomic(buff, dataOffset, input, (short) 0x00, lc); 
       } else if (p1 == P1_LAST_APDU) { 
        Util.arrayCopyNonAtomic(buff, dataOffset, input, (short) 128, lc); 
        try { 
         myCipher.doFinal(input, (short) 0x00, (short) 256, result, (short) 0x00); 
        } catch (CryptoException e) { 
         short reason = e.getReason(); 
         ISOException.throwIt((short) ((short) 0x6B00 | reason)); 
        } 
        apdu.setOutgoing(); 
        apdu.setOutgoingLength((short) 256); 
        apdu.sendBytesLong(result, (short) 0x00, (short) 256); 
       } 
       break; 

     } 

    } 
} 

的问题是,我收到doFinal()方法0x0005 CryptoException原因代码:

Select Applet begin... 
Select Applet successful. 
Send: 00 10 00 00 00 
Recv: 90 00 

Send: 00 20 00 00 00 
Recv: 90 00 

Send: 00 21 00 00 80 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 
Recv: 90 00 

Send: 00 21 01 00 80 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 
Recv: 6B 05 

问题:

  1. 正如你所知道的R eason代码0x0005表示ILLEGAL_USE。但为什么?
  2. 如何在密码对象上使用update()方法从我的小程序中删除瞬态字节数组?

回答

4

答1:作为Cipher.ALG_RSA_PKCS1文档中所述:

该算法只适合有限长度的消息。 在加密过程中处理的输入字节总数可能不会超过k-11的 ,其中k是RSA密钥的模数大小(以字节为单位)。

由于您正在加密256个字节的消息,因此您尝试加密的邮件不符合此规则。由于模数大小为256字节,因此您可以加密的最大消息为245个字节(k-11)。您必须考虑添加到消息中的附加填充字节。

回答2:由于您需要存储部分结果,因此无法删除输入和输出缓冲区。

case INS_INIT_CIPHER_ENC: 
 
       myCipher.init(myRSAPubKey, Cipher.MODE_ENCRYPT); 
 
       cipher_result_len = (short) 0x00; 
 
       break; 
 
case INS_ENC: 
 
       apdu.setIncomingAndReceive(); 
 
       if (p1 == P1_CHAIN_APDU) { 
 
        cipher_result_len += myCipher.update(buff, dataOffset, lc, result, cipher_result_len); 
 
       } else if (p1 == P1_LAST_APDU) { 
 
        
 
        try { 
 
         cipher_result_len += myCipher.doFinal(buff, dataOffset, lc, result, cipher_result_len); 
 
        } catch (CryptoException e) { 
 
         short reason = e.getReason(); 
 
         ISOException.throwIt((short) ((short) 0x6B00 | reason)); 
 
        } 
 
        apdu.setOutgoing(); 
 
        apdu.setOutgoingLength(cipher_result_len); 
 
        apdu.sendBytesLong(result, (short) 0x00, cipher_result_len); 
 
       } 
 
       break;

cipher_result_len是必须被存储在瞬态缓冲器短数据。

+0

那么,哪种填充方案适合更长时间的数据加密? – EbraHim

+0

由于您的消息是256字节,这是模数的大小,所以如果需要,可以跳过填充(ALG_RSA_NOPAD)。还有另一个我不熟悉的RSA填充ALG_RSA_PKCS1_OAEP。也许你可以试试看。 – Chooch