node.js_crypto 模块


 

crypto 模块提供了加密功能,实现了包括对 OpenSSL 的哈希、HMAC、加密、解密、签名、以及验证功能的一整套封装。

Hash 算法

Hash 类是用于创建数据哈希值的工具类。

查看 crypto 模块支持的 hash 函数:crypto.getHashes()

const crypto = require('crypto');
// 创建哈希函数 sha256
const hash = crypto.createHash('sha256'); 

// 输入流编码:utf8、ascii、binary(默认)
hash.update('some data to hash', 'utf8');
// 输出编码:hex、binary、base64
console.log(hash.digest('hex'));

// 输出
// 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50

PBKDF2

PBKDF2 是 Node.js 的 crypto 模块原生支持的标准方法。

const salt = crypto.randomBytes(32);
const result = crypto.pbkdf2Sync(password, salt, 4096, 512, 'sha256');

Hmac 算法

Hmac 类是用于创建加密 Hmac 摘要的工具。

示例一:

const crypto = require('crypto');

const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
                   .update('I love cupcakes')
                   .digest('hex');
console.log(hash);

加盐(salt)

盐值就是随机数值,用于在计算密码的哈希值时加强数据的安全性,可以有效抵御诸如字典攻击、彩虹表攻击等密码攻击媒介。

常见的 Hash 算法使用示例:

const crypto = require('crypto');
const md5 = crypto.createHash('md5');

let password = '123456';
let salt = 'hhug6dcKyCNBQ5sUC0i6hja5dCTqdSzV'; // 盐值
// 将密码拼接上任意长度的随机字符串后,再进行 Hash
md5.update(password+salt);
console.log(md5.digest('hex'));

// 输出
// b2d23b0443c319e574f1ea3f8bddc6e0

crypto.randomBytes() 方法可以生成随机数,用于作为密钥或者盐值:

const crypto = require('crypto');

// 1. 异步方法
crypto.randomBytes(32, (err, salt) => {
  if (err) throw err;

  // 记录盐值可读的字符串版本
  console.log('salt: ' + salt.toString('hex'));

  // 后续步骤:使用盐值
});

// 2. 同步方法
const buf = crypto.randomBytes(256);

加密(Cipher)和解密(Decipher)算法

对称加密算法

查看 Openssl 对称加密算法列表:

'use strict';

const crypto = require('crypto');

// 初始化参数
const text = 'Encryption Testing AES GCM mode'; // 要加密和解密的数据
const key = crypto.randomBytes(32); // 256 位的共享密钥
const iv = crypto.randomBytes(16); // 初始向量,16 字节
const algorithm = 'aes-256-gcm'; // 加密算法和操作模式

// 加密
const cipher = crypto.createCipheriv(algorithm, key, iv); // 初始化加密算法
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag(); // 生成标签,用于验证密文的来源

// 解密
const decipher = crypto.createDecipheriv(algorithm, key, iv); // 初始化解密算法
decipher.setAuthTag(tag); // 传入验证标签,验证密文的来源
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');

console.log(decrypted); // Encryption Testing AES GCM mode

AES-256-GCM 示例2:

  • Github - crypto-aes-256-gem-demo.js
  • GitHub: AES 简介
const { generateKeyPair } = require('crypto');
generateKeyPair('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki', // pkcs1、spki
    format: 'pem'
  },
  privateKeyEncoding: {
    type: 'pkcs8', // pkcs1、pkcs8、sec1
    format: 'pem',
    cipher: 'aes-256-cbc', // 对私钥使用 aes-256-cbc 算法加密后返回
    passphrase: 'top secret' // aes-256-cbc 算法密钥
  }
}, (err, publicKey, privateKey) => {
  // Handle errors and use the generated key pair.
});

使用 RSA 2048 进行公钥加密,私钥解密

使用 OpenSSL 生成 2048位 RSA 密钥:

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const root = __dirname;

const publicKey = fs.readFileSync(path.join(root, './mypubkey.pem')).toString('ascii');
const privateKey = fs.readFileSync(path.join(root, './ mykey.pem')).toString('ascii');
const data = 'data to crypt';

// 公钥加密
const encryptData = crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64');
console.log('encode', encryptData);

// 私钥解密
const decryptData = crypto.privateDecrypt(privateKey, Buffer.from(encryptData.toString('base64'), 'base64'));
console.log('decode', decryptData.toString());

签名(Sign)和验证(Verify)算法

签名算法示例:

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const root = __dirname;

// 加载公钥文件
const publicKey = fs.readFileSync(path.join(root, './rsa_public_key.pem')).toString('ascii');

const verify = crypto.createVerify('RSA-SHA256'); // 创建验证算法
verify.update('data to sign');
console.log(verify.verify(publicKey, result, 'hex'));

// 打印
// true

DH 密钥交换算法

DiffieHellman 类是一个用来创建 Diffie-Hellman 键交换的工具。 DiffieHellman 类的实例可以使用 crypto.createDiffieHellman() 方法。

const crypto = require('crypto');
const assert = require('assert');

// Generate Alice's keys...
const alice = crypto.createECDH('secp521r1');
const aliceKey = alice.generateKeys();

// Generate Bob's keys...
const bob = crypto.createECDH('secp521r1');
const bobKey = bob.generateKeys();

// Exchange and generate the secret...
const aliceSecret = alice.computeSecret(bobKey);
const bobSecret = bob.computeSecret(aliceKey);

assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
// OK

参考

  • Node.js 的加密模块 crypto 之使用 Hash 类计算数据的哈希值
  • Node.js 的加密模块 crypto 之使用 Hmac 类计算哈希密钥
  • Node.js 的加密模块 crypto 之使用 Cipher 类加密数据
  • Node.js 的加密模块 crypto 之使用 Decipher 类解密数据
  • Node.js 的加密模块 crypto 之使用 Sign 类生成数字签名并使用 Verify 类验证数字签名
  • Node.js 的加密模块 crypto 之使用 DiffieHellman 类生成交换密钥
  • Node.js 的加密模块 crypto 之使用 ECDH 类生成 EC Diffie-Hellman 交换密钥
  • Identity and Data Security for Web DevelopmentReport abuse
  • Node.js 使用 RSA 加密 / 解密

相关第三方库

  • bcrypt——密码哈希函数
  • bcrypt.js
  • node-rsa
  • node-forge