2015-09-04 24 views
3

我是Java Card的整個主題的新手,並試圖查看一些代碼示例以獲得更好的理解。 我發現在oracle forum AES使用一個樣本,但有以下部分的幾個問題:Java Card中的En-/Decryption輸出+相應的APDU

 private void doAES(APDU apdu) 
    { 

      byte b[] = apdu.getBuffer(); 

      short incomingLength = (short) (apdu.setIncomingAndReceive()); 
      if (incomingLength != 24) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); 

      //perform encryption and append results in APDU Buffer a[] automatically 

      cipherAES.init(aesKey, Cipher.MODE_ENCRYPT); 
      cipherAES.doFinal(b, (short) dataOffset, incomingLength, a, (short) (dataOffset + 24)); 
      cipherAES.init(aesKey, Cipher.MODE_DECRYPT); 
      cipherAES.doFinal(b, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48)); 

      // Send results 
      apdu.setOutgoing(); 
      apdu.setOutgoingLength((short) 72); 
      apdu.sendBytesLong(b, (short) dataOffset, (short) 72); 
    } 

從我的理解這個代碼利用從傳入APDU第24個數據字節,對它們進行加密,並將它們放入字節數組a。 然後它需要接下來的24個數據字節,解密它們並將它們放入一個。

但下面的命令不會因爲

使用這些輸出數據
apdu.sendBytesLong(b, (short) dataOffset, (short) 72); 

採用B的輸出數據......這可能是不正確的,所以請幫助我理解我哪裏錯了。

另外:一個簡單的命令APDU用於加密一個小文本和相應的答案是什麼樣的?

+0

這個例子只是傷了我的眼睛。請不要使用它。在Java **級別有非常基本的錯誤。緩衝區處理完全關閉。它當然應該從'a'而不是'b'解密,然後發送'a'。變量'a'應該是短暫的,只有在需要時纔可以填寫密鑰的內容。就我個人而言,我不太喜歡太陽論壇,像SO這樣的適度的系統會很快地消滅這些例子(然後再說,你不應該把例子發佈在藍色之外)。 –

回答

5

實際上,來自Oracle論壇的代碼並不是很好。它不遵循內存使用的基本規則,它根本不是真實世界的例子。此外,它會很慢,如果使用太頻繁,甚至可能會損壞智能卡。

我想你應該通過Java卡教程首先閱讀和學習APDU是什麼,以及一些有關它的結構,看到了這個問題:

How to get started with Java Cards?

然後,你可以繼續到Java卡加密/解密。像這樣的東西可以幫助你:

public class MiniApplet extends Applet { 
    public static void install(byte[] bArray, short bOffset, byte bLength) { 
     // GP-compliant JavaCard applet registration 
     new MiniApplet().register(bArray, (short) (bOffset + 1), 
       bArray[bOffset]); 
    } 

    private final AESKey aesKey = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false); 
    private final Cipher aes = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); 

    public void process(APDU apdu) { 
    // Good practice: Return 9000 on SELECT 
    if (selectingApplet()) { 
     return; 
    } 

    final byte[] buf = apdu.getBuffer(); 
    final short dataLen = apdu.setIncomingAndReceive(); 
    final byte ins = buf[ISO7816.OFFSET_INS]; 

    switch (ins) { 
    case (byte) 0x00: //KEY VALUE INIT FROM APDU 
     if (dataLen != 16) //checking key value length 
      ISOException.throwIt(ISO7816.SW_WRONG_LENGTH) 
     aesKey.setKey(buf, ISO7816.OFFSET_CDATA); 
     break; 
    case (byte) 0x01: //DECRYPTION 
    case (byte) 0x02: //ENCRYPTION 
     if ((dataLen & 0x000F) != 0) //checking if input data is block-aligned 
      ISOException.throwIt(ISO7816.SW_WRONG_LENGTH) 

     if (!aesKey.isInitialized()) 
      ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); 
     aes.init(aesKey, (ins == 0x02) ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT); 
     aes.doFinal(buf, ISO7816.OFFSET_CDATA, dataLen, buf, ISO7816.OFFSET_CDATA); 
     apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, dataLen); 
     break; 
    default: 
     // good practice: If you don't know the INStruction, say so: 
     ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); 
    } 
} 

} 

注:我在我的例子初始化從輸入命令鍵值。我的密鑰存儲在RAM中,這意味着在每次卡重置或另一個小程序選擇後,該值都會消失。這並不一定適合您的業務案例,只需在卡上生成一個密鑰並將其存儲在持久內存中即可。如果是這樣,您必須使用不同的密鑰類型:KeyBuilder.TYPE_AES而不是KeyBuilder.TYPE_AES_TRANSIENT_DESELECT

+0

尊敬的Vojta,1-爲什麼您將'buf'和'dataLen'定義爲'final'? 2-我們不需要檢查'aesKey'是否在0x01和0x02塊的開始處被初始化? – Abraham

+0

@Abraham final variable =更快的訪問速度。是的,我們可能應該檢查它,以及dataLen是否被分配爲塊大小(16)。我會改進我的答案。 – vojta

+1

@vojta更快的訪問從未真正物化到這個級別。但標記'最終'的東西清楚地表明變量不會在以後改變。它始終在我的Eclipse「乾淨代碼」功能中啓用,儘管我有時會在代碼示例中將其留在此處,以避免這個問題:) –