diff --git a/src/main/java/me/hatter/integrations/card/CardHmacDecryptResult.java b/src/main/java/me/hatter/integrations/card/CardHmacDecryptResult.java index 8bed4cf..22a2de8 100644 --- a/src/main/java/me/hatter/integrations/card/CardHmacDecryptResult.java +++ b/src/main/java/me/hatter/integrations/card/CardHmacDecryptResult.java @@ -2,6 +2,7 @@ package me.hatter.integrations.card; public class CardHmacDecryptResult { private String plaintext; + private String password; public String getPlaintext() { return plaintext; @@ -10,4 +11,12 @@ public class CardHmacDecryptResult { public void setPlaintext(String plaintext) { this.plaintext = plaintext; } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/src/main/java/me/hatter/integrations/card/Utils.java b/src/main/java/me/hatter/integrations/card/Utils.java index 97efd04..d27a5dd 100644 --- a/src/main/java/me/hatter/integrations/card/Utils.java +++ b/src/main/java/me/hatter/integrations/card/Utils.java @@ -12,6 +12,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; /** @@ -25,6 +27,8 @@ public class Utils { private static final File CARD_CONFIG_FILE2 = new File(USER_HOME, ".config/cryptomator/card_config.json"); private static final File DEFAULT_ENCRYPTION_KEY_BASE_PATH = new File(USER_HOME, ".config/cryptomator/card_keys/"); + private static final ConcurrentMap PASSWORD_CACHE_MAP = new ConcurrentHashMap<>(); + public static boolean isCheckPassphraseStored() { final StackTraceElement stack = getCallerStackTrace(); if (stack != null) { @@ -97,12 +101,12 @@ public class Utils { throw new KeychainAccessException("Password key file: " + keyFile + " not found"); } final String encryptedKey = readFile(keyFile); - final byte[] password = decrypt(cardConfig, encryptedKey); + final byte[] password = decrypt(cardConfig, vault, encryptedKey); return new String(password, StandardCharsets.UTF_8); } public static void storePassword(CardConfig cardConfig, String vault, String name, CharSequence password) throws KeychainAccessException { - final String encryptedPassword = encrypt(cardConfig, password.toString().getBytes(StandardCharsets.UTF_8), name); + final String encryptedPassword = encrypt(cardConfig, vault, password.toString().getBytes(StandardCharsets.UTF_8), name); final File keyFile = getKeyFile(cardConfig, vault); writeFile(keyFile, encryptedPassword); } @@ -149,32 +153,58 @@ public class Utils { } } - private static byte[] decrypt(CardConfig cardConfig, String input) throws KeychainAccessException { + private static byte[] decrypt(CardConfig cardConfig, String vault, String input) throws KeychainAccessException { + final List params = new ArrayList<>(); + params.add("hmac-decrypt"); + params.add("--ciphertext"); + params.add(input); + params.add("--auto-pbe"); + params.add("--json"); + + final String password = PASSWORD_CACHE_MAP.get(vault); + if (password != null) { + params.add("--password"); + params.add(password); + } else { + params.add("--outputs-password"); + } + final UtilsCommandResult decryptResult = runCardCli( cardConfig, null, - "hmac-decrypt", - "--ciphertext", input, - "--auto-pbe", - "--json" + params.toArray(new String[0]) ); if (decryptResult.getExitValue() != 0) { throw new KeychainAccessException("card-cli decrypt failed: " + decryptResult); } final String resultString = new String(decryptResult.getStdout(), StandardCharsets.UTF_8); final CardHmacDecryptResult result = new Gson().fromJson(resultString, CardHmacDecryptResult.class); + if (result.getPassword() != null) { + PASSWORD_CACHE_MAP.put(vault, result.getPassword()); + } return Base64.getDecoder().decode(result.getPlaintext()); } - private static String encrypt(CardConfig cardConfig, byte[] input, String name) throws KeychainAccessException { + private static String encrypt(CardConfig cardConfig, String vault, byte[] input, String name) throws KeychainAccessException { + final List params = new ArrayList<>(); + params.add("hmac-encrypt"); + params.add("--plaintext"); + params.add(Base64.getEncoder().encodeToString(input)); + params.add("--with-pbe-encrypt"); + params.add("--pbe-iteration"); + params.add("1000000"); + params.add("--json"); + + final String password = PASSWORD_CACHE_MAP.get(vault); + if (password != null) { + params.add("--password"); + params.add(password); + } + final UtilsCommandResult encryptResult = runCardCli( cardConfig, null, - "hmac-encrypt", - "--plaintext", Base64.getEncoder().encodeToString(input), - "--with-pbe-encrypt", - "--pbe-iteration", "1000000", - "--json" + params.toArray(new String[0]) ); if (encryptResult.getExitValue() != 0) { throw new KeychainAccessException("card-cli encrypt failed: " + encryptResult);