Как реализовать Java 256-битное шифрование AES с CBC - PullRequest
16 голосов
/ 17 сентября 2009

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

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

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

Ответы [ 2 ]

12 голосов
/ 17 сентября 2009

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

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

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

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

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

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

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


Обновление:

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

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

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

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

2 голосов
/ 17 сентября 2009

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

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