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对称加密,解密
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.security.InvalidKeyException;
- import java.security.Key;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import javax.crypto.BadPaddingException;
- import javax.crypto.Cipher;
- import javax.crypto.IllegalBlockSizeException;
- import javax.crypto.KeyGenerator;
- import javax.crypto.NoSuchPaddingException;
- import javax.crypto.ShortBufferException;
- public class AES {
- private Key key;
- /**
- * 生成AES对称秘钥
- * @throws NoSuchAlgorithmException
- */
- public void generateKey() throws NoSuchAlgorithmException {
- KeyGenerator keygen = KeyGenerator.getInstance("AES");
- SecureRandom random = new SecureRandom();
- keygen.init(random);
- this.key = keygen.generateKey();
- }
- /**
- * 加密
- * @param in
- * @param out
- * @throws InvalidKeyException
- * @throws ShortBufferException
- * @throws IllegalBlockSizeException
- * @throws BadPaddingException
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws IOException
- */
- public void encrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
- this.crypt(in, out, Cipher.ENCRYPT_MODE);
- }
- /**
- * 解密
- * @param in
- * @param out
- * @throws InvalidKeyException
- * @throws ShortBufferException
- * @throws IllegalBlockSizeException
- * @throws BadPaddingException
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws IOException
- */
- public void decrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
- this.crypt(in, out, Cipher.DECRYPT_MODE);
- }
- /**
- * 实际的加密解密过程
- * @param in
- * @param out
- * @param mode
- * @throws IOException
- * @throws ShortBufferException
- * @throws IllegalBlockSizeException
- * @throws BadPaddingException
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws InvalidKeyException
- */
- public void crypt(InputStream in, OutputStream out, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(mode, this.key);
- int blockSize = cipher.getBlockSize();
- int outputSize = cipher.getOutputSize(blockSize);
- byte[] inBytes = new byte[blockSize];
- byte[] outBytes = new byte[outputSize];
- int inLength = 0;
- boolean more = true;
- while (more) {
- inLength = in.read(inBytes);
- if (inLength == blockSize) {
- int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
- out.write(outBytes, 0, outLength);
- } else {
- more = false;
- }
- }
- if (inLength > 0)
- outBytes = cipher.doFinal(inBytes, 0, inLength);
- else
- outBytes = cipher.doFinal();
- out.write(outBytes);
- out.flush();
- }
- public void setKey(Key key) {
- this.key = key;
- }
- public Key getKey() {
- return key;
- }
- }
RSA非对称加密,解密对称秘钥
- public class RSA {
- public static final int KEYSIZE = 512;
- private KeyPair keyPair;
- private Key publicKey;
- private Key privateKey;
- /**
- * 生成秘钥对
- * @return
- * @throws NoSuchAlgorithmException
- */
- public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
- KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
- SecureRandom random = new SecureRandom();
- pairgen.initialize(RSA.KEYSIZE, random);
- this.keyPair = pairgen.generateKeyPair();
- return this.keyPair;
- }
- /**
- * 加密秘钥
- * @param key
- * @return
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws InvalidKeyException
- * @throws IllegalBlockSizeException
- */
- public byte[] wrapKey(Key key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException {
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.WRAP_MODE, this.privateKey);
- byte[] wrappedKey = cipher.wrap(key);
- return wrappedKey;
- }
- /**
- * 解密秘钥
- * @param wrapedKeyBytes
- * @return
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws InvalidKeyException
- */
- public Key unwrapKey(byte[] wrapedKeyBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.UNWRAP_MODE, this.publicKey);
- Key key = cipher.unwrap(wrapedKeyBytes, "AES", Cipher.SECRET_KEY);
- return key;
- }
- public Key getPublicKey() {
- return publicKey;
- }
- public void setPublicKey(Key publicKey) {
- this.publicKey = publicKey;
- }
- public Key getPrivateKey() {
- return privateKey;
- }
- public void setPrivateKey(Key privateKey) {
- this.privateKey = privateKey;
- }
- }
以上是关于uniapp接口层的aes和rsa的对称与非对称加密的主要内容,如果未能解决你的问题,请参考以下文章
对称(DES/AES)与非对称(RSA/SSL/数字证书)加密介绍及实际应用