【问题标题】:Replicating the same AES encryption from C# in PHP在 PHP 中从 C# 复制相同的 AES 加密
【发布时间】:2013-01-27 19:33:04
【问题描述】:

我正在做一个项目,我有一个 C# 应用程序,它有一个加密类,可以执行字符串值的加密和解密。我现在想使用 PHP 制作一个 Web 界面来与我的 C# 应用程序一起工作。

我正在尝试执行与我的 C# 项目在我的 PHP 网站中执行的相同类型的加密,但我无法弄清楚我需要做什么。

以下是我的 C# 应用程序的代码。

public static string encrypt(string encryptionString)
        {
            byte[] clearTextBytes = Encoding.UTF8.GetBytes(encryptionString);

            SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();

            MemoryStream ms = new MemoryStream();
            byte[] rgbIV = Encoding.ASCII.GetBytes("PRIVATE");

            byte[] key = Encoding.ASCII.GetBytes("PRIVATE");
            CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write);

            cs.Write(clearTextBytes, 0, clearTextBytes.Length);

            cs.Close();

            return Convert.ToBase64String(ms.ToArray());
        }

我正在我的 PHP Web 界面中尝试以下代码

define("CIPHERKEY", "PRIVATE");
function encrypt($data) 
    { 
        //$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_ECB, '');
        $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
        //$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($cipher), MCRYPT_RAND);
        $iv = 'PRIVATE';
        //$key = substr(CIPHERKEY, 0, mcrypt_enc_get_key_size($cipher));
        $key =CIPHERKEY;
        if (mcrypt_generic_init($cipher, $key, $iv) != 1) 
        {
            $cipherData = mcrypt_generic($cipher, $data);

            mcrypt_generic_deinit($cipher);
            mcrypt_module_close($cipher);

            $sanitizedCipherData = trim(base64_encode($cipherData)); 

            return $sanitizedCipherData;
        } 
    }

我尝试了各种变体,但找不到正确的方法。

iv 变量使用与 C# 应用程序中的 rgbIV 变量相同的密钥,PHP Web 界面中的 CIPHERKEY 使用与我的 c# 应用程序中的密钥变量相同的密钥。

感谢您提供的任何帮助

更新 目前,我不断得到不同的结果。我通过传入字符串password 对其进行测试。

在上面的 PHP 代码中,我得到 NHHloywxlybbANIH5dS7SQ== 作为加密字符串。

但是,使用相同的字符串,我得到n86Mwc5MRXzhT3v3A/uxEA== 的结果

【问题讨论】:

  • 有什么问题 - 你得到一个错误或不同的结果?您能否提供一些示例来展示您所看到的差异?
  • @PinnyM 我在问题中添加了更多信息,在回答您的问题时,我在 PHP 和 C# 之间得到了不同的结果
  • 你真的需要复制这个 C# 代码吗?它有相当多的缺陷。例如,它不使用 IV。 IV 不是一种钥匙。对于每个加密,它应该是不同的值,对于 CBC,它应该是不可预测的随机值。
  • .NET 默认为 CBC 块模式,您的 PHP 指定 ECB。
  • 切向相关:您的 C# 代码正在使用 4 个实现 IDisposable 的类(我可以看到)。这些最好包含在using 语句中。

标签: c# php encryption aes


【解决方案1】:

您得到不同结果的原因是默认情况下,C# 中的密码模式是 CBC,而在 PHP 中您使用的是 ECB 模式,有关两种不同模式的信息,请参阅 Wikipedia

CBC 比 ECB 更安全,因此我建议坚持使用默认的 .NET 实现并更改您的 PHP 代码以使用 CBC,但是您有两种选择。

选项 1 - 将 .NET 更改为使用 ECB 模式(如果您有一些遗留代码并且需要使用它)但是请阅读它,ECB 模式会在您的密文中留下伪影并使攻击者能够对您加密的内容有所了解(请参阅维基百科文章中的企鹅图像)。

要更改 .NET 代码以使用 ECB,只需为模式添加一行:

// Start of your code ...
SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
rijn.Mode = CipherMode.ECB;

MemoryStream ms = new MemoryStream();
byte[] rgbIV = Encoding.ASCII.GetBytes("PRIVATE");
// Rest of your code ...

选项 2 - 将 PHP 脚本更改为使用 CBC 模式

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

更新 我更详细地检查了这一点,发现您还需要在明文中添加填充。下面的代码会给你一个匹配:

PHP 代码:

function encrypt($data) 
{ 
    $iv = "AAAAAAAAAAAAAAAA";
    $key = CIPHERKEY;

    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, addpadding($data), MCRYPT_MODE_CBC, $iv));
}

function addpadding($string, $blocksize = 16)
{
    $len = strlen($string);
    $pad = $blocksize - ($len % $blocksize);
    $string .= str_repeat(chr($pad), $pad);
    return $string;
}

C# 代码会自动添加基于 PKCS7 的填充。

更新 2 带状填充: 如 cmets 所述,解密后需要剥离填充。

function strippadding($string)
{
    $slast = ord(substr($string, -1));
    $slastc = chr($slast);
    $pcheck = substr($string, -$slast);
    if(preg_match("/$slastc{".$slast."}/", $string)){
        $string = substr($string, 0, strlen($string)-$slast);
        return $string;
    } else {
        return false;
    }
}

【讨论】:

  • 谢谢,我尝试在 PHP 中更改模式 CBC,但得到了不同的结果,现在是 5XuJaW+G27lcJaAG1D0uZw==,但仍然与 C# 不匹配。我真的无法更改 C# 代码,因为这会影响已经工作和正在使用的软件,并且 Android 应用程序也使用了相同的加密技术,所以我只能更改 PHP
  • @Boardy 我已经更新了您需要进行的另一项更改。
  • 感谢您的帮助,解密时是否需要去掉填充,因为当我再次尝试解密时,我打印出有趣的字符,例如 Té_ªÅ 而不是 password跨度>
  • 是的,您必须剥离填充,只需将其通过我在编辑中添加的剥离填充(但仅在您进行解密之后)。
  • 再次非常感谢,非常感谢。现在完美运行
【解决方案2】:

试试这个:

   function encrypt_str($str) 
    {
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM);
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, "PRIVATE", $str, MCRYPT_MODE_ECB, $iv);
    return rtrim($encrypted);
    }

并将其添加到您的 C#

rijn.Mode = CipherMode.ECB;

【讨论】:

  • mcrypt_create_iv 的第二个参数无效。第二个参数是随机源,应始终为MCRYPT_DEV_URANDOM
  • 谢谢,我真的无法更改 C# 代码,这已经在已发布的软件中使用,并且正在使用与 Android 应用程序相同的加密技术。 Android 应用、C# 应用和网站都需要协同工作。
  • 所以将 PHP 从 MCRYPT_MODE_ECB 更改为 MCRYPT_MODE_CBC
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 2019-05-15
  • 2022-01-18
相关资源
最近更新 更多