package org.ovirt.engine.core.utils.crypt; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.crypto.Cipher; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import org.apache.commons.codec.binary.Base64; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.utils.EngineLocalConfig; import org.ovirt.engine.core.uutils.ssh.OpenSSHUtils; public class EngineEncryptionUtils { private static final String keystoreType; private static final File keystoreFile; private static final KeyStore.PasswordProtection keystorePassword; private static final String keystoreAlias; private static final String truststoreType; private static final File truststoreFile; private static final KeyStore.PasswordProtection truststorePassword; static { EngineLocalConfig config = EngineLocalConfig.getInstance(); keystoreType = config.getPKIEngineStoreType(); keystoreFile = config.getPKIEngineStore().getAbsoluteFile(); keystorePassword = new KeyStore.PasswordProtection(config.getPKIEngineStorePassword().toCharArray()); keystoreAlias = config.getPKIEngineStoreAlias(); truststoreType = config.getPKITrustStoreType(); truststoreFile = config.getPKITrustStore().getAbsoluteFile(); truststorePassword = new KeyStore.PasswordProtection(config.getPKITrustStorePassword().toCharArray()); } /** * Return the engine keystore. * @return engine key store. */ private static KeyStore getKeyStore(String type, File file, char[] password) { try (final InputStream in = new FileInputStream(file)) { KeyStore ks = KeyStore.getInstance(type); ks.load(in, password); return ks; } catch (Exception e) { throw new RuntimeException( String.format( "Failed to local keystore '%1$s'", file ), e ); } } /** * Return the engine keystore. * @return engine key store. */ public static KeyStore getKeyStore() { return getKeyStore(keystoreType, keystoreFile, keystorePassword.getPassword()); } /** * Return the trust keystore. * @return engine key store. */ public static KeyStore getTrustStore() { return getKeyStore(truststoreType, truststoreFile, truststorePassword.getPassword()); } /** * Return the engine private key entry. * @return private key entry. */ public static KeyStore.PrivateKeyEntry getPrivateKeyEntry() { try { KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)getKeyStore().getEntry( keystoreAlias, keystorePassword ); if (entry == null) { throw new RuntimeException("Alias was not found"); } return entry; } catch (Exception e) { throw new RuntimeException( String.format( "Failed to locate key '%1$s'", keystoreAlias ), e ); } } /** * Return the engine certificate. * @return certificate key. */ public static Certificate getCertificate() { return getPrivateKeyEntry().getCertificate(); } public static X509Certificate getCertificate(File file) { try (InputStream in = new FileInputStream(file)) { return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(in); } catch (CertificateException | IOException e) { throw new RuntimeException( String.format( "Failed to read certificate '%1$s'", file.getName() ), e ); } } /** * Return the engine ssh public key representation. * @return ssh public key. */ public static String getEngineSSHPublicKey() { return OpenSSHUtils.getKeyString( getCertificate().getPublicKey(), Config.getValue(ConfigValues.SSHKeyAlias) ); } /** * Encrypt string. * @param source string to encrypt. * @return encrypted string. * @throws GeneralSecurityException * Please note that empty strings are not encrypted and are returned as-is. */ public static String encrypt(String source) throws GeneralSecurityException { if (source == null || source.length() == 0) { return source; } else { Cipher rsa = Cipher.getInstance("RSA"); rsa.init(Cipher.ENCRYPT_MODE, getCertificate().getPublicKey()); return new Base64(0).encodeToString( rsa.doFinal(source.getBytes(StandardCharsets.UTF_8)) ); } } /** * Decrypt string. * @param source string to decrypt. * @return decrypted string. * @throws GeneralSecurityException * Please note that empty strings are not decrypted and are returned as-is. */ public static String decrypt(String source) throws GeneralSecurityException { if (source == null || source.length() == 0) { return source; } else { Cipher rsa = Cipher.getInstance("RSA"); rsa.init(Cipher.DECRYPT_MODE, getPrivateKeyEntry().getPrivateKey()); return new String( rsa.doFinal(new Base64().decode(source)), StandardCharsets.UTF_8 ); } } /** * Return key managers. * @return array of key managers. */ public static KeyManager[] getKeyManagers() throws GeneralSecurityException { KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmfactory.init(getKeyStore(), keystorePassword.getPassword()); return kmfactory.getKeyManagers(); } /** * Return trust managers. * @return array of trust managers. */ public static TrustManager[] getTrustManagers() throws GeneralSecurityException { TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmfactory.init(getTrustStore()); return tmfactory.getTrustManagers(); } /** * Check if we have key. * @return true if we do. * Have no idea why this is required. */ public static boolean haveKey() { try { getPrivateKeyEntry(); return true; } catch (Exception e) { return false; } } }