c# - Longitud inválida para una matriz de caracteres Base-64
asp.net viewstate (4)
Como dice el título, estoy obteniendo:
Longitud inválida para una matriz de caracteres Base-64.
He leído sobre este problema aquí y parece que la sugerencia es almacenar ViewState en SQL si es grande. Estoy usando un asistente con una gran cantidad de recopilación de datos, así que es probable que mi ViewState sea grande. Pero, antes de pasar a la solución "almacenar en DB", ¿alguien puede echar un vistazo y decirme si tengo otras opciones?
Construyo el correo electrónico para la entrega usando el siguiente método:
public void SendEmailAddressVerificationEmail(string userName, string to)
{
string msg = "Please click on the link below or paste it into a browser to verify your email account.<BR><BR>" +
"<a href=/"" + _configuration.RootURL + "Accounts/VerifyEmail.aspx?a=" +
userName.Encrypt("verify") + "/">" +
_configuration.RootURL + "Accounts/VerifyEmail.aspx?a=" +
userName.Encrypt("verify") + "</a>";
SendEmail(to, "", "", "Account created! Email verification required.", msg);
}
El método Encrypt se ve así:
public static string Encrypt(string clearText, string Password)
{
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
byte[] encryptedData = Encrypt(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
return Convert.ToBase64String(encryptedData);
}
Así es como se ve el HTML en hotmail:
Haga clic en el enlace a continuación o péguelo en un navegador para verificar su cuenta de correo electrónico.
http://localhost:1563/Accounts/VerifyEmail.aspx?a=YOHY57xYRENEOu3H+FGq1Rf09AZAI56EPjfwuK8XWKg=
En el extremo receptor, la página VerifyEmail.aspx.cs tiene la línea:
string username = Cryptography.Decrypt(_webContext.UserNameToVerify, "verify");
Aquí está el getter para UserNameToVerify:
public string UserNameToVerify
{
get
{
return GetQueryStringValue("a").ToString();
}
}
Y aquí está el método GetQueryStringValue:
private static string GetQueryStringValue(string key)
{
return HttpContext.Current.Request.QueryString.Get(key);
}
Y el método de descifrado se ve así:
public static string Decrypt(string cipherText, string password)
{
**// THE ERROR IS THROWN HERE!!**
byte[] cipherBytes = Convert.FromBase64String(cipherText);
¿Se puede remediar este error con una corrección de código o debo almacenar ViewState en la base de datos?
La longitud de una cadena codificada en base64 siempre es un múltiplo de 4. Si no es un múltiplo de 4, entonces =
caracteres se anexan hasta que lo sea. Una cadena de consulta de la forma ?name=value
tiene problemas cuando el value
contiene =
charaters (algunos de ellos se descartarán, no recuerdo el comportamiento exacto). Es posible que consiga anexar el número correcto de =
caracteres antes de realizar la decodificación base64.
Editar 1
Puede encontrar que el valor de UserNameToVerify
ha cambiado "+"
a " "
, por lo que es posible que deba hacer algo como esto:
a = a.Replace(" ", "+");
Esto debería tener la longitud correcta;
int mod4 = a.Length % 4;
if (mod4 > 0 )
{
a += new string(''='', 4 - mod4);
}
Por supuesto, llamar a UrlEncode
(como en la respuesta de LukeH) debería hacer que todo esto sea discutible.
Mi suposición inicial sin conocer los datos sería que UserNameToVerify no es un múltiplo de 4 de longitud. Verifique FromBase64String en msdn.
// Ok
byte[] b1 = Convert.FromBase64String("CoolDude");
// Exception
byte[] b2 = Convert.FromBase64String("MyMan");
No tengo la reputación suficiente para votar o comentar aún, pero la respuesta de LukeH fue perfecta para mí.
Como el cifrado AES es el estándar que se usa ahora, produce una cadena base64 (al menos todas las implementaciones de cifrado / descifrado que he visto). Esta cadena tiene una longitud en múltiplos de 4 (string.length% 4 = 0)
Las cadenas que estaba conteniendo + y = al principio o al final, y cuando acaba de concatenar eso en la cadena de consulta de una URL, se verá bien (por ejemplo, en un correo electrónico que genere), pero cuando se sigue el enlace y el La página .NET lo recibe y lo coloca en this.Page.Request.QueryString, esos caracteres especiales desaparecerán y la longitud de su cadena no estará en un múltiplo de 4.
Como los caracteres especiales están al frente de la cadena (por ej., +), Así como también = al final, no puede agregar solo algunos para compensar la diferencia ya que está alterando el texto cifrado de una manera que no lo hace. No coincide con lo que realmente estaba en la cadena de consulta original.
Por lo tanto, al envolver el texto de cifrado con HttpUtility.URLEncode (no HtmlEncode) se transforman los caracteres no alfanuméricos de modo que se asegure de que .NET los vuelva a analizar en su estado original cuando se intente en la colección querystring.
Lo bueno es que solo necesitamos hacer URLEncode al generar la cadena de consulta para la URL. En el lado de entrada, se traduce automáticamente al valor de cadena original.
Aquí hay un código de ejemplo
string cryptostring = MyAESEncrypt(MySecretString);
string URL = WebFunctions.ToAbsoluteUrl("~/ResetPassword.aspx?RPC=" + HttpUtility.UrlEncode(cryptostring));
Supongo que solo necesitas URL-encode tu cadena Base64 cuando la incluyes en la cadena de consulta.
La codificación Base64 usa algunos caracteres que deben codificarse si son parte de una cadena de consulta (es decir, +
y /
, y tal vez =
también). Si la cadena no está codificada correctamente, no podrá decodificarla con éxito en el otro extremo, de ahí los errores.
Puede usar el método HttpUtility.UrlEncode
para codificar su cadena Base64:
string msg = "Please click on the link below or paste it into a browser "
+ "to verify your email account.<br /><br /><a href=/""
+ _configuration.RootURL + "Accounts/VerifyEmail.aspx?a="
+ HttpUtility.UrlEncode(userName.Encrypt("verify")) + "/">"
+ _configuration.RootURL + "Accounts/VerifyEmail.aspx?a="
+ HttpUtility.UrlEncode(userName.Encrypt("verify")) + "</a>";