Подтвердить что ты не робот

Кросс-платформенный (php-С#.NET) шифрование/дешифрование с помощью Rijndael

В настоящее время у меня проблема с расшифровкой сообщения, зашифрованного php mcrypt. Код php выглядит следующим образом:

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

Зашифрованное сообщение затем отправляется на платформу ASP.NET(С#). Тем не менее, у меня проблема с сохранением порядка дешифрования (base64 decode to urldecode). Код, который я имел в ASP.NET, выглядит следующим образом (iv и ключ такой же, как и в 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, я преобразовал его в байт [], а затем преобразовал обратно в кодированную строку UTF8, чтобы я мог urldecode. то я передаю результат в функцию, где я преобразовал строку обратно в байт [] и запускал ее через процесс дешифрования. Однако я не могу получить желаемый результат... любые идеи?

Спасибо заранее.

4b9b3361

Ответ 1

Здесь я вижу проблемы с обеих сторон.

Пожалуйста, имейте в виду, что то, что вы получаете, когда кодировка не является строкой, а скорее массивом байтов. Таким образом, в PHP вам не нужно указывать cphertextode.

кодировка base64 - это все, что вам нужно. Когда вы открываете base64_encode help, вы видите

base64_encode Кодирует данные с базой64. Эта кодировка предназначенные для того, чтобы бинарные данные выдерживали транспорт

Еще одно: чтобы ваше сообщение было декодировано в .net с правильной длиной, вам нужно вручную добавить его с помощью дополняющих символов. Режим заполнения по умолчанию для RijndaelManaged - PKCS7, позволяет "придерживаться". Вы должны расширить свою исходную строку до четных блоков с кодом символов, равным количеству байтов заполнения.

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

На стороне С# у вас есть от base64 до байт [] до строка до байт []. Вы должны выполнить первое преобразование с base64 только на байт []. Помните, что base64 хранит зашифрованный текст, который является двоичными данными, а не строкой. Также обратите внимание, что RijndaelManaged является IDisposable, поэтому я завернул его в конструкцию using(). Вызов Close() необходим, но недостаточно, как указано в 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;
}

В результате следующий код в С# вернет вам исходную строку:

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

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