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.
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.