views:

387

answers:

4

As the title says, I am getting:

Invalid length for a Base-64 char array.

I have read about this problem on here and it seems that the suggestion is to store ViewState in SQL if it is large. I am using a wizard with a good deal of data collection so chances are my ViewSate is large. But, before I turn to the "store-in-DB" solution, maybe somebody can take a look and tell me if I have other options?

I construct the email for delivery using the below method:

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

The Encrypt method looks like this:

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

Here is what the HTML looks like in hotmail:

Please click on the link below or paste it into a browser to verify your email account.

http://localhost:1563/Accounts/VerifyEmail.aspx?a=YOHY57xYRENEOu3H+FGq1Rf09AZAI56EPjfwuK8XWKg=

On the receiving end, the VerifyEmail.aspx.cs page has the line:

 string username = Cryptography.Decrypt(_webContext.UserNameToVerify, "verify");

Here is the getter for UserNameToVerify:

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

And here is the GetQueryStringValue method:

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

And the decrypt method looks like:

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

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

Can this error be remedied with a code fix or must I store ViewState in the database?

Thanks in advance.

A: 

My initial guess without knowing the data would be that the UserNameToVerify is not a multiple of 4 in length. Check out the FromBase64String on msdn.

     // Ok
     byte[] b1 = Convert.FromBase64String("CoolDude");
     // Exception
     byte[] b2 = Convert.FromBase64String("MyMan");
SwDevMan81
Thanks SwDevMan81. Just now leaving work but will try this later tonight. Thanks for your help.
Code Sherpa
No problem, the fix would be to pad with a character to get a string that is a multiple of 4.
SwDevMan81
Thanks again SwDevMan81. I'll take a look at that. I posted UserNameToVeryify in my original post (FYI). OK... now I really need to go or I am going to get in trouble with the real boss :)
Code Sherpa
Looks like this post might help as well: http://stackoverflow.com/questions/1392970/httpserverutility-urltokendecode-fails-sometimes-invalid-length-for-a-base-64
SwDevMan81
+2  A: 

My guess is that you simply need to URL-encode your Base64 string when you include it in the querystring.

Base64 encoding uses some characters which must be encoded if they're part of a querystring (namely + and /, and maybe = too). If the string isn't correctly encoded then you won't be able to decode it successfully at the other end, hence the errors.

You can use the HttpUtility.UrlEncode method to encode your Base64 string:

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>";
LukeH
Thanks. Just tried your suggestion Luke but that didn't work :(.
Code Sherpa
@Sherpa - Keep working it, the problem is almost certainly with the trailing `=` characters.
uncle brad
Luke - I have a feeling you are right. Will try this at home. Thanks a bundle. FYI - I added what the string looks like in my hotmail inbox in my original post.
Code Sherpa
uncle brad is right, I had the same issue last week and the problem was a trailing "=" character ._.
Markust
+1  A: 

The length of a base64 encoded string is always a multiple of 4. If it is not a multiple of 4, then = characters are appended until it is. A query string of the form ?name=value has problems when the value contains = charaters (some of them will be dropped, I don't recall the exact behavior). You may be able to get away with appending the right number of = characters before doing the base64 decode.

Edit 1

You may find that the value of UserNameToVerify has had "+"'s changed to " "'s so you may need to do something like so;

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

This should get the length right;

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

Of course calling UrlEncode (as in LukeH's answer) should make this all moot.

uncle brad
Thanks Brad - It was actually this little bit of code that did the job: a = a.Replace(" ","+");
Code Sherpa
@Code Sherpa: if that is the case, your best choice is to urlencode before sending the string, and urldecode on receipt. Otherwise if another url significant character gets into your string then you'll have to add another `Replace` statement. Encoding is a coverall that protects you regardless.
Matt Ellen
A: 

Hello,

Just wanted to say thanks to Uncle Brad and LukeH. I had some problems generating a preview image from a FileUpload control, I kept getting the "Invalid length for a Base-64 char array" error when trying to convert my base 64 string to a byte array.

Both HttpUtility.UrlEncode and string.Replace(" ","+") worked brilliantly, cheers!

Henrik