2014-09-22 99 views
0

在執行其他操作的大型應用程序中 - 我需要加密和解密文件。所以我一直在環顧四周,並實現了這兩個基本上使用RSA密鑰的核心函數來包裝加密文件的隨機AES密鑰。對稱密鑰和iv被寫入文件的開頭。RSA keyblock包裝器:javax.crypto.BadPaddingException:解密錯誤

我在下面的解密函數部分收到一個異常(「javax.crypto.BadPaddingException:解密錯誤」)。在unpackKeyandIV行 - doFinal。具體來說,這一行是異常點: Object [] keyIv = unpackKeyAndIV(xCipher.doFinal(keyBlock));

我檢查並重新映射了RSA密鑰對。我也檢查了keyBlock的保存/加載。

我的直覺是問題與我如何寫/讀keyBlock ---或編碼也許有關?

一個目標是保持RSA/AES實例儘可能通用,以便不需要Bouncy Castle或額外的Java安全性無限強度擴展。

任何想法,我可能會出錯。

在此先感謝。 [最終更新:此代碼正在工作。錯誤傳遞給一個損壞的privKey]

// RSA_INSTANCE = "RSA"; 
// ASSYM_CRYPTO_STR = 1024; 
// SYM_CRYPTO_STR = 128; 
// SYM_CRYPTO = "AES"; 
// AES_INSTANCE = "AES/CTR/NoPadding"; 
// 
// File in = plain input file 
// File out = encrypted output file 
// Key pubKey = public Key (that wraps a random AES key) 
public static void encryptFile(File in, File out, Key pubKey) throws Exception { 
    FileInputStream fin; 
    FileOutputStream fout; 
    int nread = 0; 
    byte[] inbuf = new byte[1024]; 
    fout = new FileOutputStream(out); 
    fin = new FileInputStream(in); 

    SecureRandom random = new SecureRandom(); 
    // symmetric wrapping 
    Key sKey = createKeyForAES(Config.SYM_CRYPTO_STR, random); 
    IvParameterSpec sIvSpec = createCtrIvForAES(0, random); 

    // encrypt symmetric key with RSA/pub key 
    Cipher xCipher = Cipher.getInstance(Config.RSA_INSTANCE); 
    xCipher.init(Cipher.ENCRYPT_MODE, pubKey, random); 
    byte[] keyBlock = xCipher.doFinal(packKeyAndIv(sKey, sIvSpec)); 

    fout.write(keyBlock); 

    // encrypt data with symmetric key 
    Cipher sCipher = Cipher.getInstance(Config.AES_INSTANCE); 
    sCipher.init(Cipher.ENCRYPT_MODE, sKey, sIvSpec); 

    // Now read our file and encrypt it. 
    while((nread = fin.read(inbuf)) > 0) { 
     fout.write(sCipher.update(inbuf, 0, nread)); // cannot be null, by construction 
    } 
    // NB doFinal() cannot return null, but can return a zero-length array, which is benign below. 
    fout.write(sCipher.doFinal()); 

    fout.flush(); 
    fin.close(); 
    fout.close(); 
} 


// Decrypt File 
public static void decryptFile(File in, File out, Key privKey) throws Exception { 
    FileInputStream fin; 
    FileOutputStream fout; 
    int nread = 0; 
    byte[] inbuf = new byte[1024]; 
    fout = new FileOutputStream(out); 
    fin = new FileInputStream(in); 

    byte[] keyBlock = new byte[128]; 
    nread = fin.read(keyBlock); 

    Cipher xCipher = Cipher.getInstance(Config.RSA_INSTANCE); 
    Cipher sCipher = Cipher.getInstance(Config.AES_INSTANCE); 

    // symmetric key/iv unwrapping step 
    xCipher.init(Cipher.DECRYPT_MODE, privKey); 
    Object[] keyIv = unpackKeyAndIV(xCipher.doFinal(keyBlock)); 

    // decryption step 
    sCipher.init(Cipher.DECRYPT_MODE, (Key)keyIv[0], (IvParameterSpec)keyIv[1]); 

    while((nread = fin.read(inbuf)) >0) { 
     fout.write(sCipher.update(inbuf,0,nread)); 
    } 
    fout.write(sCipher.doFinal()); 

    fout.flush(); 
    fin.close(); 
    fout.close(); 

} 

public static byte[] packKeyAndIv(Key key, IvParameterSpec ivSpec) throws IOException { 
    ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 
    bOut.write(ivSpec.getIV()); 
    bOut.write(key.getEncoded()); 
    return bOut.toByteArray(); 
} 

public static Object[] unpackKeyAndIV(byte[] data) { 
    byte[] keyD = new byte[16]; 
    byte[] iv = new byte[data.length - 16]; 

    return new Object[] { 
     new SecretKeySpec(data, 16, data.length - 16, "AES"), 
     new IvParameterSpec(data, 0, 16) 
    }; 
} 
+0

1)'byte [] keyBlock = new byte [128];' - 你確定存儲的密鑰是​​128字節嗎?寫入時,應該存儲長度,然後存儲字節數組。 2)'nread = fin.read(keyBlock);' - 這並不保證完全讀取'keyBlock'。 – 2014-09-22 06:41:10

+0

System.out.println(keyBlock.length)在加密函數中的fout.write之後等於128。 fin.read之後的解密結果相同。關於也存儲長度的建議 - 我現在將其添加到函數中。 – Ramjet 2014-09-22 23:09:31

+0

關鍵是AES密鑰不是128 *字節*,它是128,192或256 *位​​。另外,你的'packKeyAndIV'方法很重要,因爲你正在做自己的填充。可能很難檢測到錯誤,並可能導致您觀察到的異常。 – 2014-09-22 23:24:57

回答

0

每編輯和評論。錯誤是一個損壞的privKey被傳遞給解密函數。上面的代碼工作正常。

0

嘗試加入你的構造在以下 -

Security.addProvider(新org.bouncycastle.jce.provider.BouncyCastleProvider());