I have currently started to work with PHP with a Java background and came accross some issues. I am using mcrypt for a basic encryption using mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )
the encryption works successfully but there is a case where I need to concatenate 2 strings and then encrypt them but when I do this the output is just as if I had encrypted each string separately then concatenated them afterwards and not before the encryption. What I am doing is this :
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}
function encryptCode($data){
return mcrypt_encrypt( MCRYPT_DES , '12345678' , $data , 'cbc' ,'87654321');
}
function decryptCode($data){
return mcrypt_decrypt( MCRYPT_DES , '12345678' , $data , 'cbc' ,'87654321');
}
$id = 'Q2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52';
$toAdd = 'hellothere';
$base64Decoded = base64url_decode($id);
$decrypted = decryptCode($base64Decoded);
$decrypted = $decrypted.$toAdd;
$encryptedID = encryptCode($decrypted);
$base64Encoded = base64url_encode($encryptedID);
print_r($base64Encoded);
and then the output is : Q2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52DG4cvxVuJVnkcrINN0Zt9g
I am aware of the weakness of DES but I need it in this case so please no comments about that. Thanks to all for your help.
I can't say why mcrypt_encrypt
is not respecting the CBC
mode of operation (without seeing actual input and output, I'm assuming it's acting as ECB
). Perhaps mcrypt
's default null padding algorithm (0x00
) is causing issues? I can say that mcrypt
is abandonware for ~10 years now, so I wouldn't spend the energy trying to figure that out. Use libsodium, or, failing that, at least openssl.
This post by Scott Arciszewski explains the issues with mcrypt
in PHP.
Update
I ran your provided code and made some additional modifications to demonstrate that CBC mode was working as expected. Here is the code I ran:
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}
function encryptCode($data){
return mcrypt_encrypt( MCRYPT_DES , '12345678' , $data , 'cbc' ,'87654321');
}
function decryptCode($data){
return mcrypt_decrypt( MCRYPT_DES , '12345678' , $data , 'cbc' ,'87654321');
}
$id = 'Q2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52';
$base64Decoded = base64url_decode($id);
$decrypted = decryptCode($base64Decoded);
print_r($decrypted."\n");
print_r("\n\n");
# Make the new plaintext string
$toAdd = 'hellothere';
$additionalCipherText = encryptCode($toAdd);
$additionalEncoded = base64url_encode($additionalCipherText);
print_r("Additional cipher text: ".$additionalEncoded."\n");
print_r("\n\n");
# Concatenate the plaintext and encrypt
$plaintext = $decrypted.$toAdd;
$cipherText = encryptCode($plaintext);
$base64Encoded = base64url_encode($cipherText);
print_r(" New cipher text: ".$base64Encoded."\n");
print_r("Original cipher text: ".$id.$additionalEncoded."\n");
print_r("\n\n");
# Try the reverse order
$plaintext = $toAdd.$decrypted;
$cipherText = encryptCode($plaintext);
$base64Encoded = base64url_encode($cipherText);
print_r(" New cipher text: ".$base64Encoded."\n");
print_r("Original cipher text: ".$additionalEncoded.$id."\n");
I received the following output:
��t
anEncryptedId
Additional cipher text: paTJPP5mr-65c1OKybvB1A
New cipher text: Q2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52DG4cvxVuJVnkcrINN0Zt9g
Original cipher text: Q2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52paTJPP5mr-65c1OKybvB1A
New cipher text: paTJPP5mr-69piYC2Ep0BM1tiph63ZFqdg_whovwRh0-4AD37H2JPQ
Original cipher text: paTJPP5mr-65c1OKybvB1AQ2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52
As you can see, encrypting just $toAdd
by itself and concatenating with the provided cipher text is not the same as concatenating the plaintexts and encrypting. You can see that the 33rd character of the Base64-encoded output is where the differences start, which makes sense: the 33rd character of Base64 is the start of the 25th byte of the cipher text. In DES, the block size is 64 bits / 8 bytes
, so the first three blocks will be encrypted identically. The following block would be modified by the ^
operation of the previous block's cipher text where the IV
would otherwise be used.
I repeated this operation with the opposite order of the two plaintext inputs. Again, I saw that the first 12 characters of the Base64 output (12 chars -> 8 bytes) are identical, and then there are differences. This is expected, as the original plaintext does not end on a full block boundary, so the new "second block" is not identical to the original "second block". The CBC operation works successfully here to "jumble" the second block.
I would double check the code around the handling of this data and ensure that you are performing the operations (and in the order) you think you are.