Ungültige Länge für ein Base-64-Zeichenarray

87

Wie der Titel sagt, bekomme ich:

Ungültige Länge für ein Base-64-Zeichenarray.

Ich habe hier über dieses Problem gelesen und es scheint, dass der Vorschlag darin besteht, ViewState in SQL zu speichern, wenn es groß ist. Ich verwende einen Assistenten mit viel Datenerfassung, sodass mein ViewState wahrscheinlich groß ist. Aber bevor ich mich der "Store-in-DB" -Lösung zuwende, kann vielleicht jemand einen Blick darauf werfen und mir sagen, ob ich andere Optionen habe?

Ich konstruiere die E-Mail für die Zustellung mit der folgenden Methode:

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

Die Verschlüsselungsmethode sieht folgendermaßen aus:

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

So sieht der HTML-Code in Hotmail aus:

Bitte klicken Sie auf den unten stehenden Link oder fügen Sie ihn in einen Browser ein, um Ihr E-Mail-Konto zu überprüfen.

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

Auf der Empfangsseite enthält die Seite VerifyEmail.aspx.cs die folgende Zeile:

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

Hier ist der Getter für UserNameToVerify:

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

Und hier ist die GetQueryStringValue-Methode:

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

Und die Entschlüsselungsmethode sieht so aus:

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

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

Kann dieser Fehler mit einem Code-Fix behoben werden oder muss ich ViewState in der Datenbank speichern?

Peter
quelle

Antworten:

202

Die Länge einer Base64-codierten Zeichenfolge ist immer ein Vielfaches von 4. Wenn es sich nicht um ein Vielfaches von 4 handelt, werden =Zeichen angehängt, bis dies der Fall ist. Eine Abfragezeichenfolge des Formulars ?name=valuehat Probleme, wenn sie Zeichen valueenthält =(einige von ihnen werden gelöscht, ich erinnere mich nicht an das genaue Verhalten). Möglicherweise können Sie die richtige Anzahl von =Zeichen anhängen, bevor Sie die base64-Dekodierung durchführen.

Bearbeiten 1

Möglicherweise stellen Sie fest, dass sich der Wert von UserNameToVerifyin in "+"geändert hat, " "sodass Sie möglicherweise Folgendes tun müssen:

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

Dies sollte die richtige Länge haben;

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

Natürlich sollte das Anrufen UrlEncode(wie in Lukas Antwort) alles in Frage stellen.

Vadim Ovchinnikov
quelle
9
Danke Brad - Es war tatsächlich dieses kleine Stück Code, das den Job gemacht hat: a = a.Replace ("", "+");
Peter
1
@Code Sherpa: Wenn dies der Fall ist, ist es am besten, vor dem Senden der Zeichenfolge einen Urlencode und nach Erhalt einen URL-Code zu verwenden. Andernfalls müssen Sie eine weitere ReplaceAnweisung hinzufügen, wenn ein anderes URL-signifikantes Zeichen in Ihre Zeichenfolge aufgenommen wird . Codierung ist ein Overall, der Sie unabhängig davon schützt.
Matt Ellen
5
Sie müssen Ihre Zeichenfolge beim Empfang nicht mit UrlDecode versehen, da die Anforderungsparameter bereits von ASP.Net UrlDecoded sind. Sie sollten jedoch beim Senden UrlEncode verwenden.
bleeeah
Oder wenn Sie eine Inline-Version wünschen : a = a + new string('=', (4 - a.Length % 4) % 4). Beispiel zum Dekodieren von RFC 4648 URL-sicherer 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
"Sie nicht zu UrlDecode" - DIESES! Beim Durchlaufen meines Codes konnte ich sehen, dass der Parameter bereits dekodiert war. Das Problem war, dass ich ihn UrlDecodedurchführte, wodurch Zeichen entfernt wurden. Danke @MattEllen
GJKH
30

Ich vermute, dass Sie Ihre Base64-Zeichenfolge einfach per URL codieren müssen, wenn Sie sie in den Querystring aufnehmen.

Bei der Base64-Codierung werden einige Zeichen verwendet, die codiert werden müssen, wenn sie Teil eines Querystrings sind (nämlich +und /, und möglicherweise =auch). Wenn die Zeichenfolge nicht korrekt codiert ist, können Sie sie am anderen Ende nicht erfolgreich decodieren, daher die Fehler.

Mit der HttpUtility.UrlEncodeMethode können Sie Ihre Base64-Zeichenfolge codieren:

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
quelle
Vielen Dank. Ich habe gerade Ihren Vorschlag versucht, Luke, aber das hat nicht funktioniert :(.
Peter
@Sherpa - Arbeite weiter, das Problem liegt mit ziemlicher Sicherheit bei den nachfolgenden =Zeichen.
Luke - Ich habe das Gefühl, du hast recht. Werde das zu Hause versuchen. Danke ein Bündel. Zu Ihrer Information - Ich habe in meinem ursprünglichen Beitrag hinzugefügt, wie die Zeichenfolge in meinem Hotmail-Posteingang aussieht.
Peter
Onkel Brad hat recht, ich hatte letzte Woche das gleiche Problem und das Problem war ein nachfolgendes "=" Zeichen ._.
Marcote
10

Ich bin noch nicht seriös genug, um zu stimmen oder zu kommentieren, aber die Antwort von LukeH war genau richtig für mich.

Da die AES-Verschlüsselung derzeit der Standard ist, wird eine base64-Zeichenfolge erzeugt (zumindest alle Verschlüsselungs- / Entschlüsselungsimplementierungen, die ich gesehen habe). Diese Zeichenfolge hat eine Länge in Vielfachen von 4 (Zeichenfolgenlänge% 4 = 0)

Die Zeichenfolgen, die ich am Anfang oder Ende erhalten habe, + und =, und wenn Sie diese nur in den Querystring einer URL verketten, sieht sie richtig aus (z. B. in einer von Ihnen generierten E-Mail), aber wenn der Link befolgt wird und die Die .NET-Seite empfängt es und fügt es in this.Page.Request.QueryString ein. Diese Sonderzeichen werden entfernt und Ihre Zeichenfolgenlänge wird nicht ein Vielfaches von 4 sein.

Da es sich um Sonderzeichen an der Vorderseite der Zeichenfolge (z. B. +) sowie um = am Ende handelt, können Sie nicht einfach einige = hinzufügen, um den Unterschied auszugleichen, wenn Sie den Chiffretext auf eine Weise ändern, die dies nicht tut stimmt nicht mit dem überein, was sich tatsächlich im ursprünglichen Querystring befand.

Wenn Sie den Chiffretext mit HttpUtility.URLEncode (nicht HtmlEncode) umschließen, werden die nicht alphanumerischen Zeichen so transformiert, dass sie von .NET in ihren ursprünglichen Zustand zurückversetzt werden, wenn sie in die Querystring-Auflistung interpretiert werden.

Das Gute ist, wir müssen nur den URLEncode ausführen, wenn wir den Querystring für die URL generieren. Auf der eingehenden Seite wird es automatisch wieder in den ursprünglichen Zeichenfolgenwert übersetzt.

Hier ist ein Beispielcode

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

Meine erste Vermutung ohne Kenntnis der Daten wäre, dass UserNameToVerify kein Vielfaches von 4 ist. Schauen Sie sich den FromBase64String auf msdn an.

// Ok
byte[] b1 = Convert.FromBase64String("CoolDude");
// Exception
byte[] b2 = Convert.FromBase64String("MyMan");
SwDevMan81
quelle
Vielen Dank, SwDevMan81. Ich verlasse gerade die Arbeit, werde es aber später heute Abend versuchen. Danke für Ihre Hilfe.
Peter
Kein Problem, die Lösung wäre, mit einem Zeichen
aufzufüllen
Nochmals vielen Dank SwDevMan81. Ich werde mir das ansehen. Ich habe UserNameToVeryify in meinem ursprünglichen Beitrag (FYI) veröffentlicht. OK ... jetzt muss ich wirklich gehen oder ich werde Ärger mit dem echten Chef bekommen :)
Peter
Dieser Beitrag könnte auch hilfreich sein: stackoverflow.com/questions/1392970/…
SwDevMan81
1

Die verschlüsselte Zeichenfolge hatte zwei Sonderzeichen +und =.

Das '+' Zeichen gab den Fehler aus, daher funktionierte die folgende Lösung gut:

//replace + sign

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

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

ODER

//encode special charactes 

encryted_string = HttpUtility.UrlEncode(encryted_string);

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