Base-64 char数组的长度无效

Pet*_*ter 80 c# asp.net viewstate base64

正如标题所说,我得到:

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);
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

以下是HTML在hotmail中的样子:

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

HTTP://本地主机:1563 /账户/ VerifyEmail.aspx一个= YOHY57xYRENEOu3H + FGq1Rf09AZAI56EPjfwuK8XWKg =

在接收端,VerifyEmail.aspx.cs页面包含以下行:

 string username = Cryptography.Decrypt(_webContext.UserNameToVerify, "verify");
Run Code Online (Sandbox Code Playgroud)

这是UserNameToVerify的getter:

public string UserNameToVerify
{
    get
    {
        return GetQueryStringValue("a").ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是GetQueryStringValue方法:

private static string GetQueryStringValue(string key)
{
    return HttpContext.Current.Request.QueryString.Get(key);
}
Run Code Online (Sandbox Code Playgroud)

解密方法如下:

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

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

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

小智 183

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

编辑1

您可能会发现的价值UserNameToVerify已经有了"+"的改变" "的,所以你可能需要做一些事情,像这样:

a = a.Replace(" ", "+");
Run Code Online (Sandbox Code Playgroud)

这应该是正确的;

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

当然,召唤UrlEncode(如LukeH的回答)应该让这一切都没有实际意义.

  • 谢谢布拉德 - 实际上这一小部分代码完成了这项工作:a = a.Replace("","+"); (8认同)
  • 您不必在收到时对您的字符串进行UrlDecode,因为请求参数已由ASP.Net进行UrlDecoded.但是,您应该在发送时使用UrlEncode. (4认同)
  • base64必须是4的倍数的事实解决了我的问题。谢谢! (2认同)

Luk*_*keH 28

我的猜测是,当你将它包含在查询字符串中时,你只需要你的Base64字符串进行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>";
Run Code Online (Sandbox Code Playgroud)


Ken*_*und 9

我还没有足够的声誉来赞扬或评论,但LukeH的回答对我来说很有意义.

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

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

由于字符串前面的特殊字符(例如:+),以及最后的=,您不能只添加一些=来弥补差异,因为您正在以不同的方式更改密码文本不匹配原始查询字符串中的实际内容.

因此,使用HttpUtility.URLEncode(而不是HtmlEncode)包装密文文本会转换非字母数字字符,以确保.NET在将其解析到查询字符串集合时将它们解析回原始状态.

好消息是,我们只需要在为URL生成查询字符串时执行URLEncode.在传入方面,它会自动转换回原始字符串值.

这是一些示例代码

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


SwD*_*n81 6

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

// Ok
byte[] b1 = Convert.FromBase64String("CoolDude");
// Exception
byte[] b2 = Convert.FromBase64String("MyMan");
Run Code Online (Sandbox Code Playgroud)