2016-02-29 145 views
1


我尝试将此代码转换为PHP,但在C#和PHP 我不能总是我得到不同的结果,这里是加密我的C#代码和解密:转换C#代码到PHP的加密和解密

private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes("1234567812345678"); 
private const int keysize = 256; 
private string pass = "sample"; 

public static string Encrypt(string plainText, string passPhrase) 
{ 
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); 
    PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null); 
    byte[] keyBytes = password.GetBytes(keysize/8); 
    RijndaelManaged symmetricKey = new RijndaelManaged(); 
    symmetricKey.Mode = CipherMode.CBC; 
    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes); 
    MemoryStream memoryStream = new MemoryStream(); 
    CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); 
    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); 
    cryptoStream.FlushFinalBlock(); 
    byte[] cipherTextBytes = memoryStream.ToArray(); 
    return Convert.ToBase64String(cipherTextBytes); 
} 

public static string Decrypt(string cipherText, string passPhrase) 
{ 
    byte[] cipherTextBytes = Convert.FromBase64String(cipherText); 
    PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null); 
    byte[] keyBytes = password.GetBytes(keysize/8); 
    RijndaelManaged symmetricKey = new RijndaelManaged(); 
    symmetricKey.Mode = CipherMode.CBC; 
    ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes); 
    MemoryStream memoryStream = new MemoryStream(cipherTextBytes); 
    CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); 
    byte[] plainTextBytes = new byte[cipherTextBytes.Length]; 
    int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); 
    return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); 
} 

,这是我的PHP代码:

$iv = "1234567812345678"; 
$out = null; 
$key = "sample"; 
foreach ($iv as $i) { $out .= chr(ord(substr($i,0,1))); } 
$res = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_CBC, implode($out)); 
+2

请注意,mcrypt是遗弃的软件,它在几年内没有更新过,所以最好不要使用它。 – zaph

+1

请勿使用固定的IV。应该随机选择每种加密方式,以实现语义安全。它不必是保密的,所以你可以将它和密文一起发送。一种常用的方法是将其预先加密到密文中。 –

回答

0
  1. 键是不一样的。 C#将密钥扩展为PasswordDeriveBytes,这是一个很好的方法。 PHP mcrypt正在扩展他们的关键与空值。您需要扩展(256位)的密钥相同。

  2. 的填充是不一样的。未加密的数据需要是块大小的倍数(AES为128位),并且不一定必须添加填充。 C#没有指定任何填充,并希望数据是块大小的倍数(128位)。 PHP将默认添加非标准的null填充,并且不适用于二进制数据。您需要添加通用填充,标准是PKCS#7(aka PKCS#5),请参阅PKCS#7 padding。 C#支持PKCS#5,但对于mcrypt,您必须在您的代码中执行此操作(mcrypt开发人员是Bozos并且没有提供标准填充)。

  3. Rijndael算法支持多种尺寸的博克,它是不明确的C#默认的块大小是什么。如果你想要的是AES(它应该是),块大小需要128位。

  4. 鉴于MSDN文档不指定默认值最好是明确地设置块大小,密钥大小,模式和填充。

+0

感谢您的信息和帮助,但是我的尝试到现在我无法得到正确的结果,请你给我示例代码?你有可能吗? – Sara

+0

我没有C#可用,但在SO上应该有很多例子。 – zaph

0

你的PHP代码将无法在PHP 5.6运行为关键的大小是错误的,它必须是32个字节。

表示在之前的版本中,PHP使用\ 0来填充密钥以达到正确的密钥长度,但在C#中,您正在创建派生字节(确实是正确的),以便为您的密钥获取足够的字节,在C#和PHP中使用不同的键。

作为一个证明,创建32个字节(32个字符)的关键,直接使用这些32个字节的关键,无论是在PHP和C#中,这样,它应该工作。

但最后你需要一个通用的方式来派生PHP和C#上的字节,最终得到一致的密钥代码,例如可以使用SHA-256哈希来生成密钥。