web-dev-qa-db-ja.com

Base-64文字配列の長さが無効です

タイトルが言うように、私は次のものを得ています:

Base-64文字配列の長さが無効です。

私はここでこの問題について読んでいますが、ViewStateが大きい場合はSQLにViewStateを保存することをお勧めしているようです。大量のデータを収集するウィザードを使用しているため、ViewStateが大きい可能性があります。しかし、「store-in-DB」ソリューションに移る前に、誰かが見て、他のオプションがあるかどうかを教えてくれるかもしれません。

以下の方法を使用して、配信用のメールを作成します。

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をデータベースに保存する必要がありますか?

76
Peter

Base64でエンコードされた文字列の長さは常に4の倍数です。4の倍数でない場合、=文字が追加されます。 ?name=value形式のクエリ文字列には、value=文字が含まれている場合に問題があります(一部は削除されますが、正確な動作は思い出せません)。 base64デコードを行う前に、適切な数の=文字を追加することで回避できる場合があります。

編集1

UserNameToVerifyの値に"+"" "に変更されていることがわかる場合があるため、次のようにする必要があります。

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

これで長さが正しくなります。

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

もちろん、UrlEncode(LukeHの答えのように)を呼び出すと、すべてが無意味になります。

178
user287466

私の推測では、クエリ文字列に含めるときに、Base64文字列を単に RL-encode する必要があるだけです。

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>";
28
LukeH

私はまだ投票したりコメントしたりするほど評判がよくありませんが、LukeHの答えは私にとってスポットでした。

AES暗号化は現在使用する標準であるため、base64文字列(少なくとも私が見たすべての暗号化/復号化実装)を生成します。この文字列の長さは4の倍数です(string.length%4 = 0)

私が取得していた文字列は、先頭と末尾に+と=を含んでおり、それをURLのクエリ文字列に連結すると、(たとえば、生成する電子メールで)正しく見えますが、リンクをたどると.NETページはそれを受け取り、this.Page.Request.QueryStringに入れます。これらの特殊文字はなくなり、文字列の長さは4の倍数になりません。

文字列の前に特殊文字(例:+)があり、末尾に=があるため、暗号テキストを変更する際に違いを補うために=を追加することはできません。 '元のクエリ文字列に実際にあったものと一致しません。

そのため、HtmlEncodeではなくHttpUtility.URLEncodeで暗号化テキストをラップすると、英数字以外の文字が変換され、.stringがクエリ文字列コレクションに解釈されたときに元の状態に解析されるようになります。

良いことは、URLのクエリ文字列を生成するときにURLEncodeを実行するだけです。受信側では、元の文字列値に自動的に変換されます。

ここにいくつかのサンプルコードがあります

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

データを知らない最初の推測は、UserNameToVerifyの長さが4の倍数ではないということです。 msdnの FromBase64String を確認してください。

// Ok
byte[] b1 = Convert.FromBase64String("CoolDude");
// Exception
byte[] b2 = Convert.FromBase64String("MyMan");
5
SwDevMan81
    string stringToDecrypt = CypherText.Replace(" ", "+");
    int len = stringToDecrypt.Length;
    byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt); 
0
JIYAUL MUSTAPHA

暗号化された文字列には、+=の2つの特殊文字が含まれていました。

「+」記号はエラーを示していたため、以下の解決策はうまくいきました:

//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
...
0
Vikrant