阅读前:文章记录crypto库的简单了解,和一些简单的用法,与具体加解密算法的实现无关。
文中例子使用到了node的crypto模块 和 npm sjcl(Stanford Javascript Crypto Library) 包。
文章概要:
- crypto
- Hash(散列)算法
- Hmac算法
- PBKDF2函数
- 对称加密 AES
- 小结
1. crypto
Crypto++ 库是一个用c++ 编写的密码类库,提供完整的加密实现,并且通常包括不太流行,不常使用的方案。(简单说:包括了加解密算法的库)
AES和AES候选(AES and AES candidates):Rijndael (AES selection), RC6, MARS, Twofish, Serpent, CAST-256
分组密码操作模式(Block cipher modes of operation): ECB, CBC, CTS, CFB, OFB, CTR
分组密码填充方案(Block ciphers padding schemes): PKCS#5, PKCS#7, Zeros, One and zeros, W3C Padding
基于密码的密钥派生函数(Password based key derivation functions):PBKDF1 and PBKDF2 from PKCS #5, PBKDF from PKCS #12 appendix B, Krawczyk and Eronen's HKDF......
后台:文中使用的是node,node 中有cypto这个模块,提供加密功能。
前端:文中使用的是sjcl库,sjcl (Stanford Javascript Crypto Library)。
2.Hash(散列)算法
散列算法也叫哈希算法,用来把任意长度的输入变换成固定长度的输出。常见的有md5,sha1等。
const crypto = require('crypto'); const hash = crypto.createHash('md5'); // 可任意多次调用update(): // 指定要摘要的原始内容,可以在摘要被输出之前使用多次update方法来添加摘要内容 hash.update('Hello, world!'); hash.update('Hello, nodejs!'); console.log(hash.digest('hex'));
eg. 一种应用:将压缩包文件计算出MD5值,当客户端下载完压缩包也计算出MD5,然后比对,文件是否下载完毕。
3. Hmac算法
HMAC算法将散列算法与一个密钥结合在一起,以阻止对签名完整性的破坏,密钥发生了变化,输出结果也会发生变化.(Hmac可以理解为用随机数“增强”的哈希算法)
let hmac = crypto.createHmac(algorithm,key); hmac.update(data); console.log(hmac.digest('hex')); // algorithm 是一个可用的摘要算法,例如 sha1、md5、sha256 // key为一个字符串,用于指定一个PEM格式的密钥
const crypto = require('crypto'); const hmac = crypto.createHmac('sha256', key); hmac.update('Hello, world!'); hmac.update('Hello, nodejs!'); console.log(hmac.digest('hex'));
4.PBKDF2函数
PBKDF2:是一个用来导出密钥的函数,常用于生成加密的密码
DK = PBKDF2(PRF, Password, Salt, c, dkLen)
PRF:一个伪随机函数,例如HASH_HMAC函数,它会输出长度为hLen的结果。
Password:是用来生成密钥的原文密码。
Salt:一个加密用的盐值。
c:重复计算的次数。
dkLen:期望得到的密钥的长度。
DK:最后产生的密钥。
基本原理:通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥。
var sjcl = require('sjcl.js'); // 密码,盐值,迭代次数,期待秘钥长度,伪随机函数 sjcl.misc.pbkdf2(pwd, salt, iteration, 256, hmacSHA256)
5.对称加密 AES
AES是一种常用的对称加密算法,加解密都用同一个密钥。
分组密码又称为秘密钥密码或对称密码。利用分组密码对明文进行加密时,首先需要对明文进行分组,每组的长度都相同,然后对每组明文分别加密得到等长的密文,分组密码的特点是加密密钥与解密密钥相同。 分组密码的安全性应该主要依赖于密钥,而不依赖于对加密算法和解密算法的保密。因此,分组密码的加密和解密算法可以公开。
重点:分组密码的安全性应该主要依赖于密钥
后端node crypto 模块
// data:需要加解密的内容, // 密钥 // 初始化向量(iv) function aesEncrypt(data, key, iv) { var ivBuffer = new Buffer(iv, 'hex'); // 给定的算法,密钥和初始化向量(iv)创建并返回Cipher对象 const cipher = crypto.createCipher('aes-256-cbc', key, ivBuffer); // 用数据更新cipherData var crypted = cipher.update(data, 'utf8', 'hex'); crypted += cipher.final('hex'); return crypted; } function aesDecrypt(data, key, iv) { var ivBuffer = new Buffer(iv, 'hex'); // 给定的算法,密钥和初始化向量(iv)解密数据 const decipher = crypto.createDecipher('aes-256-cbc', key, ivBuffer); // 用数据更新decrypted var decrypted = decipher.update(data, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; }
前端:sjcl库
// str:需要加解密的内容, // 密钥 // 初始化向量(iv) // 返回数据格式 export function encrypt(str, key, iv, sourceEncode = 'utf8String') { var aes = new sjcl.cipher.aes(sjcl.codec.hex.toBits(key)); if (sourceEncode) { str = sjcl.codec[sourceEncode].toBits(str); } var encrypted = sjcl.mode['cbc'].encrypt(aes, str, sjcl.codec.hex.toBits(iv)); return sjcl.codec.base64.fromBits(encrypted); } export function decrypt(str, key, iv, sourceEncode = 'base64') { var aes = new sjcl.cipher.aes(sjcl.codec.hex.toBits(key)); if (sourceEncode) { str = sjcl.codec[sourceEncode].toBits(str); } var decrypted = sjcl.mode['cbc'].decrypt(aes,str, sjcl.codec.hex.toBits(iv)); return sjcl.codec.utf8String.fromBits(decrypted); }
前后端的算法加解密算法一致(例子中使用的aes-256-cbc),数据可以加密传输了,怎么产生密钥就是需要思考的问题。
6.小结
文中例子比较粗糙,理解不准确之处,还请教正。
关于加解密crypto库还常用的有,非对称加密算法,以及签名。然后在实际项目中我并没有使用过 还需理解,有时间还会补上,修正本篇。