xiaoyong931011
2023-10-27 107c4d630c5b5c1b04f0d63a147e363b68dd1e8c
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package cc.mrbird.febs.pay.util;
 
 
 
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
 
/**
 * RSA加解密的工具类
 */
public class RSAUtil {
//    private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class);
    public static final String SIGNATURE_ALGORITHM_SHA1 = "SHA1withRSA";
    public static final String SIGNATURE_ALGORITHM_MD5 = "MD5withRSA";
    public static final String RSA = "RSA";
 
    public static final String ANDROID_ENCRYPT_ALGORITHM = "RSA/ECB/NoPadding";
    public static final String DEFAULT_ENCRYPT_ALGORITHM = "RSA/ECB/PKCS1Padding";
 
    public static final String PUBLIC_KEY = "publicKey";
    public static final String PRIVATE_KEY = "privateKey";
 
    /** */
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 116;
 
    /** */
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
 
    /**
     * 初始化BC提供者,RSA算法必须要先初始化BC才能进行加密解密和签名验签
     */
    private static void initProvider() {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }
 
    /**
     * 生成RSA签名串
     *
     * @param data       需要生成签名串的数据
     * @param privateKey 私钥
     * @return
     * @throws BizException
     */
    public static String sign(String data, String privateKey, boolean isSha) throws Exception {
        try {
            initProvider();
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            byte[] keyBytes = CodeUtil.base64Decode(privateKey);
            String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5;
 
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            PrivateKey priKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance(algorithm);
            signature.initSign(priKey);
            signature.update(dataBytes);
            return CodeUtil.base64Encode(signature.sign());
        }catch (Throwable e){
//            logger.error("==>sign err:", e);
            throw new Exception("生成RSA签名失败", e);
        }
    }
 
    /**
     * 验证RSA签名串
     *
     * @param data      需要验签的数据
     * @param publicKey 公钥
     * @param sign      用户传过来的签名串
     * @return
     * @throws BizException
     */
    public static boolean verify(String data, String publicKey, String sign, boolean isSha) throws Exception {
        try {
            initProvider();
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            byte[] signBytes = CodeUtil.base64Decode(sign);
            String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5;
            PublicKey publicK = getPublicKey(publicKey);
 
            Signature signature = Signature.getInstance(algorithm);
            signature.initVerify(publicK);
            signature.update(dataBytes);
            return signature.verify(signBytes);
        } catch (Throwable e) {
//            logger.error("==>verify err:", e);
            throw new Exception("RSA验签失败", e);
        }
    }
 
    /**
     * 对称密钥公钥加密
     *
     * @param publicKeyStr 公钥Str
     * @param content      密钥原文
     * @return 加密密文
     */
    public static String encryptByPublicKey(String publicKeyStr, String content) throws Exception {
       
            byte[] dataBytes = content.getBytes(StandardCharsets.UTF_8);
            dataBytes = doCipher(dataBytes, publicKeyStr, true, false);
            return CodeUtil.base64Encode(dataBytes);
       
    }
 
    /**
     * 对称密钥密文解密
     *
     * @param privateKeyStr 私钥字符串
     * @param content       对称密钥密文
     * @return 对称密钥明文
     * @throws Exception
     */
    public static String decryptByPrivateKey(String privateKeyStr, String content) throws Exception{
            byte[] dataBytes = CodeUtil.base64Decode(content);
            dataBytes = doCipher(dataBytes, privateKeyStr, false, false);
            return new String(dataBytes, StandardCharsets.UTF_8);
       
    }
 
    private static byte[] doCipher(byte[] dataBytes, String keyStr, boolean isEncrypt, boolean isAndroid) throws Exception {
 
        initProvider();
 
        Key key;
        Cipher cipher;
        int maxBlock;
 
        if (isEncrypt) {
            maxBlock = MAX_ENCRYPT_BLOCK;
            key = getPublicKey(keyStr);
            if (isAndroid) {
                cipher = Cipher.getInstance(ANDROID_ENCRYPT_ALGORITHM);// 如果是安卓机
            } else {
                cipher = Cipher.getInstance(DEFAULT_ENCRYPT_ALGORITHM);
            }
            cipher.init(Cipher.ENCRYPT_MODE, key);
        } else {
            maxBlock = MAX_DECRYPT_BLOCK;
            byte[] keyBytes = Base64.decodeBase64(keyStr);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateK);
        }
 
        int offSet = 0, i = 0, inputLen = dataBytes.length;
        byte[] cache;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
 
        try {
            // 对数据分段加密/解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > maxBlock) {
                    cache = cipher.doFinal(dataBytes, offSet, maxBlock);
                } else {
                    cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * maxBlock;
            }
            return out.toByteArray();
        } finally {
            out.close();
        }
    }
 
    /**
     * 生成公私密钥对
     * @return
     */
    public static Map<String, String> genKeyPair() throws Exception {
        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
            keyPairGen.initialize(1024);
            KeyPair keyPair = keyPairGen.generateKeyPair();
 
            Map<String, String> keyMap = new HashMap<>(2);
            keyMap.put(PUBLIC_KEY, CodeUtil.base64Encode(keyPair.getPublic().getEncoded()));
            keyMap.put(PRIVATE_KEY, CodeUtil.base64Encode(keyPair.getPrivate().getEncoded()));
            return keyMap;
        }catch (Throwable e){
            throw new Exception("生成RSA密钥对出现异常", e);
        }
    }
 
    private static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] keyBytes = CodeUtil.base64Decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        return keyFactory.generatePublic(x509KeySpec);
    }
}