feat: v0.3.11, can skip envelop data key
This commit is contained in:
@@ -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 = {"--skip-envelop"}, description = "Skip envelop data key")
|
||||||
|
boolean skipEnvelop = false;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--require-sign"}, description = "Require signature when create data key")
|
@CommandLine.Option(names = {"--require-sign"}, description = "Require signature when create data key")
|
||||||
boolean requireSign = false;
|
boolean requireSign = false;
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ public class TinyEncryptMain {
|
|||||||
}
|
}
|
||||||
boolean result;
|
boolean result;
|
||||||
if (tinyEncryptArgs.encrypt) {
|
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 {
|
} else {
|
||||||
if (tinyEncryptArgs.showInWindow) {
|
if (tinyEncryptArgs.showInWindow) {
|
||||||
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp);
|
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ 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.io.IOException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -90,45 +91,7 @@ public class TinyEncryptMainUtil {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
try (FileInputStream fis = new FileInputStream(f)) {
|
try (FileInputStream fis = new FileInputStream(f)) {
|
||||||
Tlv tlv = TlvUtil.readTlv(fis);
|
printOneFileInfo(f, 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());
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Read tiny encrypt file failed: " + e.getMessage() + ", file: " + f);
|
log.warn("Read tiny encrypt file failed: " + e.getMessage() + ", file: " + f);
|
||||||
@@ -150,4 +113,41 @@ public class TinyEncryptMainUtil {
|
|||||||
}
|
}
|
||||||
return config;
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.10";
|
public static final String VERSION = "0.3.11";
|
||||||
|
|
||||||
public static final String ENC_FILE_EXT = ".tinyenc";
|
public static final String ENC_FILE_EXT = ".tinyenc";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,12 +122,14 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
if (!decryptResult) {
|
if (!decryptResult) {
|
||||||
if (decFile.length() == 0) {
|
if (decFile.length() == 0) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
decFile.delete();
|
decFile.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return decryptResult;
|
return decryptResult;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (decFile.length() == 0) {
|
if (decFile.length() == 0) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
decFile.delete();
|
decFile.delete();
|
||||||
}
|
}
|
||||||
log.error("Decrypt file filed: " + file + ", reason: " + e.getMessage());
|
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);
|
File encFile = getEncryptFile(file);
|
||||||
if (encFile == null) {
|
if (encFile == null) {
|
||||||
log.warn("Cannot encrypt .tinyenc file: " + file);
|
log.warn("Cannot encrypt .tinyenc file: " + file);
|
||||||
@@ -147,7 +151,7 @@ public class EncryptedFileUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, comment, requireSign);
|
TinyEncryptMeta meta = TinyEncryptMetaUtil.create(config, keyName, comment, useEnvelop, requireSign);
|
||||||
meta.setFileLength(file.length());
|
meta.setFileLength(file.length());
|
||||||
meta.setFileLastModified(file.lastModified());
|
meta.setFileLastModified(file.lastModified());
|
||||||
meta.setCompress(compress);
|
meta.setCompress(compress);
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ public class TinyEncryptMetaUtil {
|
|||||||
requireLocalPrivateKeyPem(config);
|
requireLocalPrivateKeyPem(config);
|
||||||
PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
|
PrivateKey privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
|
||||||
String envelop = meta.getEnvelop();
|
String envelop = meta.getEnvelop();
|
||||||
|
if (StringUtil.isEmpty(envelop)) {
|
||||||
|
throw new JumpOutException("File encryption envelop is not present");
|
||||||
|
}
|
||||||
|
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||||
String toBeSigned = envelop + "|" + timestamp;
|
String toBeSigned = envelop + "|" + timestamp;
|
||||||
@@ -85,50 +88,40 @@ 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, boolean requireSignature) {
|
public static TinyEncryptMeta create(
|
||||||
|
TinyEncryptConfig config, String keyName, String comment,
|
||||||
|
boolean useEnvelop,
|
||||||
|
boolean requireSignature) {
|
||||||
PrivateKey privateKey = null;
|
PrivateKey privateKey = null;
|
||||||
if (requireSignature) {
|
if (requireSignature) {
|
||||||
requireLocalPrivateKeyPem(config);
|
requireLocalPrivateKeyPem(config);
|
||||||
privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
|
privateKey = KeyUtil.parsePrivateKeyPEM(config.getLocalPrivateKeyPem());
|
||||||
}
|
}
|
||||||
PublicKey publicKey = KeyUtil.parsePublicKeyPEM(config.getLocalPublicKeyPem());
|
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());
|
byte[] dataKey;
|
||||||
String toBeSigned = name + "|" + timestamp;
|
String envelop = null;
|
||||||
Bytes sign = (privateKey == null) ? null : Signatures.sha256(privateKey).sign(toBeSigned);
|
if (useEnvelop) {
|
||||||
|
JSONObject responseObject = fetchJwkEnvelop(config, keyName, privateKey, publicKey);
|
||||||
|
JSONObject responseData = responseObject.getJSONObject("data");
|
||||||
|
|
||||||
List<HttpRequest.KeyValue> keyValues = new ArrayList<>();
|
dataKey = Base64.getDecoder().decode(responseData.getString("dataKey"));
|
||||||
keyValues.add(new HttpRequest.KeyValue("name", name));
|
envelop = responseData.getString("envelopJwe");
|
||||||
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 {
|
} 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 tinyEncryptMeta = new TinyEncryptMeta();
|
||||||
tinyEncryptMeta.setVersion("1.0");
|
tinyEncryptMeta.setVersion("1.0");
|
||||||
tinyEncryptMeta.setCreated(System.currentTimeMillis());
|
tinyEncryptMeta.setCreated(System.currentTimeMillis());
|
||||||
tinyEncryptMeta.setDataKey(dataKey);
|
tinyEncryptMeta.setDataKey(dataKey);
|
||||||
tinyEncryptMeta.setEnvelop(envelop);
|
tinyEncryptMeta.setEnvelop(envelop);
|
||||||
|
|
||||||
|
PublicKey pgpEncryptPublicKey = null;
|
||||||
|
if (StringUtil.isNotBlank(config.getPgpEncryptPublicKeyPem())) {
|
||||||
|
pgpEncryptPublicKey = KeyUtil.parsePublicKeyPEM(config.getPgpEncryptPublicKeyPem());
|
||||||
|
}
|
||||||
if (pgpEncryptPublicKey != null) {
|
if (pgpEncryptPublicKey != null) {
|
||||||
if (pgpEncryptPublicKey instanceof RSAPublicKey) {
|
if (pgpEncryptPublicKey instanceof RSAPublicKey) {
|
||||||
byte[] pgpEnvelop = RSAUtil.encrypt((RSAPublicKey) pgpEncryptPublicKey, dataKey);
|
byte[] pgpEnvelop = RSAUtil.encrypt((RSAPublicKey) pgpEncryptPublicKey, dataKey);
|
||||||
@@ -143,4 +136,33 @@ public class TinyEncryptMetaUtil {
|
|||||||
tinyEncryptMeta.setComment(comment);
|
tinyEncryptMeta.setComment(comment);
|
||||||
return tinyEncryptMeta;
|
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<HttpRequest.KeyValue> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user