Привет, Хабр! Представляю вашему вниманию перевод 9 статьи "Java KeyStore" автора Jakob Jenkov из серии статей для начинающих, желающих освоить основы криптографии в Java.
Оглавление:
- Java Cryptography
- Java Cipher
- MessageDigest
- Mac
- Signature
- KeyPair
- KeyGenerator
- KeyPairGenerator
- KeyStore
- Keytool
- Certificate
- CertificateFactory
- CertPath
Хранилище ключей
Java KeyStore — это хранилище ключей в виде базы данных, представленное классом KeyStore (java.security.KeyStore). Хранилище можно записать на диск и снова прочитать, оно может быть защищено паролем, а каждая запись ключа в хранилище ключей может быть защищена собственным паролем, что делает класс KeyStore
полезным механизмом для безопасной работы с ключами шифрования. Хранилище ключей может содержать ключи следующих типов:
- Закрытые ключи (Private keys)
- Открытые ключи и сертификаты(Public keys + certificates)
- Секретные ключи (Secret keys)
Закрытый и открытый ключи используются в асимметричном шифровании. Открытый ключ может иметь связанный сертификат. Сертификат — это документ, удостоверяющий личность человека, организации или устройства, претендующего на владение открытым ключом. Сертификат обычно имеет цифровую подпись проверяющей стороны в качестве доказательства. Секретные ключи используются в симметричном шифровании. В большинстве случаев при настройке безопасного соединения симметричные ключи уступают асимметричным, поэтому чаще всего вы будете хранить открытые и закрытые ключи в хранилище ключей.
Создание хранилища ключей
Вы можете создать экземпляр KeyStore
, вызвав его метод getInstance()
. Вот пример создания экземпляра класса:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
В этом примере создается экземпляр KeyStore
по умолчанию. Также можно создавать экземпляры KeyStore с другим форматом хранения ключа, передавая параметр в метод getInstance()
. Например создание экземпляра хранилища ключей PKCS12
:
KeyStore keyStore = KeyStore.getInstance("PKCS12");
Загрузка хранилища ключей
Прежде чем использовать экземпляр хранилища ключей, его необходимо загрузить. Экземпляры класса KeyStore
часто записываются на диск или в другое хранилище для последующего использования, потому класс KeyStore
предполагает, что вы должны прочитать его данные, прежде чем сможете его использовать. Однако можно инициализировать пустой экземпляр KeyStore
без данных, как вы увидите позже.
Загрузка данных из файла или другого хранилища выполняется путем вызова метода load()
который принимает два параметра:
InputStream
из которого будут загружены данные.char[]
Массив символов, содержащий пароль от хранилища ключей.
Вот пример загрузки хранилища ключей:
char[] keyStorePassword = "123abc".toCharArray();
try(InputStream keyStoreData = new FileInputStream("keystore.ks")){
keyStore.load(keyStoreData, keyStorePassword);
}
В этом примере загружается файл хранилища ключей keystore.ks. Если вы не хотите загружать какие-либо данные в хранилище ключей, просто передайте значение null
для параметра InputStream
. Вот как выглядит загрузка пустого хранилища ключей:
keyStore3.load(null, keyStorePassword);
Экземпляр класса KeyStore
всегда должен загружаться либо с данными, либо с null
. В противном случае хранилище ключей не инициализируется, и все вызовы его методов будут вызывать исключения.
Получение ключей
Вы можете получить ключи экземпляра класса KeyStore
через его метод getEntry()
. Запись хранилища ключей сопоставлена с псевдонимом (alias), который идентифицирует ключ, и защищена паролем ключа. Таким образом, чтобы получить доступ к ключу, вы должны передать псевдоним ключа и пароль методу getEntry()
. Вот пример доступа к записи в экземпляре KeyStore
:
char[] keyPassword = "789xyz".toCharArray();
KeyStore.ProtectionParameter entryPassword =
new KeyStore.PasswordProtection(keyPassword);
KeyStore.Entry keyEntry = keyStore3.getEntry("keyAlias", entryPassword);
Если вы знаете, что запись, к которой вы хотите получить доступ, является закрытым ключом, вы можете преобразовать экземпляр KeyStore.Entry
в KeyStore.PrivateKeyEntry
. Вот как это выглядит:
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)
keyStore3.getEntry("keyAlias", entryPassword);
После приведения к KeyStore.PrivateKeyEntry
вы можете получить доступ к закрытому ключу, сертификату и цепочке сертификатов с помощью следующих методов:
getPrivateKey()
getCertificate()
getCertificateChain()
Помещение ключей в хранилище
Вы также можете поместить ключи в экземпляр класса KeyStore
. Пример помещения секретного ключа (симметричного ключа) в экземпляр KeyStore
:
SecretKey secretKey = getSecretKey();
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore3.setEntry("keyAlias2", secretKeyEntry, entryPassword);
Хранение
Иногда вы можете захотеть сохранить хранилище ключей на какое-либо хранилище (диск, база данных и т. д.), чтобы вы могли загрузить его снова в другой раз. Экземпляр класса KeyStore
сохраняется вызовом метода store()
. Пример:
char[] keyStorePassword = "123abc".toCharArray();
try (FileOutputStream keyStoreOutputStream = new FileOutputStream("data/keystore.ks")) {
keyStore3.store(keyStoreOutputStream, keyStorePassword);
}