且构网

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

使用 Rijndael 进行跨平台(php 到 C# .NET)加密/解密

更新时间:2023-02-17 17:02:15

在这里我可以看到两边的问题.

Here I can see problems on both sides.

请记住,编码时得到的不是字符串,而是字节数组.所以在 PHP 中你不需要对 cyphertext 进行 urlencode.

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 help 时,您会看到

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) . "
<br/>";
?>

在 C# 方面,您可以从 base64byte[]stringbyte[] 的转换.您只需要进行从 base64byte[] 的第一次转换.请记住,base64 保存的是二进制数据而不是字符串的加密文本.另请注意,RijndaelManaged 是 IDisposable,所以我将它包装在 using() 构造中.如 MSDN 所述,调用 Close() 是必要的,但还不够.

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# 代码将返回初始字符串:

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);