feat: tiny encrypt

This commit is contained in:
2021-04-12 00:21:23 +08:00
parent 729827d7ee
commit b18e46c406
11 changed files with 381 additions and 52 deletions

62
.gitignore vendored
View File

@@ -1,53 +1,11 @@
# ---> Java
# Compiled class file
*.class
# 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
out/
build
classes
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# 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
.gradle
.classpath
.project
.settings
*.iml
*.ipr
*.iws

92
build.gradle Normal file
View 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
View 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"
]
}
}

View File

@@ -0,0 +1,7 @@
package me.hatter.tools.tinyencrypt;
public class TinyEncryptMain {
public static void main(String[] args) {
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,5 @@
package me.hatter.tools.tinyencrypt.config;
public class TinyEncryptConstant {
public static final String VERSION = "0.1.0";
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View 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;
}
}

View File

@@ -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;
}
}