1

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ファイルに関連する特異性はありますか?

4

3 に答える 3

0

16、24、32 文字の長さのパスワード (keyspec) を使用する必要があります。幸運を

于 2013-10-13T03:24:26.913 に答える
0

ループ内で cipher.doFinal を呼び出すべきではありません。代わりに cipher.update(data, ...) を呼び出し、ループの完了後に cipher.doFinal() を呼び出します。それ以外の場合は、最後のブロックのみを処理しています。

于 2013-05-14T17:11:27.083 に答える
0

これを使用するように復号化を変更してみてください。

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て、バイトの暗号化と書き込み/読み取りの詳細を非表示にできることに注意してください。これらの要件については、実際にそれをお勧めします。

SecureRandomまた、 withをシードし"password"ても、あなたが探している意図した効果が得られるとは思いません。暗号化と復号化で同じキーを使用する必要があるため、これも問題の原因になる可能性があると思います。

更新:CipherInputStream暗号化と復号化に同じキーを使用し、 andを利用するコードは次の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();
于 2013-05-14T17:09:18.673 に答える