I am trying to encrypt rather big files (up to 150mb) with PHP and decrypt them with Java.
When I encrypt it using Java and compare it to the encryption result from PHP, I see that the last few bytes are different.
Could this be a problem with the padding? How do I fix this?
The Java code is able to en and decrypt files correctly.
The code below is not secure at all and not meant to be.
PHP Encryption:
public function encodeAndEncrypt($source, $target, $keyPhrase) {
$hSrc = fopen($source,'rb');
$hDst = fopen($target,'wb');
$iv = substr(md5($keyPhrase, true), 0, 8);
$key = substr(md5($keyPhrase, true), 0, 24);
$opts = array('iv'=>$iv, 'key'=>$key);
stream_filter_append($hDst, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
while ($chunk = fread($hSrc,8192)) {
fwrite($hDst,$chunk, 8192);
}
fclose($hDst);
fclose($hSrc);
Java Decryption:
private static final String ALGORITHM = "DESede/CBC/PKCS5Padding";
void main() {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest("O".getBytes("UTF-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
byte[] ivBytes = Arrays.copyOf(digestOfPassword, 8);
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
FileInputStream fis = new FileInputStream(new File("7za920.zip.enc"));
FileOutputStream fos = new FileOutputStream(new File("7za920.zip"));
decrypt(key, ivBytes, fis, fos);
}
private static void decrypt(SecretKey key, byte[] iv, InputStream is, OutputStream os) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static void doCopy(InputStream is, OutputStream os) throws IOException {
try {
byte[] bytes = new byte[4096];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
} finally {
is.close();
os.close();
}
}
// only for demonstration
private static byte[] encrypt(SecretKey key, IvParameterSpec iv, InputStream is, OutputStream os) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
return cipher.getIV();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
Yes, your phenomenon is related to different padding strategies. The Java implementation uses PKCS5 (which is equivalent to PKCS7) while the PHP implementation uses zero padding (see under Parameteres->data), i.e. if the message is not large enough zero bytes are added.
For future questions I would ask you to do some more thorough initial research. For my answer I just followed your lead by looking in the code to see what padding was actually specified, googled for the default padding used by mcrypt
and already the answer.
Basically, as Perseids points out, mcrypt is bad for anything serious.
Funnily enough, I found that this code is working. It probably uses a lot more memory but it works.
And again, this is not safe. I only use it to confuse stupid virus-scanning proxies.
public function encrypt($source, $target, $keyPhrase) {
$iv = substr(md5($keyPhrase, true), 0, 8);
$key = substr(md5($keyPhrase, true), 0, 24);
$file = file_get_contents('../filesfile.zip');
$Encrypt = mcrypt_encrypt(MCRYPT_3DES, $key, $file, MCRYPT_MODE_CBC, $iv);
$fpE = fopen($target, 'wb') or die("can't open file");
fwrite($fpE, $Encrypt);
fclose($fpE);
}