Простое шифрование 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?

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


person user2192774    schedule 19.10.2013    source источник


Ответы (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 символа!
person Community    schedule 19.10.2013

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

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

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

person Jonathan Rosenne    schedule 19.10.2013