Base-64 karakter dizisi için geçersiz uzunluk


91

Başlığın dediği gibi, alıyorum:

Base-64 karakter dizisi için geçersiz uzunluk.

Bu sorunu burada okudum ve görünüşe göre öneri ViewState'i büyükse SQL'de depolamak. Büyük miktarda veri toplamaya sahip bir sihirbaz kullanıyorum, bu nedenle ViewState'im büyük. Ama, "DB'de mağaza" çözümüne dönmeden önce, belki birisi bir göz atabilir ve başka seçeneklerim olup olmadığını söyleyebilir?

E-postayı teslimat için aşağıdaki yöntemi kullanarak oluşturuyorum:

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

Şifreleme yöntemi şuna benzer:

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

HTML, hotmail'de şöyle görünür:

E-posta hesabınızı doğrulamak için lütfen aşağıdaki bağlantıya tıklayın veya bir tarayıcıya yapıştırın.

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

Alıcı tarafta, VerifyEmail.aspx.cs sayfasında şu satır bulunur:

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

İşte UserNameToVerify için alıcı:

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

Ve işte GetQueryStringValue yöntemi:

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

Ve şifre çözme yöntemi şöyle görünür:

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

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

Bu hata bir kod düzeltmesiyle giderilebilir mi yoksa ViewState'i veritabanında depolamalı mıyım?

Yanıtlar:


205

Base64 olarak kodlanmış bir dizenin uzunluğu her zaman 4'ün katıdır. 4'ün katı değilse, bu dizinin =sonuna kadar karakterler eklenir. Karakterler içerdiğinde formun bir sorgu dizesinde ?name=valuesorunlar var (bazıları atılacak, tam davranışı hatırlamıyorum). Base64 kodunu çözmeden önce doğru sayıda karakter eklemekten kurtulabilirsiniz .value==

Düzenle 1

Sen değeri bulabilirsiniz UserNameToVerifyetti "+"'olarak değiştirildi s " "bunu böyle bir şey yapmak gerekebilir, böylece s':

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

Bu doğru uzunluğu almalı;

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

Elbette UrlEncodearamak (Luke'un cevabında olduğu gibi) bunu tamamen tartışmalı hale getirmelidir.


9
Teşekkürler Brad - Aslında işi yapan şu kod parçasıydı: a = a. Değiştir ("", "+");
Peter

1
@Code Sherpa: Bu durumda, en iyi seçiminiz dizeyi göndermeden önce urldecode ve makbuzda urldecode yapmaktır. Aksi takdirde, dizenize başka bir url önemli karakteri girerse, başka bir Replaceifade eklemeniz gerekir . Kodlama, sizi ne olursa olsun koruyan bir tulumdur.
Matt Ellen

5
İstek parametreleri ASP.Net tarafından zaten UrlDecoded olduğundan, makbuzda dizinizi UrlDecode yapmazsınız. Bununla birlikte, gönderirken UrlEncode yapmalısınız.
bleeeah

Veya bir satır içi sürümünü isterseniz: a = a + new string('=', (4 - a.Length % 4) % 4). RFC 4648 URL güvenli Base64 kodunu çözmek için örnek :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 yapmayın" - BU! Kodumdan geçerken, parametrenin zaten çözüldüğünü görebiliyordum, sorun, UrlDecodekarakterleri kaldırırken onu çalıştırmamdı . Teşekkürler @MattEllen
GJKH

30

Tahminim, sorgu dizesine eklediğinizde Base64 dizenizi URL olarak kodlamanız gerektiğidir.

Base64 kodlaması, bir sorgu dizesinin parçasıysa kodlanması gereken bazı karakterler kullanır (yani +ve /ve belki =de). Dize doğru şekilde kodlanmamışsa, diğer uçta başarılı bir şekilde kodunu çözemezsiniz, dolayısıyla hatalar.

HttpUtility.UrlEncodeBase64 dizenizi kodlamak için yöntemi kullanabilirsiniz :

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

Teşekkürler. Önerinizi az önce denedim Luke ama işe yaramadı :(.
Peter

@Sherpa - Çalışmaya devam edin, sorun neredeyse kesinlikle sondaki =karakterlerde.

Luke - haklı olduğunu hissediyorum. Bunu evde deneyeceğim. Bir paket teşekkürler. Bilginize - Hotmail gelen kutuma dize nasıl göründüğünü orijinal gönderime ekledim.
Peter

Brad amca haklı, geçen hafta aynı sorunu yaşadım ve sorun sondaki "=" karakteriydi ._.
Marcote

10

Henüz olumlu oy verecek veya yorum yapacak kadar saygın değilim, ancak LukeH'un cevabı benim için yerinde oldu.

AES şifrelemesi şu anda kullanılan standart olduğundan, bir base64 dizesi üretir (en azından gördüğüm tüm şifreleme / şifre çözme uygulamaları). Bu dizge 4'ün katları şeklinde bir uzunluğa sahiptir (string.length% 4 = 0)

+ Ve = dizeleri başında veya sonunda yer alıyor ve bunu bir URL'nin sorgu dizesine eklediğinizde, doğru görünecek (örneğin, oluşturduğunuz bir e-postada), ancak bağlantı izlendiğinde ve .NET sayfası onu alır ve bu sayfaya koyar.Page.Request.QueryString, bu özel karakterler kaybolacak ve dize uzunluğunuz 4'ün katı olmayacaktır.

Dizenin ÖN tarafında özel karakterler olduğu için (örneğin: +) ve sonunda =, şifre metnini değiştirirken farkı kapatmak için biraz = ekleyemezsiniz. Orijinal sorgu dizesindeki ile eşleşmiyor.

Bu nedenle, şifre metnini HttpUtility.URLEncode (HtmlEncode değil) ile sarmak, alfasayısal olmayan karakterleri .NET'in sorgu dizesi koleksiyonuna yorumlandığında orijinal durumlarına geri ayrıştırmasını sağlayacak şekilde dönüştürür.

İşin iyi yanı, URL için sorgu dizesini oluştururken yalnızca URLEncode yapmamız gerekiyor. Gelen tarafta, otomatik olarak orijinal dize değerine geri çevrilir.

İşte bazı örnek kod

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

6

Verileri bilmeden ilk tahminim, UserNameToVerify uzunluğunun 4 katı olmadığıdır. Check out FromBase64String msdn üzerinde.

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

Teşekkürler SwDevMan81. Şimdi işten çıkıyorum ama bunu bu gece daha sonra deneyeceğim Yardımınız için teşekkürler.
Peter

Sorun değil, düzeltme 4'ün katı olan bir dizge elde etmek için bir karakterle doldurmak olacaktır.
SwDevMan81

Tekrar teşekkürler SwDevMan81. Şuna bir bakacağım. Orijinal gönderimde (Bilginize) UserNameToVeryify gönderdim. Tamam ... şimdi gerçekten gitmem gerek yoksa gerçek patronla başım belaya girer :)
Peter

Görünüşe göre bu gönderi de yardımcı olabilir: stackoverflow.com/questions/1392970/…
SwDevMan81

1

Şifrelenmiş dizede iki özel karakter vardı +ve =.

'+' işareti hatayı veriyordu, bu nedenle aşağıdaki çözüm iyi çalıştı:

//replace + sign

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

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

VEYA

//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); 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.