前端AES + RSA加密

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端AES + RSA加密相关的知识,希望对你有一定的参考价值。

参考技术A

常见加密方式分为以下两类:

以中后台管理项目为例:

需完善点:

设想:
鉴于AES较高的性能及RSA公私钥方式的易用性,能否结合这两者的优点实现对数据安全的保障?

以下是构思的业务流程:

这里结合Vue实现
Tip:

结合两种加密方式使用,可以满足大多数的使用场景,发挥出各自的优点。
理解AES + RSA的结合加密思路后,实现方式可根据具体情况修改。

————加密定义及分类摘自 百度百科

欢迎大家积极讨论,共同进步。
我的掘金

RSA AES 前端JS与后台JAVA的加密解密的是实现

 

 

AES CryptoJS 
前提是编码方式,key,vi中设置一样,就可以进行跨语言加密解密

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
<link rel="stylesheet" href="<%=basePath %>/css/login.css">
 
<script  src="<%=basePath %>jslib/jquery-1.8.3.js" type="text/javascript" ></script>
<script  src="<%=basePath %>jslib/Common.js" type="text/javascript" ></script>
<script  src="<%=basePath %>jslib/core-min.js" type="text/javascript" ></script>
<script  src="<%=basePath %>jslib/aes.js" type="text/javascript" ></script>
</head>
<body>
<form action="<%=basePath %>login?action=goAES" id="login" name="form" method="post">
    <h1>Log In</h1>
    <fieldset   id="inputs">
        <input  id="name"  type="text" placeholder="Username" value="" autofocus required>
        <!-- ming -->
        <input  id="pwd" name="pwd" type="password" placeholder="Password" value=""  required>
    </fieldset>
    <fieldset id="actions">
        <input type="button" id="button" onclick="go()"  value="登 录">
        <a href="#" id="msg"></a>
    </fieldset>
    <input type="hidden" name="key" id="key">
    <!-- 密钥 -->
    <input type="hidden" id="msg_source" value="0807060504030201">
</form>
 
<script type="text/javascript">
     
    function go(){
         
        if(isEmptyById([\'name\',\'pwd\'])){
            $(\'#msg\').text(\'用户名或密码不能为空\');
            return;
        }
         
        //var pwd = $("#pwd").val();
        //console.info("加密前  : "+pwd); 
        //CryptoJS.AES.encrypt(\'明文\',\'key\');
        //var ecodeRestult = CryptoJS.AES.encrypt($("#pwd").val(),$("#msg_source").val());
        //console.info("加密后  :"+ecodeRestult);
        //$("#pwd").val(ecodeRestult);
        //CryptoJS.AES.decrypt(\'密文\',\'key\').toString(CryptoJS.enc.Utf8);
        //var decodeResult = CryptoJS.AES.decrypt(ecodeRestult,$("#msg_source").val()).toString(CryptoJS.enc.Utf8);
        //console.info("解密后  :"+decodeResult);
 
        var pwd = $("#pwd").val();
        var key  = CryptoJS.enc.Utf8.parse($("#msg_source").val());  
        var iv   = CryptoJS.enc.Utf8.parse($("#msg_source").val());  
        var srcs = CryptoJS.enc.Utf8.parse(pwd); 
        var encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv,mode:CryptoJS.mode.CBC}); 
        $("#pwd").val(encrypted);
        $(\'#login\').submit();
    }
     
     
 
</script>

这里需要注意的是$("#msg_source").val();  因为key是动态的,需要从服务器提前设置好,前端AES JS加密指定是CryptoJS.mode.CBC模式,那么Java解密的同时也必须用这个模式来解密,不然会报错Given final block not properly padded...异常
AES--Java

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
package org.common.kit;
 
import org.apache.log4j.Logger;
 
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Base64;
 
public class AESKit {
    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(AESKit.class);
     
    public static final String IV = "0807060504030201";
     
    /*******************************************************************
     * AES加密算法
     * @author moyun
     * 加密用的Key 可以用26个字母和数字组成,最好不要用保留字符,虽然不会错,至于怎么裁决,个人看情况而定    此处使用AES-128-CBC加密模式,key需要为16位。
     * */
 
    //加密
    public static String Encrypt(String sSrc, String sKey) throws Exception {
 
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes();
         
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");   
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"   
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度   
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);   
        byte[] encrypted = cipher.doFinal(sSrc.getBytes()); 
         
        return Base64.encodeBase64String(encrypted);//此处使用BAES64做转码功能,同时能起到2次
    }
 
     
    //解密
    public static String Decrypt(String sSrc, String sKey) throws Exception { 
         
        // 判断Key是否正确   
        if (sKey == null) {   
            System.out.print("Key为空null");   
            return null;   
        }   
        // 判断Key是否为16位   
        if (sKey.length() != 16) {   
            System.out.print("Key长度不是16位");   
            return null;   
        }   
        byte[] raw = sKey.getBytes("ASCII");
         
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");   
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");   
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes());   
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);   
        byte[] encrypted1 = Base64.decodeBase64(sSrc);//先用bAES64解密  
        try {   
            byte[] original = cipher.doFinal(encrypted1);   
            String originalString = new String(original);   
            return originalString;   
        catch (Exception e) {   
            logger.info(e.toString());
            return null;   
        }   
    }
     
    public static void main(String[] args) throws Exception {
         
        String pwd = "世界你好";
        String epwd = Encrypt(pwd, "abcdefghijkmlnsf");
        System.out.println(epwd);
        System.out.println(Decrypt(epwd, "abcdefghijkmlnsf"));
    }
     
}

  


RSA RSAUtils js

复制代码
 1 <link rel="stylesheet" href="<%=basePath %>/css/login.css">
 2 <script src="<%=basePath %>jslib/security.js" type="text/javascript"></script>
 3 <script src="<%=basePath %>jslib/jquery-1.8.3.js" type="text/javascript" ></script>
 4 <script src="<%=basePath %>jslib/Common.js" type="text/javascript" ></script>
 5 </head>
 6 <body>
 7 
 8 <form action="<%=basePath %>login?action=go" id="login" name="form" method="post">
 9     <h1>Log In</h1>
10     <fieldset   id="inputs">
11         <input  id="name" type="text" placeholder="Username" value="" autofocus required>
12         <input  id="pwd"  type="password" placeholder="Password" value=""  required>
13     </fieldset>
14     <fieldset id="actions">
15         <input type="button" id="button" onclick="go()"  value="登 录">
16         <a href="#" id="msg"></a> 
17     </fieldset>
18     <input type="hidden" name="modulus" id="hid_modulus" value="${modulus }">
19     <input type="hidden" name="exponent" id="hid_exponent" value="${exponent }">
20     <input type="hidden" name="key" id="key">
21 </form>
22 
23 <script type="text/javascript">
24     
25     function go(){
26         
27         if(isEmptyById([\'name\',\'pwd\'])){
28             $(\'#msg\').text(\'用户名或密码不能为空\');
29              return;
30         }
31         var modulus = $(\'#hid_modulus\').val(), exponent = $(\'#hid_exponent\').val();
32         var key = RSAUtils.getKeyPair(exponent, \'\', modulus);
33         var key2="name="+$(\'#name\').val()+"&pwd="+$(\'#pwd\').val();
34         $(\'#key\').val(RSAUtils.encryptedString(key, key2));
35         $(\'#login\').submit();
36     }
37 </script>
复制代码
复制代码
  1 package org.common.kit;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileOutputStream;
  6 import java.io.ObjectInputStream;
  7 import java.io.ObjectOutputStream;
  8 import java.math.BigInteger;
  9 import java.security.InvalidParameterException;
 10 import java.security.KeyFactory;
 11 import java.security.KeyPair;
 12 import java.security.KeyPairGenerator;
 13 import java.security.NoSuchAlgorithmException;
 14 import java.security.PrivateKey;
 15 import java.security.Provider;
 16 import java.security.PublicKey;
 17 import java.security.SecureRandom;
 18 import java.security.interfaces.RSAPrivateKey;
 19 import java.security.interfaces.RSAPublicKey;
 20 import java.security.spec.InvalidKeySpecException;
 21 import java.security.spec.RSAPrivateKeySpec;
 22 import java.security.spec.RSAPublicKeySpec;
 23 import java.util.Date;
 24 
 25 import javax.crypto.Cipher;
 26 
 27 import org.apache.commons.codec.DecoderException;
 28 import org.apache.commons.codec.binary.Hex;
 29 import org.apache.commons.io.FileUtils;
 30 import org.apache.commons.io.IOUtils;
 31 import org.apache.commons.lang3.StringUtils;
 32 import org.apache.commons.lang3.time.DateFormatUtils;
 33 import org.apache.log4j.Logger;
 34 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 35 
 36 public abstract class RSA
 37 {
 38 
 39     private static final Logger LOGGER = Logger.getLogger(RSA.class);
 40     
 41     private static final String ALGORITHOM = "RSA";
 42     private static final String RSA_PAIR_FILENAME = "/__RSA_PAIR.txt";
 43     private static final int KEY_SIZE = 1024;
 44     private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
 45 
 46     private static KeyPairGenerator keyPairGen = null;
 47     private static KeyFactory keyFactory = null;
 48 
 49     private static KeyPair oneKeyPair = null;
 50 
 51     private static File rsaPairFile = null;
 52     
 53     static
 54     {
 55         try
 56         {
 57             keyPairGen = KeyPairGenerator.getInstance("RSA", DEFAULT_PROVIDER);
 58             keyFactory = KeyFactory.getInstance("RSA", DEFAULT_PROVIDER);
 59         } catch (NoSuchAlgorithmException ex)
 60         {
 61             LOGGER.error(ex.getMessage());
 62         }
 63         rsaPairFile = new File(getRSAPairFilePath());
 64     }
 65 
 66     /***
 67      * 
 68      * 返回 解码后的 username pwd
 69      * 
 70      * add by 12
 71      * 
 72      * @param key
 73      * @return
 74      */
 75     public static String[] decryptUsernameAndPwd(String key)
 76     {
 77 
 78         key = RSA.decryptStringByJs(key);
 79 
 80         try
 81         {
 82             String username = key.substring(key.indexOf("=") + 1, key.indexOf("&"));
 83             String pwd = key.substring(key.lastIndexOf("=") + 1, key.length());
 84             return new String[] { username, pwd };
 85         } catch (Exception e)
 86         {
 87             return null;
 88         }
 89 
 90     }
 91 
 92     private static synchronized KeyPair generateKeyPair()
 93     {
 94         try
 95         {
 96             keyPairGen.initialize(1024, new SecureRandom(DateFormatUtils.format(new Date(), "yyyyMMdd").getBytes()));
 97             oneKeyPair = keyPairGen.generateKeyPair();
 98             saveKeyPair(oneKeyPair);
 99             return oneKeyPair;
100         } catch (InvalidParameterException ex)
101         {
102             LOGGER.error("KeyPairGenerator does not support a key length of 1024.", ex);
103         } catch (NullPointerException ex)
104         {
105             LOGGER.error("RSAUtils#KEY_PAIR_GEN is null, can not generate KeyPairGenerator instance.", ex);
106         }
107         return null;
108     }
109 
110     private static String getRSAPairFilePath()
111     {
112         String urlPath = RSA.class.getResource("/").getPath();
113         String str = new File(urlPath).getParent() + "/__RSA_PAIR.txt";
114 
115         urlPath = null;
116 
117         return str;
118     }
119 
120     private static boolean isCreateKeyPairFile()
121     {
122         boolean createNewKeyPair = false;
123         if ((!rsaPairFile.exists()) || (rsaPairFile.isDirectory()))
124         {
125             createNewKeyPair = true;
126         }
127         return createNewKeyPair;
128     }
129 
130     private static void saveKeyPair(KeyPair keyPair)
131     {
132         FileOutputStream fos = null;
133         ObjectOutputStream oos = null;
134         try
135         {
136             fos = FileUtils.openOutputStream(rsaPairFile);
137             oos = new ObjectOutputStream(fos);
138             oos.writeObject(keyPair);
139         } catch (Exception ex)
140         {
141             ex.printStackTrace();
142         } finally
143         {
144             IOUtils.closeQuietly(oos);
145             IOUtils.closeQuietly(fos);
146         }
147 
148         fos = null;
149         oos = null;
150     }
151 
152     public static KeyPair getKeyPair()
153     {
154         if (isCreateKeyPairFile()) { return generateKeyPair(); }
155         if (oneKeyPair != null) { return oneKeyPair; }
156         return readKeyPair();
157     }
158 
159     private static KeyPair readKeyPair()
160     {
161         FileInputStream fis = null;
162         ObjectInputStream ois = null;
163         try
164         {
165             fis = FileUtils.openInputStream(rsaPairFile);
166             ois = new ObjectInputStream(fis);
167             oneKeyPair = (KeyPair) ois.readObject();
168             return oneKeyPair;
169         } catch (Exception ex)
170         {
171             ex.printStackTrace();
172         } finally
173         {
174             IOUtils.closeQuietly(ois);
175             IOUtils.closeQuietly(fis);
176         }
177 
178         fis = null;
179         ois = null;
180         return null;
181     }
182 
183     public static RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent)
184     {
185         RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));
186         try
187         {
188             return (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
189         } catch (InvalidKeySpecException ex)
190         {
191             LOGGER.error("RSAPublicKeySpec is unavailable.", ex);
192         } catch (NullPointerException ex)
193         {
194             LOGGER.error("RSAUtils#KEY_FACTORY is null, can not generate KeyFactory instance.", ex);
195         }
196         publicKeySpec = null;
197         modulus = (byte[]) null;
198         publicExponent = (byte[]) null;
199         return null;
200     }
201 
202     public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent)
203     {
204         RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger(modulus), new BigInteger(privateExponent));
205         try
206         {
207             return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
208         } catch (InvalidKeySpecException ex)
209         {
210             LOGGER.error("RSAPrivateKeySpec is unavailable.", ex);
211         } catch (NullPointerException ex)
212         {
213             LOGGER.error("RSAUtils#KEY_FACTORY is null, can not generate KeyFactory instance.", ex);
214         }
215         privateKeySpec = null;
216         modulus = (byte[]) null;
217         privateExponent = (byte[]) null;
218         return null;
219     }
220 
221     public static RSAPrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent)
222     {
223         if ((StringUtils.isBlank(hexModulus)) || (StringUtils.isBlank(hexPrivateExponent)))
224         {
225             if (LOGGER.isDebugEnabled())
226             {
227                 LOGGER.debug("hexModulus and hexPrivateExponent cannot be empty. RSAPrivateKey value is null to return.");
228             }
229             return null;
230         }
231         byte[] modulus = (byte[]) null;
232         byte[] privateExponent = (byte[]) null;
233         try
234         {
235             modulus = Hex.decodeHex(hexModulus.toCharArray());
236             privateExponent = Hex.decodeHex(hexPrivateExponent.toCharArray());
237         } catch (DecoderException ex)
238         {
239             LOGGER.error("hexModulus or hexPrivateExponent value is invalid. return null(RSAPrivateKey).");
240         }
241         if ((modulus != null) && (privateExponent != null)) { return generateRSAPrivateKey(modulus, privateExponent); }
242         return null;
243     }
244 
245     public static RSAPublicKey getRSAPublidKey(String hexModulus, String hexPublicExponent)
246     {
247         if ((StringUtils.isBlank(hexModulus)) || (StringUtils.isBlank(hexPublicExponent)))
248         {
249             if (LOGGER.isDebugEnabled())
250             {
251                 LOGGER.debug("hexModulus and hexPublicExponent cannot be empty. return null(RSAPublicKey).");
252             }
253             return null;
254         }
255         byte[] modulus = (byte[]) null;
256         byte[] publicExponent = (byte[]) null;
257         try
258         {
259             modulus = Hex.decodeHex(hexModulus.toCharArray());
260             publicExponent = Hex.decodeHex(hexPublicExponent.toCharArray());
261         } catch (DecoderException ex)
262         {
263             LOGGER.error("hexModulus or hexPublicExponent value is invalid. return null(RSAPublicKey).");
264         }
265         if ((modulus != null) && (publicExponent != null)) { return generateRSAPublicKey(modulus, publicExponent); }
266         return null;
267     }
268 
269     public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception
270     {
271         Cipher ci = Cipher.getInstance("RSA", DEFAULT_PROVIDER);
272         ci.init(1, publicKey);
273         return ci.doFinal(data);
274     }
275 
276     public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception
277     {
278         Cipher ci = Cipher.getInstance("RSA", DEFAULT_PROVIDER);
279         ci.init(2, privateKey);
280         return ci.doFinal(data);
281     }
282 
283     public static String encryptString(PublicKey publicKey, String plaintext)
284     {
285         if ((publicKey == null) || (plaintext == null)) { return null; }
286         byte[] data = plaintext.getBytes();
287         try
288         {
289             byte[] en_data = encrypt(publicKey, data);
290             return new String(Hex.encodeHex(en_data));
291         } catch (Exception ex)
292         {
293             LOGGER.error(ex.getCause().getMessage());
294         }
295         return null;
296     }
297 
298     public static String encryptString(String plaintext)
299     {
300         if (plaintext == null) { return null; }
301         byte[] data = plaintext.getBytes();
302         KeyPair keyPair = getKeyPair();
303         try
304         {
305             byte[] en_data = encrypt((RSAPublicKey) keyPair.getPublic(), data);
306             return new String(Hex.encodeHex(en_data));
307         } catch (NullPointerException ex)
308         {
309             LOGGER.error("keyPair cannot be null.");
310         } catch (Exception ex)
311         {
312             LOGGER.error(ex.getCause().getMessage());
313         }
314         return null;
315     }
316 
317     public static String decryptString(PrivateKey privateKey, String encrypttext)
318     {
319         if ((privateKey == null) || (StringUtils.isBlank(encrypttext))) return null;
320         try
321         {
322             byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
323             byte[] data = decrypt(privateKey, en_data);
324             return new String(data);
325         } catch (Exception ex)
326         {
327             LOGGER.error(String.format("\\"%s\\" Decryption failed. Cause: %s", new Object[] { encrypttext, ex.getCause().getMessage() }));
328         }
329         return null;
330     }
331 
332     public static String decryptString(String encrypttext)
333     {
334         if (StringUtils.isBlank(encrypttext)) { return null; }
335         KeyPair keyPair = getKeyPair();
336         try
337         {
338             byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
339             byte[] data = decrypt((RSAPrivateKey) keyPair.getPrivate(), en_data);
340             return new String(data);
341         } catch (NullPointerException ex)
342         {
343             LOGGER.error("keyPair cannot be null.");
344         } catch (Exception ex)
345         {
346             LOGGER.error(String.format("\\"%s\\" Decryption failed. Cause: %s", new Object[] { encrypttext, ex.getMessage() }));
347         }
348         return null;
349     }
350 
351     public static String decryptStringByJs(String encrypttext)
352     {
353         String text = decryptString(encrypttext);
354         if (text == null) { return null; }
355         return StringUtils.reverse(text);
356     }
357 
358     public static RSAPublicKey getDefaultPublicKey()
359     {
360         KeyPair keyPair = getKeyPair();
361         if (keyPair != null) { return (RSAPublicKey) keyPair.getPublic(); }
362         return null;
363     }
364 
365     public static RSAPrivateKey getDefaultPrivateKey()
366     {
367         KeyPair keyPair = getKeyPair();
368         if (keyPair != null) { return (RSAPrivateKey) keyPair.getPrivate(); }
369         return null;
370     }
371 }
复制代码

 

以上是关于前端AES + RSA加密的主要内容,如果未能解决你的问题,请参考以下文章

RSA AES 前端JS与后台JAVA的加密解密的是实现

基于RSA+AES实现前后端(VUE+PHP)参数加密传输

rsa加密前后端不一致

RSA+AES请求组合加密

uniapp接口层的aes和rsa的对称与非对称加密

前后端交互数据加解密