Base-64 char 배열의 길이가 잘못되었습니다.


91

제목에서 알 수 있듯이 다음과 같은 결과를 얻었습니다.

Base-64 char 배열의 길이가 잘못되었습니다.

나는 여기 에서이 문제에 대해 읽었으며 ViewState가 큰 경우 SQL에 저장하는 것이 좋습니다. 데이터 수집이 많은 마법사를 사용하고 있으므로 ViewState가 클 가능성이 큽니다. 그러나 "DB에 저장"솔루션으로 전환하기 전에 누군가가 다른 옵션이 있는지 살펴보고 말해 줄 수 있습니까?

아래 방법을 사용하여 배송 용 이메일을 구성합니다.

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

Encrypt 메서드는 다음과 같습니다.

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은 다음과 같습니다.

아래 링크를 클릭하거나 브라우저에 붙여 넣어 이메일 계정을 확인하십시오.

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

받는 쪽에서 VerifyEmail.aspx.cs 페이지에는 다음 줄이 있습니다.

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

UserNameToVerify의 getter는 다음과 같습니다.

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

다음은 GetQueryStringValue 메서드입니다.

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

그리고 해독 방법은 다음과 같습니다.

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

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

이 오류는 코드 수정으로 해결할 수 있습니까? 아니면 데이터베이스에 ViewState를 저장해야합니까?

답변:


205

base64로 인코딩 된 문자열의 길이는 항상 4의 배수입니다. 4의 배수가 아닌 경우 =문자가 추가 될 때까지 추가됩니다. 형식의 쿼리 문자열 에는 문자 ?name=valuevalue포함되어 있을 때 문제가 있습니다 =(일부는 삭제되지만 정확한 동작은 기억 나지 않습니다). =base64 디코딩을 수행하기 전에 올바른 수의 문자 를 추가하지 않아도 될 수 있습니다 .

편집 1

의 값 UserNameToVerify"+"'s로 변경 되었음을 " "알 수 있으므로 다음과 같이해야 할 수 있습니다.

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

길이가 정확해야합니다.

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

물론 전화 UrlEncode(LukeH의 답변에서와 같이)는이 모든 문제를 해결해야합니다.


9
감사합니다 Brad-실제로 작업을 수행 한 코드는 다음과 같습니다. a = a.Replace ( "", "+");
피터

1
@Code Sherpa : 그렇다면 최선의 선택은 문자열을 보내기 전에 urlencode를, 영수증에 urldecode를 지정하는 것입니다. 그렇지 않으면 다른 URL 중요한 문자가 문자열에 들어가면 다른 Replace문 을 추가해야 합니다. 인코딩은 당신을 보호 해주는 작업복입니다.
Matt Ellen

5
요청 매개 변수가 이미 ASP.Net에 의해 UrlDecoded되어 있으므로 수신시 문자열을 UrlDecode하지 마십시오. 그러나 보낼 때 UrlEncode해야합니다.
bleeeah

또는 인라인 버전을 원하는 경우 : a = a + new string('=', (4 - a.Length % 4) % 4). RFC 4648 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))); }
gregmac

1
"UrlDecode를하지 마십시오"-이거! 내 코드 UrlDecode를 밟아 보면 매개 변수가 이미 디코딩 된 것을 볼 수 있었는데, 문제는 문자를 제거 하는 과정에서 실행하는 것이 었습니다 . 감사합니다 @MattEllen
GJKH

30

내 생각 엔 쿼리 문자열에 포함시킬 때 Base64 문자열 을 URL 인코딩 하기 만하면 됩니다.

Base64 인코딩은 쿼리 문자열의 일부인 경우 인코딩해야하는 일부 문자를 사용합니다 (예 : +/, 그리고 가능할 수도 있음 =). 문자열이 올바르게 인코딩되지 않으면 다른 쪽 끝에서 성공적으로 디코딩 할 수 없으므로 오류가 발생합니다.

HttpUtility.UrlEncode메서드를 사용하여 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>";

감사. Luke의 제안을 시도했지만 작동하지 않았습니다. (.
Peter

@Sherpa-계속 작업하십시오. 문제는 거의 확실하게 후행 =문자에 있습니다.

루크-당신이 옳다고 생각합니다. 집에서 이것을 시도 할 것입니다. 번들 감사합니다. 참고로-원래 게시물의 핫메일받은 편지함에 문자열이 어떻게 보이는지 추가했습니다.
Peter는

브래드 삼촌이 맞아요, 지난주에 같은 문제가 있었는데 문제는 "="문자 ._.
Marcote

10

나는 아직 찬성하거나 댓글을 달기에 충분히 평판이 좋지 않지만 LukeH의 대답은 나를 위해 자리를 잡았습니다.

AES 암호화는 현재 사용하는 표준이므로 base64 문자열을 생성합니다 (적어도 내가 본 모든 암호화 / 복호화 구현). 이 문자열의 길이는 4의 배수입니다 (string.length % 4 = 0).

내가 포함 된 문자열은 시작 또는 끝 부분에 + 및 =를 포함하고 있으며 URL의 쿼리 문자열에 연결하면 올바르게 표시되지만 (예 : 생성 한 이메일에서) 링크를 따라갈 때 .NET 페이지는 그것을 받아 this.Page.Request.QueryString에 넣습니다. 특수 문자는 사라지고 문자열 길이는 4의 배수가 아닙니다.

문자열의 FRONT에 특수 문자 (예 : +)가 있고 끝에 =가 있으므로 암호 텍스트를 변경하는 방식으로 차이를 보완하기 위해 =를 추가 할 수 없습니다. 원래 쿼리 문자열에 실제로 있던 것과 일치하지 않습니다.

따라서 암호 텍스트를 HttpUtility.URLEncode (HtmlEncode가 아님)로 래핑하면 .NET이 쿼리 문자열 컬렉션으로 해석 될 때 원래 상태로 다시 구문 분석하는 방식으로 영숫자가 아닌 문자를 변환합니다.

좋은 점은 URL에 대한 쿼리 문자열을 생성 할 때만 URLEncode를 수행하면된다는 것입니다. 들어오는 쪽에서는 자동으로 원래 문자열 값으로 다시 변환됩니다.

다음은 몇 가지 예제 코드입니다.

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

6

데이터를 알지 못하는 내 초기 추측은 UserNameToVerify가 길이가 4의 배수가 아니라는 것입니다. msdn 에서 FromBase64String 을 확인하십시오 .

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

감사합니다 SwDevMan81. 지금 막 퇴근하지만 오늘 밤 나중에 시도해 보겠습니다. 당신의 도움을 주셔서 감사합니다.
피터

문제 없습니다. 수정은 4의 배수 인 문자열을 얻기 위해 문자로
채우는 것

다시 한번 SwDevMan81에게 감사드립니다. 제가 살펴 볼게요. 원래 게시물 (FYI)에 UserNameToVeryify를 게시했습니다. 좋아요 ... 이제 정말 가야 해요 아니면 진짜 상사와 곤경에 빠질 거예요 :)
Peter

이 게시물도 도움이 될 것 같습니다 : stackoverflow.com/questions/1392970/…
SwDevMan81

1

암호화 된 문자열에는 두 개의 특수 문자 +=.

'+'기호가 오류를 발생 시켰으므로 아래 솔루션이 잘 작동했습니다.

//replace + sign

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

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

또는

//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); 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.