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."
");
print_r("
");
# Make the new plaintext string
$toAdd = 'hellothere';
$additionalCipherText = encryptCode($toAdd);
$additionalEncoded = base64url_encode($additionalCipherText);
print_r("Additional cipher text: ".$additionalEncoded."
");
print_r("
");
# Concatenate the plaintext and encrypt
$plaintext = $decrypted.$toAdd;
$cipherText = encryptCode($plaintext);
$base64Encoded = base64url_encode($cipherText);
print_r(" New cipher text: ".$base64Encoded."
");
print_r("Original cipher text: ".$id.$additionalEncoded."
");
print_r("
");
# Try the reverse order
$plaintext = $toAdd.$decrypted;
$cipherText = encryptCode($plaintext);
$base64Encoded = base64url_encode($cipherText);
print_r(" New cipher text: ".$base64Encoded."
");
print_r("Original cipher text: ".$additionalEncoded.$id."
");
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.