Межплатформенное (php to C# .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 (C#). Однако у меня возникла проблема с сохранением порядка дешифрования (от base64 до 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, я преобразовал его в byte[], а затем преобразовал обратно в строку в кодировке UTF8, чтобы я мог urldecode его. затем я передаю результат в функцию, где я преобразовал строку обратно в byte[] и провел ее через процесс расшифровки. Тем не менее, я не могу получить желаемый результат... какие-либо идеи?
Заранее спасибо.
1 ответ
Здесь я вижу проблемы с обеих сторон.
Помните, что при кодировании вы получаете не строку, а массив байтов. Так что в PHP вам не нужно кодировать зашифрованный текст.
Кодировка base64 - это все, что вам нужно. Когда вы открываете base64_encode, вы видите
base64_encode Кодирует данные с помощью base64. Эта кодировка предназначена для выживания двоичных данных при транспортировке.
Еще одна вещь - чтобы ваше сообщение было декодировано в.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/>";
?>
На стороне C# у вас есть приведение из base64 в byte[] в строку в byte[]. Вы должны сделать первое преобразование только из base64 в byte[]. Помните, что 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;
}
В результате следующий код в C# вернет вам исходную строку:
var iv = "45287112549354892144548565456541";
var key = "anjueolkdiwpoida";
var cypher = "u+rIlHB/2rrT/u/qFInnlEkg2unhizsNzGVb9O54sP8=";
var temp = DecryptRJ256(Decode(cypher), key, iv);