Merge pull request 'feature-issue-2' (#3) from feature-issue-2 into master

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
2022-04-03 00:05:12 +08:00
10 changed files with 275 additions and 84 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
__tinyencrypt_config.json
out/ out/
build build
classes classes

View File

@@ -19,7 +19,7 @@ public class TinyEncryptArgs {
@CommandLine.Option(names = {"-s", "--show"}, description = "Show decrypted text in window") @CommandLine.Option(names = {"-s", "--show"}, description = "Show decrypted text in window")
boolean showInWindow = false; boolean showInWindow = false;
@CommandLine.Option(names = {"-k", "--key"}, description = "Encrypt key") @CommandLine.Option(names = {"-k", "--key"}, description = "Encrypt KMS key")
String key; String key;
@CommandLine.Option(names = {"-c", "--comment"}, description = "Encrypt comment") @CommandLine.Option(names = {"-c", "--comment"}, description = "Encrypt comment")
@@ -28,6 +28,9 @@ public class TinyEncryptArgs {
@CommandLine.Option(names = {"--compress"}, description = "Encrypt compress") @CommandLine.Option(names = {"--compress"}, description = "Encrypt compress")
boolean compress = false; 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") @CommandLine.Option(names = {"-C", "--config"}, description = "Encrypt config")
File config; File config;
@@ -49,6 +52,9 @@ public class TinyEncryptArgs {
@CommandLine.Option(names = {"--init-config"}, description = "Init encrypt config") @CommandLine.Option(names = {"--init-config"}, description = "Init encrypt config")
boolean doInitConfig = false; 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") @CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Display a help message")
boolean helpRequested = false; boolean helpRequested = false;

View File

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

View File

@@ -9,10 +9,13 @@ import me.hatter.tools.commons.log.LogConfig;
import me.hatter.tools.commons.log.LogTool; import me.hatter.tools.commons.log.LogTool;
import me.hatter.tools.commons.log.LogTools; import me.hatter.tools.commons.log.LogTools;
import me.hatter.tools.commons.security.bc.BCUtil; 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.digest.Digests;
import me.hatter.tools.commons.security.key.KeyPairTool; import me.hatter.tools.commons.security.key.KeyPairTool;
import me.hatter.tools.commons.security.key.KeyUtil; import me.hatter.tools.commons.security.key.KeyUtil;
import me.hatter.tools.commons.security.key.PKType; 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.string.StringUtil;
import me.hatter.tools.commons.tlv.Tlv; import me.hatter.tools.commons.tlv.Tlv;
import me.hatter.tools.commons.tlv.TlvUtil; 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.config.TinyEncryptConstant;
import me.hatter.tools.tinyencrypt.encrypt.EncryptedFileUtil; import me.hatter.tools.tinyencrypt.encrypt.EncryptedFileUtil;
import me.hatter.tools.tinyencrypt.encrypt.TinyEncryptMeta; import me.hatter.tools.tinyencrypt.encrypt.TinyEncryptMeta;
import picocli.CommandLine; import me.hatter.tools.tinyencrypt.util.CardCliUtil;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.security.KeyPair; import java.security.KeyPair;
import java.util.Date; import java.util.Date;
import java.util.Optional;
public class TinyEncryptMain { public class TinyEncryptMain {
private static final String DEFAULT_TINY_ENCRYPT_CONFIG = "~/.tinyencrypt_config.json";
private static final LogTool log; private static final LogTool log;
static { static {
@@ -36,19 +39,34 @@ public class TinyEncryptMain {
log = LogTools.getLogTool(TinyEncryptMain.class); log = LogTools.getLogTool(TinyEncryptMain.class);
} }
private static TinyEncryptArgs parseTinyEncryptArgs(String[] args) { private static void doEncryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) {
TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs(); TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs);
CommandLine cmd = new CommandLine(tinyEncryptArgs); if (config == null) {
cmd.parseArgs(args); return;
if (cmd.isUsageHelpRequested()) {
cmd.usage(cmd.getOut());
return null;
} else if (cmd.isVersionHelpRequested()) {
cmd.printVersionHelp(cmd.getOut());
return null;
} }
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<byte[]> 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) { private static void doInitConfig(TinyEncryptArgs tinyEncryptArgs) {
@@ -56,12 +74,7 @@ public class TinyEncryptMain {
log.error("Default key is not assigned"); log.error("Default key is not assigned");
return; return;
} }
RFile writeTinyEncryptConfigRFile; RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
if (tinyEncryptArgs.config != null) {
writeTinyEncryptConfigRFile = RFile.from(tinyEncryptArgs.config);
} else {
writeTinyEncryptConfigRFile = RFile.from(DEFAULT_TINY_ENCRYPT_CONFIG);
}
if (writeTinyEncryptConfigRFile.exists()) { if (writeTinyEncryptConfigRFile.exists()) {
log.error("File exists: " + tinyEncryptArgs.config); log.error("File exists: " + tinyEncryptArgs.config);
return; 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) { public static void main(String[] args) {
TinyEncryptArgs tinyEncryptArgs = parseTinyEncryptArgs(args); TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args);
if (tinyEncryptArgs == null) { if (tinyEncryptArgs == null) {
return; return;
} }
@@ -164,6 +158,10 @@ public class TinyEncryptMain {
doInitConfig(tinyEncryptArgs); doInitConfig(tinyEncryptArgs);
return; return;
} }
if (tinyEncryptArgs.doEncryptConfigLocalPrivateKey) { // --encrypt-config-local-private-key
doEncryptConfigLocalPrivateKey(tinyEncryptArgs);
return;
}
if (tinyEncryptArgs.fileInfo) { // --info if (tinyEncryptArgs.fileInfo) { // --info
fileInfo(tinyEncryptArgs); fileInfo(tinyEncryptArgs);
return; return;
@@ -181,7 +179,7 @@ public class TinyEncryptMain {
return; return;
} }
TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs); TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs);
if (config == null) { if (config == null) {
return; return;
} }
@@ -202,7 +200,7 @@ public class TinyEncryptMain {
} }
boolean result; boolean result;
if (tinyEncryptArgs.encrypt) { 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 { } else {
if (tinyEncryptArgs.showInWindow) { if (tinyEncryptArgs.showInWindow) {
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp); EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp);
@@ -236,8 +234,10 @@ public class TinyEncryptMain {
index++; index++;
} }
} catch (JumpOutException joe) { } catch (JumpOutException joe) {
log.error(joe.getMessage()); if (StringUtil.isNotEmpty(joe.getMessage())) {
log.debug(joe.getMessage(), joe); log.error(joe.getMessage());
log.debug(joe.getMessage(), joe);
}
} }
System.exit(0); System.exit(0);
} }

View File

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

View File

@@ -1,11 +1,17 @@
package me.hatter.tools.tinyencrypt.config; package me.hatter.tools.tinyencrypt.config;
import me.hatter.tools.commons.string.StringUtil;
public class TinyEncryptConfig { public class TinyEncryptConfig {
private String defaultKeyName; private String defaultKeyName;
private String localPublicKeyPem; private String localPublicKeyPem;
private String localPrivateKeyPem; private String localPrivateKeyPem;
private String localPrivateKeyPemEncrypted;
private String localPrivateKeyPemChallenge;
private String pgpEncryptPublicKeyPem; private String pgpEncryptPublicKeyPem;
@Deprecated
private String pgpDecryptCmd; private String pgpDecryptCmd;
private String cardCli;
public String getDefaultKeyName() { public String getDefaultKeyName() {
return defaultKeyName; return defaultKeyName;
@@ -31,6 +37,22 @@ public class TinyEncryptConfig {
this.localPrivateKeyPem = localPrivateKeyPem; 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() { public String getPgpEncryptPublicKeyPem() {
return pgpEncryptPublicKeyPem; return pgpEncryptPublicKeyPem;
} }
@@ -46,4 +68,12 @@ public class TinyEncryptConfig {
public void setPgpDecryptCmd(String pgpDecryptCmd) { public void setPgpDecryptCmd(String pgpDecryptCmd) {
this.pgpDecryptCmd = pgpDecryptCmd; this.pgpDecryptCmd = pgpDecryptCmd;
} }
public String getCardCli() {
return StringUtil.def(cardCli, pgpDecryptCmd);
}
public void setCardCli(String cardCli) {
this.cardCli = cardCli;
}
} }

View File

@@ -1,7 +1,7 @@
package me.hatter.tools.tinyencrypt.config; package me.hatter.tools.tinyencrypt.config;
public class TinyEncryptConstant { 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"; public static final String ENC_FILE_EXT = ".tinyenc";
} }

View File

@@ -1,7 +1,5 @@
package me.hatter.tools.tinyencrypt.encrypt; 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.assertion.AssertUtil;
import me.hatter.tools.commons.bytes.Bytes; import me.hatter.tools.commons.bytes.Bytes;
import me.hatter.tools.commons.io.DefaultRollCounter; 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.commons.tlv.TlvUtil;
import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig;
import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; 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.NilOutputStream;
import me.hatter.tools.tinyencrypt.util.SwingWindow; import me.hatter.tools.tinyencrypt.util.SwingWindow;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@@ -45,44 +45,25 @@ public class EncryptedFileUtil {
log.error("File is not encrypted with PGP envelop"); log.error("File is not encrypted with PGP envelop");
return false; return false;
} }
if (StringUtil.isBlank(config.getPgpDecryptCmd())) { if (StringUtil.isBlank(config.getCardCli())) {
log.error("PGP decrypt cmd is not configed"); log.error("Card-cli is empty!");
return false; return false;
} }
if (RFile.from(config.getPgpDecryptCmd()).isNotFile()) { if (RFile.from(config.getCardCli()).isNotFile()) {
log.error("PGP decrypt cmd is miss configed"); log.error("PGP decrypt cmd is miss configed");
return false; return false;
} }
System.out.print("Input PGP PIN: "); Optional<String> pinOpt = CardCliUtil.readUserPin();
char[] pin = System.console().readPassword(); if (!pinOpt.isPresent()) {
if (pin.length < 6) {
log.error("PIN must have 6 letters");
return false; return false;
} }
ProcessBuilder pb = new ProcessBuilder( String pin = pinOpt.get();
config.getPgpDecryptCmd(), Optional<byte[]> dataKeyOpt = CardCliUtil.decryptPgpEnvelop(
"pgp-card-decrypt", config.getCardCli(), pin, meta.getPgpEnvelop());
"--cipher-base64", meta.getPgpEnvelop(), if (!dataKeyOpt.isPresent()) {
"--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())));
return false; return false;
} }
dataKey = dataKeyOpt.get();
} else { } else {
dataKey = TinyEncryptMetaUtil.decryptDataKey(config, meta); dataKey = TinyEncryptMetaUtil.decryptDataKey(config, meta);
} }
@@ -155,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); File encFile = getEncryptFile(file);
if (encFile == null) { if (encFile == null) {
log.warn("Cannot encrypt .tinyenc file: " + file); log.warn("Cannot encrypt .tinyenc file: " + file);
@@ -166,7 +147,7 @@ public class EncryptedFileUtil {
return false; return false;
} }
try { try {
TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, comment); TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, comment, requireSign);
meta.setFileLength(file.length()); meta.setFileLength(file.length());
meta.setFileLastModified(file.lastModified()); meta.setFileLastModified(file.lastModified());
meta.setCompress(compress); meta.setCompress(compress);

View File

@@ -8,6 +8,7 @@ import me.hatter.tools.commons.log.LogTool;
import me.hatter.tools.commons.log.LogTools; import me.hatter.tools.commons.log.LogTools;
import me.hatter.tools.commons.network.HttpRequest; import me.hatter.tools.commons.network.HttpRequest;
import me.hatter.tools.commons.os.OSUtil; 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.digest.Digests;
import me.hatter.tools.commons.security.key.KeyUtil; import me.hatter.tools.commons.security.key.KeyUtil;
import me.hatter.tools.commons.security.random.RandomTool; 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.commons.string.StringUtil;
import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig; import me.hatter.tools.tinyencrypt.config.TinyEncryptConfig;
import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant; import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant;
import me.hatter.tools.tinyencrypt.util.CardCliUtil;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
@@ -23,6 +25,7 @@ import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64; import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.Optional;
public class TinyEncryptMetaUtil { public class TinyEncryptMetaUtil {
private static final LogTool log = LogTools.getLogTool(TinyEncryptMetaUtil.class); private static final LogTool log = LogTools.getLogTool(TinyEncryptMetaUtil.class);
@@ -37,7 +40,27 @@ public class TinyEncryptMetaUtil {
return JSON.parseObject(meta, TinyEncryptMeta.class); 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<byte[]> 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) { public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) {
requireLocalPrivateKeyPem(config);
PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
String envelop = meta.getEnvelop(); String envelop = meta.getEnvelop();
@@ -62,9 +85,13 @@ public class TinyEncryptMetaUtil {
return Base64.getDecoder().decode(responseData.getString("dataKey")); return Base64.getDecoder().decode(responseData.getString("dataKey"));
} }
public static TinyEncryptMeta create(TinyEncryptConfig config, String comment) { 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()); PublicKey publicKey = KeyUtil.parsePublicKeyPEM(config.getLocalPublicKeyPem());
PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
PublicKey pgpEncryptPublicKey = null; PublicKey pgpEncryptPublicKey = null;
if (StringUtil.isNotBlank(config.getPgpEncryptPublicKeyPem())) { if (StringUtil.isNotBlank(config.getPgpEncryptPublicKeyPem())) {
pgpEncryptPublicKey = KeyUtil.parsePublicKeyPEM(config.getPgpEncryptPublicKeyPem()); pgpEncryptPublicKey = KeyUtil.parsePublicKeyPEM(config.getPgpEncryptPublicKeyPem());
@@ -73,14 +100,18 @@ public class TinyEncryptMetaUtil {
String timestamp = String.valueOf(System.currentTimeMillis()); String timestamp = String.valueOf(System.currentTimeMillis());
String toBeSigned = name + "|" + timestamp; String toBeSigned = name + "|" + timestamp;
Bytes sign = Signatures.sha256(privateKey).sign(toBeSigned); Bytes sign = (privateKey == null) ? null : Signatures.sha256(privateKey).sign(toBeSigned);
List<HttpRequest.KeyValue> keyValues = new ArrayList<>(); List<HttpRequest.KeyValue> keyValues = new ArrayList<>();
keyValues.add(new HttpRequest.KeyValue("name", name)); keyValues.add(new HttpRequest.KeyValue("name", name));
keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp)); keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp));
keyValues.add(new HttpRequest.KeyValue("dataKeyPublicKey", KeyUtil.serializePublicKeyToPEM(publicKey))); keyValues.add(new HttpRequest.KeyValue("dataKeyPublicKey", KeyUtil.serializePublicKeyToPEM(publicKey)));
keyValues.add(new HttpRequest.KeyValue("dataKeyRequestSign", sign.asBase64())); if (sign == null) {
log.info("Get data key from kms, key name: " + name + " ..."); 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); Bytes response = HttpRequest.fromUrl(KMS_GET_DATA_KEY).post(keyValues);
JSONObject responseObject = response.asJSON(); JSONObject responseObject = response.asJSON();
if (responseObject.getIntValue("status") != 200) { if (responseObject.getIntValue("status") != 200) {

View File

@@ -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<String> 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<byte[]> 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<String> 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<byte[]> 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<String> 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<String> 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();
}
}
}