Estoy tratando de cifrar algunos datos (cookies) en C# y luego descifrarlos en PHP. He elegido usar el cifrado Rijndael. Casi lo tengo funcionando, ¡excepto que solo una parte del texto está descifrado! Empecé a trabajar a partir de este ejemplo: Decrypt PHP encrypted string in C#C# Cifrado para descifrado PHP
Aquí está el texto (JSON) que estoy cifrando (información sensible eliminado):
{"DisplayName":"xxx", "Username": "yyy", "EmailAddress":"zzz"}
Así que iniciar sesión en el # app C que crea/codifica la cookie de almacenado Key y IV y luego redirige a la aplicación PHP que se supone debe descifrar/leer la cookie. Cuando descifrar la cookie, sale así:
{"DisplayName":"xxx","F�A ;��HP=D�������4��z����ť���k�#E���R�j�5�\�t. t�D��"
ACTUALIZACIÓN: He llegado un poco más lejos y esto ahora es el resultado
string(96) "{"DisplayName":"xxx","Username":"yyy","EmailAddress"�)ق��-�J��k/VV-v� �9�B`7^"
Como se puede ver , comienza a descifrarlo, pero luego se arruina ...
Cuando Descifra la cuerda sale correcta (con relleno, que tengo una función para eliminar e relleno), pero si cambio de la cadena de prueba por un personaje consigo la basura una vez más:
B�nHL�Ek �¿?�UΣlO����OЏ�M��NO/�f.M���Lƾ�CC�Y>F��~�qd�+
Aquí está el código C# que utilizo para generar la clave aleatoria y IV:
ACTUALIZACIÓN: Sólo estoy usando la clave estática/IV, por ahora, aquí están:
Key: lkirwf897+22#bbtrm8814z5qq=498j5
IV: 741952hheeyy66#[email protected]
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.BlockSize = 256;
symmetricKey.KeySize = 256;
symmetricKey.Padding = PaddingMode.Zeros;
symmetricKey.Mode = CipherMode.CBC;
string key = Convert.ToBase64String(symmetricKey.Key);
string IV = Convert.ToBase64String(symmetricKey.IV);
A continuación, guardo la clave y IV en una base de datos que se recuperará más tarde para la codificación/decodificación.
Ésta es la clase de cifrado completo:
public static class Encryption
{
public static string Encrypt(string prm_text_to_encrypt, string prm_key, string prm_iv)
{
var sToEncrypt = prm_text_to_encrypt;
var rj = new RijndaelManaged()
{
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
KeySize = 256,
BlockSize = 256,
//FeedbackSize = 256
};
var key = Encoding.ASCII.GetBytes(prm_key);
var IV = Encoding.ASCII.GetBytes(prm_iv);
//var key = Convert.FromBase64String(prm_key);
//var IV = Convert.FromBase64String(prm_iv);
var encryptor = rj.CreateEncryptor(key, IV);
var msEncrypt = new MemoryStream();
var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
var toEncrypt = Encoding.ASCII.GetBytes(sToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
var encrypted = msEncrypt.ToArray();
return (Convert.ToBase64String(encrypted));
}
public static string Decrypt(string prm_text_to_decrypt, string prm_key, string prm_iv)
{
var sEncryptedString = prm_text_to_decrypt;
var rj = new RijndaelManaged()
{
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
KeySize = 256,
BlockSize = 256,
//FeedbackSize = 256
};
var key = Encoding.ASCII.GetBytes(prm_key);
var IV = Encoding.ASCII.GetBytes(prm_iv);
//var key = Convert.FromBase64String(prm_key);
//var IV = Convert.FromBase64String(prm_iv);
var decryptor = rj.CreateDecryptor(key, IV);
var sEncrypted = Convert.FromBase64String(sEncryptedString);
var fromEncrypt = new byte[sEncrypted.Length];
var msDecrypt = new MemoryStream(sEncrypted);
var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return (Encoding.ASCII.GetString(fromEncrypt));
}
public static void GenerateKeyIV(out string key, out string IV)
{
var rj = new RijndaelManaged()
{
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
KeySize = 256,
BlockSize = 256,
//FeedbackSize = 256
};
rj.GenerateKey();
rj.GenerateIV();
key = Convert.ToBase64String(rj.Key);
IV = Convert.ToBase64String(rj.IV);
}
}
Aquí está el código PHP que estoy usando para descifrar los datos:
function decryptRJ256($key,$iv,$string_to_decrypt)
{
$string_to_decrypt = base64_decode($string_to_decrypt);
$rtn = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_decrypt, MCRYPT_MODE_CBC, $iv);
//$rtn = rtrim($rtn, "\0\4");
$rtn = unpad($rtn);
return($rtn);
}
function unpad($value)
{
$blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
//apply pkcs7 padding removal
$packing = ord($value[strlen($value) - 1]);
if($packing && $packing < $blockSize){
for($P = strlen($value) - 1; $P >= strlen($value) - $packing; $P--){
if(ord($value{$P}) != $packing){
$packing = 0;
}//end if
}//end for
}//end if
return substr($value, 0, strlen($value) - $packing);
}
$ky = 'lkirwf897+22#bbtrm8814z5qq=498j5'; // 32 * 8 = 256 bit key
$iv = '741952hheeyy66#[email protected]'; // 32 * 8 = 256 bit iv
$enc = $_COOKIE["MyCookie"];
$dtext = decryptRJ256($ky, $iv, $enc);
var_dump($dtext);
estoy un poco inseguro acerca de esta parte, porque todos el código de ejemplo que he visto simplemente pasa en la cadena codificada en base64 directamente al descifrador, pero en mi ejemplo, tengo que base64_decode antes de pasarlo, de lo contrario me sale el error de que la clave y IV no tienen la longitud correcta.
ACTUALIZACIÓN: Estoy usando claves ASCII en el formato necesario para PHP. Si genero claves de la clase RijndaelManaged, no funcionan en el lado de PHP, pero puedo usar claves que se sabe que funcionan en el lado de PHP y las uso en el lado de RijndaelManaged C#.
Háganme saber si omití la información pertinente. TIA!
Creo recordar que usted puede conseguir esto si el IV que proporcione para descifrar está mal – pm100
¿Funciona sin el IV? –
No funciona si no incluyo el IV. – solidau