Nodejs 第二十一章 crypto

密码学是计算机科学的一个关键领域,涵盖了加密、解密、哈希函数和数字签名等技术。Node.js作为一个流行的服务器端JavaScript运行环境,提供了一个称为crypto的强大模块,使开发人员可以轻松地在其应用程序中实施这些密码学功能。本文将解释密码学的基础概念,并详细讨论在Node.js中如何使用常见的密码学API。

  • crypto模块的目的是为了提供通用的加密和哈希算法。尽管用纯JavaScript实现这些算法是可行的,但执行速度通常很慢。因此,Node.js通过C/C++实现了这些算法,并通过crypto模块将其作为JavaScript接口提供,这不仅方便了使用,也大大提升了运行效率。

对称加密

  • 对称加密是一种简单而快速的加密方式,它使用相同的密钥(称为对称密钥)来进行加密和解密。这意味着发送者和接收者在加密和解密过程中都使用相同的密钥。对称加密算法的加密速度很快,适合对大量数据进行加密和解密操作。然而,对称密钥的安全性是一个挑战,因为需要确保发送者和接收者都安全地共享密钥,否则有风险被未授权的人获取密钥并解密数据。

    • 如果IV或密钥不足指定的长度,可能需要进行补码操作来满足算法要求的长度。补码是指在数据的末尾填充额外的字节,直到达到需要的长度。这确保了加密算法能正确执行,不会因为数据长度问题导致加密失败
js 复制代码
 const crypto = require('node:crypto');//crypto是加密的意思
 ​
 //双方协定定义一个密钥以及iv(这个iv是可以随便取名的)
 //第一个参数 algorithm 接受一个算法 aes-256-cbc
 //第二个参数 key 也就是密钥 32位
 //第三个参数 iv 初始化向量 支持16位 保证生成的密钥串每次都不一样 密钥串缺少位数还能进行补码操作
 ​
 // 生成一个随机的 16 字节的初始化向量 (IV)
 const iv = Buffer.from(crypto.randomBytes(16));
 ​
 // 生成一个随机的 32 字节的密钥
 const key = crypto.randomBytes(32);
 ​
 // 创建加密实例,使用 AES-256-CBC 算法,提供密钥和初始化向量
 const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);//Cipheriv是密码的意思
 ​
 // 对输入数据进行加密,并输出加密结果的十六进制表示(hex)
 cipher.update("小余", "utf-8", "hex");
 const result = cipher.final("hex");
 ​
 // 解密,de是解密的工具,包含了三位要素。然后把需要解密的内容丢进去就得到结果了
 const de = crypto.createDecipheriv("aes-256-cbc", key, iv);//Decipheriv是解密的意思
 de.update(result, "hex");
 const decrypted = de.final("utf-8");
 ​
 console.log("Decrypted:", decrypted);
  • 上面其中用到了一些方法,进行讲解一下:

创建加密实例

crypto.createCipheriv(algorithm, key, iv):这个函数用于创建一个加密算法的实例。它接受三个参数:

  • algorithm:加密算法,这里使用的是"AES-256-CBC"。
  • key:用于加密的密钥。
  • iv:初始化向量,用于算法的起始块加密。

加密数据

cipher.update(data, inputEncoding, outputEncoding):这个方法用于加密数据。它可以多次调用,用于加密长数据流。

  • data:要加密的数据。
  • inputEncoding:输入数据的编码格式,这里为"utf-8"。
  • outputEncoding:输出数据的编码格式,这里为"hex"。

完成加密过程

cipher.final(outputEncoding):这个方法用于结束加密过程,输出最后的加密数据。它返回的数据需要与update方法的输出连接。

  • final就是最终、结束的意思

打比方

  • 其实很简单,我就拿我跟小满进行举例:

    • 我想要给小满发一点不能让人看见的小秘密内容,所以我打算进行加密。
    • 为此,我使用了一个工具,通过了这个工具我设置了三个前置因素,分别是加密方式、暗号(iv)、钥匙(key)。

    设置OK了之后,我把要发给小满的小秘密丢进去,顺带的设置了以什么编码格式打开(因为你是知道的,打开方式不正确会是一堆乱码)。

    • 小满想要阅读到内容,他需要搞一个解密工具,解密工具叫做createDecipheriv,小满将我发给他的秘密内容丢进去,然后对了暗号(麒麟哥unshift),然后输入了我跟他讲的密码。以正确的编码格式和进制就拿到了我的消息
  • 这个从头到尾,最重要的其实就是设置密保工具,然后解密工具两个东西。有这两个东西,剩下的也就把内容丢进去加密,把内容解密出来就没了

非对称加密

非对称加密使用一对密钥,分别是公钥和私钥。发送者使用接收者的公钥进行加密,而接收者使用自己的私钥进行解密。公钥可以自由分享给任何人,而私钥必须保密。非对称加密算法提供了更高的安全性,因为即使公钥泄露,只有持有私钥的接收者才能解密数据。然而,非对称加密算法的加密速度相对较慢,不适合加密大量数据。因此,在实际应用中,通常使用非对称加密来交换对称密钥,然后使用对称加密算法来加密实际的数据。

内容提取

  1. 密钥对:非对称加密使用一对密钥,包括公钥和私钥。
  2. 加密过程:发送者用接收者的公钥加密信息。
  3. 解密过程:接收者用自己的私钥来解密信息。
  4. 公钥共享:公钥可以安全地公开给任何人。
  5. 私钥保密:私钥必须保持机密。
  6. 安全性:由于私钥的保密性,非对称加密非常安全。
  7. 性能考虑:非对称加密速度较慢,不适合直接加密大量数据。
  8. 实际应用:通常用于交换对称加密的密钥。
js 复制代码
 const crypto = require('node:crypto')
 // 生成 RSA 密钥对 privateKey私钥 publicKey公钥
 const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
   modulusLength: 2048,//长度越长越安全,但越慢
 });
 ​
 // 要加密的数据
 const text = 'XiaoYu';
 ​
 // 使用公钥进行加密
 const encrypted = crypto.publicEncrypt(publicKey, Buffer.from(text, 'utf-8'));//Encrypt 加密
 console.log(`看看公钥加密内容:${encrypted}`);
 ​
 // 使用私钥进行解密
 const decrypted = crypto.privateDecrypt(privateKey, encrypted);
 ​
 console.log(`解密内容:${decrypted.toString()}`);//XiaoYu

哈希函数

哈希函数具有以下特点:

  1. 固定长度输出:不论输入数据的大小,哈希函数的输出长度是固定的。例如,常见的哈希函数如 MD5 和 SHA-256 生成的哈希值长度分别为 128 位和 256 位。
  2. 不可逆性:哈希函数是单向的,意味着从哈希值推导出原始输入数据是非常困难的,几乎不可能。即使输入数据发生微小的变化,其哈希值也会完全不同。
  3. 唯一性:哈希函数应该具有较低的碰撞概率,即不同的输入数据生成相同的哈希值的可能性应该非常小。这有助于确保哈希值能够唯一地标识输入数据。

使用场景

  1. 我们可以避免密码明文传输 使用md5加密或者sha256

  2. 验证文件完整性:

    • 读取文件内容 转换成md5 上传给服务端 后端拿到文件内容生成md5
    • 跟前端md5 匹配 如果一致 文件就没问题,如果不一致 文件就有问题
    • 校验文件的一致性
js 复制代码
 const crypto = require('node:crypto');
 
 // 要计算哈希的数据
 let text = '123456';
 
 // 创建哈希对象,并使用 MD5 算法
 const hash = crypto.createHash('md5');
 
 // 更新哈希对象的数据
 hash.update(text);
 
 // 计算哈希值,并以十六进制字符串形式输出
 const hashValue = hash.digest('hex');//digest意思为:理解
 
 console.log('Text:', text);
 console.log('Hash:', hashValue);
  • 但其实这个不算很安全,因为会出现撞库的问题,从前面我们可以知道,这个哈希函数是唯一性的

    • 假如说有人收集了常用密码的所有md5加密,汇聚成一个数据库,然后拿到你通过md5加密的内容,去数据库比对。很可能一不小心就把你的密码试出来了
    • 这就是现在为什么密码要求越来越复杂了,有的甚至要求同时具备大写小写特殊符号数字
相关推荐
susu10830189112 分钟前
vue3 css的样式如果background没有,如何覆盖有background的样式
前端·css
Ocean☾3 分钟前
前端基础-html-注册界面
前端·算法·html
Rattenking3 分钟前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
Dragon Wu5 分钟前
前端 Canvas 绘画 总结
前端
CodeToGym10 分钟前
Webpack性能优化指南:从构建到部署的全方位策略
前端·webpack·性能优化
~甲壳虫11 分钟前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js
~甲壳虫15 分钟前
说说webpack proxy工作原理?为什么能解决跨域
前端·webpack·node.js
Cwhat17 分钟前
前端性能优化2
前端
熊的猫1 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app