From 2ca2c5241d90b3b174fdf1613d481520f091f6f5 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 3 Apr 2022 20:37:15 +0800 Subject: [PATCH] feat: v0.3.11, can skip envelop data key --- .../tools/tinyencrypt/TinyEncryptArgs.java | 3 + .../tools/tinyencrypt/TinyEncryptMain.java | 4 +- .../tinyencrypt/TinyEncryptMainUtil.java | 78 +++++++++---------- .../config/TinyEncryptConstant.java | 2 +- .../encrypt/EncryptedFileUtil.java | 8 +- .../encrypt/TinyEncryptMetaUtil.java | 78 ++++++++++++------- 6 files changed, 102 insertions(+), 71 deletions(-) diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptArgs.java index bccab44..cd224bb 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 = {"--skip-envelop"}, description = "Skip envelop data key") + boolean skipEnvelop = false; + @CommandLine.Option(names = {"--require-sign"}, description = "Require signature when create data key") boolean requireSign = false; diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java index ff5ecb0..3e1ba1f 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMain.java @@ -74,7 +74,9 @@ public class TinyEncryptMain { } boolean result; if (tinyEncryptArgs.encrypt) { - result = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f, tinyEncryptArgs.compress, tinyEncryptArgs.requireSign, tinyEncryptArgs.comment); + result = EncryptedFileUtil.encryptFile(config, tinyEncryptArgs.key, f, + tinyEncryptArgs.compress, !tinyEncryptArgs.skipEnvelop, tinyEncryptArgs.requireSign, + tinyEncryptArgs.comment); } else { if (tinyEncryptArgs.showInWindow) { EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp); diff --git a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java index 735eb20..237d27c 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/TinyEncryptMainUtil.java @@ -22,6 +22,7 @@ import me.hatter.tools.tinyencrypt.util.CardCliUtil; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.security.KeyPair; import java.util.Date; import java.util.Optional; @@ -90,45 +91,7 @@ public class TinyEncryptMainUtil { } else { try { try (FileInputStream fis = new FileInputStream(f)) { - Tlv tlv = TlvUtil.readTlv(fis); - TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class); - StringBuilder sb = new StringBuilder(256); - sb.append("File: ").append(f); - if ((meta.getCompress() != null) && meta.getCompress()) { - sb.append(" [compressed]"); - } - sb.append("\n"); - sb.append("File version: ").append(meta.getVersion()).append("\n"); - if (meta.getFileLength() != null) { - sb.append("File size: ").append(meta.getFileLength()) - .append(" (") - .append(ByteUtil.formatBytes(meta.getFileLength())) - .append(")\n"); - } - if (meta.getFileLastModified() != null) { - sb.append("Last modified: ") - .append(new Date(meta.getFileLastModified())) - .append("\n"); - } - sb.append("Enc file created: ") - .append(new Date(meta.getCreated())) - .append("\n"); - if (StringUtil.isNotBlank(meta.getPgpEnvelop())) { - sb.append("PGP envelop: YES\n"); - } else { - sb.append("PGP envelop: NO\n"); - } - if (StringUtil.isNotBlank(meta.getPgpFingerprint())) { - sb.append("PGP fingerprint: ") - .append(meta.getPgpFingerprint()) - .append("\n"); - } - sb.append("Agent: ").append(meta.getUserAgent()); - if (StringUtil.isNotBlank(meta.getComment())) { - sb.append("Comment: ").append(meta.getComment()).append("\n"); - } - - log.info(sb.toString()); + printOneFileInfo(f, fis); } } catch (Exception e) { log.warn("Read tiny encrypt file failed: " + e.getMessage() + ", file: " + f); @@ -150,4 +113,41 @@ public class TinyEncryptMainUtil { } return config; } + + private static void printOneFileInfo(File f, FileInputStream fis) throws IOException { + Tlv tlv = TlvUtil.readTlv(fis); + TinyEncryptMeta meta = tlv.getValueAsBytes().asJSONObject(TinyEncryptMeta.class); + StringBuilder sb = new StringBuilder(256); + sb.append("File: ").append(f); + if ((meta.getCompress() != null) && meta.getCompress()) { + sb.append(" [compressed]"); + } + sb.append("\n"); + sb.append("File version: ").append(meta.getVersion()).append("\n"); + if (meta.getFileLength() != null) { + sb.append("File size: ").append(meta.getFileLength()) + .append(" (").append(ByteUtil.formatBytes(meta.getFileLength())).append(")\n"); + } + if (meta.getFileLastModified() != null) { + sb.append("Last modified: ").append(new Date(meta.getFileLastModified())).append("\n"); + } + sb.append("Enc file created: ").append(new Date(meta.getCreated())).append("\n"); + sb.append("Envelop: ").append(toYesOrNo(StringUtil.isNotBlank(meta.getEnvelop()))).append("\n"); + sb.append("PGP envelop: ").append(toYesOrNo(StringUtil.isNotBlank(meta.getPgpEnvelop()))).append("\n"); + if (StringUtil.isNotBlank(meta.getPgpFingerprint())) { + sb.append("PGP fingerprint: ") + .append(meta.getPgpFingerprint()) + .append("\n"); + } + sb.append("Agent: ").append(meta.getUserAgent()).append("\n"); + if (StringUtil.isNotBlank(meta.getComment())) { + sb.append("Comment: ").append(meta.getComment()).append("\n"); + } + + log.info(sb.toString()); + } + + private static String toYesOrNo(boolean b) { + return b ? "YES" : "NO"; + } } 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 8a1f141..31b8957 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.10"; + public static final String VERSION = "0.3.11"; 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 b79a2f8..6d61af3 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/EncryptedFileUtil.java @@ -122,12 +122,14 @@ public class EncryptedFileUtil { } if (!decryptResult) { if (decFile.length() == 0) { + //noinspection ResultOfMethodCallIgnored decFile.delete(); } } return decryptResult; } catch (Exception e) { if (decFile.length() == 0) { + //noinspection ResultOfMethodCallIgnored decFile.delete(); } log.error("Decrypt file filed: " + file + ", reason: " + e.getMessage()); @@ -136,7 +138,9 @@ public class EncryptedFileUtil { } } - public static boolean encryptFile(TinyEncryptConfig config, String keyName, File file, boolean compress, boolean requireSign, String comment) { + public static boolean encryptFile(TinyEncryptConfig config, String keyName, File file, + boolean compress, boolean useEnvelop, boolean requireSign, + String comment) { File encFile = getEncryptFile(file); if (encFile == null) { log.warn("Cannot encrypt .tinyenc file: " + file); @@ -147,7 +151,7 @@ public class EncryptedFileUtil { return false; } try { - TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, comment, requireSign); + TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, keyName, comment, useEnvelop, 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 6e43b8c..9719fa0 100644 --- a/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java +++ b/src/main/java/me/hatter/tools/tinyencrypt/encrypt/TinyEncryptMetaUtil.java @@ -63,6 +63,9 @@ public class TinyEncryptMetaUtil { requireLocalPrivateKeyPem(config); PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); String envelop = meta.getEnvelop(); + if (StringUtil.isEmpty(envelop)) { + throw new JumpOutException("File encryption envelop is not present"); + } String timestamp = String.valueOf(System.currentTimeMillis()); String toBeSigned = envelop + "|" + timestamp; @@ -85,50 +88,40 @@ public class TinyEncryptMetaUtil { return Base64.getDecoder().decode(responseData.getString("dataKey")); } - public static TinyEncryptMeta create(TinyEncryptConfig config, String comment, boolean requireSignature) { + public static TinyEncryptMeta create( + TinyEncryptConfig config, String keyName, String comment, + boolean useEnvelop, + boolean requireSignature) { PrivateKey privateKey = null; if (requireSignature) { requireLocalPrivateKeyPem(config); privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem()); } PublicKey publicKey = KeyUtil.parsePublicKeyPEM(config.getLocalPublicKeyPem()); - PublicKey pgpEncryptPublicKey = null; - if (StringUtil.isNotBlank(config.getPgpEncryptPublicKeyPem())) { - pgpEncryptPublicKey = KeyUtil.parsePublicKeyPEM(config.getPgpEncryptPublicKeyPem()); - } - String name = config.getDefaultKeyName(); - String timestamp = String.valueOf(System.currentTimeMillis()); - String toBeSigned = name + "|" + timestamp; - Bytes sign = (privateKey == null) ? null : Signatures.sha256(privateKey).sign(toBeSigned); + byte[] dataKey; + String envelop = null; + if (useEnvelop) { + JSONObject responseObject = fetchJwkEnvelop(config, keyName, privateKey, publicKey); + JSONObject responseData = responseObject.getJSONObject("data"); - 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))); - if (sign == null) { - keyValues.add(new HttpRequest.KeyValue("skipDataKeyRequestSignVerify", "true")); + dataKey = Base64.getDecoder().decode(responseData.getString("dataKey")); + envelop = responseData.getString("envelopJwe"); } else { - keyValues.add(new HttpRequest.KeyValue("dataKeyRequestSign", sign.asBase64())); + log.warn("Use envelop is turned OFF!"); + dataKey = RandomTool.secureRandom().nextbytes(32); } - 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) { - throw new JumpOutException("Get data key from kms error, status: " - + responseObject.getIntValue("status") - + ", detail: " + responseObject - ); - } - JSONObject responseData = responseObject.getJSONObject("data"); - byte[] dataKey = Base64.getDecoder().decode(responseData.getString("dataKey")); - String envelop = responseData.getString("envelopJwe"); TinyEncryptMeta tinyEncryptMeta = new TinyEncryptMeta(); tinyEncryptMeta.setVersion("1.0"); tinyEncryptMeta.setCreated(System.currentTimeMillis()); tinyEncryptMeta.setDataKey(dataKey); tinyEncryptMeta.setEnvelop(envelop); + + PublicKey pgpEncryptPublicKey = null; + if (StringUtil.isNotBlank(config.getPgpEncryptPublicKeyPem())) { + pgpEncryptPublicKey = KeyUtil.parsePublicKeyPEM(config.getPgpEncryptPublicKeyPem()); + } if (pgpEncryptPublicKey != null) { if (pgpEncryptPublicKey instanceof RSAPublicKey) { byte[] pgpEnvelop = RSAUtil.encrypt((RSAPublicKey) pgpEncryptPublicKey, dataKey); @@ -143,4 +136,33 @@ public class TinyEncryptMetaUtil { tinyEncryptMeta.setComment(comment); return tinyEncryptMeta; } + + private static JSONObject fetchJwkEnvelop(TinyEncryptConfig config, String keyName, PrivateKey privateKey, PublicKey publicKey) { + String name = StringUtil.def(keyName, config.getDefaultKeyName()); + + String timestamp = String.valueOf(System.currentTimeMillis()); + String toBeSigned = name + "|" + timestamp; + 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))); + if (sign == null) { + keyValues.add(new HttpRequest.KeyValue("skipDataKeyRequestSignVerify", "true")); + } else { + keyValues.add(new HttpRequest.KeyValue("dataKeyRequestSign", sign.asBase64())); + } + String keyFromArguments = (StringUtil.isEmpty(keyName) ? "" : "[*]"); + log.info("Get data key from kms, key name: " + name + keyFromArguments + ", with sign: " + (sign != null) + " ..."); + Bytes response = HttpRequest.fromUrl(KMS_GET_DATA_KEY).post(keyValues); + JSONObject responseObject = response.asJSON(); + if (responseObject.getIntValue("status") != 200) { + throw new JumpOutException("Get data key from kms error, status: " + + responseObject.getIntValue("status") + + ", detail: " + responseObject + ); + } + return responseObject; + } }