feat: v0.7.0, add ecdh envelop
This commit is contained in:
@@ -24,6 +24,8 @@ Meta format:
|
|||||||
| pgpFingerprint | String | `deprecated` Hex(Sha256(PGP Publickey)) |
|
| pgpFingerprint | String | `deprecated` Hex(Sha256(PGP Publickey)) |
|
||||||
| ageEnvelop | String | `deprecated` PGP Publickey Encrypted DataKey |
|
| ageEnvelop | String | `deprecated` PGP Publickey Encrypted DataKey |
|
||||||
| ageRecipient | String | `deprecated` age1*** |
|
| ageRecipient | String | `deprecated` age1*** |
|
||||||
|
| ecdhEnvelop | String | `deprecated` KW:*** |
|
||||||
|
| ecdhPoint | String | `deprecated` 02*** |
|
||||||
| envelop | String | `deprecated` KMS Encrypted DataKey |
|
| envelop | String | `deprecated` KMS Encrypted DataKey |
|
||||||
| envelops | Envelop[] | Envelop Array |
|
| envelops | Envelop[] | Envelop Array |
|
||||||
| nonce | String | `base64` GCM Nonce |
|
| nonce | String | `base64` GCM Nonce |
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
},
|
},
|
||||||
"repo": {
|
"repo": {
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"me.hatter:commons:3.36",
|
"me.hatter:commons:3.56",
|
||||||
"info.picocli:picocli:4.6.1",
|
"info.picocli:picocli:4.6.1",
|
||||||
"org.bouncycastle:bcprov-jdk15on:1.69"
|
"org.bouncycastle:bcprov-jdk15on:1.69"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ public class TinyEncryptArgs {
|
|||||||
@CommandLine.Option(names = {"-A", "--age"}, description = "Decrypt use Age")
|
@CommandLine.Option(names = {"-A", "--age"}, description = "Decrypt use Age")
|
||||||
boolean age = false;
|
boolean age = false;
|
||||||
|
|
||||||
|
@CommandLine.Option(names = {"--ecdh"}, description = "Decrypt use ECDH")
|
||||||
|
boolean ecdh = false;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--use-jce"}, description = "Use JCE")
|
@CommandLine.Option(names = {"--use-jce"}, description = "Use JCE")
|
||||||
boolean useJce = false;
|
boolean useJce = false;
|
||||||
|
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ public class TinyEncryptMain {
|
|||||||
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.age, tinyEncryptArgs.editInWindow);
|
EncryptedFileUtil.decryptInWindow(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.age, tinyEncryptArgs.ecdh, tinyEncryptArgs.editInWindow);
|
||||||
encryptOrDecryptSuccess = false; // do not delete file
|
encryptOrDecryptSuccess = false; // do not delete file
|
||||||
} else if (tinyEncryptArgs.digest) {
|
} else if (tinyEncryptArgs.digest) {
|
||||||
final Bytes sha256 = EncryptedFileUtil.decryptAndDigest(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.age);
|
final Bytes sha256 = EncryptedFileUtil.decryptAndDigest(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.age, tinyEncryptArgs.ecdh);
|
||||||
if (sha256 != null) {
|
if (sha256 != null) {
|
||||||
log.info(sha256.asHex() + " - " + f);
|
log.info(sha256.asHex() + " - " + f);
|
||||||
final File clearTextFile = EncryptedFileUtil.getDecryptFile(f);
|
final File clearTextFile = EncryptedFileUtil.getDecryptFile(f);
|
||||||
@@ -109,7 +109,7 @@ public class TinyEncryptMain {
|
|||||||
}
|
}
|
||||||
encryptOrDecryptSuccess = false; // do not delete file
|
encryptOrDecryptSuccess = false; // do not delete file
|
||||||
} else {
|
} else {
|
||||||
encryptOrDecryptSuccess = EncryptedFileUtil.decryptFile(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.age);
|
encryptOrDecryptSuccess = EncryptedFileUtil.decryptFile(config, f, tinyEncryptArgs.pgp, tinyEncryptArgs.age, tinyEncryptArgs.ecdh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (encryptOrDecryptSuccess && tinyEncryptArgs.removeFile) {
|
if (encryptOrDecryptSuccess && tinyEncryptArgs.removeFile) {
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ public class TinyEncryptMainUtil {
|
|||||||
sb.append(header("Envelops")).append("KMS: ").append(toYesOrNo(meta.getEnvelop()))
|
sb.append(header("Envelops")).append("KMS: ").append(toYesOrNo(meta.getEnvelop()))
|
||||||
.append(", PGP: ").append(toYesOrNo(meta.getPgpEnvelop()))
|
.append(", PGP: ").append(toYesOrNo(meta.getPgpEnvelop()))
|
||||||
.append(", Age: ").append(toYesOrNo(meta.getAgeEnvelop()))
|
.append(", Age: ").append(toYesOrNo(meta.getAgeEnvelop()))
|
||||||
|
.append(", ECDH: ").append(toYesOrNo(meta.getEcdhEnvelop()))
|
||||||
.append("\n");
|
.append("\n");
|
||||||
if (StringUtil.isNotBlank(meta.getPgpFingerprint())) {
|
if (StringUtil.isNotBlank(meta.getPgpFingerprint())) {
|
||||||
sb.append(header("PGP fingerprint")).append(meta.getPgpFingerprint()).append("\n");
|
sb.append(header("PGP fingerprint")).append(meta.getPgpFingerprint()).append("\n");
|
||||||
@@ -193,6 +194,9 @@ public class TinyEncryptMainUtil {
|
|||||||
if (StringUtil.isNotBlank(meta.getAgeRecipient())) {
|
if (StringUtil.isNotBlank(meta.getAgeRecipient())) {
|
||||||
sb.append(header("Age recipient")).append(meta.getAgeRecipient()).append("\n");
|
sb.append(header("Age recipient")).append(meta.getAgeRecipient()).append("\n");
|
||||||
}
|
}
|
||||||
|
if (StringUtil.isNotBlank(meta.getEcdhPoint())) {
|
||||||
|
sb.append(header("ECDH point")).append(meta.getEcdhPoint()).append("\n");
|
||||||
|
}
|
||||||
if (StringUtil.isNotBlank(meta.getComment())) {
|
if (StringUtil.isNotBlank(meta.getComment())) {
|
||||||
sb.append(header("Comment")).append(meta.getComment()).append("\n");
|
sb.append(header("Comment")).append(meta.getComment()).append("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ public class TinyEncryptConfig {
|
|||||||
private String localPrivateKeyPemChallenge;
|
private String localPrivateKeyPemChallenge;
|
||||||
private Boolean turnOffEnvelop;
|
private Boolean turnOffEnvelop;
|
||||||
private String pgpEncryptPublicKeyPem;
|
private String pgpEncryptPublicKeyPem;
|
||||||
|
private String ecdhPublicKeyPoint;
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private String pgpDecryptCmd;
|
private String pgpDecryptCmd;
|
||||||
private String cardCli;
|
private String cardCli;
|
||||||
@@ -73,6 +74,14 @@ public class TinyEncryptConfig {
|
|||||||
this.pgpEncryptPublicKeyPem = pgpEncryptPublicKeyPem;
|
this.pgpEncryptPublicKeyPem = pgpEncryptPublicKeyPem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEcdhPublicKeyPoint() {
|
||||||
|
return ecdhPublicKeyPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEcdhPublicKeyPoint(String ecdhPublicKeyPoint) {
|
||||||
|
this.ecdhPublicKeyPoint = ecdhPublicKeyPoint;
|
||||||
|
}
|
||||||
|
|
||||||
public String getPgpDecryptCmd() {
|
public String getPgpDecryptCmd() {
|
||||||
return pgpDecryptCmd;
|
return pgpDecryptCmd;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.6.4";
|
public static final String VERSION = "0.7.0";
|
||||||
|
|
||||||
public static final String ENC_FILE_EXT = ".tinyenc";
|
public static final String ENC_FILE_EXT = ".tinyenc";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,14 @@ import me.hatter.tools.commons.io.IOUtil;
|
|||||||
import me.hatter.tools.commons.io.RFile;
|
import me.hatter.tools.commons.io.RFile;
|
||||||
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.misc.Base64s;
|
||||||
import me.hatter.tools.commons.security.crypt.AESCryptTool;
|
import me.hatter.tools.commons.security.crypt.AESCryptTool;
|
||||||
import me.hatter.tools.commons.security.crypt.CryptInputStream;
|
import me.hatter.tools.commons.security.crypt.CryptInputStream;
|
||||||
import me.hatter.tools.commons.security.crypt.CryptOutputStream;
|
import me.hatter.tools.commons.security.crypt.CryptOutputStream;
|
||||||
|
import me.hatter.tools.commons.security.crypt.WrapKeyUtil;
|
||||||
import me.hatter.tools.commons.security.digest.Digests;
|
import me.hatter.tools.commons.security.digest.Digests;
|
||||||
|
import me.hatter.tools.commons.security.key.KdfUtil;
|
||||||
|
import me.hatter.tools.commons.security.key.KeyUtil;
|
||||||
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;
|
||||||
@@ -24,6 +28,9 @@ 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.security.PublicKey;
|
||||||
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
import java.security.spec.ECPoint;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -36,6 +43,7 @@ public class EncryptedFileUtil {
|
|||||||
public static boolean decryptToOutputStream(TinyEncryptConfig config, File file, OutputStream os,
|
public static boolean decryptToOutputStream(TinyEncryptConfig config, File file, OutputStream os,
|
||||||
boolean pgp,
|
boolean pgp,
|
||||||
boolean age,
|
boolean age,
|
||||||
|
boolean ecdh,
|
||||||
AtomicReference<TinyEncryptMeta> metaRef) {
|
AtomicReference<TinyEncryptMeta> metaRef) {
|
||||||
if (getDecryptFile(file) == null) {
|
if (getDecryptFile(file) == null) {
|
||||||
log.warn("File is not tinyenc file, skip: " + file);
|
log.warn("File is not tinyenc file, skip: " + file);
|
||||||
@@ -86,6 +94,27 @@ public class EncryptedFileUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dataKey = dataKeyOpt.get();
|
dataKey = dataKeyOpt.get();
|
||||||
|
} else if (ecdh) {
|
||||||
|
if (StringUtil.isBlank(meta.getEcdhEnvelop())) {
|
||||||
|
log.error("File is not encrypted with ECDH envelop");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Optional<String> pinOpt = CardCliUtil.readUserPin();
|
||||||
|
final String pin = pinOpt.orElse(null);
|
||||||
|
final WrapKeyUtil.WrapKey wrapKey = WrapKeyUtil.WrapKey.parse(meta.getEcdhEnvelop());
|
||||||
|
final PublicKey ecPublicKey = KeyUtil.parsePublicKeyBytes(Base64s.uriCompatible().decode(wrapKey.getHeader().getePubKey()));
|
||||||
|
final ECPoint ecPoint = ((ECPublicKey) ecPublicKey).getW();
|
||||||
|
final byte[] ecPointXBytes = ecPoint.getAffineX().toByteArray();
|
||||||
|
final byte[] ecPointYBytes = ecPoint.getAffineY().toByteArray();
|
||||||
|
final String ePublicKeyHex = "04"
|
||||||
|
+ Bytes.from(ecPointXBytes).subBytes((ecPointXBytes.length == 33 && ecPointXBytes[0] == 0x00) ? 1 : 0).asHex()
|
||||||
|
+ Bytes.from(ecPointYBytes).subBytes((ecPointYBytes.length == 33 && ecPointYBytes[0] == 0x00) ? 1 : 0).asHex();
|
||||||
|
final Optional<byte[]> sharedSecretBytesOpt = CardCliUtil.ecdhSharedSecret(config.getCardCli(), pin, ePublicKeyHex);
|
||||||
|
if (!sharedSecretBytesOpt.isPresent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final byte[] sharedSecretBytes = sharedSecretBytesOpt.get();
|
||||||
|
dataKey = WrapKeyUtil.decryptEcdhP256((header) -> sharedSecretBytes, wrapKey);
|
||||||
} else {
|
} else {
|
||||||
dataKey = TinyEncryptMetaUtil.decryptDataKey(config, meta);
|
dataKey = TinyEncryptMetaUtil.decryptDataKey(config, meta);
|
||||||
}
|
}
|
||||||
@@ -118,18 +147,18 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bytes decryptAndDigest(TinyEncryptConfig config, File file, boolean pgp, boolean age) {
|
public static Bytes decryptAndDigest(TinyEncryptConfig config, File file, boolean pgp, boolean age, boolean ecdh) {
|
||||||
final DigestOutputStream outputStream = new DigestOutputStream(new NilOutputStream(), Digests.sha256());
|
final DigestOutputStream outputStream = new DigestOutputStream(new NilOutputStream(), Digests.sha256());
|
||||||
if (!decryptToOutputStream(config, file, outputStream, pgp, age, null)) {
|
if (!decryptToOutputStream(config, file, outputStream, pgp, age, ecdh, null)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return outputStream.digest();
|
return outputStream.digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void decryptInWindow(TinyEncryptConfig config, File file, boolean pgp, boolean age, boolean editable) {
|
public static void decryptInWindow(TinyEncryptConfig config, File file, boolean pgp, boolean age, boolean ecdh, boolean editable) {
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
final AtomicReference<TinyEncryptMeta> metaRef = new AtomicReference<>();
|
final AtomicReference<TinyEncryptMeta> metaRef = new AtomicReference<>();
|
||||||
final boolean decryptSuccess = decryptToOutputStream(config, file, baos, pgp, age, metaRef);
|
final boolean decryptSuccess = decryptToOutputStream(config, file, baos, pgp, age, ecdh, metaRef);
|
||||||
if (!decryptSuccess) {
|
if (!decryptSuccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,7 +191,7 @@ public class EncryptedFileUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean decryptFile(TinyEncryptConfig config, File file, boolean pgp, boolean age) {
|
public static boolean decryptFile(TinyEncryptConfig config, File file, boolean pgp, boolean age, boolean ecdh) {
|
||||||
final 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);
|
||||||
@@ -176,7 +205,7 @@ public class EncryptedFileUtil {
|
|||||||
final AtomicReference<TinyEncryptMeta> meta = new AtomicReference<>();
|
final AtomicReference<TinyEncryptMeta> meta = new AtomicReference<>();
|
||||||
final boolean decryptResult;
|
final boolean decryptResult;
|
||||||
try (FileOutputStream fos = new FileOutputStream(decFile)) {
|
try (FileOutputStream fos = new FileOutputStream(decFile)) {
|
||||||
decryptResult = decryptToOutputStream(config, file, fos, pgp, age, meta);
|
decryptResult = decryptToOutputStream(config, file, fos, pgp, age, ecdh, meta);
|
||||||
}
|
}
|
||||||
if (!decryptResult) {
|
if (!decryptResult) {
|
||||||
if (decFile.length() == 0) {
|
if (decFile.length() == 0) {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ public class TinyEncryptMeta {
|
|||||||
private String encryptedComment;
|
private String encryptedComment;
|
||||||
private String pgpEnvelop;
|
private String pgpEnvelop;
|
||||||
private String pgpFingerprint;
|
private String pgpFingerprint;
|
||||||
|
private String ecdhEnvelop;
|
||||||
|
private String ecdhPoint;
|
||||||
private String ageEnvelop;
|
private String ageEnvelop;
|
||||||
private String ageRecipient;
|
private String ageRecipient;
|
||||||
private String envelop;
|
private String envelop;
|
||||||
@@ -76,6 +78,22 @@ public class TinyEncryptMeta {
|
|||||||
this.pgpFingerprint = pgpFingerprint;
|
this.pgpFingerprint = pgpFingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEcdhEnvelop() {
|
||||||
|
return ecdhEnvelop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEcdhEnvelop(String ecdhEnvelop) {
|
||||||
|
this.ecdhEnvelop = ecdhEnvelop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEcdhPoint() {
|
||||||
|
return ecdhPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEcdhPoint(String ecdhPoint) {
|
||||||
|
this.ecdhPoint = ecdhPoint;
|
||||||
|
}
|
||||||
|
|
||||||
public String getAgeEnvelop() {
|
public String getAgeEnvelop() {
|
||||||
return ageEnvelop;
|
return ageEnvelop;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ 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.crypt.AESCryptTool;
|
||||||
|
import me.hatter.tools.commons.security.crypt.WrapKeyUtil;
|
||||||
import me.hatter.tools.commons.security.digest.Digests;
|
import me.hatter.tools.commons.security.digest.Digests;
|
||||||
|
import me.hatter.tools.commons.security.ec.ECUtil;
|
||||||
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;
|
||||||
import me.hatter.tools.commons.security.rsa.RSAUtil;
|
import me.hatter.tools.commons.security.rsa.RSAUtil;
|
||||||
@@ -22,6 +24,7 @@ import me.hatter.tools.tinyencrypt.util.CardCliUtil;
|
|||||||
|
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.interfaces.ECPublicKey;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
@@ -138,6 +141,15 @@ public class TinyEncryptMetaUtil {
|
|||||||
tinyEncryptMeta.setAgeEnvelop(ageEnvelop.trim());
|
tinyEncryptMeta.setAgeEnvelop(ageEnvelop.trim());
|
||||||
tinyEncryptMeta.setAgeRecipient(config.getAgeRecipient());
|
tinyEncryptMeta.setAgeRecipient(config.getAgeRecipient());
|
||||||
}
|
}
|
||||||
|
if (StringUtil.isNotBlank(config.getEcdhPublicKeyPoint())) {
|
||||||
|
final PublicKey ecPubliecKey = ECUtil.getEcPublicKey(ECUtil.CURVE_SECP256R1, Bytes.fromHex(config.getEcdhPublicKeyPoint()).bytes());
|
||||||
|
final byte[] ecPointXBytes = ((ECPublicKey) ecPubliecKey).getW().getAffineX().toByteArray();
|
||||||
|
final boolean startsWith00AndLen33 = (ecPointXBytes.length == 33 && ecPointXBytes[0] == 0x00);
|
||||||
|
final String ecdhPoint = "02" + Bytes.from(ecPointXBytes).subBytes(startsWith00AndLen33 ? 1 : 0).asHex();
|
||||||
|
final String ecdhEnvelop = WrapKeyUtil.encryptEcdhP256(null, ecPubliecKey, dataKey).toString();
|
||||||
|
tinyEncryptMeta.setEcdhEnvelop(ecdhEnvelop);
|
||||||
|
tinyEncryptMeta.setEcdhPoint(ecdhPoint);
|
||||||
|
}
|
||||||
tinyEncryptMeta.setNonce(RandomTool.secureRandom().nextbytes(12));
|
tinyEncryptMeta.setNonce(RandomTool.secureRandom().nextbytes(12));
|
||||||
tinyEncryptMeta.setUserAgent("TinyEncrypt v" + TinyEncryptConstant.VERSION + "@" + OSUtil.getCurrentOS().name());
|
tinyEncryptMeta.setUserAgent("TinyEncrypt v" + TinyEncryptConstant.VERSION + "@" + OSUtil.getCurrentOS().name());
|
||||||
tinyEncryptMeta.setComment(comment);
|
tinyEncryptMeta.setComment(comment);
|
||||||
|
|||||||
@@ -10,16 +10,17 @@ import me.hatter.tools.commons.log.LogTools;
|
|||||||
import me.hatter.tools.commons.string.StringUtil;
|
import me.hatter.tools.commons.string.StringUtil;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class CardCliUtil {
|
public class CardCliUtil {
|
||||||
private static final LogTool log = LogTools.getLogTool(CardCliUtil.class);
|
private static final LogTool log = LogTools.getLogTool(CardCliUtil.class);
|
||||||
|
|
||||||
public static Optional<String> readUserPin() {
|
public static Optional<String> readUserPin() {
|
||||||
System.out.print("Input PGP user PIN: ");
|
System.out.print("Please input user PIN: ");
|
||||||
final 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.warn("Input user PIN has " + pin.length + " char(s)");
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return Optional.of(new String(pin));
|
return Optional.of(new String(pin));
|
||||||
@@ -80,6 +81,26 @@ public class CardCliUtil {
|
|||||||
return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes());
|
return Optional.of(Bytes.fromHex(jo.getString("text_hex")).bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<byte[]> ecdhSharedSecret(String cardCli, String pin, String ePublicKeyPointHex) {
|
||||||
|
final ProcessBuilder pb = new ProcessBuilder(
|
||||||
|
cardCli,
|
||||||
|
"piv-ecdh",
|
||||||
|
"--private",
|
||||||
|
"--slot", "82",
|
||||||
|
"--epk", ePublicKeyPointHex,
|
||||||
|
"--json");
|
||||||
|
if (StringUtil.isNotBlank(pin)) {
|
||||||
|
pb.command().addAll(Arrays.asList("--pin", pin));
|
||||||
|
}
|
||||||
|
log.info("Start: " + cardCli);
|
||||||
|
final Optional<String> outputsOpt = runProcess(pb);
|
||||||
|
if (!outputsOpt.isPresent()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
final JSONObject jo = JSON.parseObject(outputsOpt.get());
|
||||||
|
return Optional.of(Bytes.fromHex(jo.getString("shared_secret_hex")).bytes());
|
||||||
|
}
|
||||||
|
|
||||||
public static Optional<String> runProcess(ProcessBuilder pb) {
|
public static Optional<String> runProcess(ProcessBuilder pb) {
|
||||||
Process p = null;
|
Process p = null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user