Статьи

Безопасное шифрование в Java

В прошлый раз, когда я писал о криптографии , я обрисовал в общих чертах API шифрования Apache Shiro и показал, как использовать два симметричных шифра. Я также написал, что «вам не нужно больше для шифрования и дешифрования конфиденциальных данных в ваших приложениях».

Я узнал больше о криптографии и узнал, что вам нужно знать больше. То, что я написал, в некоторой степени верно, но если вы не будете осторожны, ваши конфиденциальные данные могут быть защищены от всех злоумышленников.

Изначально Широ предоставляет методы шифрования Blowfish-CBC и AES-CBC, и я рекомендовал использовать их. Оба были разработаны для защиты от пассивного прослушивания злоумышленником и хороши в этом. К сожалению, настоящие злоумышленники более искушены и могут взломать систему на их основе.

Обратите внимание на «может». Злоумышленник может добиться успеха только в том случае, если атакованная система хотя бы немного сотрудничает с ним. Если вы хотите использовать эти шифры, вы должны знать, как написать систему безопасно. Конечно, другой вариант — использовать более сильный шифр и полностью избежать проблемы.

Несколько необходимых теоретических терминов и понятий объясняются в первой главе. Вторая глава показывает, как шифровать данные более безопасным способом . Затем мы опишем, как работают Blowfish-CBC и AES-CBC, и покажем две возможные атаки на них. Наконец, конец поста содержит ссылки на другие ресурсы

теория

Начнем с нескольких теоретических концепций. Если вы не хотите читать его, перейдите непосредственно к главе с решением .

Первая важная вещь, которую нужно описать, — это разница между пассивным и активным атакующим. Затем мы объясним, что такое блочные шифры и что такое аутентифицированное шифрование. В последних двух подразделах перечислены уязвимые и выбранные безопасные шифры.

Активный против пассивного атакующего

Подслушивающий только злоумышленник в основном пассивен. Он умеет читать зашифрованные сообщения, но не может их модифицировать или отправлять новые шифротексты в взаимодействующие приложения. Он не способен влиять на общение, он только слушает его. У его пассивности есть только одно исключение: злоумышленник может передать незашифрованную информацию одной из сторон связи и получить зашифрованный текст с этой точной информацией.

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

Если ему повезет, он может использовать полученные знания, чтобы взломать шифр или подделать ложную информацию.

Блочные шифры

Блочные шифры могут шифровать только короткие сообщения. Например, AES может шифровать только 16-байтовые сообщения, а Blowfish может зашифровывать только 8-байтовые сообщения.

Более длинные сообщения разбиваются на блоки. Каждый блок объединяется с ранее зашифрованными блоками и передается на блочный шифр. Объединение блоков называется режимом работы, и существует несколько безопасных способов сделать это.

В этом посте обсуждаются две активные атаки: атаки на режим работы CBC. Сами блочные шифры безопасны.

Аутентифицированное шифрование

Аутентифицированное шифрование отклоняет любой измененный зашифрованный текст как недействительный. Невозможно взять зашифрованные данные, изменить их и получить действительный зашифрованный текст. Это свойство также называется целостностью зашифрованного текста.

Шифр сначала проверяет целостность и отклоняет все измененные сообщения таким же образом. Поскольку злоумышленник не может пройти проверку целостности, он ничего не получает от отправки новых сообщений в приложение.

Аутентификация и целостность зашифрованного текста обычно, но не всегда, обеспечиваются режимом работы.

Уязвимые шифры

Любой шифр, который не обеспечивает целостность зашифрованного текста или аутентифицированное шифрование, вероятно, уязвим для некоторых активных атак. Неважно, какая библиотека шифрования используется. Алгоритмы шифрования определены в стандартах и ​​составляют одно и то же независимо от используемой библиотеки.

Иначе говоря, если возможно создать действительный зашифрованный текст, не зная секретного ключа, то вполне вероятно, что существует какая-то активная атака, даже если она еще не известна.

В этом посте описываются две атаки режима CBC. Как только вы поймете как эти атаки, так и различия между пассивным и активным злоумышленником, вы сможете приступить к подобным атакам на CFB, CTR, OFB или другие режимы шифрования без аутентификации.

Безопасные шифры

Аутентифицированные шифрования защищены от активных злоумышленников. Наиболее распространенные режимы работы, которые также обеспечивают аутентификацию:

  • GCM
  • EAX
  • CCM

Замените CBC одним из этих режимов (например, AES-EAX), и вы получите шифр, защищенный от активного злоумышленника.

Конечно, защита от активного злоумышленника не означает, что у шифра нет никаких других реальных ограничений. Например, большинство шифров безопасны, только если пользователь изменяет ключ после того, как слишком много данных было зашифровано. Если вы серьезно относитесь к шифрованию данных, вы должны изучить и знать эти ограничения.

Аутентифицированное Шифрование с Широ

В этой главе показано, как использовать аутентифицированное шифрование в Java. Для тех, кто пропустил теорию , аутентифицированное шифрование защищает от подделки данных. Никто без секретного ключа не сможет изменить зашифрованное сообщение, и активная атака на такой шифр невозможна.

Apache Shiro не реализует свои собственные алгоритмы шифрования. Он делегирует всю работу Java Cryptography Extension (JCE), которая доступна в каждой среде выполнения Java. Shiro «only» предоставляет простой в использовании API и безопасные настройки по умолчанию.

Поэтому мы должны сделать две вещи:

  • установить аутентифицированные режимы работы в Java Cryptography Extension,
  • интегрировать Shiro с новыми аутентифицированными режимами работы.

Установите аутентифицированные режимы работы

Расширение Java Cryptography — это расширяемый API. Все классы и алгоритмы создаются провайдерами, и новый провайдер может быть установлен в систему в любое время. Поставщик может быть:

  • установлен в среду выполнения Java и будет доступен для всех приложений Java,
  • распространяется и инициализируется вместе с приложением.

Мы покажем, как добавить Bouncy Castle в проект. Bouncy Castle — провайдер, распространяемый по лицензии MIT и содержащий режимы работы EAX и GCM.

Bouncy Castle распределяет несколько файлов JAR, каждый из которых оптимизирован для различных версий Java. Поскольку наш демонстрационный проект использует Java 6, мы должны использовать библиотеку bcprov-jdk16 . Добавьте maven-зависимость в pom.xml:

1
2
3
4
5
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk16</artifactId>
  <version>1.46</version>
</dependency>

Как только библиотека присутствует, вы должны установить ее провайдера в систему безопасности Java. Запустите следующий метод при запуске приложения:

1
2
3
4
5
private BouncyCastleProvider installBouncyCastle() {
  BouncyCastleProvider provider = new BouncyCastleProvider();
  Security.addProvider(provider);
  return provider;
}

Bouncy Castle теперь установлен, и доступны оба режима аутентификации.

Интеграция с Широ

Пакет криптографии Shiro — это простой в использовании фасад над JCE. Он настраивает объекты JCE для использования безопасных значений по умолчанию и повышает безопасность потоков.

Расширьте класс DefaultBlockCipherService чтобы воспользоваться этими функциями. Большая часть конфигурации выполняется этим классом, но нам все еще нужно указать три вещи:

  • название и параметры блочного шифра,
  • режим работы,
  • обивка.

Имя блочного шифра указывается в параметре конструктора. Мы будем использовать AES, потому что он не требует дополнительной настройки. Ни GCM, ни CCM не требуют заполнения, поэтому мы должны указать заполнение NONE .

Новый сервис шифрования:

01
02
03
04
05
06
07
08
09
10
11
class GCMCipherService extends DefaultBlockCipherService {
 
  private static final String ALGORITHM_NAME = "AES";
 
  public GCMCipherService() {
    super(ALGORITHM_NAME);
    setMode(OperationMode.GCM);
    setPaddingScheme(PaddingScheme.NONE);
  }
 
}

Вот и все. Вы можете использовать новый аутентифицирующий шифр как любой другой сервис шифрования Широ .

Прецедент

Мы создали простой тестовый пример, чтобы продемонстрировать, что проверка целостности работает. Он шифрует сообщение и изменяет третий байт своего зашифрованного текста. Если шифр обеспечивает аутентификацию, то попытка расшифровать модифицированный зашифрованный текст приводит к исключению времени выполнения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void testGCMAuthentication() {
  String message = "secret message";
 
  GCMCipherService gcmCipher = new GCMCipherService();
  assertIngetrityCheck(message, gcmCipher);
}
 
private void assertIngetrityCheck(String message, DefaultBlockCipherService cipher) {
  byte[] key = cipher.generateNewKey().getEncoded();
  byte[] messageBytes = CodecSupport.toBytes(message);
  ByteSource encrypt = cipher.encrypt(messageBytes, key);
 
  // change the ciphertext
  encrypt.getBytes()[3] = 0;
 
  try {
    // it should be impossible to decrypt changed ciphertext
    cipher.decrypt(encrypt.getBytes(), key).getBytes();
  } catch (Exception ex) {
    return;
  }
  fail("It should not be possible to decrypt changed ciphertext.");
}

Примечание по Java 7

Согласно документации , Java 7 поддерживает два аутентифицированных режима работы: CCM и GCM. Теоретически вам не нужен сторонний поставщик криптографии.

К сожалению, Oracle не смог обеспечить полную реализацию этих режимов в первом выпуске JDK 7. Они хотели бы добавить его в выпуск обновления, чтобы ситуация могла измениться в будущем. База данных ошибок Oracle содержит две связанные ошибки .

Java 1.7.0_01 до сих пор не имеет их.

Цепочка блоков шифрования (CBC)

Последнее, что нам нужно, прежде чем мы сможем описать обещанные атаки, это режим работы цепочки зашифрованных блоков (CBC). Этот режим работы достаточно защищен от пассивного злоумышленника, достаточно быстр и прост в реализации.

К сожалению, он также уязвим для активных атак.

основы

CBC используется для шифрования длинного сообщения блочным шифром. Блочные шифры могут шифровать только короткие блоки данных, поэтому все начинается с разделения сообщения на короткие блоки.

Первый и последний блоки являются частными случаями. Мы объясним, что с ними делать, в следующих подразделах. Пока предположим, что начало сообщения уже зашифровано, а его i-й блок m i соответствует зашифрованному тексту c i .

Зашифруйте следующий блок сообщений в два этапа:

  • xor блок с зашифрованным текстом предыдущего блока (например, m i ?c i-1 ),
  • зашифруйте результат с помощью блочного шифра (например, Blowfish(key, m i ?c i-1 ) ).

Пример: предположим, что секретное сообщение состоит из трех блоков, и мы пытаемся зашифровать его с помощью Blowfish-CBC. Первый блок уже зашифрован и его зашифрованный текст составляет 1, 2, 3, 4, 5, 6, 7, 8 . Второй блок представляет собой байтовый массив 1, 0, 1, 0, 1, 0, 1, 0 .

Шаг 1: или зашифруйте первый зашифрованный блок вторым блоком:

1
1, 2, 3, 4, 5, 6, 7, 8 ? 1, 0, 1, 0, 1, 0, 1, 0 = 0, 2, 2, 4, 4, 6, 6, 8

Шаг 2: зашифровать результат с помощью алгоритма Blowfish:

1
Blowfish(secret_key, {0, 2, 2, 4, 4, 6, 6, 8})

Первый блок — вектор инициализации

Первый блок не имеет предыдущего блока для объединения. Поэтому мы сгенерируем блок случайных данных, называемый вектором инициализации. Вектор инициализации используется в качестве самого первого блока данных. Он передается с первым блоком сообщения, а результат шифруется блочным шифром.

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

Пример: предположим, что секретное сообщение состоит из трех блоков, и мы пытаемся зашифровать его с помощью Blowfish-CBC. Первый блок — это байтовый массив 1, 1, 1, 1, 1, 1, 1, 1 .

Шаг 1: сгенерировать случайный вектор инициализации:

1
1, 8, 2, 7, 3, 6, 4, 5

Шаг 2: xor первый блок с вектором инициализации:

1
1, 8, 2, 7, 3, 6, 4, 5 ? 1, 1, 1, 1, 1, 1, 1, 1 = 0, 9, 3, 6, 2, 7, 5, 4

Шаг 3: зашифровать результат с помощью алгоритма Blowfish:

1
Blowfish(secret_key, {0, 9, 3, 6, 2, 7, 5, 4})

Шаг 4: объединить вектор инициализации и зашифрованный текст. Если результат функции Blowfish на предыдущем шаге равен 1, 2, 3, 4, 5, 6, 7, 8 , то зашифрованный текст имеет вид:

1
1, 8, 2, 7, 3, 6, 4, 5, 1, 2, 3, 4, 5, 6, 7, 8


Последний блок — обивка

Блочные шифры могут шифровать сообщения фиксированной длины, и последний блок часто короче этого. Поскольку шифр не может его зашифровать, нам нужен способ добавить дополнительные байты в конец сообщения.

Широ по умолчанию использует отступ PKCS # 5. Каждый его байт равен длине заполнения:

  • Если последний блок слишком короткий, посчитайте, сколько байтов отсутствует, и заполните недостающие байты этим числом.
  • Если последний блок имеет правильный размер, обработайте сообщение так, как если бы в нем отсутствовал целый блок. Добавьте новый блок заполнения к нему. Каждый его байт будет равен размеру блока.

Пример 1: предположим, что секретное сообщение состоит из трех блоков, и мы пытаемся зашифровать его с помощью Blowfish-CBC. Последний блок — это байтовый массив 1, 1, 1, 1 . Проложенный блок:

1
1, 1, 1, 1, 4, 4, 4, 4

Пример 2: предположим, что секретное сообщение состоит из трех блоков, и мы пытаемся зашифровать его с помощью Blowfish-CBC. Последний блок — это байтовый массив 8, 7, 6, 5, 4, 3, 2, 1 . Последний блок и отступы:

1
8, 7, 6, 5, 4, 3, 2, 1, 8, 8, 8, 8, 8, 8, 8, 8

нападки

Наконец, мы готовы показать две разные атаки на шифры на основе CBC и доказать, что проблема реальна. Наш пример проекта содержит тестовые случаи для обеих атак на шифры AES-CBC и Blowfish-CBC.

Первый подраздел показывает, как изменить начало зашифрованного текста на любое сообщение по нашему выбору. Второй подраздел объясняет, как расшифровать зашифрованный текст.

Фальсификация данных

Атака данных возможна только в том случае, если злоумышленник уже знает содержимое зашифрованного сообщения. Такой злоумышленник может изменить первый блок сообщения на то, что он пожелает.

В частности, можно:

  • изменить первые 16 байтов зашифрованного сообщения AES-CBC,
  • изменить первые 8 байтов зашифрованного сообщения Blowfish-CBC.

Потенциальная опасность

Опасен ли этот тип атаки, во многом зависит от обстоятельств.

Если вы используете шифр для отправки пароля по сети, то подделка данных не так опасна. В худшем случае законному пользователю будет отказано в доступе. Точно так же, если ваши зашифрованные данные хранятся в некотором хранилище только для чтения, вам не нужно беспокоиться о фальсификации данных.

Однако, если вы отправляете банковские поручения через сеть, фальсификация данных представляет собой реальную угрозу. Если кто-то изменит сообщение Pay Mark 100$ на Pay Tom 9999$ , Том получит 9999 $, которого он не должен получать.

Атака

Зашифрованное сообщение состоит из трех частей:

  • случайный начальный вектор,
  • первый блок зашифрованного текста,
  • остальная часть сообщения.

Получатель дешифрует первый блок зашифрованного текста с помощью блочного шифра. Это дает ему message block?initial vector . Чтобы получить сообщение, он должен xor это значение с начальным вектором:

1
message block ? initial vector ? initial vector = message block

Начальный вектор передается вместе с сообщением, и активный злоумышленник может изменить его. Если злоумышленник заменит исходный начальный вектор another iv , получатель расшифрует другое сообщение:

1
message block ? initial vector ? another iv = another message

Переставьте предыдущее уравнение, и вы получите:

1
another iv = message block ? initial vector ? another message

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

Тот, кто расшифрует модифицированный зашифрованный текст, получит модифицированное сообщение вместо исходного.

Прецедент

Мы создали простой тестовый пример, демонстрирующий эту атаку на сообщение, зашифрованное с помощью AES-CBC.

Представьте, что злоумышленник захватил зашифрованное письмо и каким-то образом знает, что в нем находится:

1
2
3
4
5
//original message
private static final String EMAIL = "Hi,\n" +
  "send Martin all requested money please.\n\n" +
  "With Regards, \n" +
  "Accounting\n";

Атакующий может изменить только первые 16 байтов сообщения, поэтому он решает перенаправить деньги Андреа:

1
2
3
4
5
//changed message
private static final String MODIFICATION = "Hi,\n" +
  "give Andrea all requested money please.\n\n" +
  "With Regards, \n" +
  "Accounting\n";

Следующий тестовый пример шифрует сообщение и модифицирует зашифрованный текст. Модифицированный зашифрованный текст расшифровывается и сравнивается с ожидаемым сообщением:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void testModifiedMessage_AES() {
  //create cipher and the secret key
  StringCipherService cipher =
      new StringCipherService(new AesCipherService());
  byte[] key = cipher.generateNewKey();
 
  //encrypt the message
  byte[] ciphertext = cipher.encrypt(EMAIL, key);
 
  //attack: modify the encrypted message
  for (int i = 0; i < 16; i++) {
    ciphertext[i] = (byte)(ciphertext[i] ^
        MODIFICATION.getBytes()[i] ^
        EMAIL.getBytes()[i]);
  }
 
  //decrypt and verify
  String result = cipher.decrypt(ciphertext, key);
  assertEquals(MODIFICATION, result);
}

Конечно, подобная атака может быть сделана на Blowfish-CBC. На этот раз мы можем изменить только первые 8 байтов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
@Test
public void testModifiedMessage_Blowfish() {
  String email = "Pay 100 dollars to them, but nothing more. Accounting\n";
   
  StringCipherService cipher =
    new StringCipherService(new BlowfishCipherService());
  byte[] key = cipher.generateNewKey();
  byte[] ciphertext = cipher.encrypt(email, key);
 
  String modified = "Pay 900 dollars to them, but nothing more. Accounting\n";
   
  for (int i = 0; i < 8; i++) {
    ciphertext[i] = (byte)(ciphertext[i] ^
        modified.getBytes()[i] ^
        email.getBytes()[i]);
  }
  String result = cipher.decrypt(ciphertext, key);
  assertEquals(modified, result);
}

Расшифровать шифр

Вторая атака позволяет злоумышленнику расшифровать секретное сообщение. Атака возможна, только если приложение, которое расшифровывает секретные сообщения, взаимодействует с атакующим.

Перетяжка Оракула

Злоумышленник создает множество поддельных шифротекстов и отправляет их получателю. Когда он пытается расшифровать эти сообщения, произойдет одна из следующих вещей:

  • зашифрованный текст расшифровывается до бессмысленного мусора,
  • измененное сообщение не будет действительным зашифрованным текстом вообще.

Если приложение ведет себя одинаково в обоих случаях, то все в порядке. Если он ведет себя по-другому, то злоумышленник может расшифровать зашифрованный текст. Есть только один способ, как зашифрованный текст на основе CBC может быть неправильным — если заполнение неверно.

Например, если зашифрованный текст содержит зашифрованный пароль, уязвимый сервер может ответить «отказано в входе» в случае неверного расшифрованного пароля и с исключением времени выполнения в случае неверного зашифрованного текста. Если это так, то злоумышленник может восстановить пароль.

Главная идея

Каждое поддельное сообщение состоит из двух частей: поддельного исходного вектора и одного блока сообщения. Оба отправляются на сервер. Если он отвечает «padding right», то мы знаем, что:

1
message ? original iv ? fake iv = valid padding

Единственной неизвестной переменной в приведенном выше уравнении является сообщение. original iv — это предыдущий блок зашифрованного текста, мы создали fake iv , а допустимый отступ — один из 1 или 2, 2 или 3, 3, 3 или ... или 8, 8, ..., 8 и так далее.

Следовательно, мы можем рассчитать содержимое блока как:

1
message = valid padding ? original iv ? fake iv

Алгоритм

Начните с восстановления последнего байта блока. Каждый поддельный начальный вектор начинается с большого числа 0 и заканчивается другим последним байтом. Таким образом, мы можем быть почти уверены, что сервер отвечает «заполнение вправо» только на сообщение, которое заканчивается 1. Используйте уравнение в предыдущей главе для вычисления последнего байта блока.

Получение второго последнего байта сообщения очень похоже. Единственное отличие состоит в том, что мы должны создать зашифрованный текст, который расшифровывает во второй кратчайший отступ 2, 2 . Последний байт сообщения уже известен, поэтому легко ввести 2 в качестве последнего значения. Начало начального вектора неважно и установите его равным 0.

Затем мы пробуем все возможные значения для второго последнего байта исходного вектора. Как только сервер ответит «правильное заполнение», мы можем получить второй байт последнего сообщения из той же формулы, что и раньше: original iv ? fake iv ? 2 original iv ? fake iv ? 2 original iv ? fake iv ? 2

Мы вычисляем третий байт последнего сообщения из ложного сообщения с заполнением 3, 3, 3 ; четвертое из сообщения с заполнением 4, 4, 4, 4 ; и так до тех пор, пока весь блок не будет расшифрован.

Прецедент

PaddingOraculum сервер моделируется классом PaddingOraculum . Каждый экземпляр этого класса генерирует случайный секретный ключ и сохраняет его в секрете. Он предоставляет только два публичных метода:

  • byte[] encrypt(String message) — шифрует строку с секретным ключом,
  • boolean verifyPadding(byte[] ciphertext) — возвращает правильность заполнения.

Атака дополнительного decryptLastBlock реализована в методе decryptLastBlock . Метод расшифровывает последний блок зашифрованного сообщения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private String decryptLastBlock(PaddingOraculum oraculum, byte[] ciphertext) {
  // extract relevant part of the ciphertext
  byte[] ivAndBlock = getLastTwoBlocks(ciphertext,
      oraculum.getBlockSize());
  // modified initial vector
  byte[] ivMod = new byte[oraculum.getBlockSize()];
  Arrays.fill(ivMod, (byte) 0);
 
  // Start with last byte of the last block and
  // continue to the first byte.
  for (int i = oraculum.getBlockSize()-1; i >= 0; i--) {
    // add padding to the initial vector   
    int expectedPadding = oraculum.getBlockSize() - i;
    xorPad(ivMod, expectedPadding);
 
    // loop through possible values of ivModification[i]
    for (ivMod[i] =  -128; ivMod[i] <  127; ivMod[i]++) {
      // create fake message and verify its padding
      byte[] modifiedCiphertext = replaceBeginning(ivAndBlock, ivMod);
      if (oraculum.verifyPadding(modifiedCiphertext)) {
        // we can stop looping
        // the ivModification[i] =
        //    = solution ^ expectedPadding ^ ivAndBlock[i]
        break;
      }
    }
 
    // remove the padding from the initial vector
    xorPad(ivMod, expectedPadding);
  }
 
  // modified initial vector now contains the solution xor
  // original initial vector
  String result = "";
  for (int i = 0; i < ivMod.length; i++) {
    ivMod[i] = (byte) (ivMod[i] ^ ivAndBlock[i]);
    result += (char) ivMod[i];
  }
  return result;
}

Наш пример проекта содержит два теста . Один зашифровывает сообщение с помощью AES-CBC, а затем использует oraculum для заполнения до последнего блока зашифрованного текста. Другие делают то же самое с Blowfish-CBC.

Тестовый набор Decrypt Blowfish-CBC:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Test
public void testPaddingOracle_Blowfish() {
  String message = "secret message!";
 
  PaddingOraculum oraculum = new PaddingOraculum(
      new BlowfishCipherService());
  //Oraculum encrypts the message with a secret key.
  byte[] ciphertext = oraculum.encrypt(message);
  //use oraculum to decrypt the message
  String result = decryptLastBlock(oraculum, ciphertext);
   
  //the original message had padding 1
  assertEquals("essage!"+(char)1, result);
}

Ресурсы

Дополнительные связанные ресурсы:

Конец

Никакой шифр не обеспечивает абсолютную защиту от всех возможных атак. Вместо этого они обеспечивают защиту только от четко определенных классов атак. Шифры безопасны только до тех пор, пока потенциальная угроза для системы соответствует силе шифра.

Защиту от активной атаки можно сделать двумя способами:

  • Сделать активную атаку невозможной по замыслу.
  • Используйте аутентифицированное шифрование.

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

Все примеры кода, используемые в этом посте, доступны на Github .

Ссылка: Безопасное шифрование на Java от нашего партнера JCG Марии Юрковичовой в блоге This Is Stuff .