专栏首页前端皮小蛋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 加密就是用的混合加密。

本文分享自微信公众号 - 前端皮小蛋(gh_e69260c16440),作者:头号前端

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-01-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [Java 安全]加密算法

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

    静默虚空
  • JAVA中的加密算法之双向加密(一)

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

    幽鸿
  • 应用加密一;非对称加密算法揭秘

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

    用户3745746
  • Python 加密解密算法

    py3study
  • nodejs中的bcryptjs密码加密

    bcryptjs是一个第三方密码加密库,是对原有bcrypt的优化,优点是不需要安装任何依赖,npmjs地址为:https://www.npmjs.com/pa...

    ccf19881030
  • RSA加密算法

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

    yawn
  • 1000 加密算法

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

    attack
  • RSA加密算法

    偏有宸机
  • 3DES_CBC加密算法

    py3study
  • CTF|玩转RSA加密算法(一)

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

    漏斗社区
  • 一个简单的加密算法

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

    老肥码码码
  • 加密货币常见加密算法

    这是「区块链技术指北」的第 20 篇文章。 如果对我感兴趣,想和我交流,我的微信号:Wentasy,加我时简单介绍下自己,并注明来自「区块链技术指北」。同时我会...

    robinwen
  • 常见加密算法之单向加密

    在接口测试过程中,常常会遇到加密算法,今天主要说说一下单向散列加密的4种算法。

    用户5521279
  • Java加密与解密之对称加密算法

    采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。在对称加密算法中,DES算法最具有代表性,DES...

    布禾
  • ROT-13加密算法

    是一种对等加密,将字母表中前13个字符与后13个字符对换,形成自身的逆反,即:还原为明文要使用同一算法。(同样的操作可以同时加密与解密)

    偏有宸机
  • 探秘加密算法

    常见的对称加密算法 DES:分组式加密算法,以64位为分组对数据加密,加解密使用同一个算法。 3DES:三重数据加密算法,对每个数据块应用三次DES加密算法。...

    用户5521279
  • 初识加密算法

    很简单,加密算法的出现正是为了解决万物互联下数据隐私与安全的问题,在畅游于网络之中时候,那便是数据在不停的交换和流动的时候,如果没有加密算法,我们的 各种密码,...

    用户1462769
  • GCAC47 Paillier加法同态加密算法

    https://blog.csdn.net/caorui_nk/article/details/83305709#_18

    安包
  • DES和AES算法加密解密

    前言:在api传递过程中或者操作cookie中的参数都是明文,很容易暴露一些用户以及私密的信息。

    王念博客

扫码关注云+社区

领取腾讯云代金券