[英]Encrypt/Decrypt pdf file with Java
我想在Android上加密/解密pdf文件(但這是Java的常見問題)
我有以下代碼來生成我的密鑰:
public static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
我的代碼寫加密文件:
inStream = new BufferedInputStream(conn.getInputStream());
outFile = new File(path + fileName);
outStream = new BufferedOutputStream(new FileOutputStream(outFile), 4096);
byte[] data = new byte[4096];
String seed = "password";
byte[] rawKey = Utils.getRawKey(seed.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
int bytesRead = 0;
while((bytesRead = inStream.read(data, 0, data.length)) >= 0)
{
outStream.write(cipher.doFinal(data),0, bytesRead);
}
outStream.flush();
outStream.close();
inStream.close();
和我的代碼解密(並將其保存到新的解密文件中):
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(tmp_file);
String seed = "password";
byte[] rawKey = Utils.getRawKey(seed.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
int b;
byte[] data = new byte[4096];
while((b = fis.read(data)) != -1) {
fos.write(cipher.doFinal(data), 0, b);
}
fos.flush();
fos.close();
fis.close();
我閱讀了很多關於stackoverflow的內容,並嘗試按照說明進行操作,但這不起作用,並且出現了此錯誤:
javax.crypto.BadPaddingException: pad block corrupted at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCi
我究竟做錯了什么 ? pdf文件有什么特殊性嗎?
嘗試更改解密以使用此方法:
int encryptedCount;
final byte[] decryptedData = new byte[4096];
final byte[] encryptedData = new byte[4096];
while ((encryptedCount = fis.read(encryptedData)) != -1) {
final int decryptedCount = cipher.update(encryptedData, 0, encryptedCount, decryptedData);
fos.write(decryptedData, 0, decryptedCount);
}
fos.write(cipher.doFinal());
同樣,在加密塊中調用doFinal
也有問題。 您還需要更改它。 請注意,您可以使用CipherOutputStream
和CipherInputStream
來隱藏加密和寫入/讀取字節的詳細信息。 我實際上建議針對這些要求。
另外,我認為用"password"
SecureRandom
不會達到您想要的預期效果。 我認為這也可能是您遇到問題的根源,因為您需要確保加密和解密使用相同的密鑰。
更新:這是使用相同密鑰進行加密和解密並利用CipherInputStream
和CipherOutputStream
:
// get the key
final KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128);
final SecretKey secretKey = generator.generateKey();
// perform encryption
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
FileInputStream fis = new FileInputStream(System.getProperty("user.home") + java.io.File.separatorChar + "plain.pdf");
FileOutputStream fos = new FileOutputStream(System.getProperty("user.home") + java.io.File.separatorChar + "test.enc");
final CipherOutputStream output = new CipherOutputStream(fos, cipher);
int bytesRead = 0;
final byte[] plainText = new byte[4096];
while ((bytesRead = fis.read(plainText)) >= 0) {
output.write(plainText, 0, bytesRead);
}
output.flush();
output.close();
fos.close();
fis.close();
final byte[] iv = cipher.getIV();
// decrypt the file
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
fis = new FileInputStream(System.getProperty("user.home") + java.io.File.separatorChar + "test.enc");
fos = new FileOutputStream(System.getProperty("user.home") + java.io.File.separatorChar + "test.pdf");
final CipherInputStream input = new CipherInputStream(fis, cipher);
final byte[] decryptedData = new byte[4096];
int decryptedRead;
while ((decryptedRead = input.read(decryptedData)) >= 0) {
fos.write(decryptedData, 0, decryptedRead);
}
fos.flush();
fos.close();
input.close();
fis.close();
您不應在循環內調用cipher.doFinal。 而是調用cipher.update(data,...),然后在循環完成后調用cipher.doFinal()。 否則,您僅處理最后一個塊。
您必須使用僅16、24、32個字符長度的密碼(在keyspec中)。 祝好運
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.