前端加密的分类
- md5 基于 单向加密算法
- AES 基于 对称加密算法
- RSA 基于 非对称加密算法
- DSA
- ......
md5
基本概念
单向加密,人如其名,就是只能单向对明文进行加密,而不能逆向通过密文得到明文。该算法在加密过程中,在得到明文后,经过加密算法得到密文,不需要使用密钥。因为没有密钥,所以就无法通过密文得到明文。
MD5,全称Message Digest Algorithm 5,翻译过来就是消息摘要算法第5版,是计算机安全领域广泛使用的一种散列函数,用于确保信息传输的完整性。MD5算法是由MD2、MD3、MD4演变而来,是一种单向加密算法,一种不可逆的加密方式。
特点
- 长度固定
无论多长的数据,经过MD5加密后其MD5值长度都是固定的。MD5值长度固定为128位,而最后的值一般都用16进制数字表示,一个16进制数字占4位,所以最后的MD5值都是用32个16进制数字表示。
- 计算简单
MD5算法说到底还是散列算法,或者叫做哈希算法,所以计算一个数据的MD5值是比较容易的,同时加密速度也是很快的。
- 抗修改性
对原数据进行任何改动,哪怕只是修改1个字节,所得到的MD5值都有很大的区别。
- 强抗碰撞性
已知原数据和其MD5值,很难找到具有相同MD5值的数据,即很难伪造数据。
安全性
MD5加密本身来讲这个过程是不可逆的, 一般通过撞库破解,首先建立一个大型的数据库,然后把最常见的,有可能出现的密码,通过MD5加密成密文,并且以这些MD5值为主键加索引,将常见的密码为单列存入数据库中,并通过不断的积累,形成一个巨大的密码MD5数据库,这样当你截取到网络上密码的MD5值时,通过查询这个巨大的数据库来直接匹配MD5值,这就是所谓的撞库,
撞库破解的概率是很低的
加盐算法,会使得破解更加困难
使用
index.html
倒入md5 即可
<script src="./resources/UtilMd5.js"></script>
// 或者使用cdn
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.min.js"></script>
使用实例
普通加密
md5(pwd)
加盐加密
//盐值
var salt = "";
md5(pwd + salt);
AES
基本概念
对称加密,美国国家标准技术研究所在2001年发布了高级加密标准(AES)。 AES是基于数据块的加密方式, 即,每次处理的数据是一块(16字节),当数据不是16字节的倍数时填充, 这就是所谓的分组密码(区别于基于比特位的流密码),16字节是分组长度。
特点
- 安全性(Security) 算法足够强,抗攻击
- 经济性(Efficiency) 算法运算效率高
- 密钥捷变(Key Agility) 更改密钥所引入的损失尽量小,即最小消耗的密钥扩展算法
- 适应性 (Versatility) 适用于不同的CPU架构,软件或硬件平台的实现
- 设计简单(Simplicity) 轮函数的设计精简,只是多轮迭代
安全性
注意到AES有很多不同的算法,如aes192,aes-128-ecb,aes-256-cbc等,AES除了密钥外还可以指定IV(Initial Vector),不同的系统只要IV不同,用相同的密钥加密相同的数据得到的加密结果也是不同的。加密结果通常有两种表示方法:hex和base64,这些功能Nodejs全部都支持,但是在应用中要注意,如果加解密双方一方用Nodejs,另一方用Java、PHP等其它语言,需要仔细测试。如果无法正确解密,要确认双方是否遵循同样的AES算法,字符串密钥和IV是否相同,加密后的数据是否统一为hex或base64格式。
使用示例
新建crypto.js文件,构建crypto类
import CryptoJS from 'crypto-js';
class CryptoFile {
constructor () {
// 秘钥
this.key = CryptoJS.enc.Utf8.parse('CRYPTOJSKEY00000'); // 16位
this.iv = CryptoJS.enc.Utf8.parse('CRYPTOJSKEY00000');
}
// 加密
encrypt(word) {
let words = CryptoJS.enc.Utf8.parse(word);
let encrypted = CryptoJS.AES.encrypt(words, this.key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
return encrypted.toString();
}
// 解密
decrypt(word) {
let decrypt = CryptoJS.AES.decrypt(word, this.key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
}
export default new CryptoFile()
前端使用
import crypto from './crypto';
let data = '你加密的数据'
let encryptData = crypto.encrypt(JSON.stringify(data)); // 加密后的数据
let decryptData = crypto.decrypt(encryptData) // 解密后的数据
前端使用
import CryptoJS from 'crypto-js';
let data = '你加密的数据'
// 加密函数
function aesMinEncrypt(word){
let _word = CryptoJS.enc.Utf8.parse(word);
let _key = CryptoJS.enc.Utf8.parse("CRYPTOJSKEY00000"),// 16位
let _iv = CryptoJS.enc.Utf8.parse("CRYPTOJSKEY00000");
// _key 是密钥 ,_iv 是密钥偏移量
// 一般由后端返回,或者写死
var encrypted = CryptoJS.AES.encrypt(_word, _key, {
iv: _iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
// mode: 采用的加密算法,有aes192,aes-128-ecb,aes-256-cbc等
// padding : 数据填充 数据采用 PKCS#7 填充 , AES是基于数据块的加密方式,每次处理的数据是一块(16字节),当数据不是16字节的倍数时填充 因此这里的 key 需要为16位!
let encryptData = aesMinEncrypt(data); // 加密后的数据
// 解密函数
function aesMinDecrypt(word){
let _word = CryptoJS.enc.Utf8.parse(word);
let _key = CryptoJS.enc.Utf8.parse("CRYPTOJSKEY00000"),// 16位
let _iv = CryptoJS.enc.Utf8.parse("CRYPTOJSKEY00000");
var decryptedStr = CryptoJS.AES.decrypt(_word, _key, {
iv: _iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return decryptedStr.toString();
}
let decryptData = aesMinDecrypt(data) // 解密后的数据
RSA
基本概念
对称加密就是加密和解密使用同一个密钥。对称加密快而且方便,但是有个缺点,密钥容易被偷或被破解。非对称算法把密钥分成两个,一个自己持有叫私钥,另一个发给对方,还可以公开,叫公钥,用公钥加密的数据只能用私钥解开。
特点
素数 又称质数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。
互质 又称互素。若N个整数的最大公因子是1,则称这N个整数互质。
模运算 即求余运算。“模”是“Mod”的音译。和模运算紧密相关的一个概念是“同余”。数学上,当两个整数除以同一个正整数,若得相同余数,则二整数同余。
欧拉函数 计算小于或等于n的正整数中与n互质的数的数目,以φ(n)表示。
安全性
RSA作为非对称加密技术的代表,加解密的速度其实相当慢,只能对小块的数据进行加解密。但是其非对称的特点,满足公钥可以随处分发,只有公钥能解密私钥加密的数据,只有私钥能解密公钥加密的数据。所以很适合用来进行密钥分发和身份验证,这两个应用场景刚好相反。
使用示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>使用jsencrypt执行OpenSSL的RSA加密,解密</title>
</head>
<!--引入jsencrypt.js-->
<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
</html>
function rsaMinEncrypt(word) {
// 公钥
const PUBLIC_KEY = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1qA+W/3WXYfOvzyoQyhgxIO+jscUrU8B
qMw0m5S1AkRu4Hocb8BOjlqsxgZwV4JTW6oZuBNbKaYaihcPpqX5NvaIQaFibIhDQAEV9+voUF2b
Zoo1yhloJ7SzYz4yw0ftZLhvoo4mmffK0Irj33q4TPAo3+8rGGjQW0dUFGAggX3sOeRMxsL4x6Vx
Ajfj9t+3en8mr02d5JLsC4XRfIgmkO6+JA7PsFJcqm4UVlQTNEoXgbuWwMyYkjZzNTx7MdJ4nTd0
ytP15n9A6Z81MN0o5IhoYhiUEUwQXkLWjVuveP7oJZqO+FIyxzHorRpaEkOosH2j3j53bPoLv9GZ
Dvbn/wIDAQAB`;
const encrypt = new JSEncrypt();
// encrypt.setPrivateKey('-----BEGIN RSA PRIVATE KEY-----'+PRIVATE_KEY+'-----END RSA PRIVATE KEY-----');
encrypt.setPublicKey(`-----BEGIN PUBLIC KEY-----${PUBLIC_KEY}-----END PUBLIC KEY-----`);
// var str = {
// "uid":"1223334",
// "pwd":"asd"
// }
const encrypted = encrypt.encrypt(word);
//console.log('加密前数据:%o', word);
//console.log('加密后数据:%o', encrypted);
return encrypted;
}
let data = '你加密的数据'
rsaMinEncrypt(data)