Простое шифрование 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 ответа
Есть несколько вещей:
msg.getBytes()
возвращает байты, представляющие кодировку строки, используя "кодировку платформы по умолчанию" (например, может быть UTF-8 или UTF-16 или...): укажите кодировку вручную, чтобы избежать путаницы! В любом случае смотритеmsgBytes.length
чтобы получить истинную длину обычного текста.DES, будучи зашифрованным блоком, будет иметь выходные данные, дополненные границей размера блока, но это всегда будет больше, чем простой текст (см.
msgBytes.length
) длина при использовании PKCS#5, потому что обычный текст всегда дополняется [1,8] байтами. Чтобы узнать, каков истинный зашифрованный размер, см.textEncrypted.length
,Зашифрованные байты кодируются с использованием base-64, и этот процесс, который не зависит от шифрования, увеличивает требуемое количество байтов примерно на 33% (поскольку используется только 6 бит на символ / байт). Реализация Java base-64 также добавляет заполнение, в котором вводится завершающий символ "=".
До тех пор, пока вы (или кто-то еще с правильным алгоритмом и ключом шифрования) сможете извлечь начальную строку - выполнив инверсию каждого шага в обратном порядке, тогда это работает. Если конкретный шаг не имеет обратной / обратной операции или не может быть "отменен", то что-то не так; но это также означает, что каждый шаг может быть проверен индивидуально.
На номера!
msg.getBytes()
возвращает кодированную последовательность ASCII/UTF-8 (если она использовала кодировку UTF-16 или другую другую "широкую" кодировку, то приведенные ниже числа были бы слишком большими)- Следовательно,
msgBytes.length
это 24 - И с тех пор
msgBytes.length
mod 8 равен 0, простой текст дополняется 8 байтами, которые имеют значение 0x08 (для CKCS#5) - Таким образом,
textEncrypted.length
32 (24 данных + 8 отступов) - Из-за кодировки base-64, 32 байта * 1,33 ~ 43 символа
- И с дополнением base-64 (
=
), конечный результат - 44 символа!
Результат шифрования DES всегда будет кратным 8 байтам. Ввод также дополняется кратным 8 байтов в соответствии с указанным алгоритмом заполнения.
Кодирование base 64 кодирует каждые 3 байта в 4 символа (3x8 = 4x6 = 24) и обеспечивает выходную длину, кратную 4, с дополнением символами =.
Таким образом, вывод 44 символов соответствует 33 байтам, но символ = в конце указывает, что на самом деле было всего 32 байта. Что хорошо, так как 24 байта чистые данные с заполнением PKCS5 становятся 32 байта.