Простое шифрование DES в зависимости от длины шифра

Я использую Java для создания игрушечной программы, которая шифрует сообщение с использованием шифрования DES. Сообщение, которое я хочу зашифровать:

String msg="This is a secret message";

Который я конвертирую в байты как:

byte [] msgBytes=msg.getBytes();

И отправьте его в функцию шифрования, которая работает следующим образом:

//encryption function
public static String encryptMsg(byte [] msgBytes, SecretKey myDesKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
    Cipher desCipher;
    // Create the cipher 
    desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
    desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);
    byte[] textEncrypted = desCipher.doFinal(msgBytes);

// converts to base64 for easier display.
byte[] base64Cipher = Base64.encode(textEncrypted);
return new String(base64Cipher);
} //end encryptMsg

Затем я отображаю длины шифра, шифра и открытого текста и получаю:

Encrypted Message: FDCU+kgWz25urbQB5HbFtqm0HqWHGlGBHlwwEatFTiI=
Original msg length: 24
Encrypted msg length: 44

Не могли бы вы уточнить, почему длина шифра равна 44, а длина исходного сообщения - 24?

РЕДАКТИРОВАТЬ: Пожалуйста, мне нужен ответ с разъяснениями. Шифр всегда заканчивается на =. Может ли это быть из-за набивки? Можете ли вы объяснить мне, почему / как шифр получен с такой длиной? И всегда заканчивается =? Мой код правильный или есть ошибка? У меня есть сомнения в части кодирования.

2 ответа

Решение

Есть несколько вещей:

  1. msg.getBytes() возвращает байты, представляющие кодировку строки, используя "кодировку платформы по умолчанию" (например, может быть UTF-8 или UTF-16 или...): укажите кодировку вручную, чтобы избежать путаницы! В любом случае смотрите msgBytes.length чтобы получить истинную длину обычного текста.

  2. DES, будучи зашифрованным блоком, будет иметь выходные данные, дополненные границей размера блока, но это всегда будет больше, чем простой текст (см. msgBytes.length) длина при использовании PKCS#5, потому что обычный текст всегда дополняется [1,8] байтами. Чтобы узнать, каков истинный зашифрованный размер, см. textEncrypted.length,

  3. Зашифрованные байты кодируются с использованием base-64, и этот процесс, который не зависит от шифрования, увеличивает требуемое количество байтов примерно на 33% (поскольку используется только 6 бит на символ / байт). Реализация Java base-64 также добавляет заполнение, в котором вводится завершающий символ "=".

До тех пор, пока вы (или кто-то еще с правильным алгоритмом и ключом шифрования) сможете извлечь начальную строку - выполнив инверсию каждого шага в обратном порядке, тогда это работает. Если конкретный шаг не имеет обратной / обратной операции или не может быть "отменен", то что-то не так; но это также означает, что каждый шаг может быть проверен индивидуально.


На номера!

  1. msg.getBytes() возвращает кодированную последовательность ASCII/UTF-8 (если она использовала кодировку UTF-16 или другую другую "широкую" кодировку, то приведенные ниже числа были бы слишком большими)
  2. Следовательно, msgBytes.length это 24
  3. И с тех пор msgBytes.length mod 8 равен 0, простой текст дополняется 8 байтами, которые имеют значение 0x08 (для CKCS#5)
  4. Таким образом, textEncrypted.length 32 (24 данных + 8 отступов)
  5. Из-за кодировки base-64, 32 байта * 1,33 ~ 43 символа
  6. И с дополнением base-64 (=), конечный результат - 44 символа!

Результат шифрования DES всегда будет кратным 8 байтам. Ввод также дополняется кратным 8 байтов в соответствии с указанным алгоритмом заполнения.

Кодирование base 64 кодирует каждые 3 байта в 4 символа (3x8 = 4x6 = 24) и обеспечивает выходную длину, кратную 4, с дополнением символами =.

Таким образом, вывод 44 символов соответствует 33 байтам, но символ = в конце указывает, что на самом деле было всего 32 байта. Что хорошо, так как 24 байта чистые данные с заполнением PKCS5 становятся 32 байта.

Другие вопросы по тегам