Skip to content

NodeJS 中的 Crypto 模块,加解密了解一下

Published:

在我们的日常开发中,不免会使用到数据加解密,哈希等功能,如果用纯 JS 代码来实现这些算法,速度会变慢很多,Node 使用 C/C++ 实现了这些算法,暴露为 javascript 接口的 crypto 模块,包含对 OpenSSL 的哈希、HMAC、加密、解密、签名、以及验证功能的一整套封装。

本文记录一些常用算法介绍和代码实现。

Hash算法

hash算法将任意长度的输入通过散列算法变换成固定长度的输出,该输出就是hash值,常见的有md5,sha1,sha256等。

其特点有:

crypto 模块可以创建 Hash 类, 通过 createHash(algorithm[, options]) 创建并返回一个 Hash 对象,该对象可用于生成哈希摘要(使用给定的 algorithm)。

实现方式

创建并返回一个 hash 对象,它是一个指定算法的加密 hash,用于生成 hash 摘要。 不能使用 new 关键字直接地创建 Hash 对象。

参数 algorithm 可选择系统上安装的 OpenSSL 版本所支持的算法。例如:sha1、md5、sha256、sha512 等。在近期发行的版本中,openssl list-message-digest-algorithms 会显示这些可用的摘要算法。

更新 hash 的内容为指定的 data。当使用流数据时可能会多次调用该方法。

计算所有传入数据的 hash 摘要。参数 encoding(字符编码)可以为 hex、binary、base64

关于字符编码,传送门:http://nodejs.cn/api/buffer.html#buffer_buffers_and_character_encodings

下面以 MD5 和 SHA1 为例

const crypto = require("crypto");

function md5(str) {
  return crypto.createHash("md5").update(str, "utf8").digest("hex");
}
function sha1(str) {
  return crypto.createHash("sha1").update(str, "utf8").digest("hex");
}

console.log(md5("hello md5")); // 741fc6b1878e208346359af502dd11c5
console.log(sha1("hello sha1")); // 64faca92dec81be17500f67d521fbd32bb3a6968

Hmac算法

HMAC算法将Hash算法与一个密钥结合在一起,以阻止对签名完整性的破坏,密钥发生了变化,输出结果也会发生变化。(Hmac可以理解为用随机数“增强”的哈希算法)

使用方法也与 生成 Hash 类似,使用crypto.createHmac(algorithm, key[, options]) 创建并返回一个 Hmac 对象。

const crypto = require("crypto");
const key = "abcmouse";

function hmacMd5(str, key) {
  return crypto.createHmac("md5", key).update(str, "utf8").digest("hex");
}

console.log(hmacMd5("hello hmacMd5", key)); // 92effcb2e4b99cc77006e26520539401

对称加密

对称加密算法,加解密都用同一个密钥

Node 的 crypto 模块,提供了 Cipher 类用于加密,Decipher 类用于解密,分别使用 crypto.createCipheriv(algorithm, key, iv[, options]) 方法和 crypto.createDecipheriv(algorithm, key, iv[, options]) 来创建并返回相应的对象。

keyalgorithm 使用的原始密钥, iv 是初始化向量。 两个参数都必须是 'utf8' 编码的字符串、BufferTypedArrayDataView

Cipher 类的实例用于加密数据。 该类可以通过以下两种方式之一使用:

  • 作为可读写的,其中写入未加密的数据以在可读侧生成加密的数据。
  • 使用 cipher.update()cipher.final() 方法生成加密的数据

Decipher 类的实例用于解密数据。 该类可以通过以下两种方式之一使用:

const crypto = require("crypto");

const algorithm = "aes-256-cbc";
// key: 密钥
// 密钥长度取决于算法。
// 在此示例中,对于 aes256,它是 32 个字节(256 位)。
const AESSecret = "abcmouse".repeat(4);
// 初始化向量(iv)
const iv = Buffer.alloc(16, 0);
// data:需要加解密的内容,
function aesEncrypt(data) {
  // 给定的算法,密钥和初始化向量(iv)创建并返回Cipher对象
  const cipher = crypto.createCipheriv(algorithm, AESSecret, iv);
  let encrypted = cipher.update(data, "utf8", "hex");
  encrypted += cipher.final("hex");
  return crypted;
}

function aesDecrypt(data) {
  // 给定的算法,密钥和初始化向量(iv)创建并返回Cipher对象
  const decipher = crypto.createDecipheriv(algorithm, AESSecret, iv);
  let decrypted = decipher.update(data, "hex", "utf8");
  decrypted += decipher.final("utf8");
  return decrypted;
}
const data = "hello abcmouse";

const encryptData = aesEncrypt(data);
const decryptData = aesDecrypt(encryptData);

console.log(encryptData); // 60b80608202e1951ef9e3634dc35f92e
console.log(decryptData); // hello abcmouse

补充:

AES是一种常用的对称加密算法。加密的分组模式有ECB/CBC/CFB/OFB

分组密码又称为秘密钥密码或对称密码。利用分组密码对明文进行加密时,首先需要对明文进行分组,每组的长度都相同,然后对每组明文分别加密得到等长的密文,分组密码的特点是加密密钥与解密密钥相同。 分组密码的安全性应该主要依赖于密钥,而不依赖于对加密算法和解密算法的保密。因此,分组密码的加密和解密算法可以公开。

总结

之前对于这个领域的东西还是比较少接触,这次通过实战学习总结,总算是理清楚了常用的加密算法以及常见用途。除了以上功能外,crypto模块还常用的有非对称加密算法,以及签名和验证算法,感兴趣的同学可以自行查阅相关资料,后续有学习使用,也会补充到这里来~

参考资料: