Недопустимая длина массива Base-64 char

Как видно из названия, я получаю:

Недопустимая длина для массива Base-64.

Я читал об этой проблеме здесь, и кажется, что предложение состоит в том, чтобы сохранить ViewState в SQL, если он большой. Я использую мастер с большим количеством сбора данных, поэтому мои ViewState велики. Но, прежде чем я перейду к решению "store-in-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 в hotmail:

Пожалуйста, нажмите на ссылку ниже или вставьте ее в браузер, чтобы подтвердить свою учетную запись электронной почты.

HTTP://локальный: 1563/Счета /VerifyEmail.aspx а = YOHY57xYRENEOu3H + FGq1Rf09AZAI56EPjfwuK8XWKg =

На принимающей стороне страница VerifyEmail.aspx.cs имеет строку:

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

Вот метод получения для UserNameToVerify:

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 в базе данных?

Ответ 1

Длина строки в кодировке base64 всегда кратна 4. Если она не кратна 4, то символы = добавляются до тех пор, пока это не произойдет. Строка запроса в форме ?name=value имеет проблемы, когда value содержит = charaters (некоторые из них будут отброшены, я не помню точное поведение). Возможно, вам удастся добавить правильное количество символов = перед выполнением декодирования base64.

Редактировать 1

Вы можете обнаружить, что значение UserNameToVerify изменилось на " " "+" на " " поэтому вам может потребоваться сделать что-то вроде этого:

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

Это должно получить правильную длину;

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

Конечно, вызов UrlEncode (как в ответе LukeH) должен сделать все это спорным.

Ответ 2

Моя догадка заключается в том, что вам просто нужно URL-кодировать вашу строку Base64, когда вы включаете ее в строку запроса.

В кодировке 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>";

Ответ 3

Я не достаточно авторитет, чтобы продвигать или комментировать, но ответ LukeH был для меня интересным.

Поскольку шифрование AES является стандартным для использования сейчас, оно создает строку base64 (по крайней мере, все реализации шифрования/расшифровки, которые я видел). Эта строка имеет длину в кратных 4 (string.length% 4 = 0)

Строки, которые я содержал + и = в начале или конце, и когда вы просто связываете это с запросом URL-адреса, он будет выглядеть правильно (например, в созданном вами письме), но когда ссылка и страница .NET получает его и помещает в this.Page.Request.QueryString, эти специальные символы исчезнут, а длина строки не будет в несколько раз.

В качестве специальных символов в FRONT строки (ex: +), а также = в конце, вы не можете просто добавить some =, чтобы изменить разницу, поскольку вы изменяете текст cypher в который не соответствует тому, что было на самом деле в исходном запросе.

Таким образом, обтекание cypher-текстом с помощью HttpUtility.URLEncode(а не HtmlEncode) преобразует не-буквенно-цифровые символы таким образом, чтобы гарантировать, что .NET проверит их обратно в исходное состояние, когда оно будет проиндексировано в коллекцию запросов.

Хорошо, нам нужно всего лишь сделать URLEncode при создании запроса для URL-адреса. На входящей стороне он автоматически переводится обратно в исходное строковое значение.

Вот пример кода

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

Ответ 4

Моим первоначальным предположением, не зная данных, было бы то, что UserNameToVerify не кратно 4 в длину. Проверьте FromBase64String на MSDN.

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

Ответ 5

Зашифрованная строка содержит два специальных символа + и =.

Знак "+" давал ошибку, поэтому нижеприведенное решение работало хорошо:

//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
...