Как реализовать Java 256-битное шифрование AES с CBC

StackOverflow https://stackoverflow.com/questions/1440030

  •  10-07-2019
  •  | 
  •  

Вопрос

Я прочитал следующие темы, и они немного помогли, но я ищу немного больше информации.

Как написать AES / CBC / PKCS5Padding шифрование и дешифрование с параметром вектора инициализации для BlackBerry

256-битное шифрование Java AES

По сути, я пишу программу, которая зашифровывает запрос, который будет отправлен по TCP / IP, а затем расшифрован серверной программой. Шифрование должно быть AES, и в ходе некоторых исследований я обнаружил, что мне нужно использовать CBC и PKCS5Padding. В общем, мне нужен секретный ключ и IV.

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

Вот некоторый код:

// My user name
byte[] loginId = "login".getBytes();

byte[] preSharedKey128 = "ACME-1234AC".getBytes();
byte[] preSharedKey192 = "ACME-1234ACME-1234A".getBytes();
// 256 bit key
byte[] preSharedKey256 = "ACME-1234ACME-1234ACME-1234".getBytes();
byte[] preSharedKey = preSharedKey256;

// Initialization Vector
// Required for CBC
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);


byte[] encodedKey = new byte[loginId.length + preSharedKey.length];

System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);

// The SecretKeySpec provides a mechanism for application-specific generation
// of cryptography keys for consumption by the Java Crypto classes.

// Create a key specification first, based on our key input.
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");

// Create a Cipher for encrypting the data using the key we created.
Cipher encryptCipher;

encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize the Cipher with key and parameters
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ips);

// Our cleartext
String clearString = "33,8244000,9999,411,5012022517,0.00,0,1,V330";
byte[] cleartext = clearString.getBytes();

// Encrypt the cleartext
byte[] ciphertext = encryptCipher.doFinal(cleartext);

// Now decrypt back again...
// Decryption cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize PBE Cipher with key and parameters
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ips);

// Decrypt the cleartext
byte[] deciphertext = decryptCipher.doFinal(ciphertext);

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

Это было полезно?

Решение

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

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

Кроме того, вы не должны использовать метод no-arg getBytes () для String . Это зависит от платформы. Если все строки, которые вы кодируете, содержат только символы из набора символов US-ASCII, сделайте это ясно, указав эту кодировку явно. В противном случае, если телефонная и серверная платформы используют разные кодировки символов, ключ и IV не получатся одинаковыми.

Для режима CBC лучше использовать новый IV для каждого отправляемого сообщения. Обычно CBC IVs генерируются случайным образом. Другие режимы, такие как CFB и OFB , требуют уникальных IV для каждого сообщения. IV обычно отправляются вместе с зашифрованным текстом - IV не нужно хранить в секрете, но многие алгоритмы сломаются, если будет использоваться предсказуемый IV.

Серверу не нужно получать секрет или IV напрямую с телефона. Вы можете настроить сервер с секретным ключом (или паролем, из которого получен секретный ключ), но во многих приложениях это будет плохим дизайном.

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

Лучший подход заключается в создании новых секретных ключей на телефоне и использовании алгоритма согласования ключей для обмена ключами с сервером. Для этого может быть использовано соглашение о ключе Диффи-Хеллмана или секретный ключ может быть зашифрован с помощью RSA и отправлен на сервер.

<Ч>

Update:

Диффи-Хеллман в "эфемерно-статическом" Режим (и режим «статический-статический», хотя это и менее желательно) возможен без первоначального сообщения от сервера на телефон, если открытый ключ сервера встроен в приложение.

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

Статический-статический режим можно использовать, но на самом деле он более сложный и немного менее безопасный. Каждому телефону потребуется своя уникальная пара ключей, иначе вы снова столкнетесь с проблемой секретного ключа. По крайней мере, серверу не нужно было бы отслеживать, какой телефон имеет какой ключ (при условии, что на уровне приложения есть какой-то механизм аутентификации, например пароль).

Я не знаю, насколько быстры телефоны. На моем рабочем столе генерация пары эфемерных ключей занимает около 1/3 секунды. Генерация параметров Диффи-Хеллмана очень медленная; Вы определенно захотите повторно использовать параметры из ключа сервера.

Другие советы

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

<Ол>
  • Безопасного способа хранения общего секрета на телефоне не существует. Вы можете использовать его, но это относится к категории Безопасность через Obscurity . Это как "ключ под матом" вид безопасности.
  • Не используйте 256-битный AES, который широко не доступен. Возможно, вам придется установить другой JCE. 128-битный AES или TripleDES по-прежнему считаются безопасными. Учитывая # 1, вы не должны беспокоиться об этом.
  • Шифрование с использованием пароля (различного для каждого пользователя) намного безопаснее. Но вы не должны использовать пароль в качестве ключа, как показано в примере. Пожалуйста, используйте PBEKeySpec (шифрование на основе пароля) для генерации ключей.
  • Если вас беспокоят атаки MITM (человек посередине), используйте SSL.
  • Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top