0. 基本介绍
对指定位置的db文件进行双层加密压缩后上传,对于文件的位置与标准名称暂时不做讨论 。
文件加密层级见下图 :
如上图(文件加密压缩结构)所示,想要生成该结构的加密压缩包,需要:
db文件需要加密,同时将加密的文件对应的秘钥也进行加密(使用A0002.key加密)之后压缩;
将1.中的压缩包与A0002.key , db.xml 两个文件同事压缩,将该压缩包加密;
将2中生成的加密包与对应的秘钥(固定秘钥加密该秘钥) 压缩 ,生成需要上传的压缩文件。
部分代码示例
0. 标准名称生成
虽然文件位置,文件名称不做过多讨论,但是还是在这里写一些生成标准文件名称的测试代码
public class StandardName {
public static String getDay() {
Date d = new Date();
SimpleDateFormat sbf = new SimpleDateFormat("yyyyMMddHHmmss");
String time = sbf.format(d) +"_" ;
return time ;
}
public static String getStandardName(String code){
String day = getDay() ;
String uuid = UUID.randomUUID().toString().replace("-", "") ;
// 此处将 企业18位信用代码替换为了 *****
String standardName = "*****_"+code+"_1001_"+day+uuid ;//0073_1001_20230129083433_ffad0045d51f4bf7a343cd063bff0073
return standardName ;
}
public static void main(String[] args) {
String stand = getStandardName("0043") ;
System.out.println("stand "+stand);
}
}
以上方法可生成一个标准名称字符串,该名称很重要,只需要生成一次即可,但是所有压缩加密包,秘钥名称,加密时的存储目录均为该名称。
文件压缩
文件需要加密前需要经过压缩,之后加密,再压缩等操作,所以需要先进行文件压缩的测试代码编写
.....
/**
* 压缩成ZIP 方法2
* @param srcFiles 需要压缩的文件列表
* @param out 压缩文件输出流
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
private static final int BUFFER_SIZE = 2 * 1024;
public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException {
long start = System.currentTimeMillis();
ZipOutputStream zos = null ;
try {
zos = new ZipOutputStream(out);
for (File srcFile : srcFiles) {
byte[] buf = new byte[BUFFER_SIZE];
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int len;
FileInputStream in = new FileInputStream(srcFile);
while ((len = in.read(buf)) != -1){
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
}
long end = System.currentTimeMillis();
// System.out.println("压缩完成,耗时:" + (end - start) +" ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils",e);
}finally{
if(zos != null){
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
.....
以后所有需要压缩的db或文件都使用这个方法进行压缩,由于文件层级比较复杂,还涉及复制,粘贴,移动 与文件夹名称/位置组织形式 ,文件所在路径需要进行处理已生成指定标准的文件存储路径。
2.文件SM2 , SM4加密
文件需要使用秘钥以SM4方式加密 ,对应的秘钥使用SM2 形式加密。
public class EncryptUtills {
/**
* @author 20180823 DS
* @param filePath 待加密文件及路径
* @param zipPath 加密后文件及路径
* @param sm4KeyPath sm4 秘钥路径及名称
* */
public static void sm4EncryptEnd( String filePath ,String zipPath,File sm4KeyPath) throws IOException {
// String fileName // 未加密db路径
filePath = new File(filePath).getCanonicalPath();
// sm4加密后zip路径
zipPath = new File(zipPath).getCanonicalPath();
String sm4Key= new FileReader(sm4KeyPath).readString();//sm4KeyPath.getCanonicalPath();
// sm4加密
SymmetricCrypto symmetricCrypto = SmUtil.sm4(sm4Key.substring(0, 16).getBytes());
Util.saveFile(zipPath, symmetricCrypto.encrypt(FileUtil.readBytes(filePath)));
System.out.println("First layer Encrypt result : "+zipPath);
}
/**
* @author 20180823 DS
* @param a0002keyPath sm2公钥路径
* @param sourcePath 加密前密钥路径
* @param targetPath 加密后密钥路径
* */
public static void sm2EncryptByString(String a0002keyPath,String sourcePath,String targetPath ) throws IOException{
// sm2公钥路径
// 读取A0002.key文件的内容(sm2公钥)
String publicKey = new FileReader(a0002keyPath).readString();
byte[] encryptedBytes = null;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream in = new FileInputStream(sourcePath)) {
byte[] buffer = new byte[1024];
int i = 0;
while ((i = in.read(buffer)) != -1) {
baos.write(buffer, 0, i);
}
byte[] baseData = baos.toByteArray();
byte[] publicKeyHex = ByteUtils.fromHexString(publicKey);
byte[] formatedPubKey = publicKeyHex;
// 在SM2公钥签名添加04标识,用于ECPoint解析
if (publicKeyHex.length == 64) {
formatedPubKey = new byte[65];
formatedPubKey[0] = 0x04;
System.arraycopy(publicKeyHex, 0, formatedPubKey, 1, publicKeyHex.length);
}
encryptedBytes = SM2Utils.encrypt(formatedPubKey, baseData);
} catch (Exception e) {
e.printStackTrace();
}
Util.saveFile(targetPath, encryptedBytes);
System.out.println(" publicKey: "+publicKey+" targetPath: "+targetPath);
}
}
这里的是一些简单的应用,具体实现方式后期会单独写一篇文章。
3.标准文件路径名生成
将已有的db文件 压缩加密为指定结构的压缩包, 将以上功能进行整合前需要生成指定格式的文件路径。具体测试代码如下:
public static void creatDir(String path,String standardName) {
File dirFile=new File(path+standardName);
// create standard name of path
if(!dirFile.exists()) {
dirFile.mkdir();
}
}
public static void copyAndRename(String originPath , String originFileName,String targetPath ,String targetFileName) {
File originFile = new File(originPath+originFileName) ;
File targetFile = new File(targetPath+targetFileName) ;
originFile.renameTo(targetFile) ;
}
// get standard pathName by (code,name)
public static String getPath(String name,String code,String standardName) {
String path = "D:\\dbdata\\"+ name +"\\encrpt\\" ;
String bathPath = path + standardName+"\\" ;
creatDir(bathPath,"");
creatDir(bathPath,"layer01");
creatDir(bathPath,"layer02");
creatDir(bathPath,"layer03");
creatDir(bathPath,"upload");
System.out.println("gzjg.fileoperate- 0034: "+bathPath);
return bathPath ;
}
工作流程
1.工作流程图:
2.具体整合代码实现
以下代码实现了将第一部分的相关应用整合并按照开头的图片中压缩加密层级进行了处理
.....
static EncryptUtills encrpt = new EncryptUtills();
// standardName can be auto-producted ,just
static StandardName standardUtils = new StandardName() ;
// 此处隐藏了相关信息, standardName 应 按照相关要求动态生成
static String standardName = "****_0043_1001_20230324161150_eaea0942952a4f63ad5dd42130f5afdf" ;
//standardUtils.getStandardName("0043") ; --Temporarily replace this method with a string
static CRUDDir standardDir = new CRUDDir() ;
static ZipUtils compressTool = new ZipUtils() ;
// layer01
public static String firstEncrpt(String name) throws Exception {
//step1 compress db file to zip ,in this test code, hidden how to get db path
String bathPath = standardDir.getPath(name, standardName) ;
//Compress db files to the specified folder(layer01) and generate a zip file with the same name
List<File> fileListlayer01 = new ArrayList<>();
fileListlayer01.add(new File(bathPath+standardName+".db"));
FileOutputStream fos2bath = new FileOutputStream(new File(bathPath+standardName+".zip"));
System.out.println("-0031 bathPath-"+bathPath);
compressTool.toZip(fileListlayer01, fos2bath);
//first layer encrypt db zip file and key
String firstFilePath = bathPath + standardName+".zip";
String firstZipPath = bathPath + "layer01\\"+standardName+".zip";
String toolsPath = "D:\\dbdata\\"+ name +"\\encrpt\\" ;
File sm4keyFirst = new File( toolsPath +"sm4key.txt");
encrpt.sm4EncryptEnd(firstFilePath, firstZipPath, sm4keyFirst);
String a0002path=toolsPath+"A0002.key";
String sourcePath=toolsPath+"sm4key.txt";
String targetPath=bathPath +"layer01\\"+standardName+".key";
encrpt.sm2EncryptByString(a0002path,sourcePath,targetPath);
//Compress these two encrypted files into layer01.zip
fileListlayer01.clear();
fileListlayer01.add(new File(firstZipPath));
fileListlayer01.add(new File(targetPath));
FileOutputStream fos2layer01 = new FileOutputStream(new File(bathPath + "\\layer01\\layer01"+".zip"));
compressTool.toZip(fileListlayer01, fos2layer01);
String layer02Path = bathPath + "layer02\\" ;
//Move file(layer01.zip) to layer02 director --bathPath + "\\layer01\\layer01"+".zip"
(new File(bathPath + "layer01\\layer01"+".zip")).renameTo(new File(layer02Path+standardName+".zip"));
//Compress layer02 files ,a0002.key db.xml to layer02.zip
fileListlayer01.clear();
fileListlayer01.add(new File(layer02Path+standardName+".zip"));
fileListlayer01.add(new File(toolsPath+"A0002.key"));
fileListlayer01.add(new File(toolsPath+ "db.xml"));
FileOutputStream fos2layer02 =new FileOutputStream(new File(layer02Path+"layer02.zip"));
compressTool.toZip(fileListlayer01, fos2layer02);
return bathPath ;
}
public static String secondEncrpt(String layer02BathPath) throws Exception {
String toolPath2nd =layer02BathPath.substring(0, layer02BathPath.length()-77) ;
String FilePath2nd=layer02BathPath+ "layer02\\"+"layer02.zip";
String ZipPath2nd=layer02BathPath+ "layer03\\"+standardName+".zip";
File sm4key2nd = new File(toolPath2nd+"sm4keylayer02.txt");
String a0002pathlayer03=toolPath2nd+"sm2Infor.key";
String sourcePathlayer03=toolPath2nd+"sm4keylayer02.txt";
String targetPathlayer03=layer02BathPath+"layer03\\" +standardName+".key";
//second layer encrypt db zip file and key
encrpt.sm4EncryptEnd(FilePath2nd,ZipPath2nd,sm4key2nd);
encrpt.sm2EncryptByString(a0002pathlayer03,sourcePathlayer03,targetPathlayer03);
//compress to a upload zip
List<File> fileListlayer02 = new ArrayList<>();
fileListlayer02.add(new File(ZipPath2nd));
fileListlayer02.add(new File(targetPathlayer03));
String uploadZip = layer02BathPath+ "upload\\"+standardName+".zip" ;
FileOutputStream fos2bath = new FileOutputStream(new File(uploadZip ));
compressTool.toZip(fileListlayer02, fos2bath);
return uploadZip ;
}
public static void main(String[] args) throws Exception {
String layer02BathPath = firstEncrpt("zzjg");
String uploadZIP = secondEncrpt( layer02BathPath) ;
System.out.println("uploadZIP: "+uploadZIP);
}
...
总结
此处工作内容是在上一篇文章的工作基础上对已经生成的db文件进行加密压缩操作,整合代码中对于标准文件名称的生成没有纳入,如果进行完成的工作流程操作,即
1.从已有系统(oracle)取出数据
2.写入到对于格式的db中
3.将db文件进行双层加密压缩操作
需要在 2. 中生成标准文件名称并开始自动新建文件夹。
最后通过相关接口上传最终生成的加密压缩包,这里不做赘述。