前後端java+vue 實現rsa 加解密與摘要簽名演算法

RSA 加密、解密、簽名、驗簽、摘要,前後端java+vue聯調測試通過

直接上程式碼

// 注意:加密密文與簽名都是唯一的,不會變化。
// 注意:vue 端密鑰都要帶pem格式。java 不要帶pem格式
// 注意:vue端及java端函數參數、返回值要求是什麼類型及何進位。搞明白哪裡用base64,哪裡2進位,哪裡16進位。
// 重點還是要了解點原理,比如sha1withrsa,先經過sha1演算法,知道aaa,哈希後的密文16進位是:7e240de74fb1ed08fa08d38063f6a6a91462a815,對比自己的程式有沒有算錯。
// 利用一些在線測試工具幫忙驗證自己的程式過程。//www.metools.info/code/c82.html ; 同時知道如何查引入的類庫各api的官網,了解如何使用各函數。
// 不然遇到莫名奇妙的錯誤無從解決。報錯的地方不一定是程式實際錯誤的地方。了解查錯的方式有:打庄、debug.

伺服器端java:

工具類,rsa加解密,RsaUtil.java

  1 package com.ruoyi.common.utils.enDeCrypt;
  2 
  3 import com.ruoyi.common.core.text.Convert;
  4 import com.ruoyi.common.exception.UtilException;
  5 
  6 import java.io.ByteArrayOutputStream;
  7 import java.io.UnsupportedEncodingException;
  8 import java.security.*;
  9 import java.util.Base64;
 10 import javax.crypto.Cipher;
 11 import java.security.interfaces.RSAPrivateKey;
 12 import java.security.interfaces.RSAPublicKey;
 13 import java.security.spec.PKCS8EncodedKeySpec;
 14 import java.security.spec.X509EncodedKeySpec;
 15 import java.util.HashMap;
 16 import java.util.Map;
 17 
 18 import static io.netty.util.CharsetUtil.UTF_8;
 19 
 20 
 21 /** 加密和解密花費時間長、速度慢,故使用RSA只能加密少量數據,大量的數據加密還要靠對稱密碼演算法。
 22  * 第一種用法是公鑰加密、私鑰解密——用於加密;第二種是私鑰簽名、公鑰驗簽——用於簽名
 23  * @author EvianZou
 24  */
 25 public class RsaUtil {
 26 
 27     /**
 28      * 密鑰長度與原文長度對應,越長速度越慢
 29      * 1024bit 密鑰 能加密明文最大的長度是 1024/8 -11 = 117 byte
 30      * 2048bit 密鑰 能加密明文最大的長度是 2048/8 -11 = 245 byte
 31      */
 32     private final static int KEY_SIZE = 1024;
 33     /*
 34      * RSA演算法 RSA-1024位 RSA2-2048位
 35      */
 36     private final static String ALGORITHM = "RSA";
 37     //java默認"RSA"="RSA/ECB/PKCS1Padding"
 38     private final static String PADDING_MODE = "RSA";
 39 
 40     /*
 41      * 簽名演算法
 42      * RSA: 常用 SHA1WithRSA,有 MD2withRSA、MD5withRSA、SHA1withRSA;
 43      * RSA2:  常用:SHA256WithRSA,有 SHA224withRSA、SHA256withRSA、SHA384withRSA、SHA512withRSA 、RIPEMD128withRSA、RIPEMD160withRSA;
 44      */
 45     public static final String SIGN_ALGORITHM = "SHA1withRSA";
 46 
 47     /*
 48      * 字元編碼
 49      */
 50     private final static String ENCODING = "UTF-8";
 51 
 52     /*
 53      * RSA最大加密明文大小
 54      * RSA:117
 55      * RSA2:245
 56      */
 57     private static final int MAX_ENCRYPT_BLOCK = 117;
 58 
 59     /*
 60      * RSA最大解密密文大小
 61      * RSA:128
 62      * RSA2:256
 63      */
 64     private static final int MAX_DECRYPT_BLOCK = 128;
 65 
 66     public Map<String, String> getKeyMap() {
 67         return keyMap;
 68     }
 69 
 70     public void setKeyMap(Map<String, String> keyMap) {
 71         this.keyMap = keyMap;
 72     }
 73 
 74     /**
 75      * 用於封裝隨機產生的公鑰與私鑰
 76      */
 77     private Map<String, String> keyMap;
 78 
 79 
 80     public RsaUtil(boolean isKeyBase64) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchProviderException {
 81         setKeyMap(generateKeyPair(isKeyBase64));
 82     }
 83 
 84     /**
 85      * 隨機生成密鑰對
 86       * @param isKeyBase64 密鑰base64加密為true,hex為false
 87      */
 88     private Map<String, String> generateKeyPair(boolean isKeyBase64) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchProviderException {
 89         // KeyPairGenerator類用於生成公鑰和私鑰對,基於RSA演算法生成對象
 90         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
 91         // 初始化密鑰對生成器
 92         keyPairGen.initialize(KEY_SIZE, new SecureRandom());
 93         // 生成一個密鑰對,保存在keyPair中
 94         KeyPair keyPair = keyPairGen.generateKeyPair();
 95         // 得到私鑰
 96         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
 97         // 得到公鑰
 98         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
 99         String publicKeyString = isKeyBase64 ? Base64.getEncoder().encodeToString(publicKey.getEncoded()) : Convert.bytesToHex(publicKey.getEncoded());
100 
101         // 得到私鑰字元串
102         String privateKeyString = isKeyBase64 ? Base64.getEncoder().encodeToString(privateKey.getEncoded()) : Convert.bytesToHex(privateKey.getEncoded());
103         // 將公鑰和私鑰保存到Map
104         Map<String, String> map = new HashMap<>(32);
105         //表示公鑰
106         map.put("publicKey", publicKeyString);
107         //表示私鑰
108         map.put("privateKey", privateKeyString);
109 
110         return map;
111     }
112 
113     /**
114      * 流程1:RSA公鑰加密,再BASE64加密,再base64解密,再RSA私鑰解密
115      * 流程2:RSA私鑰加密,再BASE64加密,再base64解密,再RSA公鑰解密
116      *
117      * @param text        加密字元串/解密字元串
118      * @param secretKey   加密秘鑰
119      * @param isPublicKey 公鑰/私鑰
120      * @param isEncrypt   加密/解密
121      * @param isKeyBase64 密鑰base64加密為true,hex為false
122      * @param isTextBase64 密文base64加密為true,hex為false
123      * @param isUrlCode 密文urlencode為true,否則為false
124      * @return 密文/明文
125      * @throws Exception 加密過程中的異常資訊
126      */
127     private String enDecrypt(String text, String secretKey, boolean isPublicKey, boolean isEncrypt, boolean isKeyBase64, boolean isTextBase64, boolean isUrlCode) throws Exception {
128         //base64編碼的秘鑰
129         byte[] decodedKey = isKeyBase64 ? Base64.getDecoder().decode(secretKey.getBytes(ENCODING)) : Convert.hexToByteArray(secretKey);
130         byte[] decodeText;
131         int encodeMode = 0;
132         int max_block = 0;
133         int textLength = 0;
134         Cipher cipher = Cipher.getInstance(PADDING_MODE);
135         UrlCode urlCode = new UrlCode();
136 
137 
138         if (isEncrypt) {
139             encodeMode = Cipher.ENCRYPT_MODE;
140             max_block = MAX_ENCRYPT_BLOCK;
141             //待加密字元串
142             decodeText = text.getBytes(ENCODING);
143             textLength = text.getBytes(ENCODING).length;
144         } else {
145             encodeMode = Cipher.DECRYPT_MODE;
146             max_block = MAX_DECRYPT_BLOCK;
147             decodeText = isUrlCode ? urlCode.decodeURL(text, UTF_8).getBytes(ENCODING) : text.getBytes(ENCODING);
148             // 注意:byte[]轉String,不能 byte[].toString(); 可用new String(byte[])
149             decodeText = isTextBase64 ? Base64.getDecoder().decode(decodeText) : Convert.hexToByteArray(new String(decodeText, ENCODING));
150             textLength = decodeText.length;
151         }
152 
153         if (isPublicKey) {
154             cipher.init(encodeMode, (RSAPublicKey) KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(decodedKey)));
155         } else {
156             cipher.init(encodeMode, (RSAPrivateKey) KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decodedKey)));
157         }
158 
159         ByteArrayOutputStream out = new ByteArrayOutputStream();
160         int offSet = 0;
161         byte[] cache;
162         int i = 0;
163         // 對數據分段加密
164         while (textLength - offSet > 0) {
165             if (textLength - offSet > max_block) {
166                 cache = cipher.doFinal(decodeText, offSet, max_block);
167             } else {
168                 cache = cipher.doFinal(decodeText, offSet, textLength - offSet);
169             }
170             out.write(cache, 0, cache.length);
171             i++;
172             offSet = i * max_block;
173         }
174         byte[] byteText = out.toByteArray();
175         out.close();
176 
177         String resultText = out.toString();
178         if (isEncrypt) {
179             resultText = isTextBase64 ? Base64.getEncoder().encodeToString(byteText) : Convert.bytesToHex(byteText);
180             resultText = isUrlCode ? urlCode.encodeURL(resultText, UTF_8) : resultText;
181         }
182 
183         return resultText;
184     }
185     
186     public String encryptByPublicKey(String plainText, String publicKey, boolean isKeyBase64, boolean isTextBase64, boolean isUrlCode) throws Exception {
187         return enDecrypt(plainText, publicKey, true, true, isKeyBase64, isTextBase64, isUrlCode);
188     }
189 
190     public String decryptByPrivateKey(String cipherText, String privateKey, boolean isKeyBase64, boolean isTextBase64, boolean isUrlCode) throws Exception {
191         return enDecrypt(cipherText, privateKey, false, false, isKeyBase64, isTextBase64, isUrlCode);
192     }
193     
194     /**
195      * RSA簽名
196      *
197      * @param signText   待簽名數據
198      * @param privateKey 私鑰
199      * @param isKeyBase64 密鑰base64加密為true,hex為false
200      * @param isTextBase64 密文base64加密為true,hex為false
201      * @param isUrlCode 密文urlencode為true,否則為false
202      * @return 簽名值
203      */
204     public String signByPrivateKey(String signText, String privateKey, boolean isKeyBase64, boolean isTextBase64, boolean isUrlCode) throws Exception {
205         try {
206             KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
207             byte[] decodeKey = isKeyBase64 ? Base64.getDecoder().decode(privateKey) : Convert.hexToByteArray(privateKey);
208 
209             PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(decodeKey);
210             //DER input, Integer tag error ,原因密鑰錯誤
211             PrivateKey private_key = (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
212             Signature signature = Signature.getInstance(SIGN_ALGORITHM);
213             signature.initSign(private_key);
214 
215             String  sign_text = isTextBase64?Convert.bytesToHexString(Base64.getDecoder().decode(signText.getBytes(ENCODING))):signText;
216            //  System.out.println("伺服器端:待簽名數據:"+sign_text);
217 
218             assert sign_text != null;
219             byte[] digestText = genDigest(sign_text,SIGN_ALGORITHM );
220 
221             // 生成消息摘要 因客戶端簽名時參數為16進位, 可以通過加密演算法驗證是否正確
222             signature.update(Convert.bytesToHexString(digestText).getBytes(ENCODING));
223             // System.out.println("伺服器端:摘要數據:"+new String(digestText));
224 
225             byte[] signedByte = signature.sign();
226             // System.out.println("伺服器端:簽名數據:"+Convert.bytesToHexString(signedByte));
227 
228             UrlCode urlCode = new UrlCode();
229 
230             String signedText = isTextBase64 ? Base64.getEncoder().encodeToString(signedByte) : Convert.bytesToHex(signedByte);
231             signedText = isUrlCode ? urlCode.encodeURL(signedText, UTF_8) : signedText;
232 
233             return signedText;
234 
235         } catch (Exception e) {
236             throw new UtilException(e.getMessage());
237         }
238     }
239 
240 
241     /*
242      * 生成消息摘要
243      */
244     public byte[] genDigest(String plainText, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException {
245 
246         MessageDigest messageDigest = MessageDigest.getInstance(algorithm.split("w")[0]);
247       //  System.out.println("伺服器端,哈希演算法:"+algorithm.split("w")[0]);
248         byte []  digestText = messageDigest.digest(plainText.getBytes(ENCODING));
249        // System.out.println("伺服器端,摘要:"+bytesToHexString(digestText));
250         return digestText;
251     }
252 
253     /**
254      * RSA驗簽名檢查
255      *
256      * @param signText   待簽名數據
257      * @param signedText 已簽名數據
258      * @param publicKey  公鑰
259      * @param isKeyBase64 密鑰base64加密為true,hex為false
260      * @param isTextBase64 密文base64加密為true,hex為false
261      * @param isUrlCode 密文urlencode為true,否則為false
262      * @return 布爾值
263      */
264     public boolean verifySignPublicKey(String signText, String signedText, String publicKey, boolean isKeyBase64, boolean isTextBase64, boolean isUrlCode) throws Exception {
265         boolean isVerified;
266         try {
267             KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
268             byte[] decodedKey = isKeyBase64 ? Base64.getDecoder().decode(publicKey) : Convert.hexToByteArray(publicKey);
269             PublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
270             Signature signature = Signature.getInstance(SIGN_ALGORITHM);
271 
272             signature.initVerify(pubKey);
273 
274             signText = isTextBase64?Convert.bytesToHexString( Base64.getDecoder().decode(signText.getBytes(ENCODING))) :signText;
275             // 生成消息摘要
276             assert signText != null;
277            // System.out.println("驗證,待簽名數據:"+signText);
278 
279             byte[] digestText = genDigest(signText,SIGN_ALGORITHM );
280             // 生成消息摘要
281             signature.update(Convert.bytesToHexString(digestText).getBytes(ENCODING));
282 
283             UrlCode urlCode = new UrlCode();
284             String decodeText = isUrlCode ? urlCode.decodeURL(signedText, UTF_8) : signedText;
285             byte[] bytesText = isTextBase64 ? Base64.getDecoder().decode(decodeText) : Convert.hexToByteArray(decodeText);
286 
287             //DER input, Integer tag error ,或 DerInputStream.getLength(): lengthTag=111, too big.原因密鑰錯誤
288             isVerified = signature.verify(bytesText);
289 
290         } catch (Exception e) {
291             throw new UtilException(e.getMessage());
292         }
293         return isVerified;
294     }
295 
296 
297     // PKCS#1 與PKCS#8 格式轉換
298     // 帶頭和尾的密鑰,去掉頭和尾後,再按指定格式增加頭和尾
299     public Map<String,String> convertKeyFormat(Map<String,String> mapSource,String keyMode)
300     {
301         Map<String,String> map = removeHeaderAndBottom(mapSource,keyMode);
302         map = formatKey (map,keyMode);
303 
304         return map;
305     }
306 
307     public Map<String,String>   removeHeaderAndBottom (Map<String,String> mapSource,String keyMode)
308     {
309         Map<String,String> map = new HashMap<>();
310         Map<String,String> mapHeaderAndBottom_publicKey = genKeyHeaderAndBottom(keyMode,false);
311         Map<String,String> mapHeaderAndBottom_privateKey  = genKeyHeaderAndBottom(keyMode,true);
312 
313         String privateKey = mapSource.get("privateKey");
314         String publicKey =  mapSource.get("publicKey");
315 
316         publicKey =  publicKey.replaceAll(mapHeaderAndBottom_publicKey.get("header"),"");
317         publicKey = publicKey.replaceAll(mapHeaderAndBottom_publicKey.get("bottom"),"");
318 
319         privateKey=privateKey.replaceAll(mapHeaderAndBottom_privateKey.get("header"),"");
320         privateKey= privateKey.replaceAll(mapHeaderAndBottom_privateKey.get("bottom"),"");
321 
322         map.put("publicKey",publicKey);
323         map.put("privateKey",privateKey);
324 
325         return map;
326     }
327 
328     // 不帶頭和尾的密鑰,按指定格式增加頭和尾
329     public  Map<String,String> formatKey( Map<String,String> mapSource, String keyMode)
330     {
331         Map<String,String> map = new HashMap<>();
332 
333         map.put("publicKey", formatKey(mapSource.get("publicKey"),keyMode,false));
334         map.put("privateKey", formatKey(mapSource.get("privateKey"),keyMode,true));
335 
336         return map;
337     }
338 
339     // 格式化key,增加頭和尾
340     private  String formatKey( String  keyBody, String keyMode,boolean isPrivateKey )
341     {
342         Map<String,String> map = genKeyHeaderAndBottom(keyMode,isPrivateKey);
343         String keyHeader = map.get("header");
344         String keyBottom =map.get("bottom");
345         String  strKey = keyHeader + "\n";
346 
347         int nPrivateKeyLen = keyBody.length();
348         char[] status = keyBody.toCharArray();
349         for(int i = 64; i < nPrivateKeyLen; i+=64)
350         {
351             if(status[i] != '\n')
352             {
353                 status[i]= '\n';
354             }
355             i++;
356         }
357         strKey += String.valueOf(status);
358         strKey += "\n";
359         strKey += keyBottom;
360         strKey += "\n";
361 
362         return strKey;
363     }
364 
365     // 按指定格式生成頭和尾
366     public Map<String,String> genKeyHeaderAndBottom(String keyMode,boolean isPrivateKey)
367     {
368         Map<String,String> map = new HashMap<>();
369         if (keyMode == "PKCS#1") {
370             if (isPrivateKey) {
371                 map.put("header", "-----BEGIN RSA PRIVATE KEY-----");
372             } else {
373                 map.put("header", "-----BEGIN RSA PUBLIC KEY-----");
374             }
375             if (isPrivateKey) {
376                 map.put("bottom", "-----END RSA PRIVATE KEY-----");
377             } else {
378                 map.put("bottom", "-----END RSA PUBLIC KEY-----");
379             }
380         }
381         else if (keyMode == "PKCS#8") {
382             if (isPrivateKey) {
383                 map.put("header", "-----BEGIN PRIVATE KEY-----");
384             } else {
385                 map.put("header", "-----BEGIN PUBLIC KEY-----");
386             }
387             if (isPrivateKey) {
388                 map.put("bottom", "-----END PRIVATE KEY-----");
389             } else {
390                 map.put("bottom", "-----END PUBLIC KEY-----");
391             }
392         }
393         return map;
394     }
395 }

View Code

測試使用流程方法

 1  public static void testRSAflow() throws Exception {
 2 
 3         // 測試前後端使用流程
 4         // 1、後端生成密鑰對,公鑰分享給前端,前端獲取到伺服器給的公鑰。
 5         // 2、前端用伺服器端給的公鑰 及演算法:RSA/CBC/PKCS1Padding 加密"xhy 我愛你 中國 依芸Yiyun !!!" 生成加密數據。
 6         // 3、前端然後生成自己的密鑰對,用自己的私鑰及演算法SHA1withRSA生成摘要簽名。
 7         // 4、前端把加密數據、自己的公鑰與簽名一併發給後端。
 8         // 3、後端收到加密數據、簽名數據、前端的公鑰,先用前端公鑰、簽名數據、演算法SHA1withRSA 驗簽,驗簽通過後再用後端的私鑰、演算法:RSA/CBC/PKCS7Padding 解密數據。
 9         // 注意:密鑰與密文全部base64編碼
10 
11         RsaUtil rsaUtil = new RsaUtil(true);
12 
13         String  privateKey_s = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIfKRPRzS0a9Rg1LQizkfIL1ciAMEFs45tl49ERuwIA1kcUrtB1Cjj3bKMLO0Sp7992ECOWVZsE6DZPle3kVYFufIBT4pjR1oJqRs4Z9g5bkwY6p743eGnT1pxri5LNqBdevlKsjqwcfIdOhIqz2BaeM3PT1O52PI9e+U40XEri7AgMBAAECgYAmNYNLqbmP0SiKCxg226AxlXEklWBw2sUSgpdxPhzKtsgqzA5lgVnXC/kfP+TZaIKpgUKjn3OHgZdae2NQAfTXxTcvhNGYSOeJ8VgslQueoJW7ypgQ/IoNy2DeglObAJ3uCgA4F566j6H7IvcllKGmDT/6PUlljxZJpBMfslspgQJBAP19EMRxmV4vYL7o55oR397UEUXn3vO88SPo2gxaPZ/ltzgaHM5R1zALPE1EfPIPqVdGf2hcowr22pC1BG+nlXsCQQCJIq4USfgNmjGwquo5PyksQ9vsYc/OxGBxEqTpVez24eJb7tvoqvbYfpleeEyWgtvzHqnlY24QdONhVVm5zOXBAkAxt7PwM6+3D2fUSe4TA+p60/FHWsEZ4TcSqfsKbTClCfMzp7t6pAamv61mIka3W2cFXShkGbdI0T3xH+/szlu9AkBi3SSgrd7td39hPSaU1MsLBXT0SmO1Te+1NNq8+VxXc+trmZzidPZ2h3ZsG9AjJf4JnM6g9/iuVoZiclS4VVZBAkEAsPkIGRvX4Nj3ljiBjgdJ68JRZC3gK/kXLNeefIeHg6F/4eyg729PlfdD2mvPb8hiszvsT1zvF8gvxGi4lT6B/w==" ;
14         String  publicKey_s = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHykT0c0tGvUYNS0Is5HyC9XIgDBBbOObZePREbsCANZHFK7QdQo492yjCztEqe/fdhAjllWbBOg2T5Xt5FWBbnyAU+KY0daCakbOGfYOW5MGOqe+N3hp09aca4uSzagXXr5SrI6sHHyHToSKs9gWnjNz09TudjyPXvlONFxK4uwIDAQAB";
15         String  publicKey_c ="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQPgskvyi9D/IuD0x73M2UOxBH3daAGbxLfUiSraG3cEgZCp7/o1RKM/Uckoplw/DDD665je4wVc0R2zZ8E9LQrrHvvVgddaCvaFZkcIno4EVtHCLldKOFzAIr8ucxCHelV9oGhrcCmeGwYnVTeXOerY9iFi2KDWwF30e2PHRpRQIDAQAB";
16 
17         // publicKey_s = rsaUtil.getKeyMap().get("publicKey");
18         // privateKey_s =rsaUtil.getKeyMap().get("privateKey");
19         System.out.println("<--- 1 --->伺服器端生成公鑰:" +publicKey_s );
20         // System.out.println("<--- 1 --->伺服器端生成私鑰:"+ privateKey_s);
21         System.out.println("<--- 1 --->伺服器端生成私鑰,不公開");
22         System.out.println("<--- 2 --->客戶端獲取到伺服器端給定的公鑰:"+ publicKey_s);
23         System.out.println("<--- 3 --->客戶端用此公鑰執行加密,加密原始數據:xhy 我愛你 中國 依芸Yiyun !!!");
24 
25         // 客戶端用伺服器端的公鑰生成的密文
26         String cipherText_c ="eCOu/WkaQ8tZHk2u+Y9bh6RKOVMQGsssjnQB5DVlUeDPhjiIybeQSe7JH7fG5FgsucCi6uFwdU7yWzmkJFmMKGnE1pGLReqSaWgecviSTl1P4jjrq84VJvreoeCmcNUCoqxQvmYuMxB/D4rZ+PTuv0B2sQ4Q5fOH6fbqoj3uD5w=";
27         cipherText_c ="MoYui9R3RZ+OYamuTvwAGWy2u8rllBQpjGzTXzje9aUM/KiD5nt8DYf1wna5a7DkBYpZ0CRVNHtOHiHgmrheBkpLuAXdh58eVn2hFLn0xCXqIRk+yEZSrF8fHJ7EBhE00WcyfqOoAM+uum57DFxtvATcEnFiEdkRb32JWkumdIY=";
28         System.out.println("<--- 3 --->客戶端生成的加密數據:"+cipherText_c);
29         System.out.println("<--- 4 --->客戶端生成自己的公鑰:"+ publicKey_c);
30        // System.out.println("<--- 4 --->客戶端生成自己的私鑰:"+ privateKey_c);
31         System.out.println("<--- 4 --->客戶端生成自己的私鑰,不公開");
32 
33         // 客戶端利用自己的私鑰生成摘要後進行的簽名
34         String  signedText_c = "uFy+PqjxdxusV5+a9VR0cvk1XY0+Th8jWBT581irWVEDyzq00xGphQ8KIyApgvPw5+KP1DB/M7tMfd0viUT4w8i4VcyhGmRlk0XNkuRhQDgcWeZ5XKIoJ1ORQ0ecxcAAAAlPwMe2wCbPClXFmhJzypJtS7nKFzE/oeZg7nr91zg=";
35         signedText_c ="reCyRzzxeo1i269BdV5TBrYqiYNyWEmk+i6Oxq/0MJz581tThBikh6/Z+hTZ3vY03UngoXwxB7pZBPW7FUxtwdqS8FcKtlVShaz0ZwU22BHbqFBvCvr4C224HQAdNeVoeHb3o8O/DEjNruUzM1NkweLqayI0unieRYxebvCweTE=";
36         System.out.println("<--- 4 --->客戶端利用自己的私鑰生成摘要而後簽名數據:"+signedText_c);
37         System.out.println("<--- 5 --->客戶端發送數據至伺服器端,1自己的公鑰,2自己的加密數據,3自己的簽名數據");
38         System.out.println("<--- 6 --->伺服器端接收到來自客戶端的數據:1客戶端的公鑰,2客戶端的加密數據,3客戶端的簽名數據");
39         System.out.println("<--- 6 --->1客戶端的公鑰:"+publicKey_c);
40         System.out.println("<--- 6 --->2客戶端的加密數據:"+cipherText_c);
41         System.out.println("<--- 6 --->2客戶端的簽名數據:"+signedText_c);
42 
43         boolean isPassed = rsaUtil.verifySignPublicKey(cipherText_c, signedText_c, publicKey_c, true,true,false);
44         System.out.println("<--- 7 --->伺服器端用自己的公鑰進行簽名驗證,結果:"+isPassed);
45         if (isPassed)
46         {
47             System.out.println("<--- 8 --->伺服器端驗簽成功,開始解密數據...");
48 
49             String  plainText = "";
50             plainText = rsaUtil.decryptByPrivateKey(cipherText_c,privateKey_s,true,true,false);
51 
52             System.out.println("<--- 9 --->伺服器端解密數據成功:"+ plainText);
53         }
54 
55         /* 測試程式碼
56         // 伺服器端用伺服器端的公鑰生成的密文
57         String cipherText_s ="";
58         String plainText = "xhy 我愛你 中國 依芸Yiyun !!!";
59         cipherText_s = rsaUtil.encryptByPublicKey(plainText, publicKey_s,true, true,false);
60         System.out.println("伺服器端執行加密,公鑰加密:"+cipherText_s);
61 
62         // 伺服器端利用客戶端的私鑰進行簽名
63         String  signedText_s = rsaUtil.signByPrivateKey(cipherText_c, privateKey_c,true, true,false);
64         System.out.println("伺服器端執行簽名,私鑰簽名:"+signedText_s);
65         */
66 
67           /* String  privateKey_c = "MIICXAIBAAKBgQDQPgskvyi9D/IuD0x73M2UOxBH3daAGbxLfUiSraG3cEgZCp7/o1RKM/Uckoplw/DDD665je4wVc0R2zZ8E9LQrrHvvVgddaCvaFZkcIno4EVtHCLldKOFzAIr8ucxCHelV9oGhrcCmeGwYnVTeXOerY9iFi2KDWwF30e2PHRpRQIDAQABAoGARuvaf7la9ojnwigTtFuO6Fz1PoSe+SHKrysL/GiGGyNyapTjccz+eAcaA5Ek8WO6K7S7nRZpeKzAGsS92aQmt66BpOqI+JJ2uM+K1HzH5K5rQ4rnaC/Hbd+4zsltVzuLbsICDGSlkpTSKK5YdIkA5YPMXoQek4zoYpUnKT2AxEECQQDoDrjIJ4MllIpc" +
68                 "gAWjahga1YrcTIcQPBwG9rfX7zk2nKFZF5rOB6iDHjE9mo9EOD/s7j3Z5eefwVkp" +
69                 "hRnbXJp3AkEA5bpMSf8zyBKfMZll3vdtDTDqnsVzOu89RxQYgceyWZ/OcFgvc9hg" +
70                 "NYoV/EkGQXcHWL1gPQwWpMRfS8L/DjbNIwJBAL3NBL/Y6YB8TOq5X2M4bHzOOiRT" +
71                 "h4j00Su08ctxA8eyNpnrH5fyVZbgw/+SAioXI9oDRp2JWHinKOk3z11HEaMCQDI/" +
72                 "qLY60xm9MQMJWaYGmtzayUcHS2glslKcy6t/gbxm3yHluCNvvcOYO6zeUDb7kSjQ" +
73                 "638O6NkLdwi8U0vJot8CQHEfumEFZ0LYbz914TZOWe2q0UKOUZaHgQIwoJ3n2yxJ" +
74                 "p7Ps3k9t2Of8Tm+HqZYCkSz8henOM8aFCS2GPD8Pkf4=" ;
75         */
76     }

View Code

客戶端vue:

工具類,常用加解密演算法,enDecrypt.js

  1  /* base64 加解密
  2   */
  3  export let Base64 = require('js-base64').Base64
  4 
  5  /* md5 加解密
  6  */
  7  export let crypto = require('crypto');
  8  export let md5 = require('js-md5');
  9  export let CryptoJS = require('crypto-js');
 10  export let MD5 = CryptoJS.MD5;
 11  /*
 12   *引入jsencrypt實現數據RSA加密
 13   */
 14  import JSEncrypt from 'jsencrypt';
 15  // jsencrypt.js處理長文本數據時報錯  Message too long for RSA
 16  // encryptlong是基於jsencrypt擴展的長文本分段加解密功能。
 17  import Encrypt from "encryptlong";
 18  // rsa sign
 19  import jsrsasign from 'jsrsasign'
 20 
 21  // Message Digest algorithm 5,資訊摘要演算法
 22  // alglorithm:md5、sha1、sha256
 23  export function Md5(plainText, alglorithm, encoding){
 24    const hash =  crypto.createHash(alglorithm)
 25    hash.update(plainText);//加密內容
 26    return  hash.digest(encoding);//密文
 27  }
 28 
 29  //Hash Message Authentication Code,散列消息鑒別碼
 30  //Secure Hash Algorithm,安全散列演算法
 31  //alglorithm:md5、sha256、sha1
 32  export function HMac(plainText, secretKey,alglorithm, encoding){
 33    const hmac= crypto.createHmac(alglorithm, secretKey);
 34    const cipherText= hmac.update(plainText);//加密內容
 35    return  cipherText.digest(encoding);//密文
 36  }
 37 
 38  // Data Encryption Standard,數據加密演算法
 39  // DES/DES3/AES 加密, key與iv長度必須是8的倍數
 40  // mode:CryptoJS.mode.CBC、CryptoJS.mode.ECB、CryptoJS.mode.CFB
 41  // padding:CryptoJS.pad.ZeroPadding、CryptoJS.pad.Pkcs7、CryptoJS.pad.NoPadding
 42  export function encrypt ( algorithm, plainText,key, iv, mode, padding, isTextBase64) {
 43      key = key ? key : "abcdefghijklmnop";
 44      iv = iv ? iv : "0102030405060708";
 45 
 46      const keyHex = CryptoJS.enc.Utf8.parse(key);
 47      const ivHex = CryptoJS.enc.Utf8.parse(iv);
 48      const option = { iv:keyHex,mode: mode, padding: padding }
 49      let encrypted = null  ;
 50      if(algorithm === "TripleDES"){
 51        encrypted = CryptoJS.TripleDES.encrypt(plainText, keyHex, option)
 52      }else if(algorithm === "DES"){
 53        encrypted = CryptoJS.DES.encrypt(plainText, keyHex, option)
 54      }
 55      else if(algorithm === "AES"){
 56        encrypted =  CryptoJS.AES.encrypt(plainText, keyHex, option)
 57      }
 58      return isTextBase64?CryptoJS.enc.Base64.stringify(encrypted.ciphertext):encrypted.ciphertext.toString();
 59  }
 60 
 61  // DES/DES3/AES解密,key與iv長度必須是8的倍數
 62  export function decrypt (algorithm,cipherText,key, iv, mode, padding, isTextBase64) {
 63      key = key ? key : "abcdefghijklmnop";
 64      iv = iv ? iv : "0102030405060708";
 65 
 66      const keyHex = CryptoJS.enc.Utf8.parse(key);
 67      const ivHex = CryptoJS.enc.Utf8.parse(iv);
 68      const decryptText = isTextBase64?  CryptoJS.enc.Base64.parse(cipherText):cipherText;
 69      const textHex = { ciphertext:  isTextBase64?decryptText:CryptoJS.enc.Hex.parse(decryptText) }
 70      const option = { iv:ivHex,mode: mode, padding: padding }
 71      let decrypted = null;
 72      if(algorithm === "TripleDES"){
 73        decrypted = CryptoJS.TripleDES.decrypt(textHex, keyHex, option);
 74      }else if(algorithm === "DES"){
 75        decrypted = CryptoJS.DES.decrypt(textHex, keyHex, option);
 76      }
 77      else if(algorithm === "AES"){
 78        decrypted =  CryptoJS.AES.decrypt(textHex, keyHex, option);
 79      }
 80      return decrypted.toString(CryptoJS.enc.Utf8);
 81  }
 82 
 83  export function stringToHex(strSource) {
 84    if(strSource === "")
 85      return "";
 86    var hexCharCode = [];
 87    for(var i = 0; i < strSource.length; i++) {
 88      hexCharCode.push((strSource.charCodeAt(i)).toString(16));
 89    }
 90    return hexCharCode.join("");
 91  }
 92 
 93  export function hexToString(hexCharCodeStr) {
 94    var trimedStr = hexCharCodeStr.trim();
 95    var len = trimedStr.length;
 96    if(len % 2 !== 0) {
 97      alert("Illegal Format ASCII Code!");
 98      return "";
 99    }
100    var curCharCode;
101    var resultStr = [];
102    for(var i = 0; i < len;i = i + 2) {
103      curCharCode = parseInt(trimedStr.substr(i, 2), 16); // ASCII Code Value
104      resultStr.push(String.fromCharCode(curCharCode));
105    }
106    return resultStr.join("");
107  }
108 
109  /** RSA 加密過程
110   * (1)A生成一對密鑰(公鑰和私鑰),私鑰不公開,A自己保留。公鑰為公開的,任何人可以獲取。
111   * (2)A傳遞自己的公鑰給B,B用A的公鑰對消息進行加密。
112   * (3)A接收到B加密的消息,利用A自己的私鑰對消息進行解密。
113   *  在這個過程中,只有2次傳遞過程,第一次是A傳遞公鑰給B,第二次是B傳遞加密消息給A,即使都被敵方截獲,也沒有危險性。
114   *  因為只有A的私鑰才能對消息進行解密,防止了消息內容的泄露。
115   *  使用方法
116   *  客戶端初始化訪問伺服器端時,伺服器端會生成一對RSA對,及公鑰和密鑰。
117   *  如果前端只需要將要傳給後端的數據進行加密後傳輸,那麼前端可以只要公鑰,通過公鑰對要傳輸的參數進行加密後把加密的字元串發給後端,後端取出保存的密碼種子或者直接保存的私鑰,採用私鑰對加密字元串進行解密,得到明文。
118   *  如果前端要獲取後端傳過來的已經加密後的字元串,並且解密使用,那麼前端就需要拿到RSA對立面的私鑰進行解密後使用了。
119   * */
120  /* JSEncrypt 公鑰加密  padding:pkcs1pad2 */
121  export function RsaJSEncrypt(plainText,publicKey,isKeyBase64,isTextBase64,isURLCode) {
122    const jsencrypt = new JSEncrypt({
123      default_key_size: 1024
124    });
125    // setPublicKey 參數默認需要base64,如果是十六進位編碼則需要轉換為base64,jsrsasign.b64tohex,jsrsasign.hextob64
126    isKeyBase64?jsencrypt.setPublicKey(publicKey):jsencrypt.setPublicKey( jsrsasign.hextob64(publicKey));
127    // 如果是對象/數組的話,需要先JSON.stringify轉換成字元串
128    // 處理中文亂碼,伺服器端:String result = java.net.URLDecoder.decode(cipherText ,"UTF-8");
129    let  cipherText = jsencrypt.encrypt(plainText);
130 
131    // 默認加密結果為base64編碼
132    cipherText = isTextBase64?cipherText:jsrsasign.b64tohex(cipherText);
133    // +號伺服器端不識別,url編碼
134    cipherText = isURLCode? encodeURIComponent(cipherText):cipherText;
135 
136    return  cipherText;
137  }
138 
139  /* JSEncrypt 私鑰解密 padding:pkcs1pad2 */
140  export function RsaJSDecrypt(cipherText,privateKey,isKeyBase64,isTextBase64,isURLCode) {
141    const jsencrypt = new JSEncrypt({
142      default_key_size: 1024,
143      padding: crypto.constants.RSA_PKCS1_PADDING
144    });
145 
146    isKeyBase64?jsencrypt.setPrivateKey(privateKey):jsencrypt.setPrivateKey(jsrsasign.hextob64(privateKey));
147 
148    cipherText = isURLCode?decodeURIComponent(cipherText):cipherText;
149    cipherText = isTextBase64?cipherText:jsrsasign.b64tohex(cipherText);
150 
151    return jsencrypt.decrypt(cipherText);
152  }
153 
154  /* 長文本分段加密 */
155  export function RsaEncrypt(plainText,publicKey,isKeyBase64,isTextBase64,isURLCode) {
156    const encryptor = new Encrypt({
157      default_key_size: 1024,
158      padding: crypto.constants.RSA_PKCS1_PADDING
159    });
160    if (isKeyBase64) {
161      encryptor.setPublicKey(publicKey)
162    }
163    else {
164      encryptor.setPublicKey(jsrsasign.hextob64(publicKey));
165    }
166 
167    // 處理中文亂碼,伺服器端:String result = java.net.URLDecoder.decode(cipherText ,"UTF-8");
168 
169   let cipherText = encryptor.encryptLong(plainText);
170 
171     cipherText = isTextBase64?cipherText:jsrsasign.hextob64(cipherText);
172    // +號伺服器端不識別,url編碼
173    cipherText = isURLCode? encodeURIComponent(cipherText):cipherText;
174 
175    return  cipherText;
176  }
177 
178  /* 長文本分段解密 */
179  export function RsaDecrypt(cipherText,privateKey,isKeyBase64,isTextBase64,isURLCode) {
180    const encryptor = new Encrypt({
181      default_key_size: 1024,
182      padding: crypto.constants.RSA_PKCS1_PADDING
183    })
184 
185    if (isKeyBase64){
186     encryptor.setPrivateKey(privateKey)
187   }
188   else{
189     encryptor.setPrivateKey(jsrsasign.hextob64(privateKey));
190   }
191    cipherText = isURLCode?decodeURIComponent(cipherText):cipherText;
192    cipherText = isTextBase64?cipherText:jsrsasign.b64tohex(cipherText);
193 
194    return encryptor.decryptLong(cipherText);
195  }
196 
197  // 獲取簽名 privateKey
198  export function RsaSign(plainText,privateKey,format_key, algorithm,isKeyBase64,isTextBase64,isURLCode)
199  {
200    // 生成簽名對象
201    let sign = genSign(isKeyBase64?privateKey:jsrsasign.hextob64(privateKey),format_key, algorithm);
202     plainText = isTextBase64?jsrsasign.b64tohex(plainText):plainText;
203   // console.log("待簽名前數據:"+plainText);
204     let plain_Text = genDigest(plainText,algorithm);
205 
206    // console.log("待簽名摘要數據:"+plain_Text);
207     sign.updateString(plain_Text);
208 
209    // 默認簽名數據為十六進位數據
210     let signedText = isTextBase64?jsrsasign.hextob64(sign.sign()):sign.sign();
211 
212    // console.log("生成簽名數據:"+sign.sign());
213    // +號伺服器端不識別,url編碼
214     signedText = isURLCode? encodeURIComponent(signedText):signedText;
215 
216     return signedText;
217  }
218 
219  // 驗證簽名 publicKey_s 伺服器端的公鑰
220  // alglorithm: SHA1withRSA、MD5withRSA、SHA256withRSA、 SHA384withRSA、SHA512withRSA、RIPEMD160withRSA
221  // format_key: PKCS#1、PKCS#5、PKCS#8
222  /*
223   * PKCS#1:定義RSA公開密鑰演算法加密和簽名機制,主要用於組織PKCS#7中所描述的數字簽名和數字信封。
224   * PKCS#3:定義Diffie-Hellman密鑰交換協議。
225   * PKCS#5:描述一種利用從口令派生出來的安全密鑰加密字元串的方法。使用MD2或MD5 從口令中派生密鑰,並採用DES-CBC模式加密。主要用於加密從一個電腦傳送到另一個電腦的私人密鑰,不能用於加密消息[24]。
226   * PKCS#6:描述了公鑰證書的標準語法,主要描述X.509證書的擴展格式。
227   * PKCS#7:定義一種通用的消息語法,包括數字簽名和加密等用於增強的加密機制,PKCS#7與PEM兼容,所以不需其他密碼操作,就可以將加密的消息轉換成PEM消息[26]。
228   * PKCS#8:描述私有密鑰資訊格式,該資訊包括公開密鑰演算法的私有密鑰以及可選的屬性集等。
229   * PKCS#9:定義一些用於PKCS#6證書擴展、PKCS#7數字簽名和PKCS#8私鑰加密資訊的屬性類型。
230   * PKCS#10:描述證書請求語法。
231   * PKCS#11:稱為Cyptoki,定義了一套獨立於技術的程式設計介面,用於智慧卡和PCMCIA卡之類的加密設備。
232   * PKCS#12:描述個人資訊交換語法標準。描述了將用戶公鑰、私鑰、證書和其他相關資訊打包的語法。
233   * PKCS#13:橢圓曲線密碼體制標準。
234   * PKCS#14:偽隨機數生成標準。
235   * PKCS#15:密碼令牌資訊格式標準。
236   */
237  export function RsaVerifySign(plainText,signedText,publicKey,format_key, algorithm,isKeyBase64,isTextBase64,isURLCode)
238  {
239    // 生成簽名
240    let verifySign = genSign(isKeyBase64?publicKey:jsrsasign.hextob64(publicKey),format_key, algorithm);
241    plainText = isTextBase64?jsrsasign.b64tohex(plainText):plainText;
242    // 根據明文生成摘要
243    let digestText = genDigest(plainText,algorithm);
244 
245    verifySign.updateString(digestText);
246 
247    signedText = isURLCode?decodeURIComponent(signedText):signedText;
248    signedText = isTextBase64?jsrsasign.b64tohex(signedText):signedText;
249 
250    return  verifySign.verify(signedText);
251  }
252 
253  // 根據明文生成摘要
254  //SHA1withRSA、MD5withRSA、SHA256withRSA、 SHA384withRSA、SHA512withRSA、RIPEMD160withRSA
255  export function genDigest(plainText,algorithm ){
256    let option = { "alg": algorithm.split('w')[0], "prov":"cryptojs/jsrsa", }
257   // console.log("演算法:"+algorithm.split('w')[0]);
258    let text = new jsrsasign.KJUR.crypto.MessageDigest(option);   // 摘要
259    text.updateString(plainText);
260 
261    let digestText = text.digest();
262    // console.log("摘要:"+digestText);
263    return digestText;
264  }
265 
266  /* 生成rsa簽名對象
267   * */
268  export function genSign(RsaKey,format_key, algorithm)
269  {
270    // 密鑰要寫開頭和結束
271    // var private_key = '-----BEGIN PRIVATE KEY-----' + privateKey_s + '-----END PRIVATE KEY-----'
272    // 讀取解析pem格式的秘鑰, 生成秘鑰實例 (RSAKey)
273    let rsaKey = new jsrsasign.RSAKey();
274    if (format_key === "PKCS#1" || format_key === "PKCS#5"|| format_key === "PKCS#7"|| format_key === "PKCS#8") {
275      rsaKey = jsrsasign.KEYUTIL.getKey(RsaKey);
276      // rsaSign.readPrivateKeyFromPEMString(privateKey_s);
277    }
278 
279    let option= {
280      "alg":algorithm,
281      "prov":"cryptojs/jsrsa",
282      "prvkeypem": rsaKey
283    };
284 
285    let sign = new jsrsasign.KJUR.crypto.Signature(option);
286    sign.init(rsaKey);
287 
288    return sign;
289  }

前端使用程式碼流程:

 1 // 測試前後端使用流程
 2       // 1、後端生成密鑰對,公鑰分享給前端,前端獲取到伺服器給的公鑰。
 3       // 2、前端用伺服器端給的公鑰 及演算法:RSA/CBC/PKCS1Padding 加密"xhy 我愛你 中國 依芸Yiyun !!!" 生成加密數據。
 4       // 3、前端然後生成自己的密鑰對,用自己的私鑰及演算法SHA1withRSA生成摘要簽名。
 5       // 4、前端把加密數據、自己的公鑰與簽名一併發給後端。
 6       // 3、後端收到加密數據、簽名數據、前端的公鑰,先用前端公鑰、簽名數據、演算法SHA1withRSA 驗簽,驗簽通過後再用後端的私鑰、演算法:RSA/CBC/PKCS7Padding 解密數據。
 7       // 注意:密鑰與密文全部base64編碼
 8 
 9       let  plainText = "xhy 我愛你 中國 依芸Yiyun !!!";
10 
11       let privateKey_c = "-----BEGIN RSA PRIVATE KEY-----" +
12         "MIICXAIBAAKBgQDQPgskvyi9D/IuD0x73M2UOxBH3daAGbxLfUiSraG3cEgZCp7/" +
13         "o1RKM/Uckoplw/DDD665je4wVc0R2zZ8E9LQrrHvvVgddaCvaFZkcIno4EVtHCLl" +
14         "dKOFzAIr8ucxCHelV9oGhrcCmeGwYnVTeXOerY9iFi2KDWwF30e2PHRpRQIDAQAB" +
15         "AoGARuvaf7la9ojnwigTtFuO6Fz1PoSe+SHKrysL/GiGGyNyapTjccz+eAcaA5Ek" +
16         "8WO6K7S7nRZpeKzAGsS92aQmt66BpOqI+JJ2uM+K1HzH5K5rQ4rnaC/Hbd+4zslt" +
17         "VzuLbsICDGSlkpTSKK5YdIkA5YPMXoQek4zoYpUnKT2AxEECQQDoDrjIJ4MllIpc" +
18         "gAWjahga1YrcTIcQPBwG9rfX7zk2nKFZF5rOB6iDHjE9mo9EOD/s7j3Z5eefwVkp" +
19         "hRnbXJp3AkEA5bpMSf8zyBKfMZll3vdtDTDqnsVzOu89RxQYgceyWZ/OcFgvc9hg" +
20         "NYoV/EkGQXcHWL1gPQwWpMRfS8L/DjbNIwJBAL3NBL/Y6YB8TOq5X2M4bHzOOiRT" +
21         "h4j00Su08ctxA8eyNpnrH5fyVZbgw/+SAioXI9oDRp2JWHinKOk3z11HEaMCQDI/" +
22         "qLY60xm9MQMJWaYGmtzayUcHS2glslKcy6t/gbxm3yHluCNvvcOYO6zeUDb7kSjQ" +
23         "638O6NkLdwi8U0vJot8CQHEfumEFZ0LYbz914TZOWe2q0UKOUZaHgQIwoJ3n2yxJ" +
24         "p7Ps3k9t2Of8Tm+HqZYCkSz8henOM8aFCS2GPD8Pkf4=" +
25         "-----END RSA PRIVATE KEY-----";
26 
27       let publicKey_c ="-----BEGIN PUBLIC KEY-----" +
28         "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQPgskvyi9D/IuD0x73M2UOxBH" +
29         "3daAGbxLfUiSraG3cEgZCp7/o1RKM/Uckoplw/DDD665je4wVc0R2zZ8E9LQrrHv" +
30         "vVgddaCvaFZkcIno4EVtHCLldKOFzAIr8ucxCHelV9oGhrcCmeGwYnVTeXOerY9i" +
31         "Fi2KDWwF30e2PHRpRQIDAQAB" +
32         "-----END PUBLIC KEY-----";
33 
34       let publicKey_s = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHykT0c0tGvUYNS0Is5HyC9XIgDBBbOObZePREbsCANZHFK7QdQo492yjCztEqe/fdhAjllWbBOg2T5Xt5FWBbnyAU+KY0daCakbOGfYOW5MGOqe+N3hp09aca4uSzagXXr5SrI6sHHyHToSKs9gWnjNz09TudjyPXvlONFxK4uwIDAQAB";
35 
36       console.log("<--- 2 --->客戶端獲取到伺服器端給定的公鑰:"+ publicKey_s);
37 
38       let cipherText_c =this.$RsaEncrypt(plainText,publicKey_s,true,true,false);
39       console.log("<--- 3 --->客戶端利用伺服器端的公鑰加密數據,生成密文,base64編碼輸出\n"+cipherText_c);
40       // 記錄 cipherText_c = "eCOu/WkaQ8tZHk2u+Y9bh6RKOVMQGsssjnQB5DVlUeDPhjiIybeQSe7JH7fG5FgsucCi6uFwdU7yWzmkJFmMKGnE1pGLReqSaWgecviSTl1P4jjrq84VJvreoeCmcNUCoqxQvmYuMxB/D4rZ+PTuv0B2sQ4Q5fOH6fbqoj3uD5w=";
41 
42      let signedText_c = this.$RsaSign(cipherText_c,privateKey_c,"PKCS#8","SHA1withRSA",true,
43        true,false);
44       console.log("<--- 4 --->客戶端利用自己生成的私鑰簽名數據,生成摘要與簽名\n"+signedText_c);
45       console.log("<--- 4 --->客戶端生成自己的公鑰\n"+publicKey_c);
46       console.log("<--- 5 --->客戶端發送數據至伺服器端,1客戶端的公鑰,2客戶端的加密數據,3客戶端的簽名數據\n");
47       // 記錄 signedText_c = "uFy+PqjxdxusV5+a9VR0cvk1XY0+Th8jWBT581irWVEDyzq00xGphQ8KIyApgvPw5+KP1DB/M7tMfd0viUT4w8i4VcyhGmRlk0XNkuRhQDgcWeZ5XKIoJ1ORQ0ecxcAAAAlPwMe2wCbPClXFmhJzypJtS7nKFzE/oeZg7nr91zg=";
48       // 注意:加密密文與簽名都是唯一的,不會變化。
49       // 注意:vue 端密鑰都要帶頭。
50       // 注意:vue端及java端函數參數要求是什麼類型及何進位。搞明白哪裡用base64,哪裡2進位,哪裡16進位。
51       // 重點還是要了解點原理,比如sha1withrsa,先經過sha1演算法,知道aaa,哈希後的密文16進位是:7e240de74fb1ed08fa08d38063f6a6a91462a815,對比自己的程式有沒有算錯。
52       // 利用一些在線測試工具幫忙驗證自己的程式過程。//www.metools.info/code/c82.html ; 同時知道如何查引入的類庫各api的官網,了解如何使用各函數。
53       // 不然遇到莫名奇妙的錯誤無從解決。報錯的地方不一定是程式實際錯誤的地方。了解查錯的方式有:打庄、debug.
54 
55       /* 僅供測試使用,加密數據及驗簽
56         let privateKey_s = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIfKRPRzS0a9Rg1LQizkfIL1ciAMEFs45tl49ERuwIA1kcUrtB1Cjj3bKMLO0Sp7992ECOWVZsE6DZPle3kVYFufIBT4pjR1oJqRs4Z9g5bkwY6p743eGnT1pxri5LNqBdevlKsjqwcfIdOhIqz2BaeM3PT1O52PI9e+U40XEri7AgMBAAECgYAmNYNLqbmP0SiKCxg226AxlXEklWBw2sUSgpdxPhzKtsgqzA5lgVnXC/kfP+TZaIKpgUKjn3OHgZdae2NQAfTXxTcvhNGYSOeJ8VgslQueoJW7ypgQ/IoNy2DeglObAJ3uCgA4F566j6H7IvcllKGmDT/6PUlljxZJpBMfslspgQJBAP19EMRxmV4vYL7o55oR397UEUXn3vO88SPo2gxaPZ/ltzgaHM5R1zALPE1EfPIPqVdGf2hcowr22pC1BG+nlXsCQQCJIq4USfgNmjGwquo5PyksQ9vsYc/OxGBxEqTpVez24eJb7tvoqvbYfpleeEyWgtvzHqnlY24QdONhVVm5zOXBAkAxt7PwM6+3D2fUSe4TA+p60/FHWsEZ4TcSqfsKbTClCfMzp7t6pAamv61mIka3W2cFXShkGbdI0T3xH+/szlu9AkBi3SSgrd7td39hPSaU1MsLBXT0SmO1Te+1NNq8+VxXc+trmZzidPZ2h3ZsG9AjJf4JnM6g9/iuVoZiclS4VVZBAkEAsPkIGRvX4Nj3ljiBjgdJ68JRZC3gK/kXLNeefIeHg6F/4eyg729PlfdD2mvPb8hiszvsT1zvF8gvxGi4lT6B/w==" ;
57 
58         console.log("RSAVerifySign_pubK="+this.$RsaVerifySign(cipherText_c, signedText_c,
59         publicKey_c,"PKCS#8","SHA1withRSA",true,true,false));
60 
61         plainText = "";
62         plainText = this.$RsaDecrypt(cipherText_c, privateKey_s,true,true,false)
63         console.log("RSADe_priK="+plainText);
64       */

測試結果截圖說明

伺服器:

  客戶端: