package com.revolsys.crypto; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyStore; import java.security.KeyStore.PasswordProtection; import java.security.KeyStore.SecretKeyEntry; import java.security.KeyStoreException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import com.revolsys.logging.Logs; public class KeyChain { private static final String SECRET_KEY_ALGORITHM = "JCEKS"; private static final String KEYSTORE_TYPE = "JCEKS"; private KeyStore store; private final char[] masterPassword; private final Path path; private final PasswordProtection passwordProtection; public KeyChain(final Path path, final String password) { this.path = path; this.masterPassword = password.toCharArray(); this.passwordProtection = new PasswordProtection(this.masterPassword); try { this.store = KeyStore.getInstance(KEYSTORE_TYPE); if (Files.exists(path)) { final InputStream inputStream = Files.newInputStream(path); this.store.load(inputStream, this.masterPassword); } else { this.store.load(null, null); } } catch (final Throwable e) { Logs.error(this, "Cannot open keychain " + path, e); } } public String getPassword(final String keyName) { try { final SecretKeyEntry entry = (SecretKeyEntry)this.store.getEntry(keyName, this.passwordProtection); final SecretKey secretKey = entry.getSecretKey(); final byte[] passwordBytes = secretKey.getEncoded(); return new String(passwordBytes, StandardCharsets.UTF_8); } catch (final Throwable e) { Logs.error(this, "Cannot get password for " + keyName + ": " + this.path, e); } return null; } public void removePassword(final String keyName) { try { this.store.deleteEntry(keyName); } catch (final KeyStoreException e) { Logs.error(this, "Cannot remove password for " + keyName + ": " + this.path, e); } } private void save() { try { final OutputStream outputStream = Files.newOutputStream(this.path); this.store.store(outputStream, this.masterPassword); } catch (final Throwable e) { Logs.error(this, "Cannot save keychain " + this.path, e); } } public void setPassword(final String keyName, final String password) { final String pass = new String(password); final byte[] passwordBytes = pass.getBytes(StandardCharsets.UTF_8); final SecretKeySpec passwordKey = new SecretKeySpec(passwordBytes, SECRET_KEY_ALGORITHM); final SecretKeyEntry entry = new SecretKeyEntry(passwordKey); try { this.store.setEntry(keyName, entry, this.passwordProtection); save(); } catch (final Throwable e) { Logs.error(this, "Cannot set password for " + keyName + ": " + this.path, e); } } }