import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.function.*;
import java.text.*;
import java.security.*;
import java.security.cert.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.text.*;
import javafx.scene.layout.*;
import javafx.scene.input.*;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.geometry.*;
import javafx.collections.*;
public class MKeyStore extends Application {
Stage stage;
boolean showChar = false;
BooleanProperty binary = new SimpleBooleanProperty(false);
BooleanProperty modifyed = new SimpleBooleanProperty(false);
ObjectProperty<File> file = new SimpleObjectProperty<>(new File(""));
String password = null;
TreeTableView<String> treeTableView;
KeyStore keyStore;
Label label;
DateFormat dateFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
FileChooser.ExtensionFilter autodtFl = new FileChooser.ExtensionFilter("Autodetect", "*.*");
FileChooser.ExtensionFilter binaryFl = new FileChooser.ExtensionFilter("Binary", "*.*");
FileChooser.ExtensionFilter base64Fl = new FileChooser.ExtensionFilter("Base-64", "*.*");
ContextMenu contextMenu = new ContextMenu();
String type = "PKCS12"; // PKCS12, JKS
@Override
public void start(Stage stage) {
this.stage = stage;
label = new Label();
BorderPane layout = new BorderPane();
stage.setScene(new Scene(layout, 400, 300));
MenuBar menuBar = new MenuBar();
Menu miFile = new Menu("File");
MenuItem miFileNew = new MenuItem("New");
miFileNew.setOnAction(ae -> { newKeyStore(null); });
MenuItem miFileOpen = new MenuItem("Open...");
miFileOpen.setOnAction(ae -> { openKeyStore(); });
MenuItem miFileSave = new MenuItem("Save");
miFileSave.setOnAction(ae -> { saveKeyStore(false); });
miFileSave.setDisable(true);
MenuItem miFileSaveAs = new MenuItem("Save as...");
miFileSaveAs.setOnAction(ae -> { saveKeyStore(true); });
MenuItem miFileExit = new MenuItem("Exit");
miFileExit.setOnAction(ae -> { if (confirmSave()) { Platform.exit(); System.exit(0); } });
miFile.getItems().addAll(miFileNew, miFileOpen, new SeparatorMenuItem(), miFileSave, miFileSaveAs, new SeparatorMenuItem(), miFileExit);
//Menu miHelp = new Menu("Help");
menuBar.getMenus().addAll(miFile);
createTreeTableView();
treeTableView.setRoot(new EntryTreeItem("", null));
treeTableView.getRoot().setExpanded(true);
layout.setTop(menuBar);
layout.setCenter(treeTableView);
layout.setBottom(label);
file.addListener((o, v, n) -> { treeTableView.getRoot().setValue((n != null ? n.getName() : "New") + " (" + keyStore.getType() + ")"); });
miFileSave.disableProperty().bind(modifyed.not());
stage.setOnCloseRequest(e -> { if (!confirmSave()) e.consume(); });
stage.show();
Platform.runLater(() -> {
List<String> p = getParameters().getRaw();
if (p.isEmpty()) { newKeyStore(null); return; }
File pFile = new File(p.get(0));
if (pFile.isFile()) {
loadKeyStore(pFile, autodtFl);
} else {
ButtonType bttp = alert(stage, Alert.AlertType.CONFIRMATION, "File " + pFile.getName() + " not found. Create?", ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
if (bttp == null || bttp == ButtonType.CANCEL) { miFileExit.getOnAction().handle(null); }
newKeyStore(bttp == ButtonType.YES ? pFile : null);
}
});
}
void loadKeyStore(File loadFile, FileChooser.ExtensionFilter flt) {
try {
if (loadFile.length() > 500_000L) sizeException();
byte[] bytes = Files.readAllBytes(loadFile.toPath());
bytes = detect(bytes, flt, binary);
keyStore = KeyStore.getInstance(type);
try {
keyStore.load(new ByteArrayInputStream(bytes), new char[0]);
password = "";
} catch (Exception e) {
String openPassword = passwordDialog();
if (openPassword == null) { newKeyStore(null); return; }
keyStore.load(new ByteArrayInputStream(bytes), openPassword.toCharArray());
password = openPassword;
}
fillTreeTableView();
file.set(loadFile);
modifyed.set(false);
} catch (Exception e) { alert(stage, Alert.AlertType.ERROR, e); newKeyStore(null); }
}
void sizeException() throws IOException { throw new IOException("File is too large"); }
void newKeyStore(File fl) {
if (!confirmSave()) return;
try {
keyStore = KeyStore.getInstance(type);
keyStore.load(null, null);
fillTreeTableView();
file.set(fl);
modifyed.set(false);
binary.set(true);
password = null;
} catch (Exception e) { e.printStackTrace(); }
}
void openKeyStore() {
if (!confirmSave()) return;
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().addAll(autodtFl, binaryFl, base64Fl);
fileChooser.setInitialFileName("KeyStore");
File openFile = fileChooser.showOpenDialog(stage);
if (openFile != null) loadKeyStore(openFile, fileChooser.getSelectedExtensionFilter());
}
byte[] detect(byte[] bytes, FileChooser.ExtensionFilter flt, BooleanProperty bin) throws IOException {
if (flt == binaryFl) { bin.set(true); return bytes; }
boolean chArr = true;
for (byte b : bytes) if (b > 0 && b < 32 && b != 9 && b != 10 && b != 13) { chArr = false; break; }
if (flt == base64Fl && !chArr) throw new IOException("Non printable character");
if (flt == autodtFl && !chArr) { bin.set(true); return bytes; }
bin.set(false);
return Base64.getMimeDecoder().decode(norm(new String(bytes)));
}
String norm(String s) {
return s.replaceAll("-----BEGIN [^-]+-----\\s+|-----END [^-]+-----|begin-base64[^\\n]+\\s+|====", "");
}
boolean confirmSave() {
if (!modifyed.get()) return true;
ButtonType bttp = alert(stage, Alert.AlertType.CONFIRMATION, "Save KeyStore?", ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
if (bttp == null || bttp == ButtonType.CANCEL) return false;
if (bttp == ButtonType.NO) return true;
return saveKeyStore(false);
}
boolean saveKeyStore(boolean saveAs) {
String savePassword = password;
File saveFile = file.get();
boolean bin = binary.get();
if (saveAs || file.get() == null) {
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().addAll(binaryFl, base64Fl);
fileChooser.setInitialFileName(saveFile != null ? (saveFile.isFile() ? "Copy" : "") + saveFile.getName() : "KeyStore");
saveFile = fileChooser.showSaveDialog(stage);
if (saveFile == null) return false;
savePassword = passwordDialog();
if (savePassword == null) return false;
bin = fileChooser.getSelectedExtensionFilter() == binaryFl;
}
try (OutputStream os = bin ? Files.newOutputStream(saveFile.toPath()) : Base64.getMimeEncoder().wrap(Files.newOutputStream(saveFile.toPath()))) {
keyStore.store(os, savePassword.toCharArray());
} catch (Exception e) { alert(stage, Alert.AlertType.ERROR, e); return false; }
password = savePassword;
binary.set(bin);
file.set(saveFile);
modifyed.set(false);
return true;
}
void createTreeTableView() {
treeTableView = new TreeTableView<>();
TreeTableColumn<String, String> column = new TreeTableColumn<>();
column.setCellValueFactory(
(TreeTableColumn.CellDataFeatures<String, String> cellData) ->
new ReadOnlyObjectWrapper<String>(cellData.getValue().getValue())
);
treeTableView.getColumns().add(column);
treeTableView.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
treeTableView.widthProperty().addListener((v, o, n) -> {
Pane header = (Pane)treeTableView.lookup("TableHeaderRow");
if (header != null && header.isVisible()) {
header.setMaxHeight(0); header.setMinHeight(0); header.setPrefHeight(0);
header.setVisible(false); header.setManaged(false);
}
});
treeTableView.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
Date date = null;
try {
if (((EntryTreeItem)n).getEntryClass() != null) date = keyStore.getCreationDate(n.getValue());
} catch (Exception e) { }
label.setText(date != null ? dateFormatter.format(date) : "");
});
MenuItem miInfo = new MenuItem("Info");
miInfo.setOnAction(ae -> { info(); });
MenuItem miView = new MenuItem("View");
miView.setOnAction(ae -> { viewDialog(true, false); });
MenuItem miIns = new MenuItem("New");
miIns.setOnAction(ae -> { viewDialog(false, true); });
MenuItem miClone = new MenuItem("Clone");
miClone.setOnAction(ae -> { viewDialog(true, true); });
MenuItem miDel = new MenuItem("Delete");
miDel.setOnAction(ae -> { delete(); });
treeTableView.setRowFactory(tv -> {
TreeTableRow<String> row = new TreeTableRow<>();
row.setOnMouseClicked(me -> {
if (contextMenu.isShowing()) contextMenu.hide();
EntryTreeItem tiRoot = (EntryTreeItem)treeTableView.getRoot();
EntryTreeItem eti = (EntryTreeItem)row.getTreeItem();
if (row.isEmpty() || eti == null) {
} else if (me.getButton() == MouseButton.PRIMARY && me.getClickCount() == 2) {
if (eti == tiRoot) {}
else if (eti.getParent() != tiRoot) miView.getOnAction().handle(null);
} else if (me.getButton() == MouseButton.SECONDARY && eti != tiRoot) {
if (eti.getParent() == tiRoot) contextMenu.getItems().setAll(miIns);
else contextMenu.getItems().setAll(miView, miInfo, new SeparatorMenuItem(), miIns, miClone, new SeparatorMenuItem(), miDel);
contextMenu.show((Node)me.getSource(), me.getScreenX(), me.getScreenY());
}
});
return row;
});
treeTableView.setOnKeyPressed(ke -> {
EntryTreeItem eti = (EntryTreeItem)treeTableView.getSelectionModel().getSelectedItem();
EntryTreeItem tiRoot = (EntryTreeItem)treeTableView.getRoot();
if (eti != null && eti != tiRoot) {
if (ke.getCode() == KeyCode.ENTER && eti.getParent() != tiRoot) miView.getOnAction().handle(null);
else if (ke.getCode() == KeyCode.INSERT) miIns.getOnAction().handle(null);
else if (ke.getCode() == KeyCode.DELETE && eti.getParent() != tiRoot) miDel.getOnAction().handle(null);
}
});
}
KeyStore.Entry getKeyStoreEntry(EntryTreeItem eti) {
String alias = eti.getValue();
KeyStore.Entry kse = null;
KeyStore.PasswordProtection ppr = null;
if (isProtected(eti.getEntryClass())) {
if (eti.getPassword() == null) {
try {
kse = keyStore.getEntry(alias, new KeyStore.PasswordProtection(new char[0]));
eti.setPassword("");
return kse;
} catch (Exception e) { }
String password = passwordDialog();
if (password == null) return null;
eti.setPassword(password);
}
ppr = new KeyStore.PasswordProtection(eti.getPassword().toCharArray());
}
try {
kse = keyStore.getEntry(alias, ppr);
} catch (Exception e) {
alert(stage, Alert.AlertType.ERROR, e);
eti.setPassword(null);
}
return kse;
}
void info() {
EntryTreeItem eti = (EntryTreeItem)treeTableView.getSelectionModel().getSelectedItem();
KeyStore.Entry kse = getKeyStoreEntry(eti);
if (kse != null) infoDialog(stage, eti.getValue(), kse.toString());
}
void delete() {
try {
EntryTreeItem eti = (EntryTreeItem)treeTableView.getSelectionModel().getSelectedItem();
String alias = eti.getValue();
if (alert(stage, Alert.AlertType.CONFIRMATION, "Delete " + alias + "?") == ButtonType.OK) {
keyStore.deleteEntry(alias);
if (!keyStore.containsAlias(alias)) eti.getParent().getChildren().remove(eti);
modifyed.set(true);
}
} catch (Exception e) { e.printStackTrace(); }
}
void fillTreeTableView() {
treeTableView.getRoot().getChildren().clear();
treeTableView.getRoot().getChildren().add(new EntryTreeItem("Private key & Certificate", KeyStore.PrivateKeyEntry.class));
treeTableView.getRoot().getChildren().add(new EntryTreeItem("Secret key", KeyStore.SecretKeyEntry.class));
treeTableView.getRoot().getChildren().add(new EntryTreeItem("Certificate", KeyStore.TrustedCertificateEntry.class));
for (TreeItem<String> eti : treeTableView.getRoot().getChildren()) eti.setExpanded(true);
treeTableView.getSelectionModel().selectFirst();
try {
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
for (TreeItem<String> eti : treeTableView.getRoot().getChildren()) {
Class<? extends KeyStore.Entry> clss = ((EntryTreeItem)eti).getEntryClass();
if (keyStore.entryInstanceOf(alias, clss)) {
eti.getChildren().add(new EntryTreeItem(alias, clss));
break;
}
}
}
} catch (Exception e) { e.printStackTrace(); }
}
String passwordDialog() {
Dialog<ButtonType> dialog = new Dialog<>();
dialog.initOwner(stage);
dialog.initStyle(StageStyle.UTILITY);
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
CheckBox checkBox = new CheckBox();
checkBox.setSelected(showChar);
PasswordField passwordField = new PasswordField();
TextField textField = new TextField();
passwordField.textProperty().bindBidirectional(textField.textProperty());
textField.managedProperty().bind(checkBox.selectedProperty());
textField.visibleProperty().bind(checkBox.selectedProperty());
passwordField.managedProperty().bind(checkBox.selectedProperty().not());
passwordField.visibleProperty().bind(checkBox.selectedProperty().not());
VBox fb = new VBox();
fb.getChildren().addAll(passwordField, textField);
HBox cb = new HBox(8);
cb.getChildren().addAll(new Label("Show characters:"), checkBox);
VBox pb = new VBox(8);
pb.getChildren().addAll(new Label("Password:"), fb, cb);
dialog.getDialogPane().setContent(pb);
Platform.runLater(() -> (showChar ? textField : passwordField).requestFocus());
dpBehavior(dialog.getDialogPane());
Optional<ButtonType> result = dialog.showAndWait();
showChar = checkBox.isSelected();
if (result.isPresent() && result.get() == ButtonType.OK) {
return textField.getText();
}
return null;
}
ButtonType alert(Window owner, Alert.AlertType type, Object cont, ButtonType... bt) {
Alert alert = new Alert(type, "", bt);
alert.initOwner(owner);
alert.initStyle(StageStyle.UTILITY);
alert.setHeaderText(null);
if (cont instanceof String) {
alert.setContentText((String)cont);
} else if (cont instanceof Throwable) {
Throwable t = (Throwable)cont;
alert.setContentText(t.getMessage() != null && !t.getMessage().isEmpty() ? t.getMessage() : t.toString());
StringWriter sw = new StringWriter();
((Throwable)cont).printStackTrace(new PrintWriter(sw));
TextArea ta = new TextArea(sw.toString());
//ta.setStyle("-fx-font-family: monospace; -fx-font-weight: bold;");
ta.setEditable(false);
ta.setPadding(new Insets(0));
alert.getDialogPane().setExpandableContent(ta);
}
dpBehavior(alert.getDialogPane());
Optional<ButtonType> result = alert.showAndWait();
return (result.isPresent() ? result.get() : null);
}
void viewDialog(boolean cnt, boolean edt) {
EntryTreeItem eti = (EntryTreeItem)treeTableView.getSelectionModel().getSelectedItem();
KeyStore.Entry kse = null;
if (cnt) {
kse = getKeyStoreEntry(eti);
if (kse == null) return;
}
Class<? extends KeyStore.Entry> clss = eti.getEntryClass();
TextField alias = new TextField(cnt ? eti.getValue() : "newAlias");
alias.setEditable(edt);
alias.setFocusTraversable(edt);
TabPane tabPane = new TabPane();
if (!tabPane.getStyleClass().contains(TabPane.STYLE_CLASS_FLOATING)) {
tabPane.getStyleClass().add(TabPane.STYLE_CLASS_FLOATING);
}
try {
if (clss == KeyStore.PrivateKeyEntry.class) {
byte[] bytes = (kse != null ? ((KeyStore.PrivateKeyEntry)kse).getPrivateKey().getEncoded() : null);
tabPane.getTabs().add(createTab(PrivateKey.class, bytes, "PrivateKey", edt));
if (kse != null) {
java.security.cert.Certificate[] serts = ((KeyStore.PrivateKeyEntry)kse).getCertificateChain();
for (java.security.cert.Certificate sert : serts) {
tabPane.getTabs().add(createTab(java.security.cert.Certificate.class, sert.getEncoded(), "Certificate", edt));
}
} else tabPane.getTabs().add(createTab(java.security.cert.Certificate.class, null, "Certificate", true));
if (edt) tabPane.getTabs().add(createTab(null, null, "+", true));
} else if (clss == KeyStore.SecretKeyEntry.class) {
byte[] bytes = (kse != null ? ((KeyStore.SecretKeyEntry)kse).getSecretKey().getEncoded() : null);
tabPane.getTabs().add(createTab(SecretKey.class, bytes, "SecretKey", edt));
} else if (clss == KeyStore.TrustedCertificateEntry.class) {
byte[] bytes = (kse != null ? ((KeyStore.TrustedCertificateEntry)kse).getTrustedCertificate().getEncoded() : null);
tabPane.getTabs().add(createTab(java.security.cert.Certificate.class, bytes, "Certificate", edt));
}
} catch (Exception e) { e.printStackTrace(); }
Dialog<ButtonType> dialog = new Dialog<>();
Window window = dialog.getDialogPane().getScene().getWindow();
dialog.initOwner(stage);
dialog.initStyle(StageStyle.UTILITY);
dialog.setTitle(clss.getSimpleName());
dialog.setResizable(true);
Button bti = new Button("Info"), bte = new Button((edt ? "Load" : "Save"));
bti.setOnAction(e -> {
StringBuilder sb = new StringBuilder();
for (Tab tb : tabPane.getTabs()) {
if(tb.getUserData() != null && !((TextArea)tb.getContent()).getText().isEmpty()) {
Object o = getKSObj(window, tb);
if (o == null) return;
sb.append(tb.getText()).append(": ").append(getKSObjString(o)).append("\n");
}
}
infoDialog(window, alias.getText(), sb.toString());
});
bte.setOnAction(e -> {
FileChooser fileChooser = new FileChooser();
if (edt) fileChooser.getExtensionFilters().addAll(autodtFl);
fileChooser.getExtensionFilters().addAll(binaryFl, base64Fl);
Tab tb = tabPane.getSelectionModel().getSelectedItem();
fileChooser.setInitialFileName(tb.getText());
TextArea ta = (TextArea)tb.getContent();
try {
if (edt) {
File file = fileChooser.showOpenDialog(window);
if (file != null) {
if (file.length() > 10_000L) sizeException();
byte[] bytes = Files.readAllBytes(file.toPath());
bytes = detect(bytes, fileChooser.getSelectedExtensionFilter(), new SimpleBooleanProperty());
ta.setText(Base64.getMimeEncoder().encodeToString(bytes));
}
} else {
File file = fileChooser.showSaveDialog(window);
if (file != null) {
Files.write(file.toPath(), fileChooser.getSelectedExtensionFilter() == binaryFl ? Base64.getMimeDecoder().decode(ta.getText()) : ta.getText().getBytes());
}
}
} catch (Exception ef) { alert(window, Alert.AlertType.ERROR, ef); }
});
tabPane.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
if (clss == KeyStore.PrivateKeyEntry.class && n.getUserData() == null) {
int sz = tabPane.getTabs().size();
Tab pnl = tabPane.getTabs().get(sz - 2);
pnl.setClosable(true);
Tab pn = tabPane.getTabs().get(sz - 1);
tabPane.getTabs().add(createTab(null, null, pn.getText(), true));
pn.setText(pnl.getText());
pn.setUserData(pnl.getUserData());
pn.setClosable(true);
}
});
tabPane.getTabs().addListener((ListChangeListener.Change<? extends Tab> c) -> {
while(c.next()) {
if (c.wasRemoved() && tabPane.getTabs().size() == 3) {
tabPane.getTabs().get(1).setClosable(false);
}
}
});
HBox hb = new HBox(8);
hb.setAlignment(Pos.CENTER_LEFT);
hb.getChildren().addAll(new Label("Alias:"), alias, bti, bte);
VBox vb = new VBox(8);
vb.getChildren().addAll(hb, tabPane);
VBox.setVgrow(tabPane, Priority.ALWAYS);
dialog.getDialogPane().setContent(vb);
dialog.getDialogPane().setPrefSize(640, 480);
BiConsumer<Event, Boolean> addEntry = (event, confirm) -> {
if (confirm.booleanValue()) {
ButtonType bttp = alert(window, Alert.AlertType.CONFIRMATION, "Save entry?", ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
if (bttp == null || bttp == ButtonType.CANCEL) { event.consume(); return; }
if (bttp == ButtonType.NO) return;
}
ArrayList<java.security.cert.Certificate> sertArr = new ArrayList<>();
PrivateKey privateKey = null;
SecretKey secretKey = null;
String password = null;
for (Tab tb : tabPane.getTabs()) {
if(tb.getUserData() != null) {
Object o = getKSObj(window, tb);
if (o == null) { event.consume(); return; }
if (o instanceof java.security.cert.Certificate) sertArr.add((java.security.cert.Certificate)o);
else if (o instanceof PrivateKey) privateKey = (PrivateKey)o;
else if (o instanceof SecretKey) secretKey = (SecretKey)o;
}
}
try {
String al = alias.getText().trim().toLowerCase();
if (al.isEmpty()) { alert(window, Alert.AlertType.ERROR, "Alias is empty"); event.consume(); return; }
boolean replace = false;
if (keyStore.containsAlias(al)) {
if (alert(window, Alert.AlertType.CONFIRMATION, "Alias " + al + " already defined. Replace?", ButtonType.YES, ButtonType.NO) != ButtonType.YES) {
event.consume();
return;
}
replace = true;
}
if (isProtected(clss)) {
password = passwordDialog();
if (password == null) { event.consume(); return; }
}
KeyStore.Entry entry = null;
if (clss == KeyStore.PrivateKeyEntry.class) {
entry = new KeyStore.PrivateKeyEntry(privateKey, sertArr.toArray(new java.security.cert.Certificate[0]));
} else if (clss == KeyStore.SecretKeyEntry.class) {
entry = new KeyStore.SecretKeyEntry(secretKey);
} else if (clss == KeyStore.TrustedCertificateEntry.class) {
entry = new KeyStore.TrustedCertificateEntry(sertArr.get(0));
}
if (replace) {
EntryTreeItem ti = getEntryTreeItem(al);
keyStore.deleteEntry(al);
if (!keyStore.containsAlias(al)) ti.getParent().getChildren().remove(ti);
}
keyStore.setEntry(al, entry, (password != null ? new KeyStore.PasswordProtection(password.toCharArray()) : null));
EntryTreeItem newEti = new EntryTreeItem(al, clss);
newEti.setPassword(password);
getEntryTreeItem(clss).getChildren().add(newEti);
treeTableView.getSelectionModel().select(treeTableView.getRow(newEti));
modifyed.set(true);
} catch (Exception ef) { alert(window, Alert.AlertType.ERROR, ef); event.consume(); }
};
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK);
if (edt) {
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.CANCEL);
Button btOk = (Button)dialog.getDialogPane().lookupButton(ButtonType.OK);
btOk.addEventFilter(ActionEvent.ACTION, e -> { addEntry.accept(e, Boolean.FALSE); });
window.setOnCloseRequest(e -> { addEntry.accept(e, Boolean.TRUE); });
dialog.getDialogPane().getScene().setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) addEntry.accept(e, Boolean.TRUE);
});
dpBehavior(dialog.getDialogPane());
}
dialog.showAndWait();
}
Tab createTab(Class<?> clss, byte[] bytes, String name, boolean edt) {
String s = (bytes != null ? Base64.getMimeEncoder().encodeToString(bytes) : "");
TextArea ta = new TextArea(s);
ta.setEditable(edt);
ta.setFont(Font.font("Monospaced"));
Tab tab = new Tab(name, ta);
tab.setUserData(clss);
tab.setClosable(false);
return tab;
}
Object getKSObj(Window window, Tab tab) {
try {
Class<?> clss = (Class<?>)tab.getUserData();
String s = ((TextArea)tab.getContent()).getText();
byte[] bytes = Base64.getMimeDecoder().decode(norm(s));
if (clss == java.security.cert.Certificate.class) {
return /*(java.security.cert.Certificate)*/ CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(bytes));
} else if (clss == PrivateKey.class) {
return /*(PrivateKey)*/ KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(bytes));
} else if (clss == SecretKey.class) {
return (SecretKey)(new SecretKeySpec(bytes, "AES"));
}
} catch (Exception e) {
tab.getTabPane().getSelectionModel().select(tab);
alert(window, Alert.AlertType.ERROR, e);
}
return null;
}
String getKSObjString(Object obj) {
if (obj instanceof Key) return (obj instanceof SecretKey ? "Size " + (((Key)obj).getEncoded().length * 8) + " bits, " : "") +
"Algorithm " + ((Key)obj).getAlgorithm() + ", Format " + ((Key)obj).getFormat();
return obj.toString();
}
boolean isProtected(Class<? extends KeyStore.Entry> clss) {
return (clss == KeyStore.PrivateKeyEntry.class || clss == KeyStore.SecretKeyEntry.class);
}
EntryTreeItem getEntryTreeItem(Class<? extends KeyStore.Entry> clss) {
for (TreeItem<String> eti : treeTableView.getRoot().getChildren())
if (((EntryTreeItem)eti).getEntryClass() == clss) return (EntryTreeItem)eti;
return null;
}
EntryTreeItem getEntryTreeItem(String alias) {
for (TreeItem<String> etir : treeTableView.getRoot().getChildren())
for (TreeItem<String> eti : etir.getChildren())
if (alias.equals(eti.getValue())) return (EntryTreeItem)eti;
return null;
}
void infoDialog(Window owner, String title, String text) {
TextArea ta = new TextArea(text);
ta.setEditable(false);
ta.setFont(Font.font("Monospaced"));
ta.setPadding(new Insets(0));
Dialog<ButtonType> dialog = new Dialog<>();
dialog.initOwner(owner);
dialog.initStyle(StageStyle.UTILITY);
dialog.setResizable(true);
dialog.setTitle(title);
dialog.getDialogPane().setContent(ta);
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK);
dialog.getDialogPane().setPrefSize(480, 320);
dpBehavior(dialog.getDialogPane());
dialog.showAndWait();
}
void dpBehavior(DialogPane dialogPane) {
for (ButtonType bt : dialogPane.getButtonTypes()) {
Button b = (Button)dialogPane.lookupButton(bt);
b.setDefaultButton(false);
b.addEventHandler(KeyEvent.KEY_PRESSED, ke -> {
if (ke.getCode() == KeyCode.ENTER) {
((Button)ke.getTarget()).fire();
ke.consume();
}
});
}
}
class EntryTreeItem extends TreeItem<String> {
Class<? extends KeyStore.Entry> entryClass;
String password = null;
EntryTreeItem(String alias, Class<? extends KeyStore.Entry> entryClass) {
super(alias, (Node)null);
this.entryClass = entryClass;
}
String getPassword() { return password; }
void setPassword(String password) { this.password = password; }
Class<? extends KeyStore.Entry> getEntryClass() { return entryClass; }
} // end class EntryTreeItem
} // end class MKeyStore