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加密的内容,以此来判断前后端加密方式是否一致。 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
双向 RSA + AES 加密是一种常见的加密方式,其中使用 RSA 算法加密 AES 密钥,然后使用 AES 算法加密数据。在 C# 中,可以使用 `RSACryptoServiceProvider` 类和 `AesCryptoServiceProvider` 类来实现此加密方式。以下是一个简单的示例: ```csharp using System; using System.IO; using System.Security.Cryptography; using System.Text; class Program { static void Main(string[] args) { string plainText = "Hello, world!"; byte[] encryptedData = Encrypt(plainText); string decryptedText = Decrypt(encryptedData); Console.WriteLine("Original text: {0}", plainText); Console.WriteLine("Encrypted data: {0}", Convert.ToBase64String(encryptedData)); Console.WriteLine("Decrypted text: {0}", decryptedText); } static byte[] Encrypt(string plainText) { byte[] aesKey = GenerateAesKey(); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] encryptedAesKey = rsa.Encrypt(aesKey, true); // 使用 RSA 加密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.GenerateIV(); using (var memoryStream = new MemoryStream()) { memoryStream.Write(aes.IV, 0, aes.IV.Length); using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] plainData = Encoding.UTF8.GetBytes(plainText); cryptoStream.Write(plainData, 0, plainData.Length); cryptoStream.FlushFinalBlock(); } byte[] encryptedData = memoryStream.ToArray(); byte[] result = new byte[encryptedAesKey.Length + encryptedData.Length]; Buffer.BlockCopy(encryptedAesKey, 0, result, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, 0, result, encryptedAesKey.Length, encryptedData.Length); return result; } } } } static string Decrypt(byte[] encryptedData) { byte[] encryptedAesKey = new byte[128]; // RSA 加密 AES 密钥得到的密文长度为 128 字节 byte[] encryptedDataOnly = new byte[encryptedData.Length - encryptedAesKey.Length]; Buffer.BlockCopy(encryptedData, 0, encryptedAesKey, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, encryptedAesKey.Length, encryptedDataOnly, 0, encryptedDataOnly.Length); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] aesKey = rsa.Decrypt(encryptedAesKey, true); // 使用 RSA 解密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.IV = encryptedDataOnly.Take(aes.IV.Length).ToArray(); using (var memoryStream = new MemoryStream()) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(encryptedDataOnly, aes.IV.Length, encryptedDataOnly.Length - aes.IV.Length); cryptoStream.FlushFinalBlock(); } byte[] decryptedData = memoryStream.ToArray(); return Encoding.UTF8.GetString(decryptedData); } } } } static byte[] GenerateAesKey() { using (var aes = new AesCryptoServiceProvider()) { aes.GenerateKey(); return aes.Key; } } } ``` 上面的代码中,首先调用 `GenerateAesKey` 方法生成 AES 密钥,然后使用 RSA 算法加密 AES 密钥。加密时,先将 AES 密钥使用 RSA 加密,然后使用 AES 算法加密数据。具体来说,将 AES 密钥和 IV 都写入 `MemoryStream` 对象中,然后使用 `CryptoStream` 对象将数据写入 `MemoryStream` 对象中。最后将密文和 RSA 加密AES 密钥一起返回。 解密时,先从密文中取出 RSA 加密AES 密钥,然后使用 RSA 算法解密 AES 密钥。解密时,先从密文中取出 AES 的 IV 值,然后使用 `CryptoStream` 对象将数据解密。最后将解密后的文本返回。 注意,上面的示例仅用于演示 RSA + AES 加密的基本原理,实际使用中还需要考虑安全性等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值