最近客户要求不能在接口中暴露信息 于是在项目中对请求接口进行加密操作,总结一下
前端常用的加密/解密算法主要有两类: 两者的主要区别在于加密和解密的密钥是否一致,一致的就是对称加密,不一致的就是非对称加密。
非对称加密算法:常用的是RSA加密算法。jsencrypt
npm install jsencrypt --save-dev
采用加解密模式为:前端使用公钥加密,公钥解密
需要进入依赖包中修改jsencrypt.js 文件中方法(可以copy一份 避免修改源码),具体方法如下:
拷贝pkcs1unpad2方法为拷贝pkcs1unpad2public方法
1. // 这里将如下三行代码注释
1. // if (b.length - i != n - 1 || b[i] != 2) {
1. // return null;
1. // }
拷贝RSAKey.prototype.decrypt方法为RSAKey.prototype.publicDecrypt方法,将 this.doPrivate(c) 改为 this.doPublic(c) ; 将 pkcs1unpad2 改为 pkcs1unpad2public
RSAKey.prototype.publicDecrypt = function (ctext) {
var c = parseBigInt(ctext, 16);
var m = this.doPublic(c);
if (m == null) {
return null;
}
return pkcs1unpad2public(m, (this.n.bitLength() + 7) >> 3);
};
使用rsa加解密过程中会出现待加密和待解密字符串过长情况,需要用到分段加解密:
公钥加密长字符
JSEncrypt.prototype.encryptLong = function(string) {
var k = this.getKey();
var maxLength = (((k.n.bitLength() + 7) >> 3) - 11);//117
try {
var ct = '';
// RSA每次加密117bytes,需要辅助方法判断字符串截取位置
// 1.获取字符串截取点
var bytes = [];
bytes.push(0);
var byteNo = 0;
var len, c;
len = string.length;
var temp = 0;
for (var i = 0; i < len; i++) {
c = string.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10FFFF) {
byteNo += 4;
} else if (c >= 0x000800 && c <= 0x00FFFF) {
byteNo += 3;
} else if (c >= 0x000080 && c <= 0x0007FF) {
byteNo += 2;
} else {
byteNo += 1;
}
// if ((byteNo % maxLength) >= maxLength-3 || (byteNo % maxLength) === 0) {
if (byteNo - temp >= maxLength) {
bytes.push(i);
temp = byteNo;
}
// }
}
// 2.截取字符串并分段加密
if (bytes.length > 1) {
for (let i = 0; i < bytes.length - 1; i++) {
var str;
if (i === 0) {
str = string.substring(0, bytes[i + 1] + 1);
} else {
str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);
}
var t1 = k.encrypt(str);
// console.log(`%c【part${i}】`, 'color:#52BBFF', ``,str)
// console.log(`part${i}`,t1)
ct += t1;
}
;
if (bytes[bytes.length - 1] !== string.length - 1) {
var lastStr = string.substring(bytes[bytes.length - 1] + 1);
ct += k.encrypt(lastStr);
// debugger;
}
return hex2b64(ct);
}
var t = k.encrypt(string);
var y = hex2b64(t);
return y;
} catch (ex) {
return false;
}
};
公钥解密长字符串
JSEncrypt.prototype.publiDecryptLong = function (string) {
// Return the decrypted string.
var k = this.getKey();
var maxLength = ((k.n.bitLength() + 7) >> 3);
try {
var str = b64tohex(string);
var inputLen = str.length;
var ct = '';
if (inputLen > maxLength) {
var lt = str.match(/.{1,256}/g);
lt.forEach(function(entry) {
var t1 = k.publicDecrypt(entry);
ct += t1;
});
return ct;
}
var y = k.publicDecrypt(b64tohex(string));
return y;
} catch (ex) {
return false;
}
};
私钥解密长字符串
JSEncrypt.prototype.privateDecryptLong = function (text) {
var k = this.getKey();
var maxLength = ((k.n.bitLength() + 7) >> 3);
try {
var str = b64tohex(text);
var inputLen = str.length;
var ct = "";
if (inputLen > maxLength) {
var lt = str.match(/.{1,256}/g);
lt.forEach(function (entry) {
console.log(entry)
var t1 = k.decrypt(entry);
console.log(t1)
ct += t1;
});
return ct;
}
var y = k.decrypt(b64tohex(string));
return y;
}
catch (ex) {
return false;
}
};
//公钥加密
export const jsencrypt = (value) => {
const jse = new JSEncrypt();
jse.setPublicKey(PUBLIC_KEY);
// 加密前使用encodeURIComponent解决中文乱码
// const encodestr =encodeURIComponent(value)
return jse.encryptLong(value)
}
//公钥解密
export function jsdecrypt(value) {
const jse = new JSEncrypt();
jse.setPublicKey(PUBLIC_KEY);
const jsestr = jse.publiDecryptLong(value)
// return decodeURIComponent(jsestr)
return jsestr
}
一顿猛虎操作后,发现在代码应用过程中还是会有加密错误的情况,非常偶现,可能是截断那块代码的问题 还不确定
于是还是选择了AES
对称加密算法:常用的是AES加密算法 crypto-js
crypto-js 是一个纯 javascript 写的加密算法类库 ,可以非常方便地在 javascript 进行 MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。
npm install crypto-js
加密字符没有长度限制,具体使用如下
/**
* 工具类
*/
import CryptoJS from 'crypto-js'
export default {// 加密
encrypt (word) {
const { keyStr,ivStr } = getIVandKEY()
// 加密前使用encodeURIComponent解决中文乱码
const urlstr = encodeURIComponent(word)
var wordstr = CryptoJS.enc.Utf8.parse(urlstr)
var key = CryptoJS.enc.Utf8.parse(keyStr)
var ivv = CryptoJS.enc.Utf8.parse(ivStr)
var encrypted = CryptoJS.AES.encrypt(
wordstr,
key,
{ iv: ivv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
)
return encrypted.toString()
},
// 解密
decrypt (word) {
const { keyStr,ivStr } = getIVandKEY()
var key = CryptoJS.enc.Utf8.parse(keyStr)
var ivv = CryptoJS.enc.Utf8.parse(ivStr)
var decrypt = CryptoJS.AES.decrypt(
word,
key,
{ iv: ivv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
)
const urlstr = CryptoJS.enc.Utf8.stringify(decrypt).toString()
return decodeURIComponent(urlstr)
}
}
😊