对jar或者war进行加密解密
whycxzp
2021-12-22 f6b935781bcb43faea7aa894ce3a55873769efb3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package com.whyc;
 
 
import com.whyc.util.*;
import com.whyc.util.*;
 
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
 
/**
 * java class解密
 *
 * @author perry
 */
public class JarDecryptor {
    //单例
    private static final JarDecryptor single = new JarDecryptor();
    //机器码
    private char[] code;
    //加密后文件存放位置
    private static final String ENCRYPT_PATH = "META-INF/" + Const.FILE_NAME + "/";
 
    //加密后文件存放位置
    private static final String DESCRIPTION_PATH = "META-INF/";
 
    /**
     * 单例
     *
     * @return 单例
     */
    public static JarDecryptor getInstance() {
        return single;
    }
 
    /**
     * 构造
     */
    public JarDecryptor() {
        this.code = SysUtils.makeMarchinCode();
    }
 
    /**
     * 根据名称解密出一个文件
     *
     * @param projectPath 项目所在的路径
     * @param fileName    文件名
     * @param password    密码
     * @return 解密后的字节
     */
    public byte[] doDecrypt(String projectPath, String fileName, char[] password) {
        long t1 = System.currentTimeMillis();
        File workDir = new File(projectPath);
        byte[] bytes = readEncryptedFile(workDir, fileName);
        if (bytes == null) {
            return null;
        }
 
        //读取机器码,有机器码,先用机器码解密
        byte[] codeBytes = readEncryptedFile(workDir, Const.CONFIG_CODE);
        if (codeBytes != null) {
            //本机器码和打包的机器码不匹配
            if (!StrUtils.equal(EncryptUtils.md5(this.code), StrUtils.toChars(codeBytes))) {
                Log.println("该项目不可在此机器上运行!\n");
                System.exit(-1);
            }
 
            //用机器码解密
            char[] pass = StrUtils.merger(fileName.toCharArray(), code);
            bytes = EncryptUtils.de(bytes, pass, Const.ENCRYPT_TYPE);
        }
 
        //无密码启动,读取隐藏的密码
        if (password.length == 1 && password[0] == '#') {
            password = readPassFromJar(workDir);
        }
 
        //密码解密
        char[] pass = StrUtils.merger(password, fileName.toCharArray());
        bytes = EncryptUtils.de(bytes, pass, Const.ENCRYPT_TYPE);
 
        long t2 = System.currentTimeMillis();
        Log.debug("解密: " + fileName + " (" + (t2 - t1) + " ms)");
 
        return bytes;
 
    }
 
    /**
     * 在jar文件或目录中读取文件字节
     *
     * @param workDir jar文件或目录
     * @param name    文件名
     * @return 文件字节数组
     */
    public static byte[] readEncryptedFile(File workDir, String name) {
        byte[] bytes = null;
        String fileName = ENCRYPT_PATH + name;
        //jar文件
        if (workDir.isFile()) {
            bytes = JarUtils.getFileFromJar(workDir, fileName);
        } else {//war解压的目录
            File file = new File(workDir, fileName);
            if (file.exists()) {
                bytes = IoUtils.readFileToByte(file);
            }
        }
        return bytes;
    }
 
    /**
     * 在jar文件或目录中读取密码字节
     *
     * @param workDir jar文件或目录
     * @param name    文件名
     * @return 文件字节数组
     */
    public static byte[] readEncryptedFile2(File workDir, String name) {
        byte[] bytes = null;
        String fileName = DESCRIPTION_PATH + name;
        //jar文件
        if (workDir.isFile()) {
            bytes = JarUtils.getFileFromJar(workDir, fileName);
        } else {//war解压的目录
            File file = new File(workDir, fileName);
            if (file.exists()) {
                bytes = IoUtils.readFileToByte(file);
            }
        }
        return bytes;
    }
 
    /**
     * 读取隐藏在jar的密码
     *
     * @param workDir jar路径
     * @return 密码char
     */
    public static char[] readPassFromJar(File workDir) {
        byte[] passbyte = readEncryptedFile(workDir, Const.CONFIG_PASS);
        if (passbyte != null) {
            char[] pass = StrUtils.toChars(passbyte);
            return EncryptUtils.md5(pass);
        }
        return null;
    }
 
    /**
     * 读取隐藏在jar的密码
     *
     * @param workDir jar路径
     * @return 密码char
     */
    public static char[] readPassFromJar2(File workDir) {
        byte[] passbyte = readEncryptedFile2(workDir, Const.FILE_NAME2);
        if (passbyte != null) {
            char[] pass = StrUtils.toChars(passbyte);
            return EncryptUtils.md5(pass);
        }
        return null;
    }
 
    /**
     * 解密配置文件,spring读取文件时调用
     *
     * @param path 配置文件路径
     * @param in   输入流
     * @return 解密的输入流
     */
    public InputStream decryptConfigFile(String path, InputStream in, char[] pass) {
        if (path.endsWith(".class")) {
            return in;
        }
        String projectPath = JarUtils.getRootPath(null);
        if (StrUtils.isEmpty(projectPath)) {
            return in;
        }
        byte[] bytes = null;
        try {
            bytes = IoUtils.toBytes(in);
        } catch (Exception e) {
 
        }
        if (bytes == null || bytes.length == 0) {//需要解密
            bytes = this.doDecrypt(projectPath, path, pass);
        }
        if (bytes == null) {
            return in;
        }
        in = new ByteArrayInputStream(bytes);
        return in;
    }
 
}