I have a class to handle the keystore.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Clase encargada de administrar el KeyStore.
*
* @author Jose Montes
*/
public class KeyStoreManager {
private KeyStore keyStore;
/**
* Constructor.
*/
public KeyStoreManager() {
}
/**
* Crea un nuevo KeyStore con el nombre y contraseña pasado por parametros,
* una vez creado almacena la instancia en la propiedad keyStore de esta
* clase.
*
* @param name | Nombre del KeyStore.
* @param password | Contraseña para proteger el KeyStore.
*/
public void createKeyStore(String name, String password) {
try {
KeyStore createKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
createKeyStore.load(null, password.toCharArray());
try (FileOutputStream fileOutputStream = new FileOutputStream(name)) {
createKeyStore.store(fileOutputStream, password.toCharArray());
fileOutputStream.close();
} catch (Exception ex) {
}
} catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException ex) {
}
}
/**
* Carga un KeyStore y almacena la instancia en la propiedad keyStore de
* esta clase.
*
* @param name | Nombre del KeyStore.
* @param password | Contraseña para proteger el KeyStore.
*/
public void loadKeyStore(String name, String password) {
try {
this.keyStore = KeyStore.getInstance("JKS");
try (FileInputStream fileInputStream = new FileInputStream(name)) {
this.keyStore.load(fileInputStream, password.toCharArray());
}
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException ex) {
}
}
/**
* Guarda una clave privada en el keyStore. El KeyStore debe estar cargado.
*
* @param alias | Alias para almacenar la clave privada.
* @param password | Contraseña para almacenar la clave privada.
* @param privateKey | PrivateKey a almacenar.
* @param x509Certificate | Certificado para guardar la clave privada.
*/
public void savePrivateKey(String alias, String password, PrivateKey privateKey, X509Certificate x509Certificate) {
Certificate[] certificate = new Certificate[1];
certificate[0] = (Certificate) x509Certificate;
try {
this.keyStore.setKeyEntry(alias, (Key) privateKey, password.toCharArray(), certificate);
} catch (KeyStoreException ex) {
}
}
/**
* Devuelve una clave privada del almacen de contraseñas. El almacen de
* contraseñas debe estar cargado.
*
* @param alias | Alias para almacenar la clave privada.
* @param password | Contraseña para almacenar la clave privada.
* @return PrivateKey | Clave privada almacenada en el KeyStore.
*/
public PrivateKey getPrivateKey(String alias, String password) {
PrivateKey privateKey = null;
try {
Key key = this.keyStore.getKey(alias, password.toCharArray());
privateKey = (PrivateKey)key;
} catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException ex) {
Exception e = ex;
}
return privateKey;
}
/**
* Guarda un certificado en el keyStore. El KeyStore debe estar cargado.
*
* @param alias | Alias para almacenar el certificado.
* @param x509Certificate | Certificado a guardar.
*/
public void saveCertificate(String alias, X509Certificate x509Certificate) {
try {
this.keyStore.setCertificateEntry(alias, (Certificate) x509Certificate);
} catch (KeyStoreException ex) {
}
}
/**
* Devuelve un certificado del keyStore. El KeyStore debe estar cargado.
*
* @param alias | Alias para almacenar el certificado.
* @return Certificate | Certificado.
*/
public Certificate getCertificate(String alias) {
Certificate certificate = null;
try {
certificate = this.keyStore.getCertificate(alias);
} catch (KeyStoreException ex) {
}
return certificate;
}
/**
* Devuelve una clave publica del keyStore desde el certificado.
*
* @param alias | Alias obtener el certificado.
* @return PublicKey | Clave publica del certificado.
*/
public PublicKey getPublicKeyFromCertificate(String alias) {
PublicKey publicKey = null;
try {
Certificate certificate = this.keyStore.getCertificate(alias);
publicKey = certificate.getPublicKey();
} catch (KeyStoreException ex) {
}
return publicKey;
}
}
And these are the calls I make.
EncryptionRSA encryptionRSA = new EncryptionRSA();
encryptionRSA.buildParKey();
X509Certificate x509Certificate = encryptionRSA.generateX509Certificate(email);
KeyStoreManager keyStoreManager = new KeyStoreManager();
keyStoreManager.createKeyStore(email, password);
keyStoreManager.loadKeyStore(email, password);
keyStoreManager.savePrivateKey(alias, password, encryptionRSA.getPrivateKey(), x509Certificate);
keyStoreManager.saveCertificate(alias, x509Certificate);
The problem I have is that I create the javakeystore fine, but when I check if it has saved the private key and the certificate, it appears as an empty jks (say I check it from console with keytool). I attach the methods to create the certificate.
public X509Certificate generateX509Certificate(String subjectDN) {
X509Certificate x509Certificate = null;
try {
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
long now = System.currentTimeMillis();
Date startDate = new Date(now);
// X500Name dnName = new X500Name(subjectDN);
X500Name dnName = new X500Name("C = DE, O = Organiztion");
BigInteger certSerialNumber = new BigInteger(Long.toString(now));
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.add(Calendar.YEAR, 1);
Date endDate = calendar.getTime();
String signatureAlgorithm = "SHA512WithRSA";
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(this.privateKey);
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, this.publicKey);
BasicConstraints basicConstraints = new BasicConstraints(true);
certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, basicConstraints);
x509Certificate = new JcaX509CertificateConverter().setProvider(provider).getCertificate(certBuilder.build(contentSigner));
} catch (CertIOException | CertificateException | OperatorCreationException ex) {
x509Certificate = null;
}
return x509Certificate;
}
Class to handle RSA:
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
/**
* Clase para cifrar los datos de la aplicación.
*
* @author Jose Montes
*/
public class EncryptionRSA {
private PublicKey publicKey;
private PrivateKey privateKey;
private final int keySize;
/**
* Constructor, define el tamaño de la clave en 2048bytes por defecto.
*/
public EncryptionRSA() {
this.keySize = 2048;
}
/**
* Constructor, permite definir el tamaño de la clave en bytes. Ejemplo:
* EncryptionRSA(1024); La clave se generará con un tamaño de 1024 bytes y
* no con los 2048 bytes que viene por defecto.
*
* @param keySize | Tamaño de la clave en bytes.
*/
public EncryptionRSA(int keySize) {
this.keySize = keySize;
}
public PublicKey getPublicKey() {
return publicKey;
}
public PrivateKey getPrivateKey() {
return privateKey;
}
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
}
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
}
/**
* Genera las claves publica/privada. Se pueden obtener con getPrivateKey()
* y getPublicKey().
*/
public void buildParKey() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(this.keySize);
KeyPair keyPair = keyPairGenerator.genKeyPair();
this.publicKey = keyPair.getPublic();
this.privateKey = keyPair.getPrivate();
} catch (NoSuchAlgorithmException ex) {
}
}
/**
* Función para cifrar con la clave pública generada.
*
* @param message | Mensaje a cifrar
* @return | byte[] cifrado
*/
public byte[] encryptMessage(String message) {
byte[] finalMessage = null;
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, this.publicKey);
finalMessage = cipher.doFinal(message.getBytes("UTF-8"));
} catch (IllegalBlockSizeException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | UnsupportedEncodingException ex) {
}
return finalMessage;
}
/**
* Función para descifrar mensaje con la clave privada.
*
* @param encrypted | Mensaje a descifrar.
* @return | byte[] descifrado.
*/
public byte[] decryptMessage(byte[] encrypted) {
byte[] finalMessage = null;
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, this.privateKey);
finalMessage = cipher.doFinal(encrypted);
} catch (IllegalBlockSizeException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException ex) {
}
return finalMessage;
}
/**
* Función para descifrar mensaje con la clave privada.
*
* @param encrypted | Mensaje a descifrar.
* @return | String descifrado.
*/
public String decryptMessage(String encrypted) {
byte[] finalMessage = null;
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.DECRYPT_MODE, this.privateKey);
byte[] encryptedByte = Base64.getDecoder().decode(encrypted);
finalMessage = cipher.doFinal(encryptedByte);
} catch (IllegalBlockSizeException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException ex) {
}
return new String(finalMessage);
}
/**
* Crea un certificado X509Certificate con las claves RSA generadas en la
* clase. Se llamará a EncryptionRSA.buildParKey() si no se ha generado las
* claves publica/privada.
*
* @param subjectDN | SubjectDN para el certificado X509Certificate;
* @return X509Certificate | Certificado X509Certificate creado.
*/
public X509Certificate generateX509Certificate(String subjectDN) {
X509Certificate x509Certificate = null;
try {
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
long now = System.currentTimeMillis();
Date startDate = new Date(now);
// X500Name dnName = new X500Name(subjectDN);
X500Name dnName = new X500Name("C = DE, O = Organiztion");
BigInteger certSerialNumber = new BigInteger(Long.toString(now));
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.add(Calendar.YEAR, 1);
Date endDate = calendar.getTime();
String signatureAlgorithm = "SHA512WithRSA";
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(this.privateKey);
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, this.publicKey);
BasicConstraints basicConstraints = new BasicConstraints(true);
certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, basicConstraints);
x509Certificate = new JcaX509CertificateConverter().setProvider(provider).getCertificate(certBuilder.build(contentSigner));
} catch (CertIOException | CertificateException | OperatorCreationException ex) {
x509Certificate = null;
}
return x509Certificate;
}
}
The certificate in principle, after debugging, seems to believe it well. Is it possible that I am failing to use bouncy castle as a provider when creating the certificate and JKS when creating and loading the java keystore? and, if not, where can the problem be? I have been investigating for a week and I can not continue, any idea is appreciated. Greetings.