2016-12-22 1 views
0

Ich bin reading ein large file in klein-klein byteschunks. Ich bin encrypting diese Datei, Chunk für Chunk, mit AES 128 bit encryption und writing jeder verschlüsselte Chunk in eine andere Datei. Die Datei lautet Encryptedsuccessfully.java - javax.crypto.BadPaddingException: Gegeben endgültigen Block nicht richtig gepolstert

Aber wenn ich bin reading dass encrypted Datei wieder in Klein-Klein byteschunks und zu versuchen, decrypt die Chunk Chunk datei, wirft es eine Ausnahme

java - javax.crypto.BadPaddingException: Given final block not properly padded 

Aber wenn ich versuche, das Ganze zu lesen Datei und versuchen Sie decrypt Bytes, es decryptes erfolgreich.

Hier ist mein Code:

import javax.crypto.BadPaddingException; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 
import java.io.File; 
import java.io.IOException; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 

/** 
* Created by Ashish Pancholi on 22-12-2016. 
*/ 
public class EncryDecryPtion implements Securable{ 
    public static void main(String[] argu){ 
     EncryDecryPtion encryDecryPtion = new EncryDecryPtion(); 
     File file = new File("shouldbeoriginal.jpg"); 
     try { 
      encryDecryPtion.encryptFile(file,"Pa$$w0rd"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (InvalidKeyException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } catch (NoSuchPaddingException e) { 
      e.printStackTrace(); 
     } 

     File file_ = new File("shouldbeoriginal.jpg"); 
     try { 
      encryDecryPtion.decryptFile(file_,"Pa$$w0rd"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (InvalidKeyException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } catch (NoSuchPaddingException e) { 
      e.printStackTrace(); 
     } 
    } 
} 




import org.apache.commons.io.FileUtils; 
import org.apache.commons.io.IOUtils; 
import javax.crypto.BadPaddingException; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 
import java.io.*; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 

/** 
* Encrypt and decrypt file with AES algorithm 
* Created by Ashish Pancholi on 20-12-2016. 
*/ 
public interface Securable { 

    /** 
    * Read and write the file in chunk. 
    * Encrypts the chunks with AES algorithm. 
    * It creates a new a file which having encrypted data, 
    * deletes old original file and 
    * rename a new file with the old file 
    * @param file which is to be encrypted and password. 
    */ 

    default File encryptFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException { 
     AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password); 
     String encryptedFilePath = file.getAbsolutePath() + ".ENCRYPTED"; 
     File encryptedFile = new File(encryptedFilePath); 
     encryptedFile.createNewFile(); 
     try 
       (FileInputStream in = new FileInputStream(file)) { 

      try 
        (OutputStream out = new FileOutputStream(encryptedFile)) { 
       byte[] chunk = new byte[1024]; 
       int chunkLen = 0; 
       while ((chunkLen = in.read(chunk)) != -1) { 
        byte[] encryptedChunk = aesEncryptionDecryption.encrypt(chunk); 
        out.write(encryptedChunk); 
       } 
      } 
     } 
     Path path_originalFile = Paths.get(file.getAbsolutePath()); 
     Path path_encryptedFile = Paths.get(encryptedFile.getAbsolutePath()); 
     try { 
      Files.delete(path_originalFile); 
     }catch (IOException ex){ 
      try { 
       FileUtils.forceDelete(file); 
      }catch (IOException ex1){ 
       //ignore 
      } 
     } 
     Path path = Files.move(path_encryptedFile, path_originalFile); 
     return path.toFile(); 
    } 

    default File encryptWholeFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException { 
     AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password); 
     String encryptedFilePath = file.getAbsolutePath() + ".ENCRYPTED"; 
     File encryptedFile = new File(encryptedFilePath); 
     encryptedFile.createNewFile(); 
     try(FileInputStream in = new FileInputStream(file)) { 
      byte[] bytes = IOUtils.toByteArray(in); 
      byte[] encryptedChunk = aesEncryptionDecryption.encrypt(bytes); 
      FileUtils.writeByteArrayToFile(encryptedFile, encryptedChunk); 
     } 
     Path path_originalFile = Paths.get(file.getAbsolutePath()); 
     Path path_encryptedFile = Paths.get(encryptedFile.getAbsolutePath()); 
     try { 
      Files.delete(path_originalFile); 
     }catch (IOException ex){ 
      try { 
       FileUtils.forceDelete(file); 
      }catch (IOException ex1){ 
       //ignore 
      } 
     } 
     Path path = Files.move(path_encryptedFile, path_originalFile); 
     return path.toFile(); 
    } 

    /** 
    * Read and write the file in chunk. 
    * Encrypts the chunks with AES algorithm. 
    * It creates a new a file which having encrypted data, 
    * deletes old original file and 
    * rename a new file with the old file 
    * @param inputStream of file which is to be encrypted and a password. 
    */ 
    default InputStream encryptFile(InputStream inputStream, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException { 
     InputStream in; 
     try { 
      AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password); 
      try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { 
       byte[] chunk = new byte[1024]; 
       int chunkLen = 0; 
       while ((chunkLen = inputStream.read(chunk)) != -1) { 
        byte[] encryptedChunk = aesEncryptionDecryption.encrypt(chunk); 
        baos.write(encryptedChunk); 
       } 
       baos.flush(); 
       in = new ByteArrayInputStream(baos.toByteArray()); 
      } 
     }finally { 
      inputStream.close(); 
     } 
     return in; 
    } 

    /** 
    * Read and write the file in chunk. 
    * Encrypts the chunks with AES algorithm. 
    * It creates a new a file which having encrypted data, 
    * deletes old original file and 
    * rename a new file with the old file 
    * @param inputStream of file which is to be encrypted and a password. 
    */ 
    default File encryptFile(InputStream inputStream, String password, String targetFileName) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException { 
     File encryptedFile = new File(targetFileName); 
     try { 
      AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password); 
      encryptedFile.getParentFile().mkdirs(); 
      encryptedFile.createNewFile(); 
      try (OutputStream baos = new FileOutputStream(encryptedFile)) { 
       byte[] chunk = new byte[1024]; 
       int chunkLen = 0; 
       while ((chunkLen = inputStream.read(chunk)) != -1) { 
        byte[] encryptedChunk = aesEncryptionDecryption.encrypt(chunk); 
        baos.write(encryptedChunk); 
       } 
      } 
     }finally { 
      inputStream.close(); 
     } 
     return encryptedFile; 

    } 

    /** 
    * Read and write the file in chunk. 
    * Decrypts the chunks with AES algorithm. 
    * It creates a new a file which having decrypted data, 
    * deletes old original encrypted file and 
    * rename a new file with the old file 
    * @param file which is to be decrypted and password. 
    */ 

    default void decryptFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException { 
     AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password); 
     String decryptedFilePath = file.getAbsolutePath() + ".DECRYPTED"; 
     File decryptedFile = new File(decryptedFilePath); 
     decryptedFile.createNewFile(); 
     try 
       (FileInputStream in = new FileInputStream(file)) { 

      try 
        (OutputStream out = new FileOutputStream(decryptedFile)) { 
       byte[] chunk = new byte[1024]; 
       int chunkLen = 0; 
       while ((chunkLen = in.read(chunk)) != -1) { 
        byte[] encryptedChunk = aesEncryptionDecryption.decrypt(chunk); 
        out.write(encryptedChunk); 
       } 
      } 
     } 
     Path path_originalFile = Paths.get(file.getAbsolutePath()); 
     Path path_decryptedFile = Paths.get(decryptedFile.getAbsolutePath()); 
     try { 
      Files.delete(path_originalFile); 
     }catch (IOException ex){ 
      try { 
       FileUtils.forceDelete(file); 
      }catch (IOException ex1){ 
       //ignore 
      } 
     } 
     Files.move(path_decryptedFile, path_originalFile); 
    } 

    default File decryptWholeFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException { 
     AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password); 
     String decryptedFilePath = file.getAbsolutePath() + ".DECRYPTED"; 
     File decryptedFile = new File(decryptedFilePath); 
     decryptedFile.createNewFile(); 
     try(FileInputStream in = new FileInputStream(file)) { 
       byte[] bytes = IOUtils.toByteArray(in); 
       byte[] encryptedChunk = aesEncryptionDecryption.decrypt(bytes); 
       FileUtils.writeByteArrayToFile(decryptedFile, encryptedChunk); 
      } 
     Path path_originalFile = Paths.get(file.getAbsolutePath()); 
     Path path_decryptedFile = Paths.get(decryptedFile.getAbsolutePath()); 
     try { 
      Files.delete(path_originalFile); 
     }catch (IOException ex){ 
      try { 
       FileUtils.forceDelete(file); 
      }catch (IOException ex1){ 
       //ignore 
      } 
     } 
     Path path = Files.move(path_decryptedFile, path_originalFile); 
     return path.toFile(); 
    } 

} 


import org.apache.commons.io.FileUtils; 
import java.io.File; 
import java.io.UnsupportedEncodingException; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.security.InvalidKeyException; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import java.util.Arrays; 
import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.spec.SecretKeySpec; 


/** 
* Encrypt and decrypt file with AES algorithm 
* Created by Ashish Pancholi on 20-12-2016. 
*/ 

public class AESEncryptionDecryption { 

    private SecretKeySpec secretKey; 
    private byte[] key; 

    public AESEncryptionDecryption(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException{ 
     MessageDigest sha = null; 
     key = password.getBytes("UTF-8"); 
     sha = MessageDigest.getInstance("SHA-1"); 
     key = sha.digest(key); 
     key = Arrays.copyOf(key, 16); // use only first 128 bit 
     this.secretKey = new SecretKeySpec(key, "AES"); 
    } 

    /** 
    * Encrypts the file with AES algorithm 
    * @param bytes of file which is to encrypted 
    * @return byte[] which is encrypted bytes 
    */ 
    public byte[] encrypt(byte[] bytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      cipher.init(Cipher.ENCRYPT_MODE, this.secretKey); 
      byte[] encrytedBytes = cipher.doFinal(bytes); 
      return encrytedBytes; 

    } 

    /** 
    * Decrypts the file with AES algorithm 
    * @param encrytedBytes of file that to be decrypted 
    * @return byte[] which is original data. 
    */ 
    public byte[] decrypt(byte[] encrytedBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException 
    { 
     Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); 
     cipher.init(Cipher.DECRYPT_MODE, this.secretKey); 
     byte[] bytes = cipher.doFinal(encrytedBytes); 
     return bytes; 
    } 
} 

Meine Frage ist-Wie eine große Datei zu verschlüsseln, ohne die gesamte Datei in den Speicher zu laden? Bitte helfen.

EDITED

Hier ist der aktualisierte Code aber immer noch bekomme ich die gleiche Ausnahme der Linie cipher.doFinal() wenn Entschlüsseln:

public void encrypt(File sourceFile, File targetFile) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException { 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, this.secretKey); 
    try(InputStream inputStream = new FileInputStream(sourceFile)){ 
     try(OutputStream outputStream = new FileOutputStream(targetFile)){ 
      byte[] chunk = new byte[8192]; 
      int chunkLen = 0; 
      while ((chunkLen = inputStream.read(chunk)) != -1) { 
       byte[] encrytedBytes = cipher.update(chunk); 
       outputStream.write(encrytedBytes); 
      } 
      byte[] finalBytes = cipher.doFinal(); 
      if(finalBytes!=null) { 
       outputStream.write(finalBytes); 
      } 
     } 
    } 
} 

public void decrypt(File encryptedFile, File targetFile) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException { 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, this.secretKey); 
    try(InputStream inputStream = new FileInputStream(encryptedFile)){ 
     try(OutputStream outputStream = new FileOutputStream(targetFile)){ 
      byte[] chunk = new byte[8192]; 
      int chunkLen = 0; 
      while ((chunkLen = inputStream.read(chunk)) != -1) { 
       byte[] decrytedBytes = cipher.update(chunk); 
       outputStream.write(decrytedBytes); 
      } 
      byte[] finalBytes = cipher.doFinal(); 
      if(finalBytes!=null) { 
       outputStream.write(finalBytes); 
      } 
     } 
    } 
} 
+1

Warum das zufällige Kapital P in der Mitte des Wortes? – EJP

+0

Ich stimme zu, dass das das falsche Benennen von Klassen ist. Danke für das Aufzeigen. –

Antwort

3

Sie sollten die cipher.update(...) Methoden verwenden, wenn Sie durch die Datei-Stream, und nur den cipher.doFinal(...) als letzten Anruf verwenden. Die löscht die Puffer + Padding usw., die Sie nicht mehr als einmal tun möchten.

Wenn Sie eine doFinal(...) in Ihrer Entschlüsselung vorzeitig tun, wird es (sehr wahrscheinlich) fehlschlagen, da eine korrekte Auffüllung in den Daten fehlt.

Edit:

Verwenden ECB-Modus nicht, es ist unsicher. Schauen Sie sich here an und scrollen Sie zum Pinguin.

Generieren Sie Ihre Schlüssel nicht mit einem einfachen Sha-1 - verwenden Sie eine geeignete Schlüsselableitungsfunktion wie PBKDF2WithHmacSHA256.

+0

Ich habe deinen Vorschlag ausprobiert. Vielen Dank. Trotzdem kann ich die Datei nicht entschlüsseln. Beim Entschlüsseln der Datei habe ich genau so vorgegangen, wie Sie es in Ihrer Antwort vorgeschlagen haben. Ich habe 'cipher.update (...)' verwendet, wenn ich durch eine Datei streame, aber wenn ich 'cipher.doFinal (...)' verwendet habe Als letzter Aufruf wird erneut eine Exception geworfen - 'javax.crypto.BadPaddingException: Gegeben letzter Block nicht richtig gepolstert'. –

+0

Eine seltsame Sache passiert auch hier - In "Entschlüsselung", wenn ich die "cipher.doFinal (...)" aus dem Code auskommentiert dann Datei entschlüsselt erfolgreich (nur, mit Hilfe von "cipher.update (...)"). Müssen wir nicht 'doFinal (...)' benutzen, während 'entschlüsseln'? Ich frage mich, ob das wirklich verschlüsselt ist. Ist das sehr einfach, die Datei von Hackern zu entschlüsseln? –

+1

Grundsätzlich würde 'cipher.update (...)' bei der Entschlüsselung nicht fehlschlagen, selbst bei zufälliger Eingabe, da es die entschlüsselten Daten nicht überprüft. Wenn Sie das 'doFinal (...)' weglassen, werden Sie den letzten Datenblock verpassen, da dieser in einem Puffer hängen bleibt, um eine korrekte Auffüllung zu ermöglichen. Wie groß sind Ihre verschlüsselten Daten im Vergleich zu den Daten klar?Es sollte 1 bis 16 Byte größer sein als die Eingabe (auf das nächste Vielfache von 16 aufgefüllt). –

Verwandte Themen