2016-05-29 76 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