Base-64 char数组的长度无效


91

如标题所示,我得到:

Base-64 char数组的长度无效。

我已经在这里阅读了有关此问题的信息,并且似乎建议将ViewState如果较大则存储在SQL中。我正在使用具有大量数据收集功能的向导,因此我的ViewState很大。但是,在我转向“数据库存储”解决方案之前,也许有人可以看看并告诉我是否还有其他选择?

我使用以下方法构造要发送的电子邮件:

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

Encrypt方法如下所示:

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

这是Hotmail中的HTML外观:

请单击下面的链接或将其粘贴到浏览器中以验证您的电子邮件帐户。

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

在接收端,VerifyEmail.aspx.cs页面的行如下:

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

这是UserNameToVerify的获取方法:

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

这是GetQueryStringValue方法:

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

解密方法如下所示:

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

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

可以通过代码修复纠正此错误,还是必须将ViewState存储在数据库中?

Answers:


205

base64编码的字符串的长度始终是4的倍数。如果它不是4的倍数,则将=附加字符,直到正确为止。?name=valuevalue包含字符时,表单的查询字符串会出现问题=(其中一些字符将被删除,我不记得确切的行为)。=在执行base64解码之前,您也许可以添加正确数量的字符。

编辑1

您可能会发现UserNameToVerifyhas的值已"+"更改为" ",因此您可能需要执行以下操作:

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

这应该使长度正确;

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

当然,打电话UrlEncode(就像卢克·H的回答一样)应该解决所有这些问题。


9
谢谢布拉德-实际上正是这段代码完成了工作:a = a.Replace(“”,“ +”);
彼得

1
@Code Sherpa:如果是这种情况,最好的选择是在发送字符串之前先进行urlencode,然后在收到时进行urldecode。否则,如果另一个URL有效字符进入您的字符串,则必须添加另一个Replace语句。编码是一套可以保护您一切的工作服。
马特·艾伦

5
您不要在收据上对字符串进行UrlDecode,因为ASP.Net已对请求参数进行UrlDecode。但是,发送时应使用UrlEncode。
bleeeah 2012年

或者,如果您需要嵌入式版本:a = a + new string('=', (4 - a.Length % 4) % 4)。解码RFC 4648 URL安全的Base64的示例:public string base64urlDecode(string encoded) { return System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(encoded.Replace("_","/").Replace("-","+") + new string('=', (4 - encoded.Length % 4) % 4))); }
gregmac

1
“您不要去UrlDecode”-这!单步执行代码,我可以看到参数已被解码,问题是我通过UrlDecode删除字符来运行它。感谢@MattEllen
GJKH

30

我的猜测是,当您将Base64字符串包含在querystring中时,只需对其进行URL编码

Base64编码使用某些字符,如果它们是查询字符串的一部分,则必须对其进行编码(即+/,也许=也是如此)。如果字符串编码不正确,则另一端将无法成功对其进行解码,因此会出现错误。

您可以使用该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>";

谢谢。刚尝试了您的建议卢克,但那
彼得

@Sherpa-继续工作,几乎可以肯定问题出在尾随=字符上。

卢克-我觉得你是对的。将在家里尝试。谢谢捆绑。仅供参考-我在原始帖子的hotmail收件箱中添加了字符串。
彼得

布拉德叔叔是对的,上周我遇到了同样的问题,问题是尾随的“ =”字符._。
Marcote

10

我的信誉尚不足以支持或发表评论,但LukeH的答案对我来说很重要。

由于AES加密是现在使用的标准,因此它会生成base64字符串(至少我见过的所有加密/解密实现)。该字符串的长度为4的倍数(string.length%4 = 0)

我在开始或结束时包含的字符串+和=,当您将其串联到URL的查询字符串中时,它看起来正确(例如,在您生成的电子邮件中),但是当链接被跟随时, .NET页面将其接收并将其放入this.Page.Request.QueryString中,这些特殊字符将消失,并且您的字符串长度将不会是4的倍数。

由于字符串的前部是特殊字符(ex:+),最后是=,所以您不能仅添加一些=来弥补差异,因为您以不与原始查询字符串中的实际值不匹配。

因此,用HttpUtility.URLEncode(不是HtmlEncode)包装密文可以转换非字母数字字符,从而确保.NET在将其解析为querystring集合时将其解析回其原始状态。

好消息是,我们只需要在生成URL的查询字符串时执行URLEncode。在输入端,它会自动转换回原始字符串值。

这是一些示例代码

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

6

我最初不知道数据的猜测是UserNameToVerify的长度不是4的倍数。检出msdn上的FromBase64String

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

谢谢SwDevMan81。刚刚离开工作,但今晚晚些时候会尝试。谢谢你的帮助。
彼得

没问题,在解决将是垫的字符得到一个字符串,它是4的倍数
SwDevMan81

再次感谢SwDevMan81。我来看一下。我在原始帖子(FYI)中发布了UserNameToVeryify。好吧...现在我真的需要走了,否则我将要遇到真正的老板:)
彼得2010年

喜欢这个职位看起来可能会有所帮助:stackoverflow.com/questions/1392970/...
SwDevMan81

1

加密的字符串有两个特殊字符,+=

“ +”号表示错误,因此以下解决方案效果很好:

//replace + sign

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

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

要么

//encode special charactes 

encryted_string = HttpUtility.UrlEncode(encryted_string);

//then pass it to the decryption process
...

0
    string stringToDecrypt = CypherText.Replace(" ", "+");
    int len = stringToDecrypt.Length;
    byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt); 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.