简体   繁体   English

Base-64 字符数组的长度无效

[英]Invalid length for a Base-64 char array

As the title says, I am getting:正如标题所说,我得到:

Invalid length for a Base-64 char array. Base-64 字符数组的长度无效。

I have read about this problem on here and it seems that the suggestion is to store ViewState in SQL if it is large.我已经在此处阅读了有关此问题的信息,似乎建议将 ViewState 存储在 SQL 中(如果它很大)。 I am using a wizard with a good deal of data collection so chances are my ViewState is large.我正在使用一个有大量数据收集的向导,所以我的 ViewState 很可能很大。 But, before I turn to the "store-in-DB" solution, maybe somebody can take a look and tell me if I have other options?但是,在我转向“store-in-DB”解决方案之前,也许有人可以看看并告诉我是否还有其他选择?

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:这是 HTML 在 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= http://localhost:1563/Accounts/VerifyEmail.aspx?a=YOHY57xYRENEOu3H+FGq1Rf09AZAI56EPjfwuK8XWKg=

On the receiving end, the VerifyEmail.aspx.cs page has the line:在接收端,VerifyEmail.aspx.cs 页面有一行:

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

Here is the getter for UserNameToVerify:这是 UserNameToVerify 的 getter:

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

And here is the GetQueryStringValue method:这是 GetQueryStringValue 方法:

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?是否可以通过代码修复来修复此错误,还是必须将 ViewState 存储在数据库中?

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. base64 编码字符串的长度始终是 4 的倍数。如果它不是 4 的倍数,则附加=字符直到它是。 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).value包含=字符时,形式为?name=value的查询字符串会出现问题(其中一些将被删除,我不记得确切的行为)。 You may be able to get away with appending the right number of = characters before doing the base64 decode.在进行 base64 解码之前,您可能能够避免附加正确数量的=字符。

Edit 1编辑 1

You may find that the value of UserNameToVerify has had "+" 's changed to " " 's so you may need to do something like so:您可能会发现UserNameToVerify的值已将"+"更改为" " ,因此您可能需要执行以下操作:

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.当然,调用UrlEncode (如在 LukeH 的回答中)应该使这一切都没有实际意义。

My guess is that you simply need to URL-encode your Base64 string when you include it in the querystring.我的猜测是,当您将 Base64 字符串包含在查询字符串中时,您只需要对其进行URL 编码

Base64 encoding uses some characters which must be encoded if they're part of a querystring (namely + and / , and maybe = too). Base64 编码使用一些必须编码的字符,如果它们是查询字符串的一部分(即+/ ,也可能是= )。 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:您可以使用HttpUtility.UrlEncode方法对 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>";

I'm not Reputable enough to upvote or comment yet, but LukeH's answer was spot on for me.我的声誉还不够高,无法进行投票或评论,但 LukeH 的回答对我来说是正确的。

As AES encryption is the standard to use now, it produces a base64 string (at least all the encrypt/decrypt implementations I've seen).由于 AES 加密是现在使用的标准,它生成一个 base64 字符串(至少我见过的所有加密/解密实现)。 This string has a length in multiples of 4 (string.length % 4 = 0)这个字符串的长度是 4 的倍数 (string.length % 4 = 0)

The strings I was getting contained + and = on the beginning or end, and when you just concatenate that into a URL's querystring, it will look right (for instance, in an email you generate), but when the the link is followed and the .NET page recieves it and puts it into this.Page.Request.QueryString, those special characters will be gone and your string length will not be in a multiple of 4.我在开头或结尾包含 + 和 = 的字符串,当您将其连接到 URL 的查询字符串中时,它看起来是正确的(例如,在您生成的电子邮件中),但是当链接被跟踪并且.NET 页面收到它并将其放入 this.Page.Request.QueryString 中,那些特殊字符将消失并且您的字符串长度不会是 4 的倍数。

As the are special characters at the FRONT of the string (ex: +), as well as = at the end, you can't just add some = to make up the difference as you are altering the cypher text in a way that doesn't match what was actually in the original querystring.由于是字符串前面的特殊字符(例如:+),以及末尾的 =,您不能只添加一些 = 来弥补差异,因为您正在以一种不会改变密码文本的方式'与原始查询字符串中的实际内容不匹配。

So, wrapping the cypher text with HttpUtility.URLEncode (not HtmlEncode) transforms the non-alphanumeric characters in a way that ensures .NET parses them back into their original state when it is intepreted into the querystring collection.因此,使用 HttpUtility.URLEncode(而不是 HtmlEncode)包装密码文本以确保 .NET 在将其解析到查询字符串集合中时将它们解析回原始状态的方式转换非字母数字字符。

The good thing is, we only need to do the URLEncode when generating the querystring for the URL.好消息是,我们只需要在为 URL 生成查询字符串时做 URLEncode。 On the incoming side, it's automatically translated back into the original string value.在传入端,它会自动转换回原始字符串值。

Here's some example code这是一些示例代码

string cryptostring = MyAESEncrypt(MySecretString);
string URL = WebFunctions.ToAbsoluteUrl("~/ResetPassword.aspx?RPC=" + HttpUtility.UrlEncode(cryptostring));

My initial guess without knowing the data would be that the UserNameToVerify is not a multiple of 4 in length.在不知道数据的情况下,我最初的猜测是 UserNameToVerify 的长度不是 4 的倍数。 Check out the FromBase64String on msdn.查看 msdn 上的FromBase64String

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

The encrypted string had two special characters, + and = .加密的字符串有两个特殊字符, +=

'+' sign was giving the error, so below solution worked well: “+”号给出了错误,所以下面的解决方案运行良好:

//replace + sign

encryted_string = encryted_string.Replace("+", "%2b");

//`%2b` is HTTP encoded string for **+** sign

OR或者

//encode special charactes 

encryted_string = HttpUtility.UrlEncode(encryted_string);

//then pass it to the decryption process
...
    string stringToDecrypt = CypherText.Replace(" ", "+");
    int len = stringToDecrypt.Length;
    byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt); 

While Encrypting use加密使用时

HttpUtility.UrlEncode(Encryptedtext)); HttpUtility.UrlEncode(Encryptedtext));

While Decrypting ,解密时

use

        value = HttpUtility.UrlDecode(value);
        value = value.Replace(" ", "+");//to remove any empty spaces
        value = value.Replace('-', '+').Replace('_', '/');//replace special char
        while (value.Length % 4 != 0) value += '='; //it should be divisible by 4 or append = 

Then send this value for decryption然后发送这个值进行解密

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM