且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

跨平台(php到C#.NET)加密/解密与Rijndael

更新时间:2023-02-17 17:06:45

这里我可以看到双方的问题。

Here I can see problems on both sides.

请记住,当编码不是字符串时,你会得到什么,而是一个字节数组。
所以在PHP中你不需要urlencode cyphertext。

Please keep in mind that what you get when encoding is not string, but rather an array of bytes. So in PHP you don't need to urlencode cyphertext.

base64编码是你需要的。当您打开 base64_encode帮助时,您会看到

base64 encoding is all you need. When you open base64_encode help you see


base64_encode 使用base64对给定的数据进行编码。这个编码是
,旨在使二进制数据在运输中生存

base64_encode Encodes the given data with base64. This encoding is designed to make binary data survive transport

还有一件事 - 让你的消息在.net中解码一个正确的长度,你必须手动附加填充字符。 RijndaelManaged的默认填充模式是PKCS7,让我们坚持下去。您必须将源字符串扩展为字符代码等于填充字节数的偶数块。

One more thing - to have your message decoded in .net with a correct length, you have to manually append it with padding characters. Default padding mode for RijndaelManaged is PKCS7, lets' stick with it. You have to extend your source string to even blocks with characters code equal to number of padding bytes.

<?php
  $iv = "45287112549354892144548565456541";
  $key = "anjueolkdiwpoida";
  $text = "This is my encrypted message";

  // to append string with trailing characters as for PKCS7 padding scheme
  $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
  $padding = $block - (strlen($text) % $block);
  $text .= str_repeat(chr($padding), $padding);

  $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);

  // this is not needed here            
  //$crypttext = urlencode($crypttext);

  $crypttext64=base64_encode($crypttext);
  print($crypttext64) . "\n<br/>";
?>

在C#端,您从 base64 转换为字节[ ] 字符串字节[] 。您必须首先从 base64 转换为 byte [] 。记住,base64正在保存二进制数据的加密文本,而不是字符串。
另请注意,RijndaelManaged是IDisposable,所以我已经使用()构造包装了它。调用关闭()是必需的,但不够,如MSDN中所述。

At C# side you have casting from base64 to byte[] to string to byte[]. You have to do the first conversion from base64 to byte[] only. Remember, base64 is holding the cyphered text that is binary data, not string. Also please note that RijndaelManaged is IDisposable, so I have wrapped it in using() construct. Calling Close() is necessary but not enough as stated in MSDN.

public byte[] Decode(string str)
{
    var decbuff = Convert.FromBase64String(str);
    return decbuff;
}

static public String DecryptRJ256(byte[] cypher, string KeyString, string IVString)
{
    var sRet = "";

    var encoding = new UTF8Encoding();
    var Key = encoding.GetBytes(KeyString);
    var IV = encoding.GetBytes(IVString);

    using (var rj = new RijndaelManaged())
    {
        try
        {
            rj.Padding = PaddingMode.PKCS7;
            rj.Mode = CipherMode.CBC;
            rj.KeySize = 256;
            rj.BlockSize = 256;
            rj.Key = Key;
            rj.IV = IV;
            var ms = new MemoryStream(cypher);

            using (var cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
            {
                using (var sr = new StreamReader(cs))
                {
                    sRet = sr.ReadLine();
                }
            }
        }
        finally
        {
            rj.Clear();
        }
    }

    return sRet;
}

因此,C#中的以下代码将返回初始字符串: / p>

As a result, following code in C# will return you the initial string:

var iv = "45287112549354892144548565456541";
var key = "anjueolkdiwpoida";
var cypher = "u+rIlHB/2rrT/u/qFInnlEkg2unhizsNzGVb9O54sP8=";

var temp = DecryptRJ256(Decode(cypher), key, iv);