2016-12-07 130 views
2

下面的代码是一个简单的.NET代码片段,其输入为test,它返回p+cTm2VODfvQnreAl02wUQ==作为输出。将.net aes256加密代码转换为php

Dim aesEncryptObj As New System.Security.Cryptography.RijndaelManaged() 
Dim encoder As System.Text.ASCIIEncoding = New System.Text.ASCIIEncoding() 

Dim tempKey As Byte() = encoder.GetBytes("00000011111111111111111111111111") 
aesEncryptObj.Key = tempKey 
aesEncryptObj.BlockSize = 128 
aesEncryptObj.Mode = System.Security.Cryptography.CipherMode.ECB 
aesEncryptObj.Padding = System.Security.Cryptography.PaddingMode.PKCS7 
aesEncryptObj.GenerateIV() 

Dim EncryptedBytes As Byte() 
Dim encryptor As System.Security.Cryptography.ICryptoTransform = aesEncryptObj.CreateEncryptor(aesEncryptObj.Key, aesEncryptObj.IV) 

Using msEncrypt As New System.IO.MemoryStream() 
    Using csEncrypt As New System.Security.Cryptography.CryptoStream(msEncrypt, encryptor, System.Security.Cryptography.CryptoStreamMode.Write) 
     Using swEncrypt As New System.IO.StreamWriter(csEncrypt) 
      swEncrypt.Write(txtInput.Text) 
     End Using 
     EncryptedBytes = msEncrypt.ToArray() 
    End Using 
End Using 

txtOutput.Text = Convert.ToBase64String(EncryptedBytes) 

现在,这里是PHP代码:

const ENCRYPT_METHOD = 'aes-256-ecb'; 

$aesKey = pack('H*', '00000011111111111111111111111111'); 
$ivSize = openssl_cipher_iv_length(ENCRYPT_METHOD); 

$plainText = "test"; 

$iv = openssl_random_pseudo_bytes($ivSize); 

$cipherText = openssl_encrypt(
    $plainText, 
    ENCRYPT_METHOD, 
    $aesKey, 
    OPENSSL_RAW_DATA, 
    $iv 
); 

$encryptedText = $iv . $cipherText; 

echo base64_encode($encryptedText); 

它返回1W3UvYVNKWEoFrpPZPd+Qw==从.NET一个不同。我已经尝试了aes-256-ecb和aes-128-ecb,结果总是与.NET不同。

据我所知,openssl_encrypt默认做PKCS7填充,是吗?你能看到PHP给出不同结果的原因吗?

回答

5

您的代码不工作,因为:

  • 在.NET GetBytes将返回该字符串的字节值。也就是说,你将得到长度为32(AES-256)的字节数组。然而,pack在PHP中与H*解码一个十六进制字符串,它将给你一个长度为16(AES-128)的密钥。这整个时间你一直用两个不同的密钥加密,但两个不同的密钥大小

解决上述问题将会使您的代码正常工作,但它会是,远离实际安全且不应使用。如果您想让代码安全,您需要:

  • 停止使用ECB模式。如果可以,请使用GCM模式,否则使用CBC。你很可能最终会使用CBC。如果这样做,则需要在密文前面加上IV,这样解密方可以检索并在解密时使用它。 IVs不需要保密,它们只需要是随机的,所以使用OpenSSL随机字节和GenerateIV方法是很好的。
  • 由于您很可能要使用CBC模式,因此您需要应用HMAC以确保完整性。否则,任何人都可以修改你的密文,你不会知道。当应用HMAC时,始终使用encrypt-then-mac。请记住在应用HMAC之前在之前包含您的IV
  • 最后,我不认为你真的打算这样做,但从不使用字符串的ASCII值作为关键。如果您想从密码创建密钥,则应该应用KDF。 PBKDF2可能是最适合的,并且在PHP和.NET中都有实现。
+0

谢谢您对该问题的完整分析。我将进一步调查并在当天晚些时候接受答案。 –

+0

你钉了它!我知道ECB模式并不安全,但是我正在使用一个封闭源设备向我发送加密数据。这将是接下来要做的事 - 当通信协议验证完全实施时,要求改变模式。再次感谢你,你保存了我的一天,因为我几乎没有.NET知识,是的,我们很可能会使用CBC。 –

+0

@StanimirStoyanov乐于帮助。对你来说很好,因为它迫使密切的开源开发者实施更安全的方法! –