Panjang tidak valid untuk array karakter Base-64

91

Seperti judulnya, saya mendapatkan:

Panjang tidak valid untuk array karakter Base-64.

Saya telah membaca tentang masalah ini di sini dan sepertinya sarannya adalah untuk menyimpan ViewState dalam SQL jika ukurannya besar. Saya menggunakan wizard dengan banyak pengumpulan data sehingga kemungkinan ViewState saya besar. Tapi, sebelum saya beralih ke solusi "store-in-DB", mungkin seseorang dapat melihat dan memberi tahu saya jika saya memiliki pilihan lain?

Saya membuat email untuk pengiriman menggunakan metode di bawah ini:

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

Metode Enkripsi terlihat seperti ini:

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

Inilah tampilan HTML di hotmail:

Silakan klik tautan di bawah ini atau tempelkan ke browser untuk memverifikasi akun email Anda.

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

Di sisi penerima, halaman VerifyEmail.aspx.cs memiliki baris:

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

Berikut adalah pengambil untuk UserNameToVerify:

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

Dan inilah metode GetQueryStringValue:

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

Dan metode dekripsi terlihat seperti:

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

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

Dapatkah kesalahan ini diatasi dengan perbaikan kode atau haruskah saya menyimpan Kondisi Tampilan dalam database?

Peter
sumber

Jawaban:

205

Panjang string yang disandikan base64 selalu merupakan kelipatan 4. Jika bukan kelipatan 4, =karakter akan ditambahkan hingga menjadi. String kueri formulir ?name=valuememiliki masalah ketika karakter valueberisi =(beberapa di antaranya akan dihapus, saya tidak ingat perilaku persisnya). Anda mungkin bisa lolos dengan menambahkan jumlah =karakter yang tepat sebelum melakukan dekode base64.

Edit 1

Anda mungkin menemukan bahwa nilai dari UserNameToVerifytelah "+"diubah menjadi " "'s sehingga Anda mungkin perlu melakukan sesuatu seperti ini:

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

Ini harus mendapatkan panjang yang tepat;

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

Tentu saja memanggil UrlEncode(seperti dalam jawaban LukeH) harus membuat ini semua diperdebatkan.

Vadim Ovchinnikov
sumber
9
Terima kasih Brad - Sebenarnya kode kecil inilah yang berhasil: a = a.Replace ("", "+");
Peter
1
@Code Sherpa: jika itu masalahnya, pilihan terbaik Anda adalah urlencode sebelum mengirim string, dan urldecode saat diterima. Jika tidak, jika karakter penting url lain masuk ke string Anda, maka Anda harus menambahkan Replacepernyataan lain . Encoding adalah coverall yang melindungi Anda.
Matt Ellen
5
Anda tidak boleh UrlDecode string Anda pada tanda terima karena parameter permintaan sudah UrlDecoded oleh ASP.Net. Namun Anda harus UrlEncode saat mengirim.
Bleeeah
Atau jika Anda ingin versi inline: a = a + new string('=', (4 - a.Length % 4) % 4). Contoh untuk mendekode RFC 4648 URL-safe 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
"Anda tidak perlu ke UrlDecode" - INI! Melangkah melalui kode saya, saya bisa melihat parameter sudah diterjemahkan, masalahnya adalah saya menjalankannya melalui UrlDecodemana yang menghapus karakter. Terima kasih @MattEllen
GJKH
30

Dugaan saya adalah bahwa Anda hanya perlu menyandikan URL string Base64 Anda saat Anda memasukkannya ke dalam string kueri.

Pengkodean Base64 menggunakan beberapa karakter yang harus disandikan jika mereka adalah bagian dari string kueri (yaitu +dan /, dan mungkin =juga). Jika string tidak dikodekan dengan benar maka Anda tidak akan dapat memecahkan kode itu dengan sukses di ujung lain, maka kesalahannya.

Anda dapat menggunakan HttpUtility.UrlEncodemetode ini untuk menyandikan string Base64 Anda:

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
sumber
Terima kasih. Baru saja mencoba saran Anda, Luke, tetapi tidak berhasil :(.
Peter
@ Sherpa - Terus kerjakan, masalahnya hampir pasti dengan =karakter yang tertinggal .
Luke - Aku merasa kamu benar. Akan mencoba ini di rumah. Terimakasih banyak. FYI - Saya menambahkan seperti apa string itu di kotak masuk hotmail saya di posting asli saya.
Peter
paman brad benar, saya mengalami masalah yang sama minggu lalu dan masalahnya adalah karakter "=" yang tertinggal ._.
Marcote
10

Saya belum cukup bereputasi untuk memberi suara positif atau berkomentar, tetapi jawaban LukeH tepat untuk saya.

Karena enkripsi AES adalah standar yang digunakan sekarang, ia menghasilkan string base64 (setidaknya semua implementasi enkripsi / dekripsi yang pernah saya lihat). String ini memiliki panjang kelipatan 4 (string.length% 4 = 0)

String yang saya dapatkan berisi + dan = di awal atau akhir, dan ketika Anda baru saja menggabungkannya menjadi string kueri URL, itu akan terlihat benar (misalnya, dalam email yang Anda buat), tetapi ketika tautan diikuti dan tautan Halaman .NET menerimanya dan memasukkannya ke this.Page.Request.QueryString, karakter khusus tersebut akan hilang dan panjang string Anda tidak akan menjadi kelipatan 4.

Karena adalah karakter khusus di FRONT string (mis .: +), serta = di akhir, Anda tidak bisa hanya menambahkan beberapa = untuk membuat perbedaan saat Anda mengubah teks sandi dengan cara yang tidak tidak cocok dengan apa yang sebenarnya ada di string kueri asli.

Jadi, membungkus teks sandi dengan HttpUtility.URLEncode (bukan HtmlEncode) mengubah karakter non-alfanumerik dengan cara yang memastikan .NET mem-parsingnya kembali ke keadaan semula ketika diintepretasikan ke dalam kumpulan querystring.

Hal baiknya adalah, kita hanya perlu melakukan URLEncode saat membuat querystring untuk URL. Di sisi masuk, itu secara otomatis diterjemahkan kembali ke nilai string asli.

Berikut beberapa contoh kode

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

Tebakan awal saya tanpa mengetahui datanya adalah bahwa UserNameToVerify bukanlah kelipatan 4 panjangnya. Lihat FromBase64String di msdn .

// Ok
byte[] b1 = Convert.FromBase64String("CoolDude");
// Exception
byte[] b2 = Convert.FromBase64String("MyMan");
SwDevMan81
sumber
Terima kasih SwDevMan81. Baru saja pulang kerja tetapi akan mencobanya nanti malam. Terima kasih atas bantuan Anda.
Peter
Tidak masalah, perbaikannya adalah mengganti dengan karakter untuk mendapatkan string yang merupakan kelipatan 4.
SwDevMan81
Terima kasih lagi SwDevMan81. Saya akan lihat itu. Saya memposting UserNameToVeryify di posting asli saya (FYI). Oke ... sekarang saya benar-benar harus pergi atau saya akan mendapat masalah dengan bos yang sebenarnya :)
Peter
Sepertinya posting ini mungkin membantu juga: stackoverflow.com/questions/1392970/…
SwDevMan81
1

String terenkripsi memiliki dua karakter khusus, +dan =.

Tanda '+' memberikan kesalahan, jadi solusi di bawah ini bekerja dengan baik:

//replace + sign

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

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

ATAU

//encode special charactes 

encryted_string = HttpUtility.UrlEncode(encryted_string);

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