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

Cross platform (php to C# .NET) encryption/decryption with Rijndael(使用 Rijndael 进行跨平台(php 到 C# .NET)加密/解密)
本文介绍了使用 Rijndael 进行跨平台(php 到 C# .NET)加密/解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我目前在解密由 php mcrypt 加密的消息时遇到了一些问题.php代码如下:

I'm currently having a bit of problem with decrypting a message encrypted by php mcrypt. The php code is as following:

<?php
  //$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
  $iv = "45287112549354892144548565456541";
  $key = "anjueolkdiwpoida";
  $text = "This is my encrypted message";
  $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
  $crypttext = urlencode($crypttext);
  $crypttext64=base64_encode($crypttext);
  print($crypttext64) . "
<br/>";
?>

然后将加密的消息发送到 ASP.NET 平台 (C#).但是,我在保留解密顺序(base64 解码到 urldecode)时遇到了问题.我在 ASP.NET 中的代码如下(iv 和 key 与 php 中的相同):

The the encrypted message is then sent to a ASP.NET platform (C#). However, I'm having problem retaining the order of decryption (base64 decode to urldecode). The code I had in ASP.NET is as the following (iv and key is the same as in php):

public string Decode(string str)
{
    byte[] decbuff = Convert.FromBase64String(str);
    return System.Text.Encoding.UTF8.GetString(decbuff);
}

static public String DecryptRJ256(string cypher, string KeyString, string IVString)
{

    string sRet = "";
    RijndaelManaged rj = new RijndaelManaged();
    UTF8Encoding encoding = new UTF8Encoding();


    try
    {
        //byte[] message = Convert.FromBase64String(cypher);
        byte[] message = encoding.GetBytes(cypher);

        byte[] Key = encoding.GetBytes(KeyString);
        byte[] IV = encoding.GetBytes(IVString);

        rj.Padding = PaddingMode.Zeros;
        rj.Mode = CipherMode.CBC;
        rj.KeySize = 256;
        rj.BlockSize = 256;
        rj.Key = Key;
        rj.IV = IV;
        MemoryStream ms = new MemoryStream(message);

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

    }
    finally
    {
        rj.Clear();
    }

    return sRet;


}

string temp = DecryptRJ256(Server.UrlDecode(Decode(cypher)), keyString, ivString);

我遇到的问题是,在收到来自 php 的加密消息后,我将其转换为 byte[],然后再转换回 UTF8 编码字符串,以便我可以对其进行 urldecode.然后我将结果提供给函数,在那里我将字符串转换回 byte[] 并通过解密过程运行它.但是,我无法得到想要的结果……有什么想法吗?

The problem I'm having is that after I recieved the encrypted message from php, I converted it into byte[] and then converted back to UTF8 encoded string so I can urldecode it. then I feed the result into the function where I converted the string back to byte[] and ran it through the decryption process. However, I can't get the desired result...any ideas?

提前致谢.

推荐答案

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

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

这篇关于使用 Rijndael 进行跨平台(php 到 C# .NET)加密/解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

DeepL的翻译效果还是很强大的,如果我们要用php实现DeepL翻译调用,该怎么办呢?以下是代码示例,希望能够帮到需要的朋友。 在这里需要注意,这个DeepL的账户和api申请比较难,不支持中国大陆申请,需要拥有香港或者海外信用卡才行,没账号的话,目前某宝可以
PHP通过phpspreadsheet导入Excel日期,导入系统后,全部变为了4开头的几位数字,这是为什么呢?原因很简单,将Excel的时间设置问文本,我们就能看到该日期本来的数值,上图对应的数值为: 要怎么解决呢?进行数据转换就行,这里可以封装方法,或者用第三方的
mediatemple - can#39;t send email using codeigniter(mediatemple - 无法使用 codeigniter 发送电子邮件)
Laravel Gmail Configuration Error(Laravel Gmail 配置错误)
Problem with using PHPMailer for SMTP(将 PHPMailer 用于 SMTP 的问题)
Issue on how to setup SMTP using PHPMailer in GoDaddy server(关于如何在 GoDaddy 服务器中使用 PHPMailer 设置 SMTP 的问题)