PHP mcrypt - mcrypt 在连接的字符串中分别加密每个字符串

PHP mcrypt - mcrypt crypts each string seperatly in concatenated string

我目前已经开始使用具有 Java 背景的 PHP 并遇到了一些问题。我正在使用 mcrypt 进行基本加密,使用 mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] ) 加密成功但在某些情况下我需要连接 2 个字符串然后加密它们但是当我这样做时输出就像我加密了每个字符串一样然后分别将它们连接起来,而不是在加密之前。我正在做的是:

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);

然后输出是:Q2JmDpmqjNmGT4FJ2EkXXITOgc31ZA52DG4cvxVuJVnkcrINN0Zt9g

我知道 DES 的弱点,但在这种情况下我需要它,所以请不要对此发表评论。感谢大家的帮助。

我不能说为什么 mcrypt_encrypt 不遵守 CBC 操作模式(没有看到实际的输入和输出,我假设它正在充当 ECB)。也许 mcrypt 的默认空填充算法 (0x00) 导致了问题?我可以说 mcrypt 已经被废弃了大约 10 年,所以我不会花精力去弄清楚它。使用 libsodium,否则,至少使用 openssl

This post by Scott Arciszewski 解释了 PHP 中 mcrypt 的问题。

更新

我 运行 您提供的代码和 made some additional modifications 证明 CBC 模式按预期工作。这是我的代码 运行:

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");

我收到以下输出:

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

如您所见,仅 $toAdd 本身加密并与提供的密文连接 与连接明文并加密 不同 。您可以看到 Base64 编码输出的第 33 个字符是差异开始的地方,这是有道理的:Base64 的第 33 个字符是密文第 25 个字节的开始。在 DES 中,块大小为 64 bits / 8 bytes,因此前三个块将被相同地加密。下一个块将被前一个块的密文的 ^ 操作修改,否则将使用 IV

我以两个明文输入的相反顺序重复了这个操作。再一次,我看到 Base64 输出的前 12 个字符(12 个字符 -> 8 个字节)是相同的,然后有差异。这是预料之中的,因为原始明文没有在完整的块边界结束,所以新的 "second block" 与原始的 "second block" 不同。 CBC 操作在这里成功地 "jumble" 第二个块。

我会仔细检查有关处理此数据的代码,并确保您正在执行您认为的操作(并按顺序)。