Problem with Java KeyStore

0

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.

    
asked by montes18295 16.05.2018 в 19:10
source

1 answer

0

The problem is in the call to the createKeyStore () function; and then in the call to the loadKeyStore (); function. I created the file and loaded it (I think it was parallel in memory, so the changes were not saved).

Solution:

A single method that creates or loads the KeyStore according to whether the KeySore exists or not.

public void loadKeyStore(String name, String password) {
        try {
            File file = new File(name);
            if (file.exists()) {
                this.keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                try (FileInputStream fileInputStream = new FileInputStream(name)) {
                    this.keyStore.load(fileInputStream, password.toCharArray());
                }
            } else {
                this.keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                this.keyStore.load(null, null);
            }

        } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException ex) {

        }
    }
    
answered by 20.05.2018 / 20:05
source