2017-02-14 88 views
0

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

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的弱点,但我需要它在这种情况下,请有关的评论。感谢大家的帮助。

+1

'myKey'和'myIV'是不可接受的值,因此您发布的代码根本无法正常工作。你应该包括真实的代码,以便我们知道你在这里实际做了什么。 – billynoah

+0

@billynoah是的,我知道他们是不可接受的值,但任何关键或iv导致相同的输出,所以它不是真正的问题在这里,我只是把这些,而不是真正的价值,但不管什么iv和关键是问题仍然存在 –

+0

最好不要使用mcrypt,现在已经抛弃了近十年。因此它已被弃用,并将在PHP 7.2中从核心和PECL中删除。它不支持标准的PKCS#7(néePKCS#5)填充,只有非标准的null填充甚至不能用于二进制数据。 mcrypt有许多可以追溯到2003年的突出错误。相反,考虑使用[defuse](https://github.com/defuse/php-encryption)或[RNCryptor](https://github.com/RNCryptor),它们提供了一个完整的解决方案,正在维护和正确。 – zaph

回答

0

我不能说为什么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个字节)是相同的,然后存在差异。这是可以预料到的,因为原始明文不会在完整的块边界上结束,所以新的“第二块”与原始的“第二块”不相同。 CBC操作在这里成功地“混杂”了第二个街区。

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

+0

每一个迹象都表明'mcrypt',对于所有的失败,都能正确执行CBC模式。我的赌注是空填充和concatenatyion不传播填充。答案更多是评论。 – zaph

+0

为什么当单独加密或连接文本时'$ id'是相同的?这部分我不明白,我在java中执行相同的过程,输出是不同的,为什么?加密的数据需要在php和java中操作,但php似乎在做一些不同的事情。通常,将任何内容添加到'$ id'应该会改变整个输出结果,而不仅仅是结尾 –

+0

@Amroelaswar所选的变量名是可怕的,并且使得难以遵循代码。诸如'$ base64Decoded','$ decrypted','$ base64Encoded'这样的名字让读者想知道什么是什么?良好的命名是迈向可理解代码的第一步。 – zaph