Я использую шифрование AES/GCM/NoPadding
в Java 8, и мне интересно, имеет ли мой код недостаток безопасности. Мой код, похоже, работает, поскольку он шифрует и расшифровывает текст, но некоторые детали неясны.
Мой главный вопрос:
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????
Соответствует ли это требованиям IV требованиям "Для данного ключа IV НЕ ДОЛЖЕН повторять". от RFC 4106
Я также благодарен за любые ответы/понимание моих связанных вопросов (см. ниже), но этот первый вопрос вызывает больше всего. Я не знаю, где найти исходный код или документацию, которая отвечает на это.
Вот полный код, грубо говоря. Приносим извинения в случае, если я ввел ошибки при написании сообщения:
class Encryptor {
Key key;
Encryptor(byte[] key) {
if (key.length != 32) throw new IllegalArgumentException();
this.key = new SecretKeySpec(key, "AES");
}
// the output is sent to users
byte[] encrypt(byte[] src) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // See question #1
assert iv.length == 12; // See question #2
byte[] cipherText = cipher.doFinal(src);
assert cipherText.length == src.length + 16; // See question #3
byte[] message = new byte[12 + src.length + 16]; // See question #4
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(cipherText, 0, message, 12, cipherText.length);
return message;
}
// the input comes from users
byte[] decrypt(byte[] message) throws Exception {
if (message.length < 12 + 16) throw new IllegalArgumentException();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, key, params);
return cipher.doFinal(message, 12, message.length - 12);
}
}
Предположим, что пользователи взломали мой секретный ключ = игра.
Более подробные вопросы/связанные вопросы:
-
Является ли IV, возвращенный cipher.getIV() безопасным для меня таким образом?
- Помогает ли это избежать катастрофы повторного использования комбинации IV, клавиш в режиме Galois/Counter?
- Является ли это еще безопасным, когда у меня есть несколько приложений, которые запускают этот код сразу, все отображают зашифрованные сообщения пользователям из одних и тех же данных src (возможно, в том же миллисекунде)?
- Из чего вернулся возвращенный IV? Это атомный счетчик плюс некоторый случайный шум?
- Нужно ли избегать
cipher.getIV()
и построить сам IV, со своим собственным счетчиком? - Является ли исходный код, реализующий
cipher.getIV()
доступным в Интернете, если я использую расширение Oracle JDK 8 + JCE Unlimited Strength?
-
Является ли это IV всегда длиной в 12 байтов?
-
Является ли тег аутентификации всегда длиной в 16 байтов (128 бит)?
-
С# 2 и # 3 и отсутствием заполнения, означает ли это, что мои зашифрованные сообщения всегда
12 + src.length + 16
bytes long? (И поэтому я могу смело просунуть их в один байт-массив, для которого я знаю правильную длину?) -
Безопасно ли мне отображать неограниченное количество шифрованных данных src для пользователей, учитывая постоянные данные src, которые знают пользователи?
-
Безопасно ли мне отображать неограниченное количество шифрованных данных src для пользователей, если данные src различаются каждый раз (например, включая
System.currentTimeMillis()
или случайные числа)? -
Помогло бы, если бы я дополнил данные src случайными числами до шифрования? Скажите 8 случайных байтов спереди и сзади или только на одном конце? Или это вообще не поможет/ухудшит шифрование?
(Поскольку эти вопросы касаются одного и того же блока моего собственного кода, и они сильно связаны друг с другом, а другие могут/должны иметь одинаковый набор вопросов при реализации одной и той же функциональности, было бы неправильно разделять вопросы в несколько сообщений.Я могу повторно опубликовать их отдельно, если это более подходит для формата StackOverflow. Сообщите мне!)