обзор
За последние несколько лет безопасность стала отличной темой для обсуждения в связи с недавним выпуском документов Эдварда Сноудена и взрывом взлома таких интернет-магазинов, как JC Penny , Sony и Target . Хотя этот пост не предоставит вам все инструменты, которые помогут предотвратить использование данных, полученных из незаконных источников, этот пост предоставит отправную точку для создания набора инструментов и тактик, которые помогут предотвратить использование данных другими сторонами.
Этот пост покажет, как принять шифрование AES для строк в среде Java. В нем будет рассказано о создании ключей AES и хранении ключей AES в формате хранилища ключей JCEKS . Рабочий пример кода в этом блоге находится по адресу https://github.com/mike-ensor/aes-256-encryption-utility.
Рекомендуется читать каждый раздел по порядку, поскольку каждый раздел строится на основе предыдущего раздела, однако, для этого вам может понадобиться просто быстро перейти к определенному разделу.
- Setup — Настройка и создание ключей с помощью keytool
- Encrypt — шифровать сообщения с помощью ключей []
- Расшифровать — расшифровать сообщения, используя тот же IV и ключ от шифрования
- Получить ключи из хранилища ключей — Получить ключи из хранилища ключей через псевдоним
Что такое JCEKS?
JCEKS расшифровывается как «Явная криптография». Это альтернативный формат хранилища ключей для платформы Java. Хранение ключей в хранилище ключей может быть мерой для предотвращения раскрытия ваших ключей шифрования. Java KeyStores безопасно содержат отдельные сертификаты и ключи, на которые может ссылаться псевдоним для использования в программе Java. Java KeyStores часто создаются с использованием « keytool », поставляемого с Java JDK.
ПРИМЕЧАНИЕ. Настоятельно рекомендуется создать сложный код-пароль для хранилищ ключей для обеспечения безопасности содержимого. KeyStore — это файл, который считается общедоступным, но рекомендуется не предоставлять легкий доступ к файлу.
Настроить
Все шифрование регулируется законами каждой страны и часто имеет ограничения по прочности шифрования. Одним из примеров является то, что в Соединенных Штатах все шифрование более 128 бит ограничено, если данные перемещаются за пределы границы. По умолчанию Java JCE реализует политику прочности для соответствия этим правилам. Если более надежное шифрование является предпочтительным и соответствует законодательству страны, то JCE должен иметь доступ к более строгой политике шифрования. Проще говоря, если вы планируете использовать 256-битное шифрование AES, вы должны установить файлы политики Unlimited Strength Jurisdiction . Без политик 256-битное шифрование невозможно.
Установка политики неограниченной прочности JCE
Этот пост фокусируется на ключах, а не на установке и настройке JCE. Установка довольно проста с явными инструкциями, найденными здесь (ПРИМЕЧАНИЕ: это для JDK7, если используется другой JDK, найдите соответствующие файлы политики JCE).
Настройка Keystore
При использовании KeyTool манипулировать хранилищем ключей просто. Хранилища ключей должны быть созданы со ссылкой на новый ключ или во время импорта существующего хранилища ключей. Чтобы создать новый ключ и хранилище ключей, просто наберите:
1
|
keytool -genseckey -keystore aes-keystore.jck -storetype jceks -storepass mystorepass -keyalg AES -keysize 256 -alias jceksaes -keypass mykeypass |
Важные флаги
В приведенном выше примере приведены пояснения к параметрам keytool:
Параметры хранилища ключей
- genseckey : генерировать SecretKey. Это флаг, указывающий на создание синхронного ключа, который станет нашим ключом AES
- хранилище ключей : расположение хранилища ключей. Если хранилище ключей не существует, инструмент создаст новое хранилище. Пути могут быть относительными или абсолютными, но должны быть локальными
- Тип магазина : это тип магазина (JCE, PK12, JCEKS и т. д.). JCEKS используется для хранения симметричных ключей (AES), не содержащихся в сертификате.
- storepass : пароль, связанный с хранилищем ключей. Настоятельно рекомендуется создать надежную фразу-пароль для хранилища ключей.
Основные параметры
- keyalg : алгоритм, используемый для создания ключа (AES / DES / и т. д.)
- Размер ключа : размер ключа (128, 192, 256 и т. д.)
- псевдоним : псевдоним, данный вновь созданному ключу, на который можно ссылаться при использовании ключа
- keypass : пароль, защищающий использование ключа
шифровать
Поскольку это относится к данным в Java и на самом базовом уровне, шифрование — это алгоритмический процесс, используемый для программного запутывания данных посредством обратимого процесса, когда обе стороны имеют информацию, касающуюся данных и того, как используется алгоритм. В шифровании Java это включает использование шифра. Объект Cipher в JCE является общей точкой входа в поставщик шифрования, обычно выбираемый алгоритмом. В этом примере используется поставщик Java по умолчанию, но он также будет работать с Bouncy Castle.
Генерация объекта Cipher
Получить экземпляр Cipher довольно просто, и для шифрования и дешифрования требуется один и тот же процесс. (ПРИМЕЧАНИЕ. Для шифрования и дешифрования требуется один и тот же алгоритм, но не один и тот же экземпляр объекта)
1
|
Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" ); |
Получив экземпляр Шифра, мы можем зашифровать и расшифровать данные в соответствии с алгоритмом. Часто алгоритм требует дополнительных частей информации для шифрования / дешифрования данных. В этом примере нам нужно будет передать алгоритму байты, содержащие ключ и начальный вектор (объяснено ниже).
инициализация
Чтобы использовать шифр, мы должны сначала инициализировать шифр. Этот шаг необходим, чтобы мы могли предоставить дополнительную информацию для алгоритма, такую как ключ AES и начальный вектор (также известный как IV).
1
|
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpecification, initialVector); |
параметры
SecretKeySpecification — это объект, содержащий ссылку на байты, формирующие ключ AES. Ключ AES — это не что иное, как байтовый массив определенного размера (256-битный для AES 256 или 32 байта), который генерируется инструментом keytool (см. Выше).
Альтернативные параметры
Существует несколько способов создания ключей, таких как хеш, включая соль, имя пользователя и пароль (или аналогичные). Этот метод будет использовать хэш SHA1 объединенных строк, преобразовывать их в байты и затем обрезать результат до желаемого размера. В этом посте не будет показано создание ключа с использованием этого метода или использование метода ключа PBE с использованием пароля и соли. Использование пароля и / или соли для ключей обрабатывается инструментом keytool с использованием входных данных при создании новых ключей.
Вектор инициализации
Алгоритм AES также требует второго параметра, называемого вектором I нитиации. IV используется в процессе для рандомизации зашифрованного сообщения и предотвращения легкого угадывания ключа. IV считается общедоступной частью информации, но опять же, не рекомендуется открыто делиться этой информацией (например, было бы неразумно размещать ее на веб-сайте вашей компании). При шифровании сообщения нередко добавляется сообщение с IV, так как IV будет иметь заданный / известный размер на основе алгоритма. ПРИМЕЧАНИЕ: алгоритм AES выдаст тот же результат, если использовать тот же IV, ключ и сообщение. Рекомендуется, чтобы IV создавался случайным образом каждый раз, когда происходит шифрование.
С недавно инициализированным шифром шифрование сообщения становится простым. Просто позвоните:
1
2
3
|
byte [] encryptedMessageInBytes = Cipher.doFinal((message.getBytes( "UTF-8" )); String base64EncodedEncryptedMsg = BaseEncoding.base64().encode(encryptedMessageInBytes); String base32EncodedEncryptedMsg = BaseEncoding.base32().encode(encryptedMessageInBytes); |
Результаты кодирования
Массивы байтов трудно визуализировать, поскольку они часто не образуют символы ни в одной кодировке. Лучшая рекомендация для решения этой проблемы — представлять байты в формате HEX (base-16) , Double HEX (base-32) или Base64 . Если сообщение будет передано через параметр URL или POST, обязательно используйте веб-безопасную кодировку Base64. Библиотека Google Guava предоставляет отличную утилиту BaseEncoding . ПРИМЕЧАНИЕ. Не забудьте декодировать закодированное сообщение перед расшифровкой.
Расшифровать
Расшифровка сообщения — это почти обратный процесс шифрования с несколькими исключениями. Дешифрование требует известного вектора инициализации в качестве параметра в отличие от процесса шифрования, генерирующего случайный IV.
Дешифрирование
При расшифровке получите объект шифрования с тем же процессом, что и у метода шифрования. Объект Cipher должен будет использовать точно такой же алгоритм, включая выбор метода и заполнения. Как только код получил ссылку на объект Cipher, следующим шагом является инициализация шифра для дешифрования и передача ссылки на ключ и вектор инициализации.
1
2
3
|
// key is the same byte[] key used in encryption SecretKeySpec secretKeySpecification = new SecretKeySpec(key, "AES" ); cipher.init(Cipher.DECRYPT_MODE, secretKeySpecification, initialVector); |
ПРИМЕЧАНИЕ . Ключ хранится в хранилище ключей и получается с использованием псевдонима . Ниже приведены подробности получения ключей из хранилища ключей.
Как только шифр был предоставлен ключом IV и инициализирован для дешифрования, шифр готов к дешифровке.
1
2
3
|
byte [] encryptedTextBytes = BaseEncoding.base64().decode(message); byte [] decryptedTextBytes = cipher.doFinal(encryptedTextBytes); String origMessage = new String(decryptedTextBytes); |
Стратегии, чтобы сохранить IV
IV, используемый для шифрования сообщения, важен для расшифровки сообщения, поэтому возникает вопрос, как они остаются вместе. Одним из решений является базовое кодирование (см. Выше) IV и добавление его к зашифрованному и закодированному сообщению: Base64UrlSafe (myIv) + delimiter + Base64UrlSafe (encryptedMessage). Другие возможные решения могут быть контекстными, такими как включение атрибута в XML-файл с IV и одно для псевдонима используемого ключа.
Получить ключ от Keystore
В начале этого поста показано, как легко создавать новые ключи AES-256, которые ссылаются на псевдоним внутри базы данных хранилища ключей. Далее в публикации рассказывается о том, как зашифровать и расшифровать сообщение с использованием ключа, но пока не показано, как получить ссылку на ключ в хранилище ключей.
Решение
01
02
03
04
05
06
07
08
09
10
11
|
// for clarity, ignoring exceptions and failures InputStream keystoreStream = new FileInputStream(keystoreLocation); KeyStore keystore = KeyStore.getInstance( "JCEKS" ); keystore.load(keystoreStream, keystorePass.toCharArray()); if (!keystore.containsAlias(alias)) { throw new RuntimeException( "Alias for key not found" ); } Key key = keystore.getKey(alias, keyPass.toCharArray()); |
параметры
- keystoreLocation : String — Расположение к локальному файлу хранилища ключей.
- keypass : String — пароль, используемый при создании или изменении файла хранилища ключей с помощью keytool (см. выше)
- alias : String — псевдоним, используемый при создании нового ключа с помощью keytool (см. выше)
Вывод
В этом посте показано, как шифровать и дешифровать строковые сообщения с использованием алгоритма шифрования AES-256. Ключи для шифрования и дешифрования этих сообщений хранятся в базе данных KeyStore в формате JCEKS, созданной с помощью утилиты «keytool», предоставленной JDK. Примеры в этом посте следует рассматривать как надежное начало для шифрования / дешифрования симметричных ключей, таких как AES. Это не должно рассматриваться как единственная линия защиты при шифровании сообщений, например поворот ключа. Поворот ключа — это метод снижения рисков в случае утечки данных. Если злоумышленник получает данные и может взломать один ключ, данные, содержащиеся в нескольких файлах, должны были использовать несколько ключей для шифрования данных, таким образом снижая риск полной потери воздействия.
Все примеры в этом сообщении блога были сведены в простой инструмент, позволяющий просматривать ключи внутри хранилища ключей, — операция, которая не поддерживается «из коробки» инструментом для ключей JDK. Каждый аспект шагов и тем, изложенных в этом посте, доступен по адресу: https://github.com/mike-ensor/aes-256-encryption-utility . ПРИМЕЧАНИЕ: примеры, пример кода и любые ссылки должны использоваться на риск единоличного исполнителя, и нет никаких подразумеваемых гарантий или ответственности, вы принимаете на себя все риски.