feat: v0.5.3

This commit is contained in:
2023-02-10 23:12:06 +08:00
parent 5f2cd622d6
commit 84748768e1
9 changed files with 106 additions and 99 deletions

View File

@@ -8,8 +8,8 @@ public class TinyEncryptArgsUtil {
public static TinyEncryptArgs parseTinyEncryptArgs(String[] args) { public static TinyEncryptArgs parseTinyEncryptArgs(String[] args) {
TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs(); final TinyEncryptArgs tinyEncryptArgs = new TinyEncryptArgs();
CommandLine cmd = new CommandLine(tinyEncryptArgs); final CommandLine cmd = new CommandLine(tinyEncryptArgs);
cmd.parseArgs(args); cmd.parseArgs(args);
if (cmd.isUsageHelpRequested()) { if (cmd.isUsageHelpRequested()) {

View File

@@ -24,7 +24,7 @@ public class TinyEncryptMain {
} }
public static void main(String[] args) { public static void main(String[] args) {
TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args); final TinyEncryptArgs tinyEncryptArgs = TinyEncryptArgsUtil.parseTinyEncryptArgs(args);
if (tinyEncryptArgs == null) { if (tinyEncryptArgs == null) {
return; return;
} }
@@ -44,9 +44,9 @@ public class TinyEncryptMain {
} }
// ==================================================================================== // ====================================================================================
boolean isCreate = tinyEncryptArgs.create; final boolean isCreate = tinyEncryptArgs.create;
boolean isEncrypt = tinyEncryptArgs.encrypt; final boolean isEncrypt = tinyEncryptArgs.encrypt;
boolean isDecrypt = tinyEncryptArgs.decrypt; final boolean isDecrypt = tinyEncryptArgs.decrypt;
if ((isEncrypt && isDecrypt) || (isCreate && isEncrypt) || (isCreate && isDecrypt)) { if ((isEncrypt && isDecrypt) || (isCreate && isEncrypt) || (isCreate && isDecrypt)) {
log.error("Encrypt create or decrypt flag cannot multiple assigned."); log.error("Encrypt create or decrypt flag cannot multiple assigned.");
return; return;
@@ -56,7 +56,7 @@ public class TinyEncryptMain {
return; return;
} }
TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs); final TinyEncryptConfig config = TinyEncryptMainUtil.loadTinyEncryptConfig(tinyEncryptArgs);
if (config == null) { if (config == null) {
return; return;
} }
@@ -67,54 +67,54 @@ public class TinyEncryptMain {
try { try {
if (isCreate) { if (isCreate) {
TinyEncryptMainUtil.crateFileFromWindow(tinyEncryptArgs, config); TinyEncryptMainUtil.createFileFromWindow(tinyEncryptArgs, config);
throw new JumpOutException(); throw new JumpOutException();
} }
int index = 1; int index = 1;
int total = tinyEncryptArgs.files.length; final int total = tinyEncryptArgs.files.length;
for (File f : tinyEncryptArgs.files) { for (File f : tinyEncryptArgs.files) {
log.info("Start processing file: " + f + ", " + index + " of " + total); log.info("Start processing file: " + f + ", " + index + " of " + total);
index++;
if (!f.isFile()) { if (!f.isFile()) {
log.info("Skip not a file: " + f); log.info("Skip not a file: " + f);
continue; continue;
} }
boolean decryptSuccess; final boolean encryptOrDecryptSuccess;
if (tinyEncryptArgs.encrypt) { if (tinyEncryptArgs.encrypt) {
decryptSuccess = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f, encryptOrDecryptSuccess = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f,
tinyEncryptArgs.compress, !tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign, tinyEncryptArgs.compress, !tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign,
tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment); tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment);
} else { } else {
if (tinyEncryptArgs.showInWindow || tinyEncryptArgs.editInWindow) { if (tinyEncryptArgs.showInWindow || tinyEncryptArgs.editInWindow) {
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.editInWindow); EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.editInWindow);
decryptSuccess = false; // do not delete file encryptOrDecryptSuccess = false; // do not delete file
} else if (tinyEncryptArgs.digest) { } else if (tinyEncryptArgs.digest) {
Bytes sha256 = EncryptedFileUtil.decryptAndDigest(config, f, tinyEncryptArgs.pgp); final Bytes sha256 = EncryptedFileUtil.decryptAndDigest(config, f, tinyEncryptArgs.pgp);
if (sha256 != null) { if (sha256 != null) {
log.info(sha256.asHex() + " - " + f); log.info(sha256.asHex() + " - " + f);
File clearTextFile = EncryptedFileUtil.getDecryptFile(f); final File clearTextFile = EncryptedFileUtil.getDecryptFile(f);
if ((clearTextFile != null) && clearTextFile.exists()) { if ((clearTextFile != null) && clearTextFile.exists()) {
Bytes clearTextSha256 = RFile.from(clearTextFile).digest(Digests.sha256()); final Bytes clearTextSha256 = RFile.from(clearTextFile).digest(Digests.sha256());
if (clearTextSha256.equals(sha256)) { if (clearTextSha256.equals(sha256)) {
log.info("Clear text file exists, and MATCHES."); log.info("Clear text file exists, and MATCHES.");
} else { } else {
String nfn = f.toString(); final String nfn = f.toString();
log.warn(clearTextSha256.asHex() + " - " + nfn.substring(0, nfn.length() - TinyEncryptConstant.ENC_FILE_EXT.length())); log.warn(clearTextSha256.asHex() + " - " + nfn.substring(0, nfn.length() - TinyEncryptConstant.ENC_FILE_EXT.length()));
} }
} }
} }
decryptSuccess = false; // do not delete file encryptOrDecryptSuccess = false; // do not delete file
} else { } else {
decryptSuccess = EncryptedFileUtil.decryptFile(config, f, tinyEncryptArgs.pgp); encryptOrDecryptSuccess = EncryptedFileUtil.decryptFile(config, f, tinyEncryptArgs.pgp);
} }
} }
if (decryptSuccess && tinyEncryptArgs.removeFile) { if (encryptOrDecryptSuccess && tinyEncryptArgs.removeFile) {
log.info("Remove file: " + f); log.info("Remove file: " + f);
if (!f.delete()) { if (!f.delete()) {
log.warn("Remove file: " + f + " failed."); log.warn("Remove file: " + f + " failed.");
} }
} }
index++;
} }
} catch (JumpOutException joe) { } catch (JumpOutException joe) {
if (StringUtil.isNotEmpty(joe.getMessage())) { if (StringUtil.isNotEmpty(joe.getMessage())) {

View File

@@ -34,7 +34,7 @@ public class TinyEncryptMainUtil {
private static final LogTool log = LogTools.getLogTool(TinyEncryptMainUtil.class); private static final LogTool log = LogTools.getLogTool(TinyEncryptMainUtil.class);
public static void encryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) { public static void encryptConfigLocalPrivateKey(TinyEncryptArgs tinyEncryptArgs) {
TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs); final TinyEncryptConfig config = loadTinyEncryptConfig(tinyEncryptArgs);
if (config == null) { if (config == null) {
return; return;
} }
@@ -47,15 +47,15 @@ public class TinyEncryptMainUtil {
log.error("Local private key is already encrypted!"); log.error("Local private key is already encrypted!");
return; return;
} }
String challenge = RandomTool.secureRandom().nextBytes(16).asHex(); final String challenge = RandomTool.secureRandom().nextBytes(16).asHex();
Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), challenge); final Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), challenge);
if (!keyOpt.isPresent()) { if (!keyOpt.isPresent()) {
return; return;
} }
byte[] key = keyOpt.get(); final byte[] key = keyOpt.get();
String localPrivateKeyPemEncrypted = AESCryptTool.gcmEncrypt(key).from(Bytes.from(config.getLocalPrivateKeyPem())).toBytes().asBase64(); final String localPrivateKeyPemEncrypted = AESCryptTool.gcmEncrypt(key).from(Bytes.from(config.getLocalPrivateKeyPem())).toBytes().asBase64();
RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); final RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
config.setLocalPrivateKeyPem(null); config.setLocalPrivateKeyPem(null);
config.setLocalPrivateKeyPemChallenge(challenge); config.setLocalPrivateKeyPemChallenge(challenge);
config.setLocalPrivateKeyPemEncrypted(localPrivateKeyPemEncrypted); config.setLocalPrivateKeyPemEncrypted(localPrivateKeyPemEncrypted);
@@ -68,13 +68,13 @@ public class TinyEncryptMainUtil {
log.error("Default key is not assigned"); log.error("Default key is not assigned");
return; return;
} }
RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); final RFile writeTinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
if (writeTinyEncryptConfigRFile.exists()) { if (writeTinyEncryptConfigRFile.exists()) {
log.error("File exists: " + tinyEncryptArgs.config); log.error("File exists: " + tinyEncryptArgs.config);
return; return;
} }
KeyPair keyPair = KeyPairTool.ins(PKType.secp256r1).generate().getKeyPair(); final KeyPair keyPair = KeyPairTool.ins(PKType.secp256r1).generate().getKeyPair();
TinyEncryptConfig writeTinyEncryptConfig = new TinyEncryptConfig(); final TinyEncryptConfig writeTinyEncryptConfig = new TinyEncryptConfig();
writeTinyEncryptConfig.setDefaultKeyName(tinyEncryptArgs.key); writeTinyEncryptConfig.setDefaultKeyName(tinyEncryptArgs.key);
writeTinyEncryptConfig.setLocalPublicKeyPem(KeyUtil.serializePublicKeyToPEM(keyPair.getPublic())); writeTinyEncryptConfig.setLocalPublicKeyPem(KeyUtil.serializePublicKeyToPEM(keyPair.getPublic()));
writeTinyEncryptConfig.setLocalPrivateKeyPem(KeyUtil.serializePrivateKeyToPEM(keyPair.getPrivate())); writeTinyEncryptConfig.setLocalPrivateKeyPem(KeyUtil.serializePrivateKeyToPEM(keyPair.getPrivate()));
@@ -88,7 +88,7 @@ public class TinyEncryptMainUtil {
return; return;
} }
for (File f : tinyEncryptArgs.files) { for (File f : tinyEncryptArgs.files) {
boolean isTinyEncFile = f.getName().endsWith(TinyEncryptConstant.ENC_FILE_EXT); final boolean isTinyEncFile = f.getName().endsWith(TinyEncryptConstant.ENC_FILE_EXT);
if (!isTinyEncFile) { if (!isTinyEncFile) {
log.warn("File is not tiny enc file: " + f); log.warn("File is not tiny enc file: " + f);
} else { } else {
@@ -104,12 +104,12 @@ public class TinyEncryptMainUtil {
} }
public static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) { public static TinyEncryptConfig loadTinyEncryptConfig(TinyEncryptArgs tinyEncryptArgs) {
RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs); final RFile tinyEncryptConfigRFile = TinyEncryptArgsUtil.getTinyEncryptConfigRFile(tinyEncryptArgs);
if (tinyEncryptConfigRFile.notExists()) { if (tinyEncryptConfigRFile.notExists()) {
log.error("Config file not found: " + tinyEncryptConfigRFile.file()); log.error("Config file not found: " + tinyEncryptConfigRFile.file());
return null; return null;
} }
TinyEncryptConfig config = tinyEncryptConfigRFile.parseJSONObject(TinyEncryptConfig.class); final TinyEncryptConfig config = tinyEncryptConfigRFile.parseJSONObject(TinyEncryptConfig.class);
if (StringUtil.isNotBlank(tinyEncryptArgs.key)) { if (StringUtil.isNotBlank(tinyEncryptArgs.key)) {
log.info("Using key from args: " + tinyEncryptArgs.key); log.info("Using key from args: " + tinyEncryptArgs.key);
config.setDefaultKeyName(tinyEncryptArgs.key); config.setDefaultKeyName(tinyEncryptArgs.key);
@@ -117,7 +117,7 @@ public class TinyEncryptMainUtil {
return config; return config;
} }
public static void crateFileFromWindow(TinyEncryptArgs tinyEncryptArgs, TinyEncryptConfig config) { public static void createFileFromWindow(TinyEncryptArgs tinyEncryptArgs, TinyEncryptConfig config) {
if (tinyEncryptArgs.files.length != 1) { if (tinyEncryptArgs.files.length != 1) {
log.error("Create only can assign one file"); log.error("Create only can assign one file");
return; return;
@@ -132,14 +132,14 @@ public class TinyEncryptMainUtil {
return; return;
} }
String editResult = SwingWindow.create("Create file: " + file.getName()) final String editResult = SwingWindow.create("Create file: " + file.getName())
.message("File: " + file) .message("File: " + file)
.text("") .text("")
.editable(true) .editable(true)
.show().getResult(); .show().getResult();
byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8); final byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8);
TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, tinyEncryptArgs.key, final TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, tinyEncryptArgs.key,
tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment, tinyEncryptArgs.comment, tinyEncryptArgs.encryptedComment,
!tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign); !tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign);
meta.setFileLength((long) bytes.length); meta.setFileLength((long) bytes.length);
@@ -147,7 +147,7 @@ public class TinyEncryptMainUtil {
meta.setFileLastModified(System.currentTimeMillis()); meta.setFileLastModified(System.currentTimeMillis());
meta.setCompress(tinyEncryptArgs.compress); meta.setCompress(tinyEncryptArgs.compress);
InputStream inputStream = new ByteArrayInputStream(bytes); final InputStream inputStream = new ByteArrayInputStream(bytes);
try { try {
EncryptedFileUtil.encryptFromInputStream(inputStream, file, meta); EncryptedFileUtil.encryptFromInputStream(inputStream, file, meta);
log.info("Create file: " + file + " success"); log.info("Create file: " + file + " success");
@@ -157,10 +157,10 @@ public class TinyEncryptMainUtil {
} }
private static void printOneFileInfo(File f, FileInputStream fis) throws IOException { private static void printOneFileInfo(File f, FileInputStream fis) throws IOException {
Tlv tlv = TlvUtil.readTlv(fis); final Tlv tlv = TlvUtil.readTlv(fis);
TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class); final TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class);
log.debug("Tiny encrypt meta: " + JSON.toJSONString(meta, true)); log.debug("Tiny encrypt meta: " + JSON.toJSONString(meta, true));
StringBuilder sb = new StringBuilder(256); final StringBuilder sb = new StringBuilder(256);
sb.append("Tiny Encrypt File Info\n"); sb.append("Tiny Encrypt File Info\n");
sb.append(header("File")).append(f); sb.append(header("File")).append(f);
if ((meta.getCompress() != null) && meta.getCompress()) { if ((meta.getCompress() != null) && meta.getCompress()) {
@@ -196,7 +196,7 @@ public class TinyEncryptMainUtil {
} }
private static String header(String h) { private static String header(String h) {
int width = 18; final int width = 18;
return h + StringUtil.repeat(".", Math.max(width - h.length(), 0)) + ": "; return h + StringUtil.repeat(".", Math.max(width - h.length(), 0)) + ": ";
} }

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.5.2"; public static final String VERSION = "0.5.3";
public static final String ENC_FILE_EXT = ".tinyenc"; public static final String ENC_FILE_EXT = ".tinyenc";
} }

View File

@@ -23,6 +23,7 @@ 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.Date;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -38,13 +39,13 @@ public class EncryptedFileUtil {
} }
try { try {
try (FileInputStream fis = new FileInputStream(file)) { try (FileInputStream fis = new FileInputStream(file)) {
Tlv tlv = TlvUtil.readTlv(fis); final Tlv tlv = TlvUtil.readTlv(fis);
TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class); final TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class);
if (metaRef != null) { if (metaRef != null) {
metaRef.set(meta); metaRef.set(meta);
} }
byte[] dataKey; final byte[] dataKey;
if (pgp) { if (pgp) {
if (StringUtil.isBlank(meta.getPgpEnvelop())) { if (StringUtil.isBlank(meta.getPgpEnvelop())) {
log.error("File is not encrypted with PGP envelop"); log.error("File is not encrypted with PGP envelop");
@@ -58,12 +59,12 @@ public class EncryptedFileUtil {
log.error("PGP decrypt cmd is miss configed"); log.error("PGP decrypt cmd is miss configed");
return false; return false;
} }
Optional<String> pinOpt = CardCliUtil.readUserPin(); final Optional<String> pinOpt = CardCliUtil.readUserPin();
if (!pinOpt.isPresent()) { if (!pinOpt.isPresent()) {
return false; return false;
} }
String pin = pinOpt.get(); final String pin = pinOpt.get();
Optional<byte[]> dataKeyOpt = CardCliUtil.decryptPgpEnvelop( final Optional<byte[]> dataKeyOpt = CardCliUtil.decryptPgpEnvelop(
config.getCardCli(), pin, meta.getPgpEnvelop()); config.getCardCli(), pin, meta.getPgpEnvelop());
if (!dataKeyOpt.isPresent()) { if (!dataKeyOpt.isPresent()) {
return false; return false;
@@ -75,14 +76,14 @@ public class EncryptedFileUtil {
meta.setDataKey(dataKey); meta.setDataKey(dataKey);
if (StringUtil.isNotEmpty(meta.getEncryptedComment())) { if (StringUtil.isNotEmpty(meta.getEncryptedComment())) {
Bytes decryptedComment = AESCryptTool.gcmDecrypt(meta.getDataKey(), meta.getNonce()) final Bytes decryptedComment = AESCryptTool.gcmDecrypt(meta.getDataKey(), meta.getNonce())
.from(Bytes.fromBase64(meta.getEncryptedComment())) .from(Bytes.fromBase64(meta.getEncryptedComment()))
.toBytes(); .toBytes();
log.info("Decrypted comment: >>> " + decryptedComment.string() + " <<<"); log.info("Decrypted comment: >>> " + decryptedComment.string() + " <<<");
} }
try (InputStream newIs = getDecryptInputStream(fis, meta)) { try (InputStream newIs = getDecryptInputStream(fis, meta)) {
boolean isCompressed = (meta.getCompress() != null) && meta.getCompress(); final boolean isCompressed = (meta.getCompress() != null) && meta.getCompress();
if (isCompressed) { if (isCompressed) {
GZIPInputStream gzIs = new GZIPInputStream(newIs); GZIPInputStream gzIs = new GZIPInputStream(newIs);
IOUtil.copy(gzIs, os, new DefaultRollCounter().prefix("Decrypting, ")); IOUtil.copy(gzIs, os, new DefaultRollCounter().prefix("Decrypting, "));
@@ -102,7 +103,7 @@ public class EncryptedFileUtil {
} }
public static Bytes decryptAndDigest(TinyEncryptConfig config, File file, boolean pgp) { public static Bytes decryptAndDigest(TinyEncryptConfig config, File file, boolean pgp) {
DigestOutputStream outputStream = new DigestOutputStream(new NilOutputStream(), Digests.sha256()); final DigestOutputStream outputStream = new DigestOutputStream(new NilOutputStream(), Digests.sha256());
if (!decryptToOutputStream(config, file, outputStream, pgp, null)) { if (!decryptToOutputStream(config, file, outputStream, pgp, null)) {
return null; return null;
} }
@@ -110,15 +111,15 @@ public class EncryptedFileUtil {
} }
public static void decryptInWindow(TinyEncryptConfig config, File file, boolean pgp, boolean editable) { public static void decryptInWindow(TinyEncryptConfig config, File file, boolean pgp, boolean editable) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
AtomicReference<TinyEncryptMeta> metaRef = new AtomicReference<>(); final AtomicReference<TinyEncryptMeta> metaRef = new AtomicReference<>();
boolean decryptSuccess = decryptToOutputStream(config, file, baos, pgp, metaRef); final boolean decryptSuccess = decryptToOutputStream(config, file, baos, pgp, metaRef);
if (!decryptSuccess) { if (!decryptSuccess) {
return; return;
} }
String decrypted = new String(baos.toByteArray(), StandardCharsets.UTF_8); final String decrypted = new String(baos.toByteArray(), StandardCharsets.UTF_8);
String editResult = SwingWindow.create((editable ? "Edit" : "View") + " file: " + file.getName()) final String editResult = SwingWindow.create((editable ? "Edit" : "View") + " file: " + file.getName())
.message("File: " + file) .message("File: " + file)
.text(decrypted) .text(decrypted)
.editable(editable) .editable(editable)
@@ -130,10 +131,10 @@ public class EncryptedFileUtil {
log.warn("Text is not modified"); log.warn("Text is not modified");
} else { } else {
log.debug("Write to encrypt file: " + file); log.debug("Write to encrypt file: " + file);
byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8); final byte[] bytes = editResult.getBytes(StandardCharsets.UTF_8);
InputStream inputStream = new ByteArrayInputStream(bytes); final InputStream inputStream = new ByteArrayInputStream(bytes);
try { try {
TinyEncryptMeta meta = metaRef.get(); final TinyEncryptMeta meta = metaRef.get();
meta.setFileLength((long) bytes.length); meta.setFileLength((long) bytes.length);
meta.setFileLastModified(System.currentTimeMillis()); meta.setFileLastModified(System.currentTimeMillis());
encryptFromInputStream(inputStream, file, meta); encryptFromInputStream(inputStream, file, meta);
@@ -146,7 +147,7 @@ public class EncryptedFileUtil {
} }
public static boolean decryptFile(TinyEncryptConfig config, File file, boolean pgp) { public static boolean decryptFile(TinyEncryptConfig config, File file, boolean pgp) {
File decFile = getDecryptFile(file); final File decFile = getDecryptFile(file);
if (decFile == null) { if (decFile == null) {
log.warn("File is not tinyenc file, skip: " + decFile); log.warn("File is not tinyenc file, skip: " + decFile);
return false; return false;
@@ -156,9 +157,10 @@ public class EncryptedFileUtil {
return false; return false;
} }
try { try {
boolean decryptResult; final AtomicReference<TinyEncryptMeta> meta = new AtomicReference<>();
final boolean decryptResult;
try (FileOutputStream fos = new FileOutputStream(decFile)) { try (FileOutputStream fos = new FileOutputStream(decFile)) {
decryptResult = decryptToOutputStream(config, file, fos, pgp, null); decryptResult = decryptToOutputStream(config, file, fos, pgp, meta);
} }
if (!decryptResult) { if (!decryptResult) {
if (decFile.length() == 0) { if (decFile.length() == 0) {
@@ -166,6 +168,11 @@ public class EncryptedFileUtil {
decFile.delete(); decFile.delete();
} }
} }
if (meta.get().getFileLastModified() != null) {
log.debug("Set file last modified time to: " + new Date(meta.get().getFileLastModified()));
//noinspection ResultOfMethodCallIgnored
decFile.setLastModified(meta.get().getFileLastModified());
}
return decryptResult; return decryptResult;
} catch (Exception e) { } catch (Exception e) {
if (decFile.length() == 0) { if (decFile.length() == 0) {

View File

@@ -48,12 +48,12 @@ public class TinyEncryptMetaUtil {
|| StringUtil.isEmpty(config.getLocalPrivateKeyPemEncrypted())) { || StringUtil.isEmpty(config.getLocalPrivateKeyPemEncrypted())) {
throw new JumpOutException("Cannot prepare local private key pem!"); throw new JumpOutException("Cannot prepare local private key pem!");
} }
Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), config.getLocalPrivateKeyPemChallenge()); final Optional<byte[]> keyOpt = CardCliUtil.getChall(config.getCardCli(), config.getLocalPrivateKeyPemChallenge());
if (!keyOpt.isPresent()) { if (!keyOpt.isPresent()) {
throw new JumpOutException("Get challenge failed!"); throw new JumpOutException("Get challenge failed!");
} }
byte[] key = keyOpt.get(); final byte[] key = keyOpt.get();
String localPrivateKeyPem = AESCryptTool.gcmDecrypt(key) final String localPrivateKeyPem = AESCryptTool.gcmDecrypt(key)
.from(Bytes.fromBase64(config.getLocalPrivateKeyPemEncrypted())).toBytes().string(); .from(Bytes.fromBase64(config.getLocalPrivateKeyPemEncrypted())).toBytes().string();
log.info("Decrypt local private key success!"); log.info("Decrypt local private key success!");
config.setLocalPrivateKeyPem(localPrivateKeyPem); config.setLocalPrivateKeyPem(localPrivateKeyPem);
@@ -61,30 +61,30 @@ public class TinyEncryptMetaUtil {
public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) { public static byte[] decryptDataKey(TinyEncryptConfig config, TinyEncryptMeta meta) {
requireLocalPrivateKeyPem(config); requireLocalPrivateKeyPem(config);
PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); final PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
String envelop = meta.getEnvelop(); final String envelop = meta.getEnvelop();
if (StringUtil.isEmpty(envelop)) { if (StringUtil.isEmpty(envelop)) {
throw new JumpOutException("File encryption envelop is not present"); throw new JumpOutException("File encryption envelop is not present");
} }
String timestamp = String.valueOf(System.currentTimeMillis()); final String timestamp = String.valueOf(System.currentTimeMillis());
String toBeSigned = envelop + "|" + timestamp; final String toBeSigned = envelop + "|" + timestamp;
Bytes sign = Signatures.sha256(privateKey).sign(toBeSigned); final Bytes sign = Signatures.sha256(privateKey).sign(toBeSigned);
List<HttpRequest.KeyValue> keyValues = new ArrayList<>(); final List<HttpRequest.KeyValue> keyValues = new ArrayList<>();
keyValues.add(new HttpRequest.KeyValue("envelop", envelop)); keyValues.add(new HttpRequest.KeyValue("envelop", envelop));
keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp)); keyValues.add(new HttpRequest.KeyValue("timestamp", timestamp));
keyValues.add(new HttpRequest.KeyValue("signature", sign.asBase64())); keyValues.add(new HttpRequest.KeyValue("signature", sign.asBase64()));
log.info("Decrypt data key ..."); log.info("Decrypt data key ...");
Bytes response = HttpRequest.fromUrl(KMS_DECRYPT_DATA_KEY).post(keyValues); final Bytes response = HttpRequest.fromUrl(KMS_DECRYPT_DATA_KEY).post(keyValues);
JSONObject responseObject = response.asJSON(); final JSONObject responseObject = response.asJSON();
if (responseObject.getIntValue("status") != 200) { if (responseObject.getIntValue("status") != 200) {
throw new JumpOutException("Get data key from kms error, status: " throw new JumpOutException("Get data key from kms error, status: "
+ responseObject.getIntValue("status") + responseObject.getIntValue("status")
+ ", detail: " + responseObject + ", detail: " + responseObject
); );
} }
JSONObject responseData = responseObject.getJSONObject("data"); final JSONObject responseData = responseObject.getJSONObject("data");
return Base64.getDecoder().decode(responseData.getString("dataKey")); return Base64.getDecoder().decode(responseData.getString("dataKey"));
} }

View File

@@ -17,7 +17,7 @@ public class CardCliUtil {
public static Optional<String> readUserPin() { public static Optional<String> readUserPin() {
System.out.print("Input PGP user PIN: "); System.out.print("Input PGP user PIN: ");
char[] pin = System.console().readPassword(); final char[] pin = System.console().readPassword();
if (pin.length < 6) { if (pin.length < 6) {
log.error("User PIN must have 6 letters"); log.error("User PIN must have 6 letters");
return Optional.empty(); return Optional.empty();
@@ -29,35 +29,35 @@ public class CardCliUtil {
if (StringUtil.isEmpty(cardCli)) { if (StringUtil.isEmpty(cardCli)) {
throw new JumpOutException("Card-cli is empty!"); throw new JumpOutException("Card-cli is empty!");
} }
ProcessBuilder pb = new ProcessBuilder( final ProcessBuilder pb = new ProcessBuilder(
cardCli, cardCli,
"chall", "chall",
"--challenge-hex", challenge, "--challenge-hex", challenge,
"--json", "--sha256"); "--json", "--sha256");
log.info("Start: " + cardCli); log.info("Start: " + cardCli);
Optional<String> outputsOpt = runProcess(pb); final Optional<String> outputsOpt = runProcess(pb);
if ((!outputsOpt.isPresent()) || outputsOpt.get().trim().isEmpty()) { if ((!outputsOpt.isPresent()) || outputsOpt.get().trim().isEmpty()) {
return Optional.empty(); return Optional.empty();
} }
JSONObject jo = JSON.parseObject(outputsOpt.get()); final JSONObject jo = JSON.parseObject(outputsOpt.get());
return Optional.of(Bytes.fromHex(jo.getString("response_sha256_hex")).bytes()); return Optional.of(Bytes.fromHex(jo.getString("response_sha256_hex")).bytes());
} }
public static Optional<byte[]> decryptPgpEnvelop(String cardCli, String pin, String pgpEnvelop) { public static Optional<byte[]> decryptPgpEnvelop(String cardCli, String pin, String pgpEnvelop) {
ProcessBuilder pb = new ProcessBuilder( final ProcessBuilder pb = new ProcessBuilder(
cardCli, cardCli,
"pgp-card-decrypt", "pgp-card-decrypt",
"--cipher-base64", pgpEnvelop, "--cipher-base64", pgpEnvelop,
"--pin", pin, "--pin", pin,
"--json"); "--json");
log.info("Start: " + cardCli); log.info("Start: " + cardCli);
Optional<String> outputsOpt = runProcess(pb); final Optional<String> outputsOpt = runProcess(pb);
if (!outputsOpt.isPresent()) { if (!outputsOpt.isPresent()) {
return Optional.empty(); return Optional.empty();
} }
JSONObject jo = JSON.parseObject(outputsOpt.get()); final JSONObject jo = JSON.parseObject(outputsOpt.get());
return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes()); return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes());
} }
@@ -66,7 +66,7 @@ public class CardCliUtil {
try { try {
log.debug("Start process: " + pb.command()); log.debug("Start process: " + pb.command());
p = pb.start(); p = pb.start();
int ret = p.waitFor(); final int ret = p.waitFor();
if (ret == 0) { if (ret == 0) {
log.info("Finished command, ret code: " + ret); log.info("Finished command, ret code: " + ret);
} else { } else {
@@ -74,13 +74,13 @@ public class CardCliUtil {
} }
if (log.isDebugEnable()) { if (log.isDebugEnable()) {
byte[] errorBytes = IOUtil.readToBytes(p.getErrorStream()); final byte[] errorBytes = IOUtil.readToBytes(p.getErrorStream());
String errorOutputs = new String(errorBytes, StandardCharsets.UTF_8); final String errorOutputs = new String(errorBytes, StandardCharsets.UTF_8);
log.debug("Read cmd error outputs: [[[~" + errorOutputs + "~]]]"); log.debug("Read cmd error outputs: [[[~" + errorOutputs + "~]]]");
} }
byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream()); final byte[] jsonBytes = IOUtil.readToBytes(p.getInputStream());
String outputs = new String(jsonBytes, StandardCharsets.UTF_8); final String outputs = new String(jsonBytes, StandardCharsets.UTF_8);
if (log.isDebugEnable()) { if (log.isDebugEnable()) {
log.debug("Read cmd outputs: [[[~" + outputs + "~]]]"); log.debug("Read cmd outputs: [[[~" + outputs + "~]]]");
} }

View File

@@ -13,13 +13,13 @@ public class MacDockerHelper {
static { static {
if (ClassLoaderUtil.isClassCanBeLoad(COM_APPLE_EAWT_APPLICATION)) { if (ClassLoaderUtil.isClassCanBeLoad(COM_APPLE_EAWT_APPLICATION)) {
try { try {
Class<?> comAppleEawtApplication = ClassLoaderUtil.loadClass(COM_APPLE_EAWT_APPLICATION); final Class<?> comAppleEawtApplication = ClassLoaderUtil.loadClass(COM_APPLE_EAWT_APPLICATION);
Method getApplicationMetohd = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "getApplication", new Class[0]); final Method getApplicationMetohd = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "getApplication", new Class[0]);
//noinspection RedundantArrayCreation //noinspection RedundantArrayCreation
Object application = ReflectUtil.invokeMethod(getApplicationMetohd, null, new Object[0]); final Object application = ReflectUtil.invokeMethod(getApplicationMetohd, null, new Object[0]);
byte[] iconBytes = RResource.from(SwingWindow.class.getClassLoader()).rStream("icon.png").bytesAndClose(); final byte[] iconBytes = RResource.from(SwingWindow.class.getClassLoader()).rStream("icon.png").bytesAndClose();
Image image = Toolkit.getDefaultToolkit().createImage(iconBytes); final Image image = Toolkit.getDefaultToolkit().createImage(iconBytes);
Method setDockIconImageMethod = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "setDockIconImage", new Class[]{Image.class}); final Method setDockIconImageMethod = ReflectUtil.getDeclaredMethod(comAppleEawtApplication, "setDockIconImage", new Class[]{Image.class});
//noinspection RedundantArrayCreation //noinspection RedundantArrayCreation
ReflectUtil.invokeMethod(setDockIconImageMethod, application, new Object[]{image}); ReflectUtil.invokeMethod(setDockIconImageMethod, application, new Object[]{image});
} catch (Error e) { } catch (Error e) {

View File

@@ -62,7 +62,7 @@ public class SwingWindow {
public SwingWindow show() { public SwingWindow show() {
countDownLatch = new CountDownLatch(1); countDownLatch = new CountDownLatch(1);
JFrame frame = new JFrame((StringUtil.isEmpty(title) ? "" : (title + " - ")) + "Tiny Encrypt Window"); final JFrame frame = new JFrame((StringUtil.isEmpty(title) ? "" : (title + " - ")) + "Tiny Encrypt Window");
frame.addWindowListener(new WindowListenerImpl() { frame.addWindowListener(new WindowListenerImpl() {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
@@ -71,12 +71,12 @@ public class SwingWindow {
countDownLatch.countDown(); countDownLatch.countDown();
} }
}); });
JTextArea text = new JTextArea(StringUtil.def(this.text, ""), 30, 80); final JTextArea text = new JTextArea(StringUtil.def(this.text, ""), 30, 80);
text.setWrapStyleWord(true); text.setWrapStyleWord(true);
text.setLineWrap(true); text.setLineWrap(true);
text.setEditable(editable); text.setEditable(editable);
JScrollPane textScrollPane = new JScrollPane(text); final JScrollPane textScrollPane = new JScrollPane(text);
JLabel label = new JLabel(StringUtil.def(message, "Tiny Encrypt default message.")); final JLabel label = new JLabel(StringUtil.def(message, "Tiny Encrypt default message."));
JButton btnOk = null; JButton btnOk = null;
if (editable) { if (editable) {
btnOk = new JButton("OK!"); btnOk = new JButton("OK!");
@@ -88,13 +88,13 @@ public class SwingWindow {
countDownLatch.countDown(); countDownLatch.countDown();
}); });
} }
JButton btnCancel = new JButton("Cancel"); final JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener((e) -> { btnCancel.addActionListener((e) -> {
frame.setVisible(false); frame.setVisible(false);
frame.dispose(); frame.dispose();
countDownLatch.countDown(); countDownLatch.countDown();
}); });
JPanel pane = new JPanel(); final JPanel pane = new JPanel();
if (btnOk != null) { if (btnOk != null) {
pane.add(btnOk); pane.add(btnOk);
} }
@@ -106,7 +106,7 @@ public class SwingWindow {
frame.pack(); frame.pack();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); final Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation( frame.setLocation(
(dim.width / 2) - (frame.getSize().width / 2), (dim.width / 2) - (frame.getSize().width / 2),
(dim.height / 2) - (frame.getSize().height / 2) (dim.height / 2) - (frame.getSize().height / 2)