feat: cache password

This commit is contained in:
2025-05-09 23:52:59 +08:00
parent 33f08e094f
commit b834644e0c
2 changed files with 52 additions and 13 deletions

View File

@@ -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;
}
}

View File

@@ -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<String, String> 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<String> 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<String> 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);