feat: tiny encrypt
This commit is contained in:
62
.gitignore
vendored
62
.gitignore
vendored
@@ -1,53 +1,11 @@
|
|||||||
# ---> Java
|
out/
|
||||||
# Compiled class file
|
build
|
||||||
*.class
|
classes
|
||||||
|
|
||||||
# Log file
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# BlueJ files
|
|
||||||
*.ctxt
|
|
||||||
|
|
||||||
# Mobile Tools for Java (J2ME)
|
|
||||||
.mtj.tmp/
|
|
||||||
|
|
||||||
# Package Files #
|
|
||||||
*.jar
|
|
||||||
*.war
|
|
||||||
*.nar
|
|
||||||
*.ear
|
|
||||||
*.zip
|
|
||||||
*.tar.gz
|
|
||||||
*.rar
|
|
||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
|
||||||
hs_err_pid*
|
|
||||||
|
|
||||||
# ---> macOS
|
|
||||||
# General
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.AppleDouble
|
.gradle
|
||||||
.LSOverride
|
.classpath
|
||||||
|
.project
|
||||||
# Icon must end with two \r
|
.settings
|
||||||
Icon
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
# Thumbnails
|
|
||||||
._*
|
|
||||||
|
|
||||||
# Files that might appear in the root of a volume
|
|
||||||
.DocumentRevisions-V100
|
|
||||||
.fseventsd
|
|
||||||
.Spotlight-V100
|
|
||||||
.TemporaryItems
|
|
||||||
.Trashes
|
|
||||||
.VolumeIcon.icns
|
|
||||||
.com.apple.timemachine.donotpresent
|
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share
|
|
||||||
.AppleDB
|
|
||||||
.AppleDesktop
|
|
||||||
Network Trash Folder
|
|
||||||
Temporary Items
|
|
||||||
.apdisk
|
|
||||||
|
|||||||
92
build.gradle
Normal file
92
build.gradle
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'eclipse'
|
||||||
|
apply plugin: 'idea'
|
||||||
|
|
||||||
|
def JsonSlurper = Class.forName('groovy.json.JsonSlurper');
|
||||||
|
def buildJSON = JsonSlurper.newInstance().parseText(new File("build.json").text)
|
||||||
|
|
||||||
|
if (buildJSON.application) { apply plugin: 'application' }
|
||||||
|
|
||||||
|
def baseProjectName = buildJSON?.project?.name ?: '__project_name__';
|
||||||
|
def shellCommandName = baseProjectName
|
||||||
|
def eclipseProjectName = baseProjectName
|
||||||
|
def eclipseProjectComment = buildJSON?.project?.comment ?: '__project_name_comment__'
|
||||||
|
def jarManifestMainClass = buildJSON?.project?.main ?: 'SampleMain'
|
||||||
|
|
||||||
|
if (buildJSON.application) { mainClassName = jarManifestMainClass }
|
||||||
|
archivesBaseName = buildJSON?.project?.archiveName ?: baseProjectName
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
def addRepo = new File(System.getProperty("user.home"), ".build_add.repo")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
// mavenCentral()
|
||||||
|
maven() { url 'https://maven.aliyun.com/repository/central' }
|
||||||
|
if (addRepo.exists()) { maven() { url addRepo.text.trim() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
options.encoding = "UTF-8"
|
||||||
|
}
|
||||||
|
|
||||||
|
// '-x test' skip unit test
|
||||||
|
defaultTasks 'build'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
maven() { url 'https://maven.aliyun.com/repository/central' }
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.11.RELEASE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply plugin: 'org.springframework.boot'
|
||||||
|
springBoot {
|
||||||
|
mainClass = jarManifestMainClass
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile files(fileTree(dir: 'lib', includes: ['*.jar'], excludes: ['*-sources.jar', '*-javadoc.jar']))
|
||||||
|
|
||||||
|
if (buildJSON.repo != null && buildJSON.repo.dependencies != null) {
|
||||||
|
buildJSON.repo.dependencies.each {
|
||||||
|
compile("${it}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buildJSON.repo != null && buildJSON.repo.testDependencies != null) {
|
||||||
|
buildJSON.repo.testDependencies.each {
|
||||||
|
testCompile("${it}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eclipse {
|
||||||
|
project {
|
||||||
|
name = eclipseProjectName
|
||||||
|
comment = eclipseProjectComment
|
||||||
|
}
|
||||||
|
classpath {
|
||||||
|
defaultOutputDir = file('classes')
|
||||||
|
downloadSources = true
|
||||||
|
file {
|
||||||
|
whenMerged { classpath ->
|
||||||
|
classpath.entries.findAll { it.kind=='lib' }.each {
|
||||||
|
if ((it.path != null) && (it.sourcePath == null) && file(it.path.replace(".jar", "-sources.jar")).exists()) {
|
||||||
|
it.sourcePath = getFileReferenceFactory().fromPath(it.path.replace(".jar", "-sources.jar"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eclipseJdt << {
|
||||||
|
File f = file('.settings/org.eclipse.core.resources.prefs')
|
||||||
|
f.write('eclipse.preferences.version=1\n')
|
||||||
|
f.append('encoding/<project>=utf-8')
|
||||||
|
}
|
||||||
22
build.json
Normal file
22
build.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"project": {
|
||||||
|
"name": "tiny-encrypt-java",
|
||||||
|
"main": "me.hatter.tools.tinyencrypt.TinyEncryptMain",
|
||||||
|
"archiveName": "tiny-encrypt"
|
||||||
|
},
|
||||||
|
"application": false,
|
||||||
|
"java": "1.8",
|
||||||
|
"builder": {
|
||||||
|
"name": "gradle",
|
||||||
|
"version": "3.1"
|
||||||
|
},
|
||||||
|
"repo": {
|
||||||
|
"dependencies": [
|
||||||
|
"me.hatter:commons:3.0",
|
||||||
|
"org.bouncycastle:bcall-jdk15on:1.60"
|
||||||
|
],
|
||||||
|
"testDependencies": [
|
||||||
|
"junit:junit:4.12"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt;
|
||||||
|
|
||||||
|
public class TinyEncryptMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.config;
|
||||||
|
|
||||||
|
public class TinyEncryptConfig {
|
||||||
|
private String defaultKeyName;
|
||||||
|
|
||||||
|
public String getDefaultKeyName() {
|
||||||
|
return defaultKeyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultKeyName(String defaultKeyName) {
|
||||||
|
this.defaultKeyName = defaultKeyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.config;
|
||||||
|
|
||||||
|
public class TinyEncryptConstant {
|
||||||
|
public static final String VERSION = "0.1.0";
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.encrypt;
|
||||||
|
|
||||||
|
import me.hatter.tools.commons.security.crypt.CryptOutputStream;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
public class EncryptedFile extends FilterOutputStream {
|
||||||
|
static {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
}
|
||||||
|
// private TinyEncryptMeta tinyEncryptMeta;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
DataOutputStream dos = new DataOutputStream(new FileOutputStream("aaa.enc"));
|
||||||
|
TinyEncryptMeta meta = TinyEncryptMetaUtil.create("prod_ec_key", "...");
|
||||||
|
EncryptedFile file = new EncryptedFile(dos, meta);
|
||||||
|
file.write("Hello World".getBytes(StandardCharsets.UTF_8));
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public EncryptedFile(DataOutputStream rawOut, TinyEncryptMeta tinyEncryptMeta) throws IOException {
|
||||||
|
super(getCryptoOutputStream(rawOut, tinyEncryptMeta));
|
||||||
|
// this.tinyEncryptMeta = tinyEncryptMeta;
|
||||||
|
TlvUtil.write(rawOut, TlvUtil.create(0, TinyEncryptMetaUtil.toString(tinyEncryptMeta)));
|
||||||
|
rawOut.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OutputStream getCryptoOutputStream(OutputStream out, TinyEncryptMeta tinyEncryptMeta) {
|
||||||
|
return CryptOutputStream.gcmEncrypt(out, tinyEncryptMeta.getDataKey(), tinyEncryptMeta.getNonce());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.encrypt;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
|
||||||
|
public class TinyEncryptMeta {
|
||||||
|
private String version;
|
||||||
|
private long created;
|
||||||
|
private String userAgent;
|
||||||
|
private String comment;
|
||||||
|
private String envelop;
|
||||||
|
@JSONField(serialize = false)
|
||||||
|
private byte[] dataKey;
|
||||||
|
private byte[] nonce;
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(long created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserAgent() {
|
||||||
|
return userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserAgent(String userAgent) {
|
||||||
|
this.userAgent = userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getComment() {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComment(String comment) {
|
||||||
|
this.comment = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnvelop() {
|
||||||
|
return envelop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnvelop(String envelop) {
|
||||||
|
this.envelop = envelop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getDataKey() {
|
||||||
|
return dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataKey(byte[] dataKey) {
|
||||||
|
this.dataKey = dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNonce(byte[] nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.encrypt;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import me.hatter.tools.commons.bytes.Bytes;
|
||||||
|
import me.hatter.tools.commons.network.HttpRequest;
|
||||||
|
import me.hatter.tools.commons.os.OSUtil;
|
||||||
|
import me.hatter.tools.commons.security.random.RandomTool;
|
||||||
|
import me.hatter.tools.tinyencrypt.config.TinyEncryptConstant;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TinyEncryptMetaUtil {
|
||||||
|
private static final String KMS_GET_DATA_KEY = "https://hatter.ink/kms/get_data_key.json";
|
||||||
|
|
||||||
|
public static String toString(TinyEncryptMeta tinyEncryptMeta) {
|
||||||
|
return JSON.toJSONString(tinyEncryptMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TinyEncryptMeta parse(String meta) {
|
||||||
|
return JSON.parseObject(meta, TinyEncryptMeta.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TinyEncryptMeta create(String name, String comment) {
|
||||||
|
List<HttpRequest.KeyValue> keyValues = new ArrayList<>();
|
||||||
|
keyValues.add(new HttpRequest.KeyValue("name", name));
|
||||||
|
Bytes response = HttpRequest.fromUrl(KMS_GET_DATA_KEY).post(keyValues);
|
||||||
|
|
||||||
|
JSONObject responseObject = response.asJSON();
|
||||||
|
if (responseObject.getIntValue("status") != 200) {
|
||||||
|
throw new RuntimeException("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);
|
||||||
|
tinyEncryptMeta.setNonce(RandomTool.secureRandom().nextbytes(12));
|
||||||
|
tinyEncryptMeta.setUserAgent("TinyEncrypt v" + TinyEncryptConstant.VERSION + "@" + OSUtil.getCurrentOS().name());
|
||||||
|
tinyEncryptMeta.setComment("test");
|
||||||
|
return tinyEncryptMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TinyEncryptMeta tinyEncryptMeta = create("prod_ec_key", "");
|
||||||
|
|
||||||
|
System.out.println(JSON.toJSONString(tinyEncryptMeta, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/main/java/me/hatter/tools/tinyencrypt/encrypt/Tlv.java
Normal file
31
src/main/java/me/hatter/tools/tinyencrypt/encrypt/Tlv.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.encrypt;
|
||||||
|
|
||||||
|
public class Tlv {
|
||||||
|
private int tag;
|
||||||
|
private int length;
|
||||||
|
private byte[] value;
|
||||||
|
|
||||||
|
public int getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTag(int tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLength(int length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(byte[] value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package me.hatter.tools.tinyencrypt.encrypt;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class TlvUtil {
|
||||||
|
|
||||||
|
public static void write(DataOutputStream os, Tlv tlv) throws IOException {
|
||||||
|
os.writeShort(tlv.getTag());
|
||||||
|
os.writeInt(tlv.getLength());
|
||||||
|
os.write(tlv.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tlv read(DataInputStream is) throws IOException {
|
||||||
|
int tag = is.readShort();
|
||||||
|
int length = is.readInt();
|
||||||
|
byte[] bs = new byte[length];
|
||||||
|
is.readFully(bs);
|
||||||
|
Tlv tlv = new Tlv();
|
||||||
|
tlv.setTag(tag);
|
||||||
|
tlv.setLength(length);
|
||||||
|
tlv.setValue(bs);
|
||||||
|
return tlv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tlv create(int tag, String value) {
|
||||||
|
return create(tag, value.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tlv create(int tag, byte[] value) {
|
||||||
|
Tlv tlv = new Tlv();
|
||||||
|
tlv.setTag(tag);
|
||||||
|
tlv.setLength(value.length);
|
||||||
|
tlv.setValue(value);
|
||||||
|
return tlv;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user