Как получить мой открытый и закрытый ключ из хранилища ключей, которое мы создали
Моя задача заключается в следующем:
- Получите мой открытый и закрытый ключ из хранилища ключей, которое я создал.
- Используйте эти ключи для шифрования абзаца с использованием моего открытого ключа RSA 2048-bit.
- Цифровая подпись результата с использованием алгоритма подписи DSA-SHA-1.
- Сохраните вывод цифровой подписи в файл с именем
output.dat
,
Программа ниже выдает ошибку: "java.security.InvalidKeyException: ни один из установленных провайдеров не поддерживает этот ключ: sun.security.provider.DSAPublicKeyImpl".
import java.security.*;
import java.security.KeyStore.*;
import java.io.*;
import java.security.PublicKey;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import java.nio.charset.*;
import sun.security.provider.*;
import javax.crypto.*;
public class Code {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
/* getting data for keystore */
File file = new File(System.getProperty("user.home") + File.separatorChar + ".keystore");
FileInputStream is = new FileInputStream(file);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
/*Information for certificate to be generated */
String password = "abcde";
String alias = "mykeys";
String alias1 = "skeys";
String filepath ="C:\\email.txt";
/* getting the key*/
keystore.load(is, password.toCharArray());
PrivateKey key = (PrivateKey)keystore.getKey(alias, "bemylife".toCharArray());
//PrivateKey key = cert1.getPrivateKey();
//PublicKey key1= (PrivateKey)key;
/* Get certificate of public key */
java.security.cert.Certificate cert = keystore.getCertificate(alias);
/* Here it prints the public key*/
System.out.println("Public Key:");
System.out.println(cert.getPublicKey());
/* Here it prints the private key*/
System.out.println("\nPrivate Key:");
System.out.println(key);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE,cert.getPublicKey());
String cleartextFile = "C:\\email.txt";
String ciphertextFile = "D:\\ciphertextRSA.png";
FileInputStream fis = new FileInputStream(cleartextFile);
FileOutputStream fos = new FileOutputStream(ciphertextFile);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
byte[] block = new byte[32];
int i;
while ((i = fis.read(block)) != -1) {
cos.write(block, 0, i);
}
cos.close();
/* computing the signature*/
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initSign(key);
FileInputStream f = new FileInputStream(ciphertextFile);
BufferedInputStream in = new BufferedInputStream(f);
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) >= 0) {
dsa.update(buffer, 0, len);
};
in.close();
/* Here it prints the signature*/
System.out.println("Digital Signature :");
System.out.println( dsa.sign());
/* Now Exporting Certificate */
System.out.println("Exporting Certificate. ");
byte[] buffer_out = cert.getEncoded();
FileOutputStream os = new FileOutputStream(new File("d:\\signedcetificate.cer"));
os.write(buffer_out);
os.close();
/* writing signature to output.dat file */
byte[] buffer_out1 = dsa.sign();
FileOutputStream os1 = new FileOutputStream(new File("d:\\output.dat"));
os1.write(buffer_out1);
os1.close();
} catch (Exception e) {System.out.println(e);}
}
}
5 ответов
Проблема в том, что ключ DSA не подходит для шифрования RSA. Вам нужен ключ RSA для шифрования, возможно, вы можете переключить алгоритм подписи на RSA/SHA1, чтобы избежать необходимости в двух ключах.
Вы должны прочитать его из файла хранилища ключей (который, вероятно, заканчивается .jks
) в объект java.security.KeyStore.
/**
* Reads a Java keystore from a file.
*
* @param keystoreFile
* keystore file to read
* @param password
* password for the keystore file
* @param keyStoreType
* type of keystore, e.g., JKS or PKCS12
* @return the keystore object
* @throws KeyStoreException
* if the type of KeyStore could not be created
* @throws IOException
* if the keystore could not be loaded
* @throws NoSuchAlgorithmException
* if the algorithm used to check the integrity of the keystore
* cannot be found
* @throws CertificateException
* if any of the certificates in the keystore could not be loaded
*/
public static KeyStore loadKeyStore(final File keystoreFile,
final String password, final String keyStoreType)
throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException {
if (null == keystoreFile) {
throw new IllegalArgumentException("Keystore url may not be null");
}
LOG.debug("Initializing key store: {}", keystoreFile.getAbsolutePath());
final URI keystoreUri = keystoreFile.toURI();
final URL keystoreUrl = keystoreUri.toURL();
final KeyStore keystore = KeyStore.getInstance(keyStoreType);
InputStream is = null;
try {
is = keystoreUrl.openStream();
keystore.load(is, null == password ? null : password.toCharArray());
LOG.debug("Loaded key store");
} finally {
if (null != is) {
is.close();
}
}
return keystore;
}
Когда у вас есть KeyStore
, вы можете добраться до Certificate
и открытый и закрытый ключи.
Но использование этого для подписи текста и сохранения его в файле более сложное и легко сделать неправильно. Взгляните на строку подписи с использованием данного открытого ключа и замените getKeyPair
метод с тем, который использует KeyStore
, Нечто подобное
public static KeyPair getKeyPair(final KeyStore keystore,
final String alias, final String password) {
final Key key = (PrivateKey) keystore.getKey(alias, password.toCharArray());
final Certificate cert = keystore.getCertificate(alias);
final PublicKey publicKey = cert.getPublicKey();
return KeyPair(publicKey, (PrivateKey) key);
}
(очевидно, немного грубее, у меня не было образца под рукой)
В Spring Boot (мой пример использует 2.4.x) вы можете использовать bean-компонент для своего хранилища ключей, например:
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
@Configuration
public class KeyStoreConfiguration {
private static final String KEY_STORE = "keystore.p12";
private static final String KEY_STORE_TYPE = "PKCS12";
private static final String KEY_STORE_PASSWORD = "password";
@Bean
public KeyStore keyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
keyStore.load(new ClassPathResource(KEY_STORE).getInputStream(), KEY_STORE_PASSWORD.toCharArray());
return keyStore;
}
}
и затем вы можете получить открытый и закрытый ключ следующим образом:
import java.security.PrivateKey;
import java.security.PublicKey;
PrivateKey privateKey = (PrivateKey) keyStore.getKey("my-alias", "my-password".toCharArray());
PublicKey publicKey = keyStore.getCertificate("my-alias").getPublicKey();
trusted.load(in, ((PBCApplication) context.getApplicationContext()).getBuildSettings().getCertificatePass());
Enumeration enumeration = trusted.aliases();
while (enumeration.hasMoreElements()) {
String alias = (String) enumeration.nextElement();
System.out.println("alias name: " + alias);
Certificate certificate = trusted.getCertificate(alias);
certificate.getPublicKey();
}
Я не храню Java-код в верхней части моего мозга, но некоторые общие проверки работоспособности:
хранится ли публичный сертификат, который вы хотите, где вы хотите? В частности, я помню, что сертификат с открытым ключом и закрытым ключом хранится вместе под одним псевдонимом, поэтому две настройки псевдонима, которые вы там используете, кажутся действительно странными. Попробуйте сохранить оба под одним и тем же псевдонимом и сослаться на него при вызовах с закрытым и открытым ключами
Вы можете получить что-нибудь еще из сертификата - например, DN субъекта или DN эмитента являются обязательными полями в сертификате. Это дает вам хорошее доказательство того, что сертификат читается, как и ожидалось.
Практически в любой крипто-транзакции будьте очень осторожны с тем, как вы читаете из файлов и переносите свои методы кодирования. Если вы создали свой File IO и извлекли из него странным образом, вы можете испортить кодировку материала ключа. Это последнее, что нужно проверить - обычно Java и JKS не так уж плохи для этого, но это случается. В том же духе, уясните формат файла - файлы JKS отличаются, например, от файлов PKCS 12.