Jak mówi tytuł, otrzymuję:
Nieprawidłowa długość tablicy znaków Base-64.
Czytałem o tym problemie tutaj i wydaje się, że sugestia jest taka, aby przechowywać ViewState w SQL, jeśli jest duży. Używam kreatora z dużą ilością danych, więc prawdopodobnie mój ViewState jest duży. Ale zanim przejdę do rozwiązania „przechowuj w bazie danych”, może ktoś może rzucić okiem i powiedzieć mi, czy mam inne opcje?
Konstruuję wiadomość e-mail do dostarczenia za pomocą poniższej metody:
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);
}
Metoda Encrypt wygląda następująco:
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);
}
Oto jak wygląda HTML w hotmailu:
Kliknij poniższy link lub wklej go do przeglądarki, aby zweryfikować swoje konto e-mail.
Po stronie odbierającej strona VerifyEmail.aspx.cs zawiera wiersz:
string username = Cryptography.Decrypt(_webContext.UserNameToVerify, "verify");
Oto metoda pobierająca UserNameToVerify:
public string UserNameToVerify
{
get
{
return GetQueryStringValue("a").ToString();
}
}
A oto metoda GetQueryStringValue:
private static string GetQueryStringValue(string key)
{
return HttpContext.Current.Request.QueryString.Get(key);
}
A metoda deszyfrowania wygląda następująco:
public static string Decrypt(string cipherText, string password)
{
**// THE ERROR IS THROWN HERE!!**
byte[] cipherBytes = Convert.FromBase64String(cipherText);
Czy ten błąd można naprawić za pomocą poprawki kodu, czy też muszę przechowywać ViewState w bazie danych?
Replace
instrukcję. Encoding to kombinezon, który chroni Cię niezależnie.a = a + new string('=', (4 - a.Length % 4) % 4)
. Przykład dekodowania RFC 4648 bezpiecznego adresu 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))); }
UrlDecode
co usunąłem znaki. Dzięki @MattEllenDomyślam się, że wystarczy zakodować adres URL ciąg Base64, gdy umieścisz go w kwerendzie.
Kodowanie Base64 wykorzystuje pewne znaki, które muszą być zakodowane, jeśli są częścią kwerendy (mianowicie
+
i/
, a może=
też). Jeśli ciąg nie jest poprawnie zakodowany, nie będzie można go pomyślnie zdekodować na drugim końcu, stąd błędy.Możesz użyć
HttpUtility.UrlEncode
metody do zakodowania ciągu 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>";
źródło
=
znaków końcowych .Nie mam jeszcze wystarczającej reputacji, aby głosować za lub komentować, ale odpowiedź LukeHa była dla mnie trafna.
Ponieważ szyfrowanie AES jest obecnie standardem, tworzy ciąg base64 (przynajmniej wszystkie implementacje szyfrowania / deszyfrowania, które widziałem). Ten łańcuch ma długość będącą wielokrotnością 4 (string.length% 4 = 0)
Ciągi, które otrzymałem, zawierały + i = na początku lub na końcu, a kiedy po prostu połączysz je w kwerendę adresu URL, będzie wyglądać dobrze (na przykład w wygenerowanej wiadomości e-mail), ale gdy podążasz za linkiem i Strona .NET odbiera go i umieszcza w this.Page.Request.QueryString, te znaki specjalne zostaną usunięte, a długość ciągu nie będzie wielokrotnością 4.
Ponieważ znaki specjalne znajdują się na PRZODU ciągu (np. +), A także = na końcu, nie możesz po prostu dodać znaku =, aby nadrobić różnicę, ponieważ zmieniasz szyfrogram w sposób, który tego nie robi nie pasuje do tego, co faktycznie było w oryginalnym querystring.
Tak więc zawijanie szyfrowanego tekstu za pomocą HttpUtility.URLEncode (nie HtmlEncode) przekształca znaki niealfanumeryczne w sposób, który zapewnia, że .NET analizuje je z powrotem do ich pierwotnego stanu, gdy zostanie zinterpretowany w kolekcji querystring.
Dobrą rzeczą jest to, że musimy wykonać kod URLEncode tylko podczas generowania zapytania dotyczącego adresu URL. Po stronie przychodzącej jest automatycznie tłumaczona z powrotem na oryginalną wartość ciągu.
Oto przykładowy kod
string cryptostring = MyAESEncrypt(MySecretString); string URL = WebFunctions.ToAbsoluteUrl("~/ResetPassword.aspx?RPC=" + HttpUtility.UrlEncode(cryptostring));
źródło
Moje początkowe przypuszczenie bez znajomości danych byłoby takie, że UserNameToVerify nie jest wielokrotnością 4 długości. Sprawdź FromBase64String na msdn.
// Ok byte[] b1 = Convert.FromBase64String("CoolDude"); // Exception byte[] b2 = Convert.FromBase64String("MyMan");
źródło
Zaszyfrowany ciąg miał dwa znaki specjalne
+
i=
.Znak '+' podawał błąd, więc poniższe rozwiązanie działało dobrze:
//replace + sign encryted_string = encryted_string.Replace("+", "%2b"); //`%2b` is HTTP encoded string for **+** sign
LUB
//encode special charactes encryted_string = HttpUtility.UrlEncode(encryted_string); //then pass it to the decryption process ...
źródło
string stringToDecrypt = CypherText.Replace(" ", "+"); int len = stringToDecrypt.Length; byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt);
źródło