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加密的内容,去数据库比对。很可能一不小心就把你的密码试出来了
    • 这就是现在为什么密码要求越来越复杂了,有的甚至要求同时具备大写小写特殊符号数字
相关推荐
轻口味16 分钟前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami19 分钟前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
wakangda1 小时前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡1 小时前
lodash常用函数
前端·javascript
丰云1 小时前
一个简单封装的的nodejs缓存对象
缓存·node.js
emoji1111111 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼1 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250031 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O1 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235951 小时前
web复习(三)
前端