2013-05-14 3 views
1

Я хочу, чтобы зашифровать/расшифровать файл в формате PDF на 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?

ответ

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 с "password" будет иметь предполагаемый эффект, который вы ищете. Я думаю, что это также может быть источником ваших проблем, так как вам нужно обеспечить, чтобы шифрование и дешифрование использовали один и тот же ключ.

Update: Вот код, который использует тот же ключ для шифрования и дешифрования и использует 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(); 
+0

Я пробовал свой код, но теперь у меня есть javax.crypto.IllegalBlockSizeException: последний незавершенный блок в расшифровке – JuSchz

+0

«пароль» - это просто пример для этого случая. Что вы предлагаете для генерации ключей? – JuSchz

+0

Вам необходимо убедиться, что для шифрования и дешифрования используется тот же ключ, которым этот текущий подход не является. – laz

0

Вы не должны призывающую cipher.doFinal внутри цикла. Вместо этого вызовите cipher.update (data, ...) , а затем вызовите cipher.doFinal() после завершения цикла. В противном случае вы обрабатываете только последний блок.

+0

Должен ли я модифицировать функции шифрования и дешифрования? – JuSchz

+0

Да. Ознакомьтесь с документами Cipher ... doFinal завершает обработку, а обновление добавляет данные в процесс. Таким образом, вы хотите update(), пока не закончите, а затем doFinal(), либо с дополнительными данными, либо без них. Да, применяется как для шифрования, так и для дешифрования. – user1676075

0

вы должны использовать пароль (в ключах) только с длиной 16, 24,32 символа . удачи

Смежные вопросы