Como dice el título, obtengo:
Longitud no vá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, por lo que es probable que mi ViewState sea grande. Pero, antes de pasar a la solución "almacenar en base de datos", ¿quizás alguien pueda echar un vistazo y decirme si tengo otras opciones?
Construyo el correo electrónico para la entrega utilizando 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.
En el extremo receptor, la página VerifyEmail.aspx.cs tiene la línea:
string username = Cryptography.Decrypt(_webContext.UserNameToVerify, "verify");
Aquí está el captador de 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 solucionar este error con una corrección de código o debo almacenar ViewState en la base de datos?
Replace
declaración. La codificación es un mono que te protege independientemente.a = a + new string('=', (4 - a.Length % 4) % 4)
. Ejemplo para decodificar RFC 4648 Base64 segura para URL :public string base64urlDecode(string encoded) { return System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(encoded.Replace("_","/").Replace("-","+") + new string('=', (4 - encoded.Length % 4) % 4))); }
UrlDecode
que estaba eliminando caracteres. Gracias @MattEllenSupongo que simplemente necesita codificar en URL su cadena Base64 cuando la incluye en la cadena de consulta.
La codificación Base64 utiliza algunos caracteres que deben ser codificados si son parte de una cadena de consulta (es decir,
+
e/
, y tal vez=
también). Si la cadena no está codificada correctamente, no podrá decodificarla correctamente en el otro extremo, de ahí los errores.Puede usar el
HttpUtility.UrlEncode
método 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>";
fuente
=
caracteres finales .No soy lo suficientemente reputado como para votar o comentar todavía, pero la respuesta de LukeH fue acertada para mí.
Como el cifrado AES es el estándar para usar 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 obteniendo contenían + y = al principio o al final, y cuando las concatena en la cadena de consulta de una URL, se verá bien (por ejemplo, en un correo electrónico que genere), pero cuando se siga 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 será múltiplo de 4.
Como hay caracteres especiales al FRENTE de la cadena (por ejemplo: +), así como = al final, no puede simplemente agregar algunos = para compensar la diferencia, ya que está alterando el texto cifrado de una manera que no lo hace. no coincide con lo que estaba realmente en la cadena de consulta original.
Por lo tanto, envolver el texto cifrado con HttpUtility.URLEncode (no HtmlEncode) transforma los caracteres no alfanuméricos de una manera que garantiza que .NET los vuelva a analizar en su estado original cuando se interprete en la colección de cadenas de consulta.
Lo bueno es que solo necesitamos hacer el código URLEncode al generar la cadena de consulta para la URL. En el lado entrante, 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));
fuente
Mi suposición inicial sin conocer los datos sería que UserNameToVerify no es un múltiplo de 4 de longitud. Consulte FromBase64String en msdn.
// Ok byte[] b1 = Convert.FromBase64String("CoolDude"); // Exception byte[] b2 = Convert.FromBase64String("MyMan");
fuente
La cadena cifrada tenía dos caracteres especiales
+
y=
.El signo '+' estaba dando el error, por lo que la siguiente solución funcionó bien:
//replace + sign encryted_string = encryted_string.Replace("+", "%2b"); //`%2b` is HTTP encoded string for **+** sign
O
//encode special charactes encryted_string = HttpUtility.UrlEncode(encryted_string); //then pass it to the decryption process ...
fuente
string stringToDecrypt = CypherText.Replace(" ", "+"); int len = stringToDecrypt.Length; byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt);
fuente