likes
comments
collection
share

Crypto 小记

作者站长头像
站长
· 阅读数 15

Node 中的Crypto 模块提供了加解密算法,包括hash,HAMC,加解密、签名以及验证等,每种算法都有自己的应用场景。下面详解介绍

散列算法(hash)

又称散列函数哈希****函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。

Hash 的特点

  • hash值不可逆,无法根据hash 值推测出原本的数值

  • 不同输入会有不同的输出

  • 果两个散列值相同,两个输入值很可能是相同的,但也可能不同,这种情况称为“杂凑碰撞(collision),好的 hash 算法冲突概率会很低。

Hash 的应用:密码存储,页面版本、数据校验等。

常用的hash 算法:

Crypto 小记

获取所有 hash 算法

const crypto = require('crypto');
console.log(crypto.getHashes())
[
  'RSA-MD4',
  'RSA-MD5',
  'RSA-MDC2',
  'RSA-RIPEMD160',
  'RSA-SHA1',
  'RSA-SHA1-2',
  'RSA-SHA224',
  'RSA-SHA256',
  'RSA-SHA3-224',
  'RSA-SHA3-256',
  'RSA-SHA3-384',
  'RSA-SHA3-512',
  'RSA-SHA384',
  'RSA-SHA512',
  'RSA-SHA512/224',
  'RSA-SHA512/256',
  'RSA-SM3',
]

常用的hash 算有:md5 、sha256 等。

使用hash 实例

const crypto = require('crypto');

const hash = crypto.createHash('sha256'); // 创建基于 sha256 算法的hash 对象

hash.update('111111', 'utf-8');//增加要添加摘要的数据,摘要输出前可以使用多次update
let value = hash.digest('hex');//输出摘要内容,输出后则不能再添加摘要内容

console.log(value) //bcb15f821479b4d5772bd0ca866c00ad5f926e3580720659cc80d39c9d09802a
  • 多次update
var fs = require('fs'); 
const crypto = require('crypto');

const hash = crypto.createHash('sha256'); // 创建基于 sha256 算法的hash 对象

const rs = fs.createReadStream('./readme.txt'); 
rs.on('data', function (data) {     
hash.update(data);
});
 rs.on('end', function () {   
   let  result = hash.digest('hex');     
console.log(result); })

HMAC 算法

Hmac 算法可以看做是hash 算法的一种扩展,虽然hash算法是不可逆的,不能有hash 值反解出来原始值,但是可以通过"彩虹表",使用碰撞法,根据hash 值得到原始值。hmac 是将hash 算法和秘钥结合在一起,在计算hash值的时候增加秘钥。来防止对hash 值的破解。

用法

crypto.createHmac(algorithm, key[, options])

  • // algorithm : hash 算法 和hash 算法保持一致

  • // key: 加密秘钥,客户是string buffer 等类型

  • // 可选参数 options encoding <string> The string encoding to use when key is a string.

实例

const hash = crypto.createHmac('sha256', 'sdakljdjajkdlsajeiw');
hash.update('111111', 'utf-8');//增加要添加摘要的数据,摘要输出前可以使用多次update
let value = hash.digest('hex');//输出摘要内容,输出后则不能再添加摘要内容
console.log(value) //4eb53842bf5fee692014ba84ddab4b444aed7183bc334e1870ef33d8a2be43e8

对称加密

对称加密就是加解密需要使用相同的秘钥。

查看node中 提供了 Cipher 和 Decipher ,类来进行对称的加解密。node中提供的对称加解密的算法有:

console.log(crypto.getCiphers())


  'aes-128-cbc',
  'aes-128-cbc-hmac-sha1',
  'aes-128-cbc-hmac-sha256',
  'aes-128-ccm',
  'aes-128-cfb',
  .....

常用的 算法有: AES、blowfish 等

用法

加密

crypto.createCipheriv(algorithm, key, iv[, options])

  • algorithm**: 加密算法**

  • Key & iv : 秘钥和初始化向量

解密

crypto.createDecipheriv(algorithm, key, iv[, options])

  • algorithm**: 加密算法**

  • Key & iv : 秘钥和初始化向量

实例

// 加密
let secret = 'iamasecret111111';
let iv = crypto.randomBytes(16);
// let iv = Buffer.alloc(16, 0);
let content = 'password';
const cipher = crypto.createCipheriv("aes128", secret, iv);
cipher.update(content, "utf8");
let digest = cipher.final("hex");
console.log('加密后结果', digest);

// 解密
const decipher = crypto.createDecipheriv("aes128", secret, iv);
decipher.update(digest, "hex");
console.log(decipher.final("utf8"));

运行过程出现:

** Error: Invalid IV length

** Error: Invalid key length

在使用不同的算时,对秘钥和IV的长度是有要求不一样的。一般是 256 bits = 32 bytes 大小的密钥。同样地,aes128也是有要求的,需要 128bits =16 bytes

非对称加密

非对称加密即加密和解密用的秘钥是不一样的。就是公钥(publickey)和私钥(privatekey),公钥和私钥成对出现。公钥可以公开到网络上,私钥的安全性决定加解密的安全性。数据如果用公钥加密,只有用对应的私钥才能解密,如果用私钥加密,可以使用对应的公钥解密。

生成秘钥

# 生成私钥
openssl genrsa -out privatekey.pem 1024

# 生成公钥
openssl rsa -in privatekey.pem -pubout -out publickey.pem

用法

// 私钥加密
crypto.privateEncrypt(privateKey, buffer)
// 私钥解密
crypto.privateDecrypt(privateKey, buffer)

// 公钥加密
crypto.publicEncrypt(key, buffer)
// 公钥解密
crypto.publicDecrypt(key, buffer)

实例

// 公钥加密私钥解密
let publicKey = fs.readFileSync('./publickey.pem');
let privateKey = fs.readFileSync('./privatekey.pem');
let content = '我是内容';

let encData = crypto.publicEncrypt(publicKey, Buffer.from(content));
console.log('公钥加密结果', encData.toString('base64'));

let decData = crypto.privateDecrypt(privateKey, encData);
console.log('私钥解密结果', decData.toString());

//输出
// 公钥加密结果 Fjuvn1WMplihuNbhVywbzIFYpEhVcSu8wTgsqW2y8OZAlyNgQ5QlpoexhiCoUTrsQ+wLpFrhyN7I5IDPujT9XppupE/ysVpdKLJceDS3OEckgqPLbaIcwaxsCs7Uob1ufelxrotw+nz1OA+QU0tJKKx6lVdpsi+nS3svq2WA1W8=
// 私钥解密结果 我是内容
// 私钥加密,公钥解密
let publicKey = fs.readFileSync('./publickey.pem');
let privateKey = fs.readFileSync('./privatekey.pem');
let content = '我是内容';

let encData = crypto.privateEncrypt(privateKey, Buffer.from(content));
console.log('私钥加密结果:', encData.toString('base64'));

let decData = crypto.publicDecrypt(publicKey, encData);
console.log('公钥解密结果:', decData.toString());

// 输出
// 私钥加密结果: BJSY163/PhlCAyLWo8ky04flTr69aoi4fVhS16pAFXKnPONLOTkpyrm7DANXe74lMm7huNVzKnU8Go3T4Y7XKOHPh8FQrAo/3eZcvFK3TXsrCPRtDo/+WgQbZyve1k+AnJ1KWV8VPZSKPnmfXD+9FgZ2QTi+ILw+xQL+rEfMWAs=
// 公钥解密结果: 我是内容

签名&& 验签

签名和验签主要用于确保数据在传输过程中未被修改和伪造。在数据发送之前,数据方先用hash+私钥 得到一个数据签名值,并把数据和签名值同时传输给客户。客户拿到数据后,使用数据方的公钥对签名进行验签,来保证数据未被修改和伪造。

用法

let publicKey = fs.readFileSync('./publickey.pem');
let privateKey = fs.readFileSync('./privatekey.pem');
let content = '我是内容';

const sign = crypto.createSign('SHA256');
sign.update(content);
sign.end();
const signature = sign.sign(privateKey);

const verify = crypto.createVerify('SHA256');
verify.update(content);
verify.end();
console.log(verify.verify(publicKey, signature));

常见安全加密算法

  1. Advanced Encryption Standard (AES):这是一种对称密钥加密算法,被广泛应用于保护数据的机密性。它是目前最常用的加密算法之一,也是美国政府采用的标准加密算法之一。
  2. RSA:这是一种非对称密钥加密算法,用于加密和数字签名。RSA算法基于一个数学问题,即如何对两个大质数的乘积进行因式分解。RSA算法在许多应用程序中广泛使用,包括安全电子邮件、虚拟专用网络 (VPN)、数字证书等。
  3. Elliptic Curve Cryptography (ECC):这是一种非对称密钥加密算法,使用椭圆曲线上的点来代表密钥。ECC算法比传统的RSA算法更短,更快,更安全,因此在许多应用程序中被广泛使用,例如物联网、移动设备和无线传感器网络等。
  4. Blowfish:这是一种对称密钥加密算法,被广泛应用于保护数据的机密性。Blowfish算法是一种快速、高效、安全的加密算法,被广泛应用于各种应用程序中,例如虚拟专用网络 (VPN)、电子邮件加密等。

参考:

nodejs.org/api/crypto.…