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

Posted F_cy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp接口层的aes和rsa的对称与非对称加密相关的知识,希望对你有一定的参考价值。

在一些安全性比较高的网站中要求数据的传输是密文传输,例如涉及支付的网站,这就需要前后端人员在进行数据请求和响应的时候进行数据加密,此处仅介绍前端接口层的加密,其核心原理就是在数据请求阶段进行数据的加密,在数据响应阶段进行数据的解密,保证应用内数据的安全传输。

先说一下我的这个案例的加密流程:

前端在进行数据传输的时候,将需要传输的数据进行aes加密,然后在请求头添加sKey字段,sKey的值是通过rsa加密之后的密文,rsa是非对称加密,通过rsa的公钥进行加密,私钥进行解密,前端rsa加密的公钥是后端给的。总结来说:

前端需要发送给后端的内容:

请求数据: aes机密后的密文

请求头:sKey:rsa公钥加密后的aes密钥

下面进行过程演示:

aes在线密钥生成:AES 密钥在线生成器 - iMaeGoo's Blog

rsa在线公私钥生成:在线RSA密钥对生成工具 - UU在线工具

aes加密需要依赖 crypto-js

rsa加密需要依赖 jsencrypt

 1、 在uniapp项目中新建终端,初始化npm,然后依赖插件

npm init -y

npm install crypto-js --s

npm install jsencrypt --s

2、加密文件的封装

在根目录新建config文件夹,将所有文件放下该文件夹下

新建aes.js进行aes加密封装:

import CryptoJS from "crypto-js"

export default 

//加密:
	jiami(content,key1)  //需要加密的内容,aes密钥
	
		var key = CryptoJS.enc.Utf8.parse(key1)
		var plaintText = content
		var encryptedData = CryptoJS.AES.encrypt(plaintText, key, 
			mode: CryptoJS.mode.ECB,
			padding: CryptoJS.pad.Pkcs7
		)
		return encryptedData
	,

//解密:
	jiemi(decryptString, key)  //需要解密的数据  aes密钥
		var key = CryptoJS.enc.Utf8.parse(key);
		var decrypt = CryptoJS.AES.decrypt(decryptString, key, 
			mode: CryptoJS.mode.ECB,
			padding: CryptoJS.pad.Pkcs7
		);
		return CryptoJS.enc.Utf8.stringify(decrypt).toString();
	


新建rsa.js进行rsa加密封装:

import JSEncrypt  from "jsencrypt"//存放路径
 
//传入数据,公钥私钥
export default 

//加密:
    jiami(dat,publicKey)   //需要加密的数据 rsa公钥
        let data;
        if (typeof dat==='string')
            data =dat
        else 
            data = JSON.stringify(dat)
        
        let encrypt = new JSEncrypt();
        encrypt.setPublicKey(publicKey);	
        let encryptMsg = encrypt.encrypt(data);
        return encryptMsg;
    ,
 
//解密
    jiemi(data,privateKey)//需要解密的数据, rsa私钥
        let decrypt = new JSEncrypt();
        decrypt.setPrivateKey(privateKey);	  
        let decryptMsg = decrypt.decrypt(data);
        return decryptMsg;
    

新建一个key.js用来存储rsa的公钥信息

export default 
publicKey:'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq2Otneh6q+N1HwQXpWZA2+fck7Dp0EhW6XncJx4kwM1rMQulN0tvVytDZ5TA2rJj8gfL2J76Lj0nRqYlWMegzrdemHFParUywiwgMZednEP8jsYC8kv0s5N1M9Xpbhu+GeZsGQ22rgriKQcOJI7uf7HJ/eQ6DXVSAjIQ3KUpLCrizAtsfsAOVVFKcuN7PVtGb/Km2pFNVtJO+ulVTU7Yd3A3eZGvojwD7HmAdr9PTBIbgdU9sOfB+0yxL4uAdPRpBXKmfTygLqHN2I548ok5s1Dr0AraTsDtw4GaAEYeZ8okreG4JV2hUycNjdPNKqXkE9XXXsLLpGD2jOEyC99v9wIDAQAB'

//这里是我的rsa公钥信息,仅做测试用途,可以自己在线生成

新建一个untils.js文件,用来生成随机的aes密钥,因为每次发送数据,加密的密钥都需要不同。


export default 
	// 生成aes随机密钥
	getAesKey(n) 
		var chars = [
			'0',
			'1',
			'2',
			'3',
			'4',
			'5',
			'6',
			'7',
			'8',
			'9',
			'A',
			'B',
			'C',
			'D',
			'E',
			'F',
			'G',
			'H',
			'I',
			'J',
			'K',
			'L',
			'M',
			'N',
			'O',
			'P',
			'Q',
			'R',
			'S',
			'T',
			'U',
			'V',
			'W',
			'X',
			'Y',
			'Z'
		];
		if (n == null) 
			n = 8;
		
		var res = '';
		for (var i = 0; i < n; i++) 
			var id = Math.ceil(Math.random() * 35);
			res += chars[id];
		
		return res;
	

3 进行拦截器加密解密配置

在封装uni.$u.http文件中,即request.js中进行配置

//引入先前配置的加密文件和工具包
import untils from "@/config/untils.js";
import aes from "@/config/aes.js";
import rsa from "@/config/rsa.js"; 
import key from "@/config/key.js"; 

//接口配置
module.exports = (vm) => 
	let aesKey = ""; // 声明全局 aes 密钥
	// 初始化请求配置
	uni.$u.http.setConfig((config) => 
		config.baseURL = "http://baidu.com"; /* 配置你的根域名 */
		return config;
	);

	// 请求拦截
	uni.$u.http.interceptors.request.use(
		(config) => 

		    // 匹配特定路由
			if (config.url.search("body") != -1) 
			
				aesKey = untils.getAesKey(16); //每次匹配拦截 生成不同的 aes 密钥
				
                //rsa  加密 aes 密钥 携带在请求头部
                config.header.sKey = rsa.jiami(aesKey, key.publicKey); 

				if (config.data)   //如果有请求数据,进行加密
                    // 对传输内容进行 aes 加密
					config.data = aes.jiami(JSON.stringify(config.data), aesKey); 

				 else //如果没有请求数据,随便加密一段数据
					config.data = aes.jiami(JSON.stringify(
						msg: "无信息"
					), aesKey); // 对传输内容进行 aes 加密
				
			

			return config;
		,
		(config) => 
		
			return Promise.reject(config);
		
	);

	// 响应拦截
	uni.$u.http.interceptors.response.use(
		(response) => 
			
            //匹配特定url,进行解密操作
			if (
				response.config.url.search("body") != -1
			) 
				let data = response.data.replace(/\\s+/g, ""); //去除返回密文中的空格
			
				return JSON.parse(aes.jiemi(data, aesKey)); //aes密文解密
			

			return response.data;
		,
		(response) => 

			return Promise.reject(response);

		
	);
;

测试一个请求

export const queryMoney = (data) => http.post('body/system/appUser/queryLeaderAmount', data)

可以看到sKey已经是加密后的内容了,传输的数据也是加密后端的内容

 

 这是后台返回的加密数据:

响应拦截器解密后的内容

 

 到此,在接口层面的数据加密解密就已完成,需要注意的是,前端的加密需要和后端的加密相匹配,否则会导致前端加密的内容后端不能解密,后端加密的内容前端不能解密。需要特别看看加密和解密方法中的方式类型。

aes在线解密:AES在线解密 AES在线加密 Aes online hex 十六进制密钥 - The X 在线工具 (the-x.cn)

此网站可以解析aes加密的内容,以此来判断前后端加密方式是否一致。 

Java对称与非对称加密解密,AES与RSA

加密技术可以分为对称与非对称两种.

对称加密,解密,即加密与解密用的是同一把秘钥,常用的对称加密技术有DES,AES等

而非对称技术,加密与解密用的是不同的秘钥,常用的非对称加密技术有RSA等

 

为什么要有非对称加密,解密技术呢

假设这样一种场景A要发送一段消息给B,但是又不想以明文发送,所以就需要对消息进行加密.如果采用对称加密技术,那么加密与解密用的是同一把秘钥.除非B事先就知道A的秘钥,并且保存好.这样才可以解密A发来的消息.

由于对称技术只有一把秘钥,所以秘钥的管理是一个很麻烦的问题.而非对称技术的诞生就解决了这个问题.非对称加密与解密使用的是不同的秘钥,并且秘钥对是一一对应的,即用A的私钥加密的密文只有用A的公钥才能解密.

这样的话,每个人都有两把秘钥,私钥和公钥,私钥是只有自己才知道的,不能告诉别人,而公钥是公开的,大家都可以知道.这样,当A想要发送消息给B的时候,只需要用B的公钥对消息进行加密就可以了,由于B的私钥只有B才拥有,所以A用B的公钥加密的消息只有B才能解开.而B想更换自己的秘要时也很方便,只须把公钥告诉大家就可以了.

那么,既然非对称加密如此之好,对称加密就没有存在的必要了啊,其实不然,由于非对称加密算法的开销很大,所以如果直接以非对称技术来加密发送的消息效率会很差.那么怎么办呢?解决的办法也很简单,就是把对称加密技术与非对称加密技术结合起来使用.

还是这个例子:A要发送一个消息给B.

一,A先生成一个对称秘钥,这个秘钥可以是随机生成的,

二,A用B的公钥加密第一步生成的这个对称秘钥

三,A把加密过的对称秘钥发给B

四,A用第一步生成的这个对称秘钥加密实际要发的消息

五,A把用对称秘钥加密的消息发给B

对于B

他先收到A发来的对称秘钥,这个秘钥是用B的公钥加密过的,所以B需要用自己的私钥来解密这个秘钥

然后B又收到A发来的密文,这时候用刚才解密出来的秘钥来解密密文

 

这样子的整个过程既保证了安全,又保证了效率.

 

接下来是Java实现:

我这个Java实现使用的是AES的对称加密和RSA的非对称加密(DES的对称加密实现方法和AES的是一样的,但是由于DES算法本身有缺陷,容易被破解,所以现在多用其升级版AES对称加密)

 

AES对称加密,解密

Java代码  技术分享
  1. import java.io.IOException;  
  2. import java.io.InputStream;  
  3. import java.io.OutputStream;  
  4. import java.security.InvalidKeyException;  
  5. import java.security.Key;  
  6. import java.security.NoSuchAlgorithmException;  
  7. import java.security.SecureRandom;  
  8.   
  9. import javax.crypto.BadPaddingException;  
  10. import javax.crypto.Cipher;  
  11. import javax.crypto.IllegalBlockSizeException;  
  12. import javax.crypto.KeyGenerator;  
  13. import javax.crypto.NoSuchPaddingException;  
  14. import javax.crypto.ShortBufferException;  
  15.   
  16. public class AES {  
  17.       
  18.     private Key key;  
  19.       
  20.     /** 
  21.      * 生成AES对称秘钥 
  22.      * @throws NoSuchAlgorithmException 
  23.      */  
  24.     public void generateKey() throws NoSuchAlgorithmException {  
  25.         KeyGenerator keygen = KeyGenerator.getInstance("AES");  
  26.         SecureRandom random = new SecureRandom();  
  27.         keygen.init(random);  
  28.         this.key = keygen.generateKey();  
  29.     }  
  30.       
  31.       
  32.     /** 
  33.      * 加密 
  34.      * @param in 
  35.      * @param out 
  36.      * @throws InvalidKeyException 
  37.      * @throws ShortBufferException 
  38.      * @throws IllegalBlockSizeException 
  39.      * @throws BadPaddingException 
  40.      * @throws NoSuchAlgorithmException 
  41.      * @throws NoSuchPaddingException 
  42.      * @throws IOException 
  43.      */  
  44.     public void encrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {  
  45.         this.crypt(in, out, Cipher.ENCRYPT_MODE);  
  46.     }  
  47.       
  48.     /** 
  49.      * 解密 
  50.      * @param in 
  51.      * @param out 
  52.      * @throws InvalidKeyException 
  53.      * @throws ShortBufferException 
  54.      * @throws IllegalBlockSizeException 
  55.      * @throws BadPaddingException 
  56.      * @throws NoSuchAlgorithmException 
  57.      * @throws NoSuchPaddingException 
  58.      * @throws IOException 
  59.      */  
  60.     public void decrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {  
  61.         this.crypt(in, out, Cipher.DECRYPT_MODE);  
  62.     }  
  63.   
  64.     /** 
  65.      * 实际的加密解密过程 
  66.      * @param in 
  67.      * @param out 
  68.      * @param mode 
  69.      * @throws IOException 
  70.      * @throws ShortBufferException 
  71.      * @throws IllegalBlockSizeException 
  72.      * @throws BadPaddingException 
  73.      * @throws NoSuchAlgorithmException 
  74.      * @throws NoSuchPaddingException 
  75.      * @throws InvalidKeyException 
  76.      */  
  77.     public void crypt(InputStream in, OutputStream out, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {  
  78.         Cipher cipher = Cipher.getInstance("AES");  
  79.         cipher.init(mode, this.key);  
  80.           
  81.         int blockSize = cipher.getBlockSize();  
  82.         int outputSize = cipher.getOutputSize(blockSize);  
  83.         byte[] inBytes = new byte[blockSize];  
  84.         byte[] outBytes = new byte[outputSize];  
  85.           
  86.         int inLength = 0;  
  87.         boolean more = true;  
  88.         while (more) {  
  89.             inLength = in.read(inBytes);  
  90.             if (inLength == blockSize) {  
  91.                 int outLength = cipher.update(inBytes, 0, blockSize, outBytes);  
  92.                 out.write(outBytes, 0, outLength);  
  93.             } else {  
  94.                 more = false;  
  95.             }  
  96.         }  
  97.         if (inLength > 0)  
  98.             outBytes = cipher.doFinal(inBytes, 0, inLength);  
  99.         else  
  100.             outBytes = cipher.doFinal();  
  101.         out.write(outBytes);  
  102.         out.flush();  
  103.     }  
  104.   
  105.     public void setKey(Key key) {  
  106.         this.key = key;  
  107.     }  
  108.   
  109.     public Key getKey() {  
  110.         return key;  
  111.     }  
  112.       
  113. }  

 

RSA非对称加密,解密对称秘钥

Java代码  技术分享
  1. public class RSA {  
  2.   
  3.     public static final int KEYSIZE = 512;  
  4.       
  5.     private KeyPair keyPair;  
  6.     private Key publicKey;  
  7.     private Key privateKey;  
  8.       
  9.     /** 
  10.      * 生成秘钥对 
  11.      * @return 
  12.      * @throws NoSuchAlgorithmException 
  13.      */  
  14.     public KeyPair generateKeyPair() throws NoSuchAlgorithmException {  
  15.         KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");  
  16.         SecureRandom random = new SecureRandom();  
  17.         pairgen.initialize(RSA.KEYSIZE, random);  
  18.         this.keyPair = pairgen.generateKeyPair();  
  19.         return this.keyPair;  
  20.     }  
  21.   
  22.     /** 
  23.      * 加密秘钥 
  24.      * @param key 
  25.      * @return 
  26.      * @throws NoSuchAlgorithmException 
  27.      * @throws NoSuchPaddingException 
  28.      * @throws InvalidKeyException 
  29.      * @throws IllegalBlockSizeException 
  30.      */  
  31.     public byte[] wrapKey(Key key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException {  
  32.         Cipher cipher = Cipher.getInstance("RSA");  
  33.         cipher.init(Cipher.WRAP_MODE, this.privateKey);  
  34.         byte[] wrappedKey = cipher.wrap(key);  
  35.         return wrappedKey;  
  36.     }  
  37.       
  38.     /** 
  39.      * 解密秘钥 
  40.      * @param wrapedKeyBytes 
  41.      * @return 
  42.      * @throws NoSuchAlgorithmException 
  43.      * @throws NoSuchPaddingException 
  44.      * @throws InvalidKeyException 
  45.      */  
  46.     public Key unwrapKey(byte[] wrapedKeyBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {  
  47.         Cipher cipher = Cipher.getInstance("RSA");  
  48.         cipher.init(Cipher.UNWRAP_MODE, this.publicKey);  
  49.         Key key = cipher.unwrap(wrapedKeyBytes, "AES", Cipher.SECRET_KEY);  
  50.         return key;  
  51.     }  
  52.   
  53.     public Key getPublicKey() {  
  54.         return publicKey;  
  55.     }  
  56.   
  57.     public void setPublicKey(Key publicKey) {  
  58.         this.publicKey = publicKey;  
  59.     }  
  60.   
  61.     public Key getPrivateKey() {  
  62.         return privateKey;  
  63.     }  
  64.   
  65.     public void setPrivateKey(Key privateKey) {  
  66.         this.privateKey = privateKey;  
  67.     }  
  68.       
  69. }  

以上是关于uniapp接口层的aes和rsa的对称与非对称加密的主要内容,如果未能解决你的问题,请参考以下文章

对称(DES/AES)与非对称(RSA/SSL/数字证书)加密介绍及实际应用

区块链之加解密算法&数字证书

对称加密与非对称加密算法

加密算法:DESAES等

[转]加密算法(DES,AES,RSA,MD5,SHA1,Base64)比较和项目应用

技术解读区块链密码学的起源,了解多链与非对称加密