Độ dài không hợp lệ cho mảng ký tự Base-64


91

Như tiêu đề cho biết, tôi nhận được:

Độ dài không hợp lệ cho mảng ký tự Base-64.

Tôi đã đọc về vấn đề này ở đây và có vẻ như đề xuất là lưu trữ ViewState trong SQL nếu nó lớn. Tôi đang sử dụng một trình hướng dẫn với nhiều thu thập dữ liệu nên rất có thể ViewState của tôi lớn. Tuy nhiên, trước khi tôi chuyển sang giải pháp "store-in-DB", có lẽ ai đó có thể xem qua và cho tôi biết liệu tôi có các tùy chọn khác không?

Tôi tạo email để gửi bằng phương pháp dưới đây:

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

Phương thức Mã hóa trông giống như sau:

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

Đây là HTML trong hotmail:

Vui lòng nhấp vào liên kết bên dưới hoặc dán vào trình duyệt để xác minh tài khoản email của bạn.

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

Ở đầu nhận, trang VerifyEmail.aspx.cs có dòng:

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

Đây là getter cho UserNameToVerify:

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

Và đây là phương thức GetQueryStringValue:

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

Và phương pháp giải mã giống như sau:

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

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

Lỗi này có thể được khắc phục bằng bản sửa lỗi mã hay tôi phải lưu trữ ViewState trong cơ sở dữ liệu?

Câu trả lời:


205

Độ dài của một chuỗi được mã hóa base64 luôn là bội số của 4. Nếu nó không phải là bội số của 4, thì các =ký tự sẽ được nối thêm cho đến khi có. Một chuỗi truy vấn của biểu mẫu ?name=valuecó vấn đề khi valuechứa các =charaters (một số trong số chúng sẽ bị loại bỏ, tôi không nhớ lại hành vi chính xác). Bạn có thể thoát khỏi việc thêm đúng số =ký tự trước khi thực hiện giải mã base64.

Chỉnh sửa 1

Bạn có thể thấy rằng giá trị của UserNameToVerifyđã được "+"thay đổi thành " "'s, vì vậy bạn có thể cần phải làm như vậy:

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

Điều này sẽ có độ dài phù hợp;

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

Tất nhiên việc gọi điện UrlEncode(như trong câu trả lời của LukeH) sẽ khiến mọi chuyện trở nên náo nhiệt.


9
Cảm ơn Brad - Nó thực sự là đoạn mã nhỏ này đã thực hiện công việc: a = a.Replace ("", "+");
Peter

1
@Code Sherpa: nếu đúng như vậy, lựa chọn tốt nhất của bạn là urlencode trước khi gửi chuỗi và urldecode khi nhận. Nếu không, nếu một ký tự quan trọng khác của url lọt vào chuỗi của bạn thì bạn sẽ phải thêm một Replacecâu lệnh khác . Mã hóa là một tổng thể bảo vệ bạn bất kể.
Matt Ellen

5
Bạn không phải UrlDecode chuỗi của bạn khi nhận được vì các tham số yêu cầu đã được ASP.Net UrlDecodes. Tuy nhiên, bạn nên UrlEncode khi gửi.
bleeeah

Hoặc nếu bạn muốn một phiên bản nội tuyến: a = a + new string('=', (4 - a.Length % 4) % 4). Ví dụ để giải mã RFC 4648 URL an toàn 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
"Bạn không để UrlDecode" - NÀY! Bước qua mã của tôi, tôi có thể thấy thông số đã được giải mã, vấn đề là tôi chạy nó qua UrlDecodeđó sẽ xóa các ký tự. Cảm ơn @MattEllen
GJKH

30

Tôi đoán là bạn chỉ cần mã hóa URL chuỗi Base64 của mình khi bạn đưa nó vào chuỗi truy vấn.

Mã hóa Base64 sử dụng một số ký tự phải được mã hóa nếu chúng là một phần của chuỗi truy vấn (cụ thể là +/và có thể =cũng vậy). Nếu chuỗi không được mã hóa chính xác thì bạn sẽ không thể giải mã thành công ở đầu bên kia, do đó sẽ xảy ra lỗi.

Bạn có thể sử dụng HttpUtility.UrlEncodephương pháp để mã hóa chuỗi Base64 của mình:

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

Cảm ơn. Chỉ cần thử gợi ý của bạn Luke nhưng điều đó không hiệu quả :(.
Peter

@Sherpa - Hãy tiếp tục làm việc, vấn đề gần như chắc chắn là với các =ký tự ở cuối .

Luke - Tôi có cảm giác là bạn nói đúng. Sẽ thử điều này ở nhà. Cảm ơn nhiều lắm. FYI - Tôi đã thêm chuỗi trông như thế nào trong hộp thư đến hotmail trong bài đăng gốc của mình.
Peter

chú brad nói đúng, tuần trước tôi cũng gặp vấn đề tương tự và vấn đề là ký tự dấu "=" ._.
Marcote

10

Tôi không đủ uy tín để ủng hộ hoặc bình luận, nhưng câu trả lời của LukeH đã phù hợp với tôi.

Vì mã hóa AES là tiêu chuẩn để sử dụng hiện nay, nó tạo ra một chuỗi base64 (ít nhất là tất cả các triển khai mã hóa / giải mã mà tôi đã thấy). Chuỗi này có độ dài theo bội số của 4 (string.length% 4 = 0)

Các chuỗi mà tôi nhận được chứa + và = ở đầu hoặc cuối, và khi bạn chỉ nối chuỗi đó vào chuỗi truy vấn của URL, nó sẽ trông đúng (ví dụ: trong email bạn tạo), nhưng khi liên kết được theo sau và Trang .NET nhận nó và đưa nó vào trang này.Page.Request.QueryString, những ký tự đặc biệt đó sẽ biến mất và độ dài chuỗi của bạn sẽ không nằm trong bội số của 4.

Vì là các ký tự đặc biệt ở TRƯỚC của chuỗi (ví dụ: +), cũng như = ở cuối, bạn không thể chỉ thêm một số = để tạo ra sự khác biệt khi bạn đang thay đổi văn bản cypher theo cách không không khớp với những gì thực sự có trong chuỗi truy vấn ban đầu.

Vì vậy, gói văn bản cypher bằng HttpUtility.URLEncode (không phải HtmlEncode) sẽ biến đổi các ký tự không phải chữ và số theo cách đảm bảo .NET phân tích cú pháp chúng trở lại trạng thái ban đầu khi nó được thâm nhập vào bộ sưu tập chuỗi truy vấn.

Điều tốt là chúng ta chỉ cần thực hiện URLEncode khi tạo chuỗi truy vấn cho URL. Ở phía đến, nó tự động được dịch ngược lại thành giá trị chuỗi ban đầu.

Đây là một số mã ví dụ

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

6

Dự đoán ban đầu của tôi mà không biết dữ liệu sẽ là UserNameToVerify không phải là bội số của 4 chiều dài. Kiểm tra FromBase64String trên msdn.

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

Cảm ơn SwDevMan81. Vừa rồi tan sở nhưng tối nay sẽ thử cái này. Cảm ơn bạn đã giúp đỡ.
Peter

Không có vấn đề gì, cách khắc phục sẽ là thêm một ký tự để nhận một chuỗi là bội số của 4.
SwDevMan81

Cảm ơn một lần nữa SwDevMan81. Tôi sẽ xem xét nó. Tôi đã đăng UserNameToVeryify trong bài đăng ban đầu của mình (FYI). Được rồi ... bây giờ tôi thực sự cần phải đi nếu không tôi sẽ gặp rắc rối với ông chủ thực sự :)
Peter

Có vẻ như bài đăng này cũng có thể hữu ích: stackoverflow.com/questions/1392970/…
SwDevMan81

1

Chuỗi được mã hóa có hai ký tự đặc biệt +=.

Dấu '+' báo lỗi, vì vậy giải pháp dưới đây hoạt động tốt:

//replace + sign

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

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

HOẶC LÀ

//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); 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.