2010-05-27 70 views
57

Como dice el título, estoy consiguiendo:Longitud no válida para una matriz de caracteres base 64

Longitud no válida para una base 64 Char matriz.

He leído acerca de este problema aquí y parece que la sugerencia es para almacenar ViewState en SQL si es grande. Estoy usando un asistente con una gran cantidad de recopilación de datos, así que las posibilidades son que mi ViewState es grande. Pero, antes de pasar a la solución "store-in-DB" , ¿alguien puede echar un vistazo y decirme si tengo otras opciones?

construyo el correo electrónico para la entrega utilizando el método siguiente:

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 de cifrado es el siguiente:

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); 
} 

Aquí es lo que el HTML se ve como en hotmail:

Por favor, haga clic en el enlace de abajo 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í es el captador de UserNameToVerify:

public string UserNameToVerify 
{ 
    get 
    { 
     return GetQueryStringValue("a").ToString(); 
    } 
} 

Y aquí es el método GetQueryStringValue:

private static string GetQueryStringValue(string key) 
{ 
    return HttpContext.Current.Request.QueryString.Get(key); 
} 

Y el método de descifrado se parece a:

public static string Decrypt(string cipherText, string password) 
{ 

    **// THE ERROR IS THROWN HERE!!** 
    byte[] cipherBytes = Convert.FromBase64String(cipherText); 

¿Puede este error puede remediar con una solución de código o debo almacenar ViewState en la base de datos?

+2

PLZ me envía teh error – DevDemon

+0

DevDemon - el error se registró como "FormatException: Longitud no válida para una matriz de caracteres Base-64." ¿Hay algo más que deba enviar? –

Respuesta

127

La longitud de una cadena base64 es siempre un múltiplo de 4. Si no es un múltiplo de 4, entonces = personajes son anexado hasta que sea. Una cadena de consulta del formulario ?name=value tiene problemas cuando el value contiene = caracteres (algunos de ellos se descartarán, no recuerdo el comportamiento exacto). Es posible que pueda salir con la adición del número correcto de = caracteres antes de realizar la decodificación base64.

Editar 1

Es posible que el valor de UserNameToVerify ha tenido "+" 's cambiaron a " "' s lo que puede tener que hacer algo así:

a = a.Replace(" ", "+"); 

Esto debería obtener la longitud derecho;

int mod4 = a.Length % 4; 
if (mod4 > 0) 
{ 
    a += new string('=', 4 - mod4); 
} 

Por supuesto llamando UrlEncode (como en la respuesta de LukeH) debería hacer esto todo discutible.

+8

Gracias Brad - En realidad fue este pequeño código el que hizo el trabajo: a = a.Replace ("", "+"); –

+1

@Code Sherpa: si ese es el caso, tu mejor opción es urlencode antes de enviar la cadena y urldecode en el recibo. De lo contrario, si otro carácter significativo de URL entra en tu cadena, entonces tendrás que agregar otra instrucción 'Reemplazar '. La codificación es un sobretodo que te protege independientemente. –

+0

trabajó totalmente para soy yo esta es la solución chicos. – tugberk

4

Mi conjetura inicial sin conocer los datos sería que el UserNameToVerify no es un múltiplo de 4 de longitud. Consulte el FromBase64String en msdn.

// Ok 
byte[] b1 = Convert.FromBase64String("CoolDude"); 
// Exception 
byte[] b2 = Convert.FromBase64String("MyMan"); 
+0

Gracias SwDevMan81. Justo ahora, dejando el trabajo, intentaré esto más tarde esta noche. Gracias por tu ayuda. –

+0

No hay problema, la solución sería rellenar con un personaje para obtener una cadena que es un múltiplo de 4. – SwDevMan81

+0

Gracias de nuevo SwDevMan81. Echaré un vistazo a eso. Publiqué UserNameToVeryify en mi publicación original (FYI). DE ACUERDO...ahora realmente necesito irme o me voy a meter en problemas con el verdadero jefe :) –

23

Mi conjetura es que sólo hay que URL-encode la cadena de base 64 cuando se incluye en la cadena de consulta.

codificación Base64 utiliza algunos caracteres que deben ser codificados 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.

Usted puede utilizar el método HttpUtility.UrlEncode para codificar la cadena de base 64:

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>"; 
+0

Gracias. Acabo de probar su sugerencia Lucas, pero eso no funcionó :(. –

+0

@Sherpa - Sigue trabajando, el problema es casi seguro con los caracteres '=' finales. –

+0

Luke - Tengo la sensación de que tienes razón. Lo intentaré en Gracias por un paquete. FYI - Agregué cómo se ve la cadena en mi bandeja de entrada de Hotmail en mi publicación original. –

7

No soy lo suficientemente respetable como 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 concatenas eso en la cadena de consulta de una URL, mira bien (por ejemplo, en un correo electrónico que generas), pero cuando se sigue el enlace y la página .NET lo recibe y lo pone en this.Page.Request.QueryString, esos caracteres especiales desaparecerán y la longitud de tu cadena se no estar en un múltiplo de 4.

Como los caracteres especiales están en el FRENTE de la cadena (ej .: +), 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 coincide con lo que realmente estaba en la cadena de consulta original.

Por lo tanto, al ajustar el texto cifrado con HttpUtility.URLEncode (no HtmlEncode) se transforman los caracteres no alfanuméricos de forma 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 de 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)); 
Cuestiones relacionadas