C# PHP&;兼容Rijndael管理的CBC模式,256位加密/解密

C# PHP&;兼容Rijndael管理的CBC模式,256位加密/解密,c#,php,encryption,cryptography,rijndaelmanaged,C#,Php,Encryption,Cryptography,Rijndaelmanaged,这是我第一次尝试加密,我在将加密从PHP移植到C#时遇到了麻烦 我在互联网上搜索了一个有效的解决方案,但我所尝试的一切都不起作用。我在两种语言之间得到了不同的结果 在PHP中,我有以下代码: function encrypt($Key, $strToEncrypt){ $md5Key = md5(pack("H*", $Key)); $md5Iv = md5($Key); $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_25

这是我第一次尝试加密,我在将加密从PHP移植到C#时遇到了麻烦

我在互联网上搜索了一个有效的解决方案,但我所尝试的一切都不起作用。我在两种语言之间得到了不同的结果

在PHP中,我有以下代码:

function encrypt($Key, $strToEncrypt){
    $md5Key = md5(pack("H*", $Key));
    $md5Iv = md5($Key);

    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);

    $padding = $block - (strlen($strToEncrypt) % $block);
    $strToEncrypt .= str_repeat(chr($padding), $padding);

    $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $md5Key, $strToEncrypt, MCRYPT_MODE_CBC, $md5Iv);
    $enc2 = base64_encode($enc);

    return $enc2;
}
    public string Encrypt(string strToEncrypt)
    {
        string ret;
        var pKey = PackH(_appkey);
        var md5Key = CalcMd5(pKey);
        var iv = CalcMd5(_appkey);

        var enc =Encoding.UTF8;
        var eIv = enc.GetBytes(iv);
        var eKey = enc.GetBytes(md5Key);

        using (var rij = new RijndaelManaged { BlockSize = 256, KeySize = 256, IV = eIv, Key = eKey, Mode = CipherMode.CBC, Padding = PaddingMode.Zeros})
        using (var memoryStream = new MemoryStream())
        using (var cryptoStream = new CryptoStream(memoryStream, rij.CreateEncryptor(eKey, eIv), CryptoStreamMode.Write))
        {
            using (var sw = new StreamWriter(cryptoStream))
            {
                sw.Write(strToEncrypt);

            }
            ret = Convert.ToBase64String(memoryStream.ToArray());
        }


        return ret;
    }
C#中的代码如下:

function encrypt($Key, $strToEncrypt){
    $md5Key = md5(pack("H*", $Key));
    $md5Iv = md5($Key);

    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);

    $padding = $block - (strlen($strToEncrypt) % $block);
    $strToEncrypt .= str_repeat(chr($padding), $padding);

    $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $md5Key, $strToEncrypt, MCRYPT_MODE_CBC, $md5Iv);
    $enc2 = base64_encode($enc);

    return $enc2;
}
    public string Encrypt(string strToEncrypt)
    {
        string ret;
        var pKey = PackH(_appkey);
        var md5Key = CalcMd5(pKey);
        var iv = CalcMd5(_appkey);

        var enc =Encoding.UTF8;
        var eIv = enc.GetBytes(iv);
        var eKey = enc.GetBytes(md5Key);

        using (var rij = new RijndaelManaged { BlockSize = 256, KeySize = 256, IV = eIv, Key = eKey, Mode = CipherMode.CBC, Padding = PaddingMode.Zeros})
        using (var memoryStream = new MemoryStream())
        using (var cryptoStream = new CryptoStream(memoryStream, rij.CreateEncryptor(eKey, eIv), CryptoStreamMode.Write))
        {
            using (var sw = new StreamWriter(cryptoStream))
            {
                sw.Write(strToEncrypt);

            }
            ret = Convert.ToBase64String(memoryStream.ToArray());
        }


        return ret;
    }
C#Pack功能:

protected byte[] PackH(string hex)
    {
        if ((hex.Length % 2) == 1) hex += '0';
        var bytes = new byte[hex.Length / 2];
        for (var i = 0; i < hex.Length; i += 2)
        {
            bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        }
        return bytes;
    }
protected string CalcMd5(string textToEnc)
    {
        var sB = new StringBuilder();
        using (var mdHash = MD5.Create())
        {
            var cHash = mdHash.ComputeHash(Encoding.UTF8.GetBytes(textToEnc));

            foreach (byte t in cHash)
            {
                sB.Append(t.ToString("x2"));
            }
        }

        return sB.ToString();
    }
我有另一个接受字节[]的CalcMd5函数(与上面的函数类似,但没有GetBytes部分)

需要加密的密钥和字符串在PHP和C中都是相同的:

钥匙:“24acd2fcc7b20b8bd33ff45176f03061a09b729487e10d2dd38ab917”和

我要编码的字符串:“110114135AB96637711100”

在C#中,函数的结果是:“lhtqpxcjronmbddufhyuzzuf94z1rmsxwo85/wyEew=”而在PHP中是:“5mkcjfs0vp2hskdy5xpauv68ysrp31q+ddZsd5p7Sc=”

我尝试过在C#中修改填充模式,也尝试过stackoverflow站点上的不同方法,但都不起作用

我已经检查过了,传递给mcrypt函数和RijndaelManaged函数的最后一个键和Iv是相同的,都有32字节大小

奇怪的是,解密函数工作得非常好(用C#函数解密PHP加密字符串,用PHP函数解密围绕C#加密字符串的另一场战争)


可能是编码有问题吗?或者是填充物?还是我忽略了什么

问题似乎在于您的填充,在PHP端,您正在手动执行以下操作:

在C侧,您正在使用:

Padding = PaddingMode.Zeros

要解决此问题,您可以通过删除上述两行来修改PHP代码,因为
mcrypt()
会自动为您执行
ZeroBytePadding

或者您可以将C#中的填充改为:


顺便说一句,当我看到在安全上下文中使用MD5时,我总是感到害怕。这不一定总是一个问题,但作为一个哈希函数,它现在被认为是相当不安全的。我相信我们现在在SHA-3(尽管那里也有一些争议)。哦,我还注意到你的静脉注射似乎是钥匙的功能。它应该是随机的。我建议两边都使用PKCS7。除非对纯文本进行假设(即它不会以零字节结尾),否则不能删除零填充。好的加密可以在任何字节序列上工作。