TripleDES Недопустимая длина данных для шифрования

У меня есть следующий код:

public static string Encrypt3Des(string cipherString)
{
    string result = "";

    byte[] keyArray;
    byte[] ivArray;

    byte[] toEncryptArray = Enc3DesPerChar(cipherString);
    //string toEncryptString = ByteArrayToString(toEncryptArray);

    // Get the key from config file
    System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
    string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
    string iv = (string)settingsReader.GetValue("InitializationVector", typeof(String));

    keyArray = StringToByteArray(key);
    ivArray = StringToByteArray(iv);

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    //set the secret key for the tripleDES algorithm

    tdes.Key = keyArray;
    tdes.IV = ivArray;

    //ChiperMode
    tdes.Mode = CipherMode.CBC;

    //PaddingMode(if any extra byte added)
    tdes.Padding = PaddingMode.None;

    ICryptoTransform cTransform = tdes.CreateEncryptor();
    //transform the specified region of bytes array to resultArray
    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

    //Release resources held by TripleDes Encryptor
    tdes.Clear();

    result = ByteArrayToString(resultArray);

    return result;
}

И это мой метод:

protected static string ByteArrayToString(byte[] ba)
{
    StringBuilder hex = new StringBuilder(ba.Length * 2);
    foreach (byte b in ba)
        hex.AppendFormat("{0:x2}", b);
    return hex.ToString();
}

protected static byte[] StringToByteArray(String hex)
{
    int NumberChars = hex.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    return bytes;
}

protected static byte[] Enc3DesPerChar(String toEncrypt)
{
    string toAsciiString = ByteArrayToString(Encoding.ASCII.GetBytes(toEncrypt));

    string toRoll = toAsciiString;

    int NumberChars = toRoll.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(toRoll.Substring(i, 2), 16);
    }
    return bytes;
}

Все работает нормально с вышеуказанным методом, пока я не обнаружил, что метод не может принимать менее 8 символов.

Код блока, который вызывает ошибку:

byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

Сообщение об ошибке :

Недопустимая длина данных для шифрования.

Пример ввода:

Encrypt3Des("14022000"); // return encrypt because 8 character or more

Encrypt3Des("1402200"); // return error because 7 character

Кто-нибудь знает, почему это так или как я могу это исправить? (Я не знаю, исходит ли это от моего метода шифрования, но я знаю веб-приложение, которое использует то же самое для шифрования строк, и оно действительно работает.)

РЕДАКТИРОВАТЬ: Инструмент, который я использовал для ручного шифрования: 3des

Вариант должен:

  • Тип ввода текста
  • Открытый текст ввода
  • Функция 3DES
  • режим CBC
  • Фиксированный шестигранный ключ
  • Фиксированный вектор инициализации

person Ronald T.    schedule 11.12.2017    source источник
comment
Вы должны использовать дополнение для этого шифра в этом режиме (CBC).   -  person Evk    schedule 11.12.2017
comment
3DES — блочный шифр, в режиме CBC он может шифровать данные только кратными 8 байтам, если вы хотите использовать его для шифрования данных длиной не кратной 8 байтам, то необходимо использовать заполнение, с оговоркой что ваши зашифрованные данные могут быть длиннее ваших входных данных на 8 байт.   -  person Iridium    schedule 11.12.2017
comment
Не используйте 3DES для новой работы, он не так безопасен, как AES, и имеет только 112-битную защиту с тройным ключом. Вместо этого используйте AES (Advanced Encryption Standard), который поддерживает размеры ключей 128, 192 и 256. биты.   -  person zaph    schedule 11.12.2017
comment
Вы превращаете свою строку в байты (хорошо), чтобы превратить ее в шестнадцатеричный (да?), чтобы снова превратить ее в байты (?!). Шаги два и три можно было бы удалить. Но тогда вы пытаетесь сделать 3DES для каждого персонажа за раз. И это чертовски странно. Вы хотите заполнить PKCS7 и просто передать весь массив байтов в TransformFinalBlock. Получится ((inputBytes.Length + 15)/8) * 8)` байт. (0 -> 8, 7 -> 8, 8 -> 16, 15 -> 16, 16 -> 24 и т. д.)   -  person bartonjs    schedule 11.12.2017
comment
Это инструменты, которые я использовал для ручного шифрования по ссылке . Вариант заполнения и мой клиент, использующий этот инструмент для шифрования с помощью языка PHP CI. Итак, что я должен сделать, чтобы пересмотреть свой код, и результат может быть таким же, как инструмент? Параметр должен быть Обычный вводимый текст, функция 3des, режим CBC, фиксированный шестнадцатеричный ключ и фиксированный IV.   -  person Ronald T.    schedule 12.12.2017


Ответы (2)


Вы используете заполнение как none. Установите режим заполнения на PKCS7.

person Luke Joshua Park    schedule 11.12.2017
comment
Если я использую режим заполнения для PKCS7, результат всегда будет возвращать мне зашифрованную строку больше, чем я ожидал. - person Ronald T.; 11.12.2017
comment
Да, зашифрованные данные будут на один блок длиннее, 8 байт для DES/3DES. - person zaph; 11.12.2017

Хорошо, я думаю, что только что нашел решение (мой клиент сказал мне, как), мне нужно заполнить символ нулем перед циклом. null можно преобразовать в ascii с помощью «00». поэтому я решаю PadRight для результата ascii с символом от 0 до 16, поэтому один из моих методов становится:

protected static byte[] Enc3DesPerChar(String toEncrypt)
{
    string toAsciiString = ByteArrayToString(Encoding.ASCII.GetBytes(toEncrypt));

    string toRoll = toAsciiString.PadRight(16,'0');

    int NumberChars = toRoll.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(toRoll.Substring(i, 2), 16);
    }
    return bytes;
}
person Ronald T.    schedule 12.12.2017
comment
Использование нулевого заполнения - плохая идея. - person Luke Joshua Park; 12.12.2017
comment
И если вы хотите использовать этот отступ, проще просто изменить PaddingMode на Zeros. Но заполнение нулями не может быть удалено расшифровщиком, получатель должен понять, являются ли конечные нули семантическими или нет. - person bartonjs; 13.12.2017