Подтвердить что ты не робот

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

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

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

Java 256bit AES Encryption

В основном, то, что я делаю, это написать программу, которая будет шифровать запрос для отправки по 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, известные на сервере? Не стесняйтесь говорить мне, чтобы сделать вещи более ясными, если они не являются.

4b9b3361

Ответ 1

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

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

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

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

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

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

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


Update:

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

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

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

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

Ответ 2

Выполняйте аналогичные проекты в мидлете раньше, я вам совет:

  • Безопасный способ хранения общего секрета на телефоне не существует. Вы можете использовать его, но это относится к категории под названием Безопасность через Obscurity. Это похоже на "безопасность под ключ".
  • Не используйте 256-битный AES, который не является широко доступным. Возможно, вам придется установить еще один JCE. 128-битные AES или TripleDES по-прежнему считаются безопасными. Учитывая # 1, вы не должны беспокоиться об этом.
  • Шифрование с использованием пароля (разное для каждого пользователя) гораздо более безопасно. Но вы не должны использовать пароль в качестве ключа, как показано в примере. Для генерации ключей используйте PBEKeySpec (шифрование на основе пароля).
  • Если вы просто обеспокоены атаками MITM (man-in-the-middle), используйте SSL.