From f1ed2bae7e2f71b30126ecdd87adffe85240ba82 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 2 Apr 2022 21:48:46 +0800 Subject: [PATCH 1/3] v0.3.10 --- .gitignore | 1 + .../tools/tinyencrypt/TinyEncryptArgs.java | 3 + .../tinyencrypt/TinyEncryptArgsUtil.java | 32 +++++++ .../tools/tinyencrypt/TinyEncryptMain.java | 86 +++++++++---------- .../tinyencrypt/TinyEncryptMainUtil.java | 25 ++++++ .../tinyencrypt/config/TinyEncryptConfig.java | 30 +++++++ .../config/TinyEncryptConstant.java | 2 +- .../encrypt/EncryptedFileUtil.java | 43 +++------- .../encrypt/TinyEncryptMetaUtil.java | 24 ++++++ .../tools/tinyencrypt/util/CardCliUtil.java | 85 ++++++++++++++++++ 10 files changed, 256 insertions(+), 75 deletions(-) create mode 100644 src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java create mode 100644 src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java create mode 100644 src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java diff --git a/.gitignore b/.gitignore index 5def27e..d96080a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +__tinyencrypt_config.json out/ build classes diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java index bae65fd..d6b9306 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java @@ -49,6 +49,9 @@ public class TinyEncryptArgs { @CommandLine.Option(names = {"--init-config"}, description = "Init encrypt config") boolean doInitConfig = false; + @CommandLine.Option(names = {"--encrypt-config-local-private-key"}, description = "Do encrypt config local private key") + boolean doEncryptConfigLocalPrivateKey = false; + @CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Display a help message") boolean helpRequested = false; diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java new file mode 100644 index 0000000..1dbac23 --- /dev/null +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgsUtil.java @@ -0,0 +1,32 @@ +package me.hatter.tools.tinyencrypt; + +import me.hatter.tools.commons.io.RFile; +import picocli.CommandLine; + +public class TinyEncryptArgsUtil { + private static final String DEFAULT_TINY_ENCRYPT_CONFIG = "~/.tinyencrypt_config.json"; + + + public static TinyEncryptArgs parseTinyEncryptArgs(String[] args) { + TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs(); + CommandLine cmd = new CommandLine(tinyEncryptArgs); + cmd.parseArgs(args); + + if (cmd.isUsageHelpRequested()) { + cmd.usage(cmd.getOut()); + return null; + } else if (cmd.isVersionHelpRequested()) { + cmd.printVersionHelp(cmd.getOut()); + return null; + } + return tinyEncryptArgs; + } + + public static RFile getTinyEncryptConfigRFile(TinyEncryptArgs tinyEncryptArgs) { + if (tinyEncryptArgs.config != null) { + return RFile.from(tinyEncryptArgs.config); + } else { + return RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG); + } + } +} diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java index 537b929..981560a 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java @@ -9,10 +9,13 @@ import me.hatter.tools.commons.log.LogConfig; import me.hatter.tools.commons.log.LogTool; import me.hatter.tools.commons.log.LogTools; import me.hatter.tools.commons.security.bc.BCUtil; +import me.hatter.tools.commons.security.crypt.AESCryptTool; import me.hatter.tools.commons.security.digest.Digests; import me.hatter.tools.commons.security.key.KeyPairTool; import me.hatter.tools.commons.security.key.KeyUtil; import me.hatter.tools.commons.security.key.PKType; +import me.hatter.tools.commons.security.random.RandomTool; +import me.hatter.tools.commons.string.JSONUtil; import me.hatter.tools.commons.string.StringUtil; import me.hatter.tools.commons.tlv.Tlv; import me.hatter.tools.commons.tlv.TlvUtil; @@ -20,15 +23,15 @@ import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; import me.hatter.tools.tinyencrypt.encrypt.EncryptedFileUtil; import me.hatter.tools.tinyencrypt.encrypt.TinyEncryptMeta; -import picocli.CommandLine; +import me.hatter.tools.tinyencrypt.util.CardCliUtil; import java.io.File; import java.io.FileInputStream; import java.security.KeyPair; import java.util.Date; +import java.util.Optional; public class TinyEncryptMain { - private static final String DEFAULT_TINY_ENCRYPT_CONFIG = "~/.tinyencrypt_config.json"; private static final LogTool log; static { @@ -36,19 +39,34 @@ public class TinyEncryptMain { log = LogTools.getLogTool(TinyEncryptMain.class); } - private static TinyEncryptArgs parseTinyEncryptArgs(String[] args) { - TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs(); - CommandLine cmd = new CommandLine(tinyEncryptArgs); - cmd.parseArgs(args); - - if (cmd.isUsageHelpRequested()) { - cmd.usage(cmd.getOut()); - return null; - } else if (cmd.isVersionHelpRequested()) { - cmd.printVersionHelp(cmd.getOut()); - return null; + private static void doEncryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) { + TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs); + if (config == null) { + return; } - return tinyEncryptArgs; + if (StringUtil.isEmpty(config.getLocalPrivateKeyPem())) { + log.error("Local private key pem is empty!"); + return; + } + if (StringUtil.isNotEmpty(config.getLocalPrivateKeyPemEncrypted()) + || StringUtil.isNotEmpty(config.getLocalPrivateKeyPemChallenge())) { + log.error("Local private key is already encrypted!"); + return; + } + String challenge = RandomTool.secureRandom().nextBytes(16).asHex(); + Optional keyOpt = CardCliUtil.getChall(config.getCardCli(), challenge); + if (!keyOpt.isPresent()) { + return; + } + byte[] key = keyOpt.get(); + String localPrivateKeyPemEncrypted = AESCryptTool.gcmEncrypt(key).from(Bytes.from(config.getLocalPrivateKeyPem())).toBytes().asBase64(); + + RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); + config.setLocalPrivateKeyPem(null); + config.setLocalPrivateKeyPemChallenge(challenge); + config.setLocalPrivateKeyPemEncrypted(localPrivateKeyPemEncrypted); + tinyEncryptConfigRFile.write(JSONUtil.pretty(config)); + log.info("Write file success: " + tinyEncryptConfigRFile.file()); } private static void doInitConfig(TinyEncryptArgs tinyEncryptArgs) { @@ -56,12 +74,7 @@ public class TinyEncryptMain { log.error("Default key is not assigned"); return; } - RFile writeTinyEncryptConfigRFile; - if (tinyEncryptArgs.config != null) { - writeTinyEncryptConfigRFile = RFile.from(tinyEncryptArgs.config); - } else { - writeTinyEncryptConfigRFile = RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG); - } + RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); if (writeTinyEncryptConfigRFile.exists()) { log.error("File exists: " + tinyEncryptArgs.config); return; @@ -134,27 +147,8 @@ public class TinyEncryptMain { } } - private static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) { - TinyEncryptConfig config; - if (tinyEncryptArgs.config != null) { - config = RFile.from(tinyEncryptArgs.config).parseJSONObject(TinyEncryptConfig.class); - } else { - RFile defaultTinyEncryptConfigFile = RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG); - if (defaultTinyEncryptConfigFile.notExists()) { - log.error("Config file not assigned, and no default config file: " + DEFAULT_TINY_ENCRYPT_CONFIG); - return null; - } - config = defaultTinyEncryptConfigFile.parseJSONObject(TinyEncryptConfig.class); - } - if (StringUtil.isNotBlank(tinyEncryptArgs.key)) { - log.info("Using key from args: " + tinyEncryptArgs.key); - config.setDefaultKeyName(tinyEncryptArgs.key); - } - return config; - } - public static void main(String[] args) { - TinyEncryptArgs tinyEncryptArgs = parseTinyEncryptArgs(args); + TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args); if (tinyEncryptArgs == null) { return; } @@ -164,6 +158,10 @@ public class TinyEncryptMain { doInitConfig(tinyEncryptArgs); return; } + if (tinyEncryptArgs.doEncryptConfigLocalPrivateKey) { // --encrypt-config-local-private-key + doEncryptConfigLocalPrivateKey(tinyEncryptArgs); + return; + } if (tinyEncryptArgs.fileInfo) { // --info fileInfo(tinyEncryptArgs); return; @@ -181,7 +179,7 @@ public class TinyEncryptMain { return; } - TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs); + TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs); if (config == null) { return; } @@ -236,8 +234,10 @@ public class TinyEncryptMain { index++; } } catch (JumpOutException joe) { - log.error(joe.getMessage()); - log.debug(joe.getMessage(), joe); + if (StringUtil.isNotEmpty(joe.getMessage())) { + log.error(joe.getMessage()); + log.debug(joe.getMessage(), joe); + } } System.exit(0); } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java new file mode 100644 index 0000000..90819e9 --- /dev/null +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java @@ -0,0 +1,25 @@ +package me.hatter.tools.tinyencrypt; + +import me.hatter.tools.commons.io.RFile; +import me.hatter.tools.commons.log.LogTool; +import me.hatter.tools.commons.log.LogTools; +import me.hatter.tools.commons.string.StringUtil; +import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; + +public class TinyEncryptMainUtil { + private static final LogTool log = LogTools.getLogTool(TinyEncryptMainUtil.class); + + public static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) { + RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); + if (tinyEncryptConfigRFile.notExists()) { + log.error("Config file not found: " + tinyEncryptConfigRFile.file()); + return null; + } + TinyEncryptConfig config = tinyEncryptConfigRFile.parseJSONObject(TinyEncryptConfig.class); + if (StringUtil.isNotBlank(tinyEncryptArgs.key)) { + log.info("Using key from args: " + tinyEncryptArgs.key); + config.setDefaultKeyName(tinyEncryptArgs.key); + } + return config; + } +} diff --git a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java index 3c9bee9..4131de2 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConfig.java @@ -1,11 +1,17 @@ package me.hatter.tools.tinyencrypt.config; +import me.hatter.tools.commons.string.StringUtil; + public class TinyEncryptConfig { private String defaultKeyName; private String localPublicKeyPem; private String localPrivateKeyPem; + private String localPrivateKeyPemEncrypted; + private String localPrivateKeyPemChallenge; private String pgpEncryptPublicKeyPem; + @Deprecated private String pgpDecryptCmd; + private String cardCli; public String getDefaultKeyName() { return defaultKeyName; @@ -31,6 +37,22 @@ public class TinyEncryptConfig { this.localPrivateKeyPem = localPrivateKeyPem; } + public String getLocalPrivateKeyPemEncrypted() { + return localPrivateKeyPemEncrypted; + } + + public void setLocalPrivateKeyPemEncrypted(String localPrivateKeyPemEncrypted) { + this.localPrivateKeyPemEncrypted = localPrivateKeyPemEncrypted; + } + + public String getLocalPrivateKeyPemChallenge() { + return localPrivateKeyPemChallenge; + } + + public void setLocalPrivateKeyPemChallenge(String localPrivateKeyPemChallenge) { + this.localPrivateKeyPemChallenge = localPrivateKeyPemChallenge; + } + public String getPgpEncryptPublicKeyPem() { return pgpEncryptPublicKeyPem; } @@ -46,4 +68,12 @@ public class TinyEncryptConfig { public void setPgpDecryptCmd(String pgpDecryptCmd) { this.pgpDecryptCmd = pgpDecryptCmd; } + + public String getCardCli() { + return StringUtil.def(cardCli, pgpDecryptCmd); + } + + public void setCardCli(String cardCli) { + this.cardCli = cardCli; + } } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java index 2817d8c..8a1f141 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/config/TinyEncryptConstant.java @@ -1,7 +1,7 @@ package me.hatter.tools.tinyencrypt.config; public class TinyEncryptConstant { - public static final String VERSION = "0.3.9"; + public static final String VERSION = "0.3.10"; public static final String ENC_FILE_EXT = ".tinyenc"; } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java index 67eafd6..c7aa165 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java @@ -1,7 +1,5 @@ package me.hatter.tools.tinyencrypt.encrypt; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import me.hatter.tools.commons.assertion.AssertUtil; import me.hatter.tools.commons.bytes.Bytes; import me.hatter.tools.commons.io.DefaultRollCounter; @@ -18,11 +16,13 @@ import me.hatter.tools.commons.tlv.Tlv; import me.hatter.tools.commons.tlv.TlvUtil; import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; +import me.hatter.tools.tinyencrypt.util.CardCliUtil; import me.hatter.tools.tinyencrypt.util.NilOutputStream; import me.hatter.tools.tinyencrypt.util.SwingWindow; import java.io.*; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -45,44 +45,25 @@ public class EncryptedFileUtil { log.error("File is not encrypted with PGP envelop"); return false; } - if (StringUtil.isBlank(config.getPgpDecryptCmd())) { - log.error("PGP decrypt cmd is not configed"); + if (StringUtil.isBlank(config.getCardCli())) { + log.error("Card-cli is empty!"); return false; } - if (RFile.from(config.getPgpDecryptCmd()).isNotFile()) { + if (RFile.from(config.getCardCli()).isNotFile()) { log.error("PGP decrypt cmd is miss configed"); return false; } - System.out.print("Input PGP PIN: "); - char[] pin = System.console().readPassword(); - if (pin.length < 6) { - log.error("PIN must have 6 letters"); + Optional pinOpt = CardCliUtil.readUserPin(); + if (!pinOpt.isPresent()) { return false; } - ProcessBuilder pb = new ProcessBuilder( - config.getPgpDecryptCmd(), - "pgp-card-decrypt", - "--cipher-base64", meta.getPgpEnvelop(), - "--pass", new String(pin), - "--json"); - log.info("Start: " + config.getPgpDecryptCmd()); - log.debug("Start process: " + pb.command()); - Process p = pb.start(); - p.waitFor(); - log.info("Finished command"); - try { - byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream()); - String jsonStr = new String(jsonBytes, StandardCharsets.UTF_8); - if (log.isDebugEnable()) { - log.debug("Read cmd JSON: " + jsonStr); - } - JSONObject jo = JSON.parseObject(jsonStr); - dataKey = Bytes.fromHex(jo.getString("text_hex")).bytes(); - } catch (Exception e) { - log.error("Error in parse pgp-card-decrypt: " + e, e); - log.error("err out: " + Bytes.from(IOUtil.readToBytes(p.getErrorStream()))); + String pin = pinOpt.get(); + Optional dataKeyOpt = CardCliUtil.decryptPgpEnvelop( + config.getCardCli(), pin, meta.getPgpEnvelop()); + if (!dataKeyOpt.isPresent()) { return false; } + dataKey = dataKeyOpt.get(); } else { dataKey = TinyEncryptMetaUtil.decryptDataKey(config, meta); } diff --git a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java index 1bfe404..84ae5ab 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java @@ -8,6 +8,7 @@ import me.hatter.tools.commons.log.LogTool; import me.hatter.tools.commons.log.LogTools; import me.hatter.tools.commons.network.HttpRequest; import me.hatter.tools.commons.os.OSUtil; +import me.hatter.tools.commons.security.crypt.AESCryptTool; import me.hatter.tools.commons.security.digest.Digests; import me.hatter.tools.commons.security.key.KeyUtil; import me.hatter.tools.commons.security.random.RandomTool; @@ -16,6 +17,7 @@ import me.hatter.tools.commons.security.sign.Signatures; import me.hatter.tools.commons.string.StringUtil; import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; +import me.hatter.tools.tinyencrypt.util.CardCliUtil; import java.security.PrivateKey; import java.security.PublicKey; @@ -23,6 +25,7 @@ import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.Optional; public class TinyEncryptMetaUtil { private static final LogTool log = LogTools.getLogTool(TinyEncryptMetaUtil.class); @@ -37,7 +40,27 @@ public class TinyEncryptMetaUtil { return JSON.parseObject(meta, TinyEncryptMeta.class); } + public static void requireLocalPrivateKeyPem(TinyEncryptConfig config) { + if (StringUtil.isNotEmpty(config.getLocalPrivateKeyPem())) { + return; + } + if (StringUtil.isEmpty(config.getLocalPrivateKeyPemChallenge()) + || StringUtil.isEmpty(config.getLocalPrivateKeyPemEncrypted())) { + throw new JumpOutException("Cannot prepare local private key pem!"); + } + Optional keyOpt = CardCliUtil.getChall(config.getCardCli(), config.getLocalPrivateKeyPemChallenge()); + if (!keyOpt.isPresent()) { + throw new JumpOutException(); + } + byte[] key = keyOpt.get(); + String localPrivateKeyPem = AESCryptTool.gcmDecrypt(key) + .from(Bytes.fromBase64(config.getLocalPrivateKeyPemEncrypted())).toBytes().string(); + log.info("Decrypt local private key success!"); + config.setLocalPrivateKeyPem(localPrivateKeyPem); + } + public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) { + requireLocalPrivateKeyPem(config); PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); String envelop = meta.getEnvelop(); @@ -63,6 +86,7 @@ public class TinyEncryptMetaUtil { } public static TinyEncryptMeta create(TinyEncryptConfig config, String comment) { + requireLocalPrivateKeyPem(config); PublicKey publicKey = KeyUtil.parsePublicKeyPEM(config.getLocalPublicKeyPem()); PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); PublicKey pgpEncryptPublicKey = null; diff --git a/src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java new file mode 100644 index 0000000..fad70f5 --- /dev/null +++ b/src/main/java/me/hatter/tools/tinyencrypt/util/CardCliUtil.java @@ -0,0 +1,85 @@ +package me.hatter.tools.tinyencrypt.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import me.hatter.tools.commons.bytes.Bytes; +import me.hatter.tools.commons.exception.JumpOutException; +import me.hatter.tools.commons.io.IOUtil; +import me.hatter.tools.commons.log.LogTool; +import me.hatter.tools.commons.log.LogTools; +import me.hatter.tools.commons.string.StringUtil; + +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +public class CardCliUtil { + private static final LogTool log = LogTools.getLogTool(CardCliUtil.class); + + public static Optional readUserPin() { + System.out.print("Input PGP user PIN: "); + char[] pin = System.console().readPassword(); + if (pin.length < 6) { + log.error("User PIN must have 6 letters"); + return Optional.empty(); + } + return Optional.of(new String(pin)); + } + + public static Optional getChall(String cardCli, String challenge) { + if (StringUtil.isEmpty(cardCli)) { + throw new JumpOutException("Card-cli is empty!"); + } + ProcessBuilder pb = new ProcessBuilder( + cardCli, + "chall", + "--challenge-hex", challenge, + "--json", "--sha256"); + log.info("Start: " + cardCli); + + Optional outputsOpt = runProcess(pb); + if (!outputsOpt.isPresent()) { + return Optional.empty(); + } + JSONObject jo = JSON.parseObject(outputsOpt.get()); + return Optional.of(Bytes.fromHex(jo.getString("response_sha256_hex")).bytes()); + } + + public static Optional decryptPgpEnvelop(String cardCli, String pin, String pgpEnvelop) { + ProcessBuilder pb = new ProcessBuilder( + cardCli, + "pgp-card-decrypt", + "--cipher-base64", pgpEnvelop, + "--pin", pin, + "--json"); + log.info("Start: " + cardCli); + Optional outputsOpt = runProcess(pb); + if (!outputsOpt.isPresent()) { + return Optional.empty(); + } + JSONObject jo = JSON.parseObject(outputsOpt.get()); + return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes()); + } + + public static Optional runProcess(ProcessBuilder pb) { + Process p = null; + try { + log.debug("Start process: " + pb.command()); + p = pb.start(); + p.waitFor(); + log.info("Finished command"); + + byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream()); + String outputs = new String(jsonBytes, StandardCharsets.UTF_8); + if (log.isDebugEnable()) { + log.debug("Read cmd outputs: " + outputs); + } + return Optional.of(outputs); + } catch (Exception e) { + log.error("Error in run card-cli: " + e, e); + if (p != null) { + log.error("err out: " + Bytes.from(IOUtil.readToBytes(p.getErrorStream()))); + } + return Optional.empty(); + } + } +} -- 2.27.0 From 1fa032ca06a2ffaf96d1eb096bec6d910980b8c1 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 2 Apr 2022 23:59:01 +0800 Subject: [PATCH 2/3] v0.4.10, allow create data key without sign --- .../tools/tinyencrypt/TinyEncryptArgs.java | 3 +++ .../tools/tinyencrypt/TinyEncryptMain.java | 2 +- .../encrypt/EncryptedFileUtil.java | 4 ++-- .../encrypt/TinyEncryptMetaUtil.java | 19 +++++++++++++------ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java index d6b9306..1fd7bdc 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java @@ -28,6 +28,9 @@ public class TinyEncryptArgs { @CommandLine.Option(names = {"--compress"}, description = "Encrypt compress") boolean compress = false; + @CommandLine.Option(names = {"--require-sign"}, description = "Require signature when create data key") + boolean requireSign = false; + @CommandLine.Option(names = {"-C", "--config"}, description = "Encrypt config") File config; diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java index 981560a..1bb5e4e 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java @@ -200,7 +200,7 @@ public class TinyEncryptMain { } boolean result; if (tinyEncryptArgs.encrypt) { - result = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f, tinyEncryptArgs.compress, tinyEncryptArgs.comment); + result = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f, tinyEncryptArgs.compress, tinyEncryptArgs.requireSign, tinyEncryptArgs.comment); } else { if (tinyEncryptArgs.showInWindow) { EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp); diff --git a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java index c7aa165..b79a2f8 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java @@ -136,7 +136,7 @@ public class EncryptedFileUtil { } } - public static boolean encryptFile(TinyEncryptConfig config, String keyName, File file, boolean compress, String comment) { + public static boolean encryptFile(TinyEncryptConfig config, String keyName, File file, boolean compress, boolean requireSign, String comment) { File encFile = getEncryptFile(file); if (encFile == null) { log.warn("Cannot encrypt .tinyenc file: " + file); @@ -147,7 +147,7 @@ public class EncryptedFileUtil { return false; } try { - TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, comment); + TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, comment, requireSign); meta.setFileLength(file.length()); meta.setFileLastModified(file.lastModified()); meta.setCompress(compress); diff --git a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java index 84ae5ab..6e43b8c 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java @@ -85,10 +85,13 @@ public class TinyEncryptMetaUtil { return Base64.getDecoder().decode(responseData.getString("dataKey")); } - public static TinyEncryptMeta create(TinyEncryptConfig config, String comment) { - requireLocalPrivateKeyPem(config); + public static TinyEncryptMeta create(TinyEncryptConfig config, String comment, boolean requireSignature) { + PrivateKey privateKey = null; + if (requireSignature) { + requireLocalPrivateKeyPem(config); + privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); + } PublicKey publicKey = KeyUtil.parsePublicKeyPEM(config.getLocalPublicKeyPem()); - PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); PublicKey pgpEncryptPublicKey = null; if (StringUtil.isNotBlank(config.getPgpEncryptPublicKeyPem())) { pgpEncryptPublicKey = KeyUtil.parsePublicKeyPEM(config.getPgpEncryptPublicKeyPem()); @@ -97,14 +100,18 @@ public class TinyEncryptMetaUtil { String timestamp = String.valueOf(System.currentTimeMillis()); String toBeSigned = name + "|" + timestamp; - Bytes sign = Signatures.sha256(privateKey).sign(toBeSigned); + Bytes sign = (privateKey == null) ? null : Signatures.sha256(privateKey).sign(toBeSigned); List keyValues = new ArrayList<>(); keyValues.add(new HttpRequest.KeyValue("name", name)); keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp)); keyValues.add(new HttpRequest.KeyValue("dataKeyPublicKey", KeyUtil.serializePublicKeyToPEM(publicKey))); - keyValues.add(new HttpRequest.KeyValue("dataKeyRequestSign", sign.asBase64())); - log.info("Get data key from kms, key name: " + name + " ..."); + if (sign == null) { + keyValues.add(new HttpRequest.KeyValue("skipDataKeyRequestSignVerify", "true")); + } else { + keyValues.add(new HttpRequest.KeyValue("dataKeyRequestSign", sign.asBase64())); + } + log.info("Get data key from kms, key name: " + name + ", with sign: " + (sign != null) + " ..."); Bytes response = HttpRequest.fromUrl(KMS_GET_DATA_KEY).post(keyValues); JSONObject responseObject = response.asJSON(); if (responseObject.getIntValue("status") != 200) { -- 2.27.0 From 0a12ac717c068e16166aad954297280ec19b976c Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 3 Apr 2022 00:02:28 +0800 Subject: [PATCH 3/3] chore: command line help --- src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java index 1fd7bdc..bccab44 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java @@ -19,7 +19,7 @@ public class TinyEncryptArgs { @CommandLine.Option(names = {"-s", "--show"}, description = "Show decrypted text in window") boolean showInWindow = false; - @CommandLine.Option(names = {"-k", "--key"}, description = "Encrypt key") + @CommandLine.Option(names = {"-k", "--key"}, description = "Encrypt KMS key") String key; @CommandLine.Option(names = {"-c", "--comment"}, description = "Encrypt comment") -- 2.27.0