BadPaddingException and some files stuck at 99%

302 Views Asked by At

I've tried to gather all possible information about Encryption/Decryption from here. Tinkered with it, some success and failures.
But now I've applied the code and its hit and a miss too. Some files (exe or msi's) are working but they still gives error about BadPaddingException. Moreover, some other media files like (mp4, mkv etc) are stuck at 99% and doesn't go beyond that, although they r fully received (just some minor bytes difference but Size on Disk always matches).

I just want some help to get rid of these both problems. The files r transfering from 1 PC to another via socket programming.
Server: (Edited)

    DataInputStream dis = new DataInputStream(msock.getInputStream());
    DataOutputStream dos = new DataOutputStream(msock.getOutputStream());

    String file2dl = dis.readLine(); //2
    File file = new File(sharedDirectory.toString() + "\\" + file2dl);
    dos.writeLong(file.length()); //3+

    //Get file name without extension.
    String fileName = Files.getNameWithoutExtension(file2dl);

    //AES-128 bit key initialization.
    byte[] keyvalue = "AES128BitPasswd".getBytes();
    SecretKey key = new SecretKeySpec(keyvalue, "AES");

    //Initialize the Cipher.
    Cipher encCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    encCipher.init(Cipher.ENCRYPT_MODE, key);

    //Get the IV from cipher.
    IvParameterSpec spec = null;
    try {
        spec = encCipher.getParameters().getParameterSpec(IvParameterSpec.class);
    } catch (InvalidParameterSpecException ex) {
        Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
    }

    byte[] iv = spec.getIV();

    dos.write(iv, 0, iv.length);
    File tempDir = new File(tempDirectory.toString());
    //Encryption Mechanism.
        try (FileInputStream fis = new FileInputStream(file)) {
            try (CipherOutputStream cos = new CipherOutputStream(dos, encCipher);
                    FileInputStream stream = new FileInputStream(tempDir + "\\" + fileName + ".encr")) {
                int read, r;
                byte[] buffer = new byte[1024 * 1024];
                while ((read = fis.read(buffer)) != -1) {
                    cos.write(buffer, 0, read);
                }
        }
    }
 }


Client:

 long len;
 int count = 0;
 int dflag = 0;
 String size;
 dos.writeBytes("Download\r\n"); //1+
 dos.writeBytes(filename + "\r\n"); //2+
 System.out.println("File to fetch: -> " + filename);
 len = dis.readLong(); //3
 System.out.println("Size of file: -> " + len);

//Get file name without Extension.
String fileName = Files.getNameWithoutExtension(filename);

//Get Initialization Vector from Encryption Cypher.
byte[] iv = new byte[16];
int j = dis.read(iv, 0, iv.length);

final File encrypted = new File(sharedDirectory.toString() + "\\" + fileName + ".encr");
final File decrypted = new File(sharedDirectory.toString() + "\\" + filename);
try (FileOutputStream fos = new FileOutputStream(encrypted)) {
    byte[] b = new byte[1024 * 1024];
    while (fetching) {
        int r = dis.read(b, 0, b.length); //4
        count = count + r;
        double p = (double) count / len;
        double per = new BigDecimal(p).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
        fos.write(b, 0, r);
        System.out.println("Size Appending: -> " + count);
        System.out.println("Percentage: ->" + per);
        Platform.runLater(() -> {
            pBar.setProgress(per);
        });
        if (count >= len) {
         dflag = 1;
         break;
        }
    }
}


If encrypted data is fully received

if(dflag == 1) {
     //AES-128 bit key initialization.
     System.out.println("File completely received");
     byte[] keyvalue = "AES128PeerBuLLet".getBytes();
     Key key = new SecretKeySpec(keyvalue, "AES");

     //Initialization Vector initialized
     IvParameterSpec ivParameterSpec = null;

     //Cipher Initialization.
     Cipher decCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      try {
           decCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
     } catch (InvalidAlgorithmParameterException ex) {
                        Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
      }
      System.out.println(decCipher.getProvider().getInfo());

      //Decryption Mechanism.
      try (FileOutputStream stream = new FileOutputStream(decrypted)) {
             try (FileInputStream fis = new FileInputStream(encrypted)) {
                    try (CipherInputStream cis = new CipherInputStream(fis, decCipher)) {
                           int read, i = 0;
                           byte[] buffer = new byte[(1024 * 1024) + 16];
                           while ((read = cis.read(buffer)) != -1) {
                                    stream.write(buffer, 0, read);
                                    i = i + read;
                                    double d = (double) i / len;
                                    double progress = new BigDecimal(d).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
                                    Platform.runLater(() -> {
                                        pBar.setProgress(progress);
                                        progressText.setText("Decrypting..");
                                    });
                                }
                            } catch (Exception e) {
                                System.out.println(e.getMessage());
                            }
                        }
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
        }

Any input is highly appreciated. Thank You.

Edit 1: Added the link to the sizes of encrypted and decrypted file received via stream. Dropbox Link

Edit 2: So finally the problem is solved with the help of three members who participated in helping me to the fullest. I was reviewing other solutions to my problem and I encounter with this solution which helped me to think deep bout the actual scenario happening in the background. Thanks to Artjom B. for his referral solution and @zaph & @jtahlborn for clearing my false assumptions bout padding and Input/Output streams.

2

There are 2 best solutions below

4
On BEST ANSWER

When using padding, PKCS#5 or PKCS#7, the encrypted output will be larger, up to and including one block size. See PKCS#7. The padding is removed after decryption.

The encrypted data will be longer so that must be accounted for. How depends on how the output is being handled. If it is going to a pre-allocated area such as a memory buffer the buffer must be allocated one block-size (16-bytes for AES) larger. If streaming usually just make sure all encrypted bytes are sent, n=it just the length of the input. All of this is per-implementation and system/language dependent.

The padding bytes are dynamically created by the encryption method so the input does not need to be altered. This assumes that the encryption method is adding the padding and the decryption method is removing the padding.

Example 1: If you have 1024-bytes of data the encrypted output will be 1040-bytes. On decryption the input data will be 1040-bytes and the output decrypted data will be 1024-bytes.

Example 2: If you have 1020-bytes of data the encrypted output will be 1024-bytes. On decryption the input data will be 1024-bytes and the output decrypted data will be 1020-bytes.

12
On

You can't use FileInputStream to read a file which you are currently writing. It's not built to read an in-progress file.

It looks like you are trying to write the encrypted stream to dos (you don't include it's definition in the server code). If so, you should be using that as the underlying stream for the CipherOutputStream.

Likewise, in the client, you try the same thing. If you want to write the file to disk first, then write the entire file to disk, then decrypt. if you want to stream decrypt, then wrap the CipherInputStream around the socket InputStream (presumably dis?).

Additionally, you don't show where you get len from on the client, but i'm assuming it is the length of the original data? if so, then your progress computation is incorrect because the length of the encrypted data will usually be different from the length of the original data.