一、知识点分析
1.crypto 模块提供了加密功能,实现了包括对openSSl的哈希、HMAC、加密、解密、签名、以及验证功能的一整套封装
2.crypto模块的目的是为了提供通用的加密和哈希算法,用纯javascript代码实现这些功能不是不可能,但速度会非常慢,node.js用C/C++实现这些算法后,通过cypto这个模块暴露为javascript接口,这样用起来也方便,运行速度也快
二、PBKDF2加密
①关于PBKDF2加密解释
PBKDF2通过哈希算法进行加密,由于哈希算法是单向的,能够将不论大小的数据转化为定长的“指纹”,并且无法被反向计算。另外,即使数据源仅仅修改了一点点,哈希的结果也会全然不同。
这种特性是的他很适合用于保存password。由于我们需要加密后的password无法被破解,同时也能保证正确校验每一个用户的password。可是哈希加密能够通过字典攻击和暴力攻击破解。
password加盐。盐是一个加入到用户的password哈希过程中的一段随机序列。这个机制可以防止通过预先计算结果的彩虹表破解。每一个用户都有自己的盐,这种结果就是即使用户的password一样,通过加盐后哈希值也将不同。为了校验password是否正确,我们需要存储盐值,通常和password哈希值一起存放在账户数据库中,或者直接存为哈希字符串的一部分。
②使用
1)方法一,使用cropty加密
PBKDF2 是 Node.js 的 crypto 模块原生支持的标准方法。
1.引入crypto模块(已经存在node,直接引入crypto模块)
引入方式1: import cropty from "cropty"
引入方式2: const crypto = require('crypto');
2.使用
1.crypto-生成随机盐值-提供异步基于密码的密钥派生函数 2 (PBKDF2) 实现:
应用由 digest 指定的选定 HMAC 摘要算法以从 password、salt 和 iterations 导出请求字节长度 (keylen) 的密钥。
参数简介:
- password: 需要加密的密码
- salt: 盐值,应该尽可能唯一,建议盐值随机,长度至少为16字节。--
crypto.randomBytes() - iterations: 迭代次数,必须是数字格式,迭代次数越多,派生密钥就越安全,但需要时间也会更长
- keylen: 导出请求字节长度的密钥
- digest:
digest是null,则将使用'sha1'。 此行为已弃用,请显式指定digest,值一个哈希函数,eg:'MD5'、'sha1'、'sha256'、'sha512' - callback: 它是一个具有两个参数的函数,即err和DerivedKey。如果在派生密钥时发生错误,则设置
err;否则err将是null。 默认情况下,成功生成的derivedKey将作为Buffer传给回调。 如果任何输入参数指定了无效的值或类型,则会抛出错误。
function pbkdf2_encrypt(username, password) {
// crypto.randomBytes()方法生成 32 字节的随机数 - 这里作为盐值
crypto.randomBytes(32, (err, salt) => {
if (err) throw err;
// 参数列表:(密码(password),盐值(salt),迭代次数(iterations),生成密钥长度(keylen),摘要函数(digest))
crypto.pbkdf2(password, salt, 4096, 512, 'sha256', (err, key) => {
if (err) throw err;
// 将用户名、密码哈希值和盐值存入数据库
console.log(username, key.toString('hex'), salt.toString('hex'));
});
});
}
pbkdf2_encrypt('zhangSan', '123456');
2.crypto-生成随机盐值-提供同步基于密码的密钥派生函数 2 (PBKDF2) 实现:
function pbkdf2_encrypt(username, password) {
const salt = crypto.randomBytes(32);//方法生成 32 字节的随机数 - 这里作为盐值
const result = crypto.pbkdf2Sync(password, salt, iterations, keylen, 'sha256');
return keyvalue.toString('hex') //字符串加密成hex字符串
}
2)方法二:使用croptyjs加密
// 官方示例
var str = '123456';
var salt = CryptoJS.lib.WordArray.random(128/8); //随机产生盐值
var saltTwo =parseInt(salt,16).toString(16)
var key128Bits = CryptoJS.PBKDF2(str, saltTwo, { keySize: 128/32 });
var key256Bits = CryptoJS.PBKDF2(str, saltTwo, { keySize: 256/32 });
var key512Bits = CryptoJS.PBKDF2(str, saltTwo, { keySize: 512/32 });
var key512Bits1000Iterations = CryptoJS.PBKDF2("Secret Passphrase", saltTwo, {
keySize: 512/32,
iterations: 1000
});
var key256Bits1000Iterations = CryptoJS.PBKDF2(word, salt, {
keySize: 256/32,
iterations: 10000,
hasher: CryptoJS.algo.SHA256
});
return key256Bits1000Iterations.toString(CryptoJS.enc.Hex);