简体   繁体   English

使用Java加密/解密pdf文件

[英]Encrypt/Decrypt pdf file with Java

I want to encrypt/decrypt a pdf file on Android (but it's a java common issue) 我想在Android上加密/解密pdf文件(但这是Java的常见问题)

I have this code to generate my key : 我有以下代码来生成我的密钥:

 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;
 }

my code to write encrypted file : 我的代码写加密文件:

 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();

And my code to decrypt it (and save it, to a new decrypted file) : 和我的代码解密(并将其保存到新的解密文件中):

  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();

I read a lot on stackoverflow, and try to follow instructions, but this not working and I got this error : 我阅读了很多关于stackoverflow的内容,并尝试按照说明进行操作,但这不起作用,并且出现了此错误:

 javax.crypto.BadPaddingException: pad block corrupted at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCi

What am I doing wrong ? 我究竟做错了什么 ? Is there any specificity related to pdf file ? pdf文件有什么特殊性吗?

Try changing the decryption to use this: 尝试更改解密以使用此方法:

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());

Likewise, calling doFinal in the encryption block is problematic. 同样,在加密块中调用doFinal也有问题。 You would need to alter that as well. 您还需要更改它。 Note that you could use CipherOutputStream and CipherInputStream to hide the details of encrypting and writing/reading the bytes. 请注意,您可以使用CipherOutputStreamCipherInputStream来隐藏加密和写入/读取字节的详细信息。 I would actually recommend that for these requirements. 我实际上建议针对这些要求。

Also, I don't think that seeding the SecureRandom with "password" will have the intended effect you are looking for. 另外,我认为用"password" SecureRandom不会达到您想要的预期效果。 I think that could also be a source of your problems, as you need to ensure that encrypting and decrypting use the same key. 我认为这也可能是您遇到问题的根源,因为您需要确保加密和解密使用相同的密钥。

Update: Here is code that makes use of the same key for encryption and decryption and utilizes CipherInputStream and CipherOutputStream : 更新:这是使用相同密钥进行加密和解密并利用CipherInputStreamCipherOutputStream

// 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();

You shouldn't be calling cipher.doFinal inside your loop. 您不应在循环内调用cipher.doFinal。 Instead call cipher.update(data, ...) and then call cipher.doFinal() after the loop completes. 而是调用cipher.update(data,...),然后在循环完成后调用cipher.doFinal()。 Otherwise you're only processing the last block. 否则,您仅处理最后一个块。

you must use a password (in keyspec) with only 16, 24,32 character length . 您必须使用仅16、24、32个字符长度的密码(在keyspec中)。 good luck 祝好运

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM