学习
实践
活动
专区
工具
TVP
写文章
专栏首页前端皮小蛋NodeJS加密算法(一)

NodeJS加密算法(一)

你真的了解NodeJS的加密模块crypto吗?本文通过crypto的api深入了解加密算法

安全加密

当发送方A向接收方B发送数据时,需要考虑的问题有:

  1. 数据的安全性。
  2. 数据的完整性,即数据不被篡改。
  3. 数据的真实性,即数据确实来自于发送方,传输过程中没有被替换。
  4. 数据的不可否认性,即验证发送方确实发送了数据。

保证安全性

对称密钥加密 Symmetric Encryption

对称密钥加密又叫专用密钥加密或共享密钥加密,即发送和接收数据的双方必使用相同的密钥对明文进行加密和解密运算。

流程

  1. A 使用密钥加密数据
  2. A 将密文发送给 B
  3. B 收到密文后,使用相同的密钥对其进行解密,取得原始数据
优点:速度快
缺点:密钥被盗就被破解、密钥管理不方便(每个用户都要对应一个密钥)
实现算法有:凯撒密码,AES(Advanced Encryption Standard)、DES(Data Encryption Standard)、动态口令等。
推荐:AES

AES加解密特点

分组长度是128bit,也就是16字节。

  1. 加密第一步,针对每个分组逐个字节的进行SubBytes的操作。笼统的说,就是每个字节根据256个值的替换表,将当前字节替换成另外一个字节。
  2. 加密第二步,以单个字节为单位进行ShiftRows处理,就是将字节有规律的打乱。
  3. 加密第三步,再以4字节为单位进行MixColumns处理,就是进行比特运算变成另外的4个字节。
  4. 加密第四步,还是4字节为单位与轮密钥进行XOR运算。至此一轮运算就结束了。

解密的过程就是加密的逆向过程。

分组密码的模式

对称密钥算法DES、AES都属于分组密码,分组密码的特点是分组的长度是固定的。但是由于明文的长度不固定且基本超过分组长度,所以就需要进行多轮的迭代加密。模式就是指的多轮迭代的方式。

  • ECB模式:Electronic CodeBook mode(电子密码本模式)
  • CBC模式:Cipher Block Chaining mode(密码分组链接模式)推荐使用
  • CFB模式:Cipher FeedBack mode(密文反馈模式)
  • OFB模式:Output FeedBack mode(输出反馈模式)
  • CTR模式:CounTeR mode(计数器模式)推荐使用

NodeJS示例:Cipher、Decipher

// 加密
const crypto = require("crypto");

const algorithm = "aes-192-cbc";
const password = "Password used to generate key";
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(password, "salt", 24);
// Use `crypto.randomBytes` to generate a random iv instead of the static iv
// shown here.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const cipher = crypto.createCipheriv(algorithm, key, iv);

let encrypted = cipher.update("some clear text data", "utf8", "hex");
encrypted += cipher.final("hex");
console.log(encrypted);
// Prints: e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa
// 解密
const crypto = require("crypto");

const algorithm = "aes-192-cbc";
const password = "Password used to generate key";
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(password, "salt", 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = crypto.createDecipheriv(algorithm, key, iv);

// Encrypted using same algorithm, key and iv.
const encrypted =
  "e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa";
let decrypted = decipher.update(encrypted, "hex", "utf8");
decrypted += decipher.final("utf8");
console.log(decrypted);
// Prints: some clear text data

openssl list -cipher-algorithms 可以列出支持的加密算法

Cipher 类的创建

创建 Cipher 类可以使用crypto模块的 crypto.createCipher()crypto.createCipheriv() 方法。OpenSSL推荐使用 pbkdf2 来替换 EVP_BytesToKey ,因此在创建 Cipher 类时,建议使用 crypto.pbkdf2 来派生 keyiv ,并使用 createCipheriv() 来创建加密流。

  • crypto.createCipher(algorithm, password) :用给定的算法和密钥,创建并返回一个 Cipher 加密算法的对象。参数:algorithm 算法是依赖OpenSSL库支持的算法, 例如: 'aes192' 算法等, password 是用来派生 keyiv 的,它必须是一个 'binary' 二进制格式的字符串或者是一个 Buffer
  • crypto.createCipheriv(algorithm, key, iv) :用给定的算法、密钥和向量,创建并返回一个 Cipher 加密算法的对象。参数:algorithmcreateCipher 方法相同, key 密钥是一个被算法使用的原始密钥, iv 是一个 初始化向量 。key 密钥和 iv 向量必须是 'binary' 二进制格式的字符串或者是一个 Buffer

使用 Cipher 类加密数据

Cipher 加密对象是一个可读写的 Stream 流。可以使用 Cipher 类中的 update 方法写入纯文本的数据,数据输入完成后通过 final 方法返回加密后的数据。

  • cipher.update(data, [input_encoding], [output_encoding]) :更新 Cipher 类的加密数据。data :要更新的 Cipher 加密对象的数据,编码 input_encoding 可以是:'utf8''ascii''binary' 。如果没有编码参数,那么 data 必须是一个 Buffer
  • 参数 output_encoding 指定加密数据的输出编码,可以是:'binary''base64''hex' ,如果未设置这个参数,将会返回一个 Buffer
  • cipher.final([output_encoding]) :返回加密后的内容, output_encoding 为:'binary''base64''hex' 。如果没有提供编码格式,如果未设置这个参数,将会返回一个 Buffer
  • 注意:调用 final() 后不能再用 Cipher 对象
  • cipher.setAutoPadding(auto_padding=true) :设置输入数据自动填充到块大小功能,这个函数必须在 cipher.final 之前调用。如果 auto_padding 是false,那么整个输入数据的长度必须是加密器的块大小的整倍数,否则 final 会失败。这对非标准的填充很有用,例如:使用 0x0 而不是 PKCS 的填充。
  • cipher.setAuthTag(buffer) :加密认证模式(目前支持:GCM),这个方法返回经过计算的认证标志Buffer 。必须在使用 final 方法完成加密后调用。
  • cipher.setAAD(buffer) :对于加密认证模式(目前支持:GCM),用这个方法设置附加认证数据( AAD )。

相关API资料:

Node.js的加密模块crypto之使用Cipher类加密数据:https://itbilu.com/nodejs/core/EJOj6hBY.html

Node.js的加密模块crypto之使用Decipher类解密数据:https://itbilu.com/nodejs/core/4ySMqlUF.html

非对称密钥加密 Asymmetric Encryption

非对称加密算法需要两个密钥:公开密钥 (publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

公开密钥加密

流程

  1. 首先由接收方 B 生成公钥和私钥
  2. B 把公钥发送给 A
  3. A 使用 B 发来的公钥加密数据,然后发送给 B
  4. B 使用私钥对密文进行解密,得到原始数据
优点:安全性高、密钥管理方便
缺点:加密速度慢、无法防止中间人攻击,A 不知道收到的公钥是否是来自 B
实现算法有:RSA 算法、椭圆曲线加密算法等 
推荐:RSA

NodeJS示例:privateEncrypt、privateDecrypt、publicEncrypt、publicDecrypt

// 公钥加密
let encryptString = crypto.publicEncrypt(
  {
    key: publicKey,
    padding: crypto.constants.RSA_NO_PADDING
  },
  Buffer.from("需要加密的内容")
);
encryptString = encryptString.toString("base64");

// 私钥加密
let encryptString = crypto.privateEncrypt(
  {
    key: privateKey,
    padding: crypto.constants.RSA_NO_PADDING
  },
  Buffer.from("需要加密的内容")
);
encryptString = encryptString.toString("base64");

// 私钥解密
crypto.privateDecrypt(privateKey, buffer);
// 公钥解密
crypto.publicDecrypt(key, buffer);

注意

1024位的证书,加密时最大支持117个字节,解密时为128;2048位的证书,加密时最大支持245个字节,解密时为256。所以在加密和解密较大内容的过程中需要分块进行。推荐使用node-rsa库。

非对称密钥概览

密钥配送

密钥配送问题:如何安全地把密钥给到接受者?

配送问题解决办法

  • 事先共享密钥,缺点是需要很多密钥,且管理麻烦。
  • 通过密钥中心分配,缺点是全部人员所有通信密钥都产生于一个地方,这个地方的压力就相当大,而且一旦此服务器坏掉,则所有人员无法通信。
  • 公钥密码解决办法,缺点如果得到服务器私钥就可以解密所有数据。
  • Diffie-Hellman密钥交换解决办法:SSL通信使用的就是这种技术。

密钥交换协议

流程

  1. A 生成密钥 P
  2. A 把密钥 P 发送给 B
  3. A 和 B 各自准备自己的私钥 SA 和 SB
  4. A 利用密钥 P 和私钥 SA 合成新的密钥 P-SA
  5. B 也利用密钥 P 和私有密钥 SB 合成新的密钥 P-SB
  6. A 将密钥 P-SA 发送给 B,B 也将密钥 P-SB 发送给 A
  7. A 将私有密钥 SA 和收到的密钥 P-SB 合成新的密钥 SA-P-SB(合成结果和合成顺序无关,合成密钥无法被分解) h)同样地,B 也将私钥 SB 和收到的密钥 P-SA 合成新的密钥 P-SA-SB。于是 A 和 B 都得到了密钥 P-SA-SB。这个密钥将作为“加密密钥”和“解密密钥”使用。
优点:DH 利用“离散对数问题”解决中间人攻击
实现算法有:DH、ECDH 
推荐:ECDH > DH

NodeJS示例:DiffieHellman、DiffieHellmanGroup、ECDH

ECDH 是基于ECC(Elliptic Curve Cryptosystems,椭圆曲线密码体制,参看ECC)的Diffie-Hellma密钥交换算法。交换双方可以在不共享任何秘密的情况下协商出一个密钥。与 Diffie-Hellman 相比ECDH具有ECC的高强度、短密钥长度、计算速度快等优点。Node.js的crypto模块,封装了 ECDH 类,可以用这个类来生成EC Diffie-Hellman交换密钥。

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

相关API资料:

Node.js的加密模块crypto之使用DiffieHellman类生成交换密钥:https://itbilu.com/nodejs/core/EknZWVKt.html

Node.js的加密模块crypto之使用ECDH类生成EC Diffie-Hellman交换密钥:https://itbilu.com/nodejs/core/41iXzVot.html

常用密钥交换算法:https://chziyue.com/post/57.html

DH需要和数字签名一起使用才安全,相关:https://www.slideshare.net/dganesan11/active-attacks-on-dh-key-exchange-143931907

混合加密

流程

  1. 接收方 B 事先生成公钥和私钥
  2. B 将公钥发送给 A
  3. A 使用收到的公钥对共享密钥(对称密钥)进行加密,并发送给 B
  4. B 使用私钥解密,得到共享密钥
  5. 接下来 A 只要使用对称密钥加密好数据发送给 B 即可

优点:使用处理速度快的对称密钥加密数据同时保证对称密钥的安全性。HTTPS 的 TLS 加密就是用的混合加密。

文章分享自微信公众号:
前端皮小蛋

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:头号前端
原始发表时间:2021-01-25
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • Nodejs学习笔记(一)——初识Nodejs

    前言:目前工作的分内之事相对较为单一,希望可以通过工作之余的时间给自己充充电,只是没有一个学伴或大神带,只能说是摸索着前进。起初准备好好研究下Spring这个框...

    JackieZheng
  • Nodejs笔记(一)

    我是攻城师
  • CTF|玩转RSA加密算法(一)

    RSA是一种非对称加密算法,它由 公钥(n/e),私钥(n/d),明文M和密文C组成。我们做CTF题目时,一般题目中会给出公钥和密文让我们推出对应的私钥或者明文...

    漏斗社区
  • [Java 安全]加密算法

    Base64编码 算法简述 定义 Base64内容传送编码是一种以任意8位字节序列组合的描述形式,这种形式不易被人直接识别。 Base64是一种很常见的编码规范...

    静默虚空
  • 深入浅出 Nodejs ( 一 ) :Nodejs 的简介

    我认为 Node 是一门独具风格的技术,它的特点很有意思,本章我们主要讲 Node 的特点,Node 应用场景以及 Node 的使用者。

    serena
  • SM4 加密算法_des加密算法流程

    SM4是一种分组密码算法,其分组长度为128位(即16字节,4字),密钥长度也为128位(即16字节,4字)。其加解密过程采用了32轮迭代机制(与DES、AES...

    全栈程序员站长
  • 一个简单的加密算法

    凯撒加密是一种简单的加密技术。据记载,这是凯撒大帝曾经用来对军事信息进行加密的方法。

    老肥码码码
  • 应用加密一;非对称加密算法揭秘

      RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)

    用户3745746
  • RSA加密算法

    import java.math.BigInteger; import java.util.ArrayList; import java.util.List; ...

    yawn
  • 加密算法详解

    派大星在吗
  • 【nodejs每日一讲】nodejs的进程间通信

    之前提了一个问题:nodejs中如何实现兄弟进程间的通信,大家分别列举了redis、ZooKeeper,MessageChannel,还有linux操作系统提供...

    theanarkh
  • 一键安装Nodejs

    华创信息技术
  • Nodejs学习笔记(三)——一张图看懂Nodejs建站

    前言:一条线,竖着放,如果做不到精进至深,那就旋转90°,至少也图个幅度宽广。 通俗解释上面的胡言乱语:还没学会爬,就学起走了?! 继上篇《Nodejs学习笔记...

    JackieZheng
  • 1000 加密算法

    题目描述 神龙数码公司设计了一个加密算法:用a代替z,用b代替y,用c代替x,......,用z代替a。现要求输入一个小写字母,对其进行加密输出。 输入 输入一...

    attack
  • RSA加密算法

    偏有宸机
  • 某神奇App data加密算法解析(一)

    李老板:奋飞呀,我遇到一个超级牛掰的App,它请求的时候有个data参数加密,用尽了你介绍的所有的方法,都找不到它是如何加密的。

    fenfei331
  • JAVA中的加密算法之双向加密(一)

           加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容。大体上分为双向加密...

    幽鸿
  • 对称加密算法与非对称加密算法的优缺点

    对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥,作为私钥。

    MavenTalker
  • 分析网站登录处的加密算法(一)

    在某次渗透过程中,碰到了一个登录的网站。于是随便输了个 admin/123456进行登录尝试,准备burp抓包,进行爆破。

    谢公子

扫码关注腾讯云开发者

领取腾讯云代金券