簡體   English   中英

安全性-用Java“ BadPaddingException”解密

[英]Security- decrypting in java “BadPaddingException”

我正在加密字符串並將其寫入文本文件。 為了解密內容,我正在讀取該文件並打印解密后的數據。 當我用一個字符串值測試我的代碼時,它可以很好地加密和解密。 但是,當我添加更多字符串進行加密時,加密工作正常,但是解密給了我這個異常“ javax.crypto.BadPaddingException:給定的最終塊未正確填充”

這是我的代碼。 請幫忙!

// these are initialized in main
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
            ecipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            dcipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
// catches ..

// it will take a string and the file that will have the encrypted strings
private static void encrypt(String s, OutputStream os) throws IllegalBlockSizeException, BadPaddingException {
        try {
            byte[] buf = s.getBytes();
            byte[] b = ecipher.doFinal(buf);
            os.write(b);
// this is to write a new line after writing each encrypted value and avoid overwriting
            os.write(System.getProperty("line.separator").getBytes()); 
            os.flush();
            os.close();
        }
    catch (IOException e) {
        System.out.println("I/O Error:" + e.getMessage());
    }
}
// this will take the file that has all of the encryptions
private static void decrypt(InputStream is) throws IllegalBlockSizeException, BadPaddingException {
    try {
        byte[] buf = new byte[is.available()];
        is.read(buf);
        byte[] decrypted = dcipher.doFinal(buf);  // THE CAUSE OF THE PROBLEM!!!!
        System.out.println(new String (decrypted));
        is.close();
    }
    catch (IOException e) {
        System.out.println("I/O Error:" + e.getMessage());
    }

加密時,您將加密的數據寫入輸出文件,然后添加換行符,但是解密時,您似乎正在讀取文件的全部內容並將其解密,這將包括換行符,它將嘗試解密好像它是密文的一部分一樣,導致填充異常。 您還嘗試使用一個解密調用來解密所有單獨編寫的字符串,而它們需要分別解密。

我建議將加密的數據轉換為Base64, 然后再將其寫入輸出文件並附加換行符。 解密時,讀取一行,從Base64轉換回byte[]並解密,然后對輸入中的每一行重復一次。

在加密的字節之后多余的行,應將其刪除。

問題的真正原因是使用InputStream.available()來獲取數據的大小。 此方法可以返回從0到輸入流中實際字節數的任何值,因此不適合確定輸入數據的大小。 在您的示例中,它返回一些值,並且您讀取了等於該值的字節數,但是很有可能它不是全部加密數據,並且密碼將無法正確解碼。

通常,無法確定輸入流的大小,因此您將不得不使用循環來讀取流。 解密代碼應基於以下范例:

private static byte[] decrypt( Cipher dcipher, InputStream in, int BUFFER_SIZE ) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] inputBuffer = new byte[ BUFFER_SIZE ]; // 4K or 8K are pretty good buffer size values 
    int r = in.read( inputBuffer );
    while ( r >= 0 ) {
        byte[] outputUpdate = dcipher.update( inputBuffer, 0, r );
        out.write( outputUpdate );
        r = in.read( inputBuffer );
    }
    byte[] outputFinalUpdate = dcipher.doFinal();
    out.write( outputFinalUpdate );
    return out.toByteArray();
}
  • 當您不知道大小時,必須循環讀取InputStream
  • 您永遠不應忽略InputStream.read(byte[])的返回值。
  • 如果要一次全部獲取解密后的數據,則可以將ByteArrayOutputStream用作獲取可調整大小的字節數組的最簡單方法。

您也可以先使用類似於上述循環的代碼讀取整個加密數據,但沒有中間的Cipher.update() ,然后使用單個Cipher.doFinal()調用一次性解碼它。

private static byte[] decrypt( Cipher dcipher, InputStream in, int BUFFER_SIZE ) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] inputBuffer = new byte[ BUFFER_SIZE ]; // 4K or 8K are pretty good buffer size values
    int r = in.read( inputBuffer );
    while ( r >= 0 ) {
        out.write( inputBuffer, 0, r );
        r = in.read( inputBuffer );
    }
    return dcipher.doFinal( out.toByteArray() );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM