首页 文章

C#加密到PHP解密

提问于
浏览
18

我几乎让它工作了,除了只有部分文本被解密了!我从这个例子开始工作:Decrypt PHP encrypted string in C#

这是我正在加密的文本(JSON)(删除了敏感信息):

{"DisplayName":"xxx", "Username": "yyy", "EmailAddress":"zzz"}

所以我登录到C#app,它从存储的Key和IV创建/编码cookie,然后重定向到应该解密/读取cookie的PHP应用程序 . 当我解密cookie时,它出现如下:
{“DisplayName”:“xxx”,“F A; HP=D 4 z ť k #E R j 5 \ t.t D “
更新:我已经进一步了,现在是结果字符串(96)“{”DisplayName“:”xxx“,”用户名“:”yyy“,”EmailAddress“ )ق - J k/ VV-v 9 B`7^“
正如你所看到的,它开始解密它,但后来搞砸了......

当解密字符串时它出来是正确的(使用填充,我有一个删除填充的函数),但如果我将测试字符串改为一个字符,我会再次得到垃圾:

B�nHL�Ek    �¿?�UΣlO����OЏ�M��NO/�f.M���Lƾ�CC�Y>F��~�qd�+

这是我用来生成随机密钥和IV的c#代码:

UPDATE :我现在只使用静态键/ IV,它们是:

Key: lkirwf897+22#bbtrm8814z5qq=498j5
IV: 741952hheeyy66#cs!9hjv887mxx7@8y

RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.BlockSize = 256;
symmetricKey.KeySize = 256;
symmetricKey.Padding = PaddingMode.Zeros;
symmetricKey.Mode = CipherMode.CBC;
string key = Convert.ToBase64String(symmetricKey.Key);
string IV = Convert.ToBase64String(symmetricKey.IV);
然后,我将密钥和IV保存到数据库中,以便稍后检索以进行编码/解码 .

这是完整的加密类:

public static class Encryption
    {
        public static string Encrypt(string prm_text_to_encrypt, string prm_key, string prm_iv)
        {
            var sToEncrypt = prm_text_to_encrypt;

            var rj = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = 256,
                BlockSize = 256,
                //FeedbackSize = 256
            };

            var key = Encoding.ASCII.GetBytes(prm_key);
            var IV = Encoding.ASCII.GetBytes(prm_iv);
            //var key = Convert.FromBase64String(prm_key);
            //var IV = Convert.FromBase64String(prm_iv);

            var encryptor = rj.CreateEncryptor(key, IV);

            var msEncrypt = new MemoryStream();
            var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

            var toEncrypt = Encoding.ASCII.GetBytes(sToEncrypt);

            csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
            csEncrypt.FlushFinalBlock();

            var encrypted = msEncrypt.ToArray();

            return (Convert.ToBase64String(encrypted));
        }

        public static string Decrypt(string prm_text_to_decrypt, string prm_key, string prm_iv)
        {

            var sEncryptedString = prm_text_to_decrypt;

            var rj = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = 256,
                BlockSize = 256,
                //FeedbackSize = 256
            };

            var key = Encoding.ASCII.GetBytes(prm_key);
            var IV = Encoding.ASCII.GetBytes(prm_iv);
            //var key = Convert.FromBase64String(prm_key);
            //var IV = Convert.FromBase64String(prm_iv);

            var decryptor = rj.CreateDecryptor(key, IV);

            var sEncrypted = Convert.FromBase64String(sEncryptedString);

            var fromEncrypt = new byte[sEncrypted.Length];

            var msDecrypt = new MemoryStream(sEncrypted);
            var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);

            csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);

            return (Encoding.ASCII.GetString(fromEncrypt));
        }

        public static void GenerateKeyIV(out string key, out string IV)
        {
            var rj = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = 256,
                BlockSize = 256,
                //FeedbackSize = 256
            };
            rj.GenerateKey();
            rj.GenerateIV();

            key = Convert.ToBase64String(rj.Key);
            IV = Convert.ToBase64String(rj.IV);
        }
    }

这是我用来解密数据的PHP代码:

function decryptRJ256($key,$iv,$string_to_decrypt)
{
    $string_to_decrypt = base64_decode($string_to_decrypt);
    $rtn = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_decrypt, MCRYPT_MODE_CBC, $iv);
    //$rtn = rtrim($rtn, "\0\4");
    $rtn = unpad($rtn);
    return($rtn);
}

function unpad($value)
{
    $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    //apply pkcs7 padding removal
    $packing = ord($value[strlen($value) - 1]);
    if($packing && $packing < $blockSize){
        for($P = strlen($value) - 1; $P >= strlen($value) - $packing; $P--){
            if(ord($value{$P}) != $packing){
                $packing = 0;
            }//end if
        }//end for
    }//end if 

    return substr($value, 0, strlen($value) - $packing); 
}

$ky = 'lkirwf897+22#bbtrm8814z5qq=498j5'; // 32 * 8 = 256 bit key
$iv = '741952hheeyy66#cs!9hjv887mxx7@8y'; // 32 * 8 = 256 bit iv

$enc = $_COOKIE["MyCookie"];

$dtext = decryptRJ256($ky, $iv, $enc);
var_dump($dtext);

我对这一部分有点不确定,因为我看到的所有示例代码都只是将base64编码的字符串直接传递给解密器,但在我的示例中,我必须在传递它之前对其进行base64_decode,否则我会收到错误键和IV的长度不正确 .

UPDATE :我正在使用PHP所需格式的ASCII密钥 . 如果我从RijndaelManaged类生成键,他们不在PHP方面工作,但我可以使用已知在PHP端工作的键并在RijndaelManaged C#端使用它们 .

如果我遗漏任何相关信息,请告诉我 . TIA!

2 回答

  • 5

    由于字符串部分正常,但最后会有乱码,这表明加密中的填充问题需要256字节的精确块 . 我建议在C#端将填充设置为 PKCS7 (PaddingMode.PKCS7)而不是 Zeros ,PHP将理解没有问题(因为它是该解析器的默认模式) .

    Edit: 哎呀,我没注意到你的PHP中有以下内容:

    $enc = $_COOKIE["MyCookie"];
    

    这是警告 . PHP可能无法按原样获取加密数据,并且正在运行一些urldecode清理 . 您应该打印此变量以查看它与C#代码发送的内容真正匹配 .

    Edit2:

    通过添加以下内容将空格转换为cookie中缺少的字符:

    str_replace(' ', '+', $enc);
    
  • 19

    对于后人,我在这里放置完整的解决方案 .

    C# Encryption Class

    public static class Encryption
    {
        public static string Encrypt(string prm_text_to_encrypt, string prm_key, string prm_iv)
        {
            var sToEncrypt = prm_text_to_encrypt;
    
            var rj = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = 256,
                BlockSize = 256,
            };
    
            var key = Convert.FromBase64String(prm_key);
            var IV = Convert.FromBase64String(prm_iv);
    
            var encryptor = rj.CreateEncryptor(key, IV);
    
            var msEncrypt = new MemoryStream();
            var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
    
            var toEncrypt = Encoding.ASCII.GetBytes(sToEncrypt);
    
            csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
            csEncrypt.FlushFinalBlock();
    
            var encrypted = msEncrypt.ToArray();
    
            return (Convert.ToBase64String(encrypted));
            }
    
        public static string Decrypt(string prm_text_to_decrypt, string prm_key, string prm_iv)
        {
    
            var sEncryptedString = prm_text_to_decrypt;
    
            var rj = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = 256,
                BlockSize = 256,
            };
    
            var key = Convert.FromBase64String(prm_key);
            var IV = Convert.FromBase64String(prm_iv);
    
            var decryptor = rj.CreateDecryptor(key, IV);
    
            var sEncrypted = Convert.FromBase64String(sEncryptedString);
    
            var fromEncrypt = new byte[sEncrypted.Length];
    
            var msDecrypt = new MemoryStream(sEncrypted);
            var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
    
            csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
    
            return (Encoding.ASCII.GetString(fromEncrypt));
            }
    
        public static void GenerateKeyIV(out string key, out string IV)
        {
            var rj = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = 256,
                BlockSize = 256,
            };
            rj.GenerateKey();
            rj.GenerateIV();
    
            key = Convert.ToBase64String(rj.Key);
            IV = Convert.ToBase64String(rj.IV);
        }
    }
    

    PHP Decryption Snippet

    <?php
    function decryptRJ256($key,$iv,$encrypted)
    {
        //PHP strips "+" and replaces with " ", but we need "+" so add it back in...
        $encrypted = str_replace(' ', '+', $encrypted);
    
        //get all the bits
        $key = base64_decode($key);
        $iv = base64_decode($iv);
        $encrypted = base64_decode($encrypted);
    
        $rtn = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
        $rtn = unpad($rtn);
        return($rtn);
    }
    
    //removes PKCS7 padding
    function unpad($value)
    {
        $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
        $packing = ord($value[strlen($value) - 1]);
        if($packing && $packing < $blockSize)
        {
            for($P = strlen($value) - 1; $P >= strlen($value) - $packing; $P--)
            {
                if(ord($value{$P}) != $packing)
                {
                    $packing = 0;
                }
            }
        }
    
        return substr($value, 0, strlen($value) - $packing); 
    }
    ?>
    <pre>
    <?php
    
    $enc = $_COOKIE["MyCookie"];
    
    $ky = ""; //INSERT THE KEY GENERATED BY THE C# CLASS HERE
    $iv = ""; //INSERT THE IV GENERATED BY THE C# CLASS HERE
    
    $json_user = json_decode(decryptRJ256($ky, $iv, $enc), true);
    
    var_dump($json_user);
    
    ?>
    

相关问题