非对称加密验签和加解密全过程【JSEncrypt】

1,296 阅读4分钟

image.png

非对称加密,又称为公钥加密,是密码学中的一种加密方式,它涉及到两个密钥一个公钥和一个私钥。公钥可以公开给任何人,而私钥必须严格保密。非对称加密在前端开发中主要用于安全通信和身份验证。JSEncrypt 是一个纯 JavaScript 库,用于实现非对称加密,即公钥和私钥加密。它允许你在浏览器端使用 RSA 加密,而不需要服务器端的任何支持

对称加密入口:前端加密之 CryptoJS学习文档【完整实例】

常见算法及使用场景

常见的非对称加密算法:

  1. RSA最常用的非对称加密算法之一,广泛应用于安全数据传输和数字签名。
  2. ECC (椭圆曲线加密):一种相对较新的算法,相比 RSA,它在相同安全级别下需要更短的密钥长度,因此计算效率更高,资源消耗更少。
  3. DSA (数字签名算法):主要用于数字签名,而不是数据加密。

前端非对称加密的应用场景:

  1. HTTPS:在 HTTPS 协议中,服务器使用非对称加密技术与客户端建立安全连接。
  2. 数据加密:在不安全的通道上发送敏感信息时,可以使用接收方的公钥进行加密,确保只有接收方能够解密。
  3. 数字签名:用于验证数据的完整性和发送者的身份,常用于软件分发、电子合同等场景

安装准备

钥匙对生成

  • openssl genrsa 是生成密钥的命令
  • -out rsa_1024_priv.pem 将密钥输出到文件中
openssl genrsa -out rsa_1024_priv.pem 1024
# 查看文件密钥内容
cat rsa_1024_priv.pem

image.png

根据密钥生成对应公钥

  • openssl rsa 生成公钥
  • -pubout 输出一个公钥
  • -in file 根据输入的文件
  • -out file 输出到某个文件
openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem

# 查看公钥内容
cat rsa_1024_pub.pem

image.png

代码示例

安装加密库

 npm i crypto-js jsencrypt
  1. 将公钥和私钥的内容进行存储,可以是文件也可以是字符串(使用模版字符串,保证起格式),并进行设置
let priv_key = `-----BEGIN RSA PRIVATE KEY-----  ...```
let pub_key = `-----BEGIN PUBLIC KEY-----...```
let message = "Hello, World!";

var encrypt = new JSEncrypt()
encrypt.setPublicKey(pub_key)

var decrypt = new JSEncrypt()
decrypt.setPrivateKey(priv_key)
  1. 对消息进行验证,签名和验签的过程,注意,必须是私钥进行签名,公钥进行验签
  • sign 需要指定散列函数。我们使用 CryptoJS 库中的一个,除非使用自定义散列函数,否则应该向 sign 方法提供散列类型。取值包括:md2、md5、sha1、sha224、sha256、sha384、sha512、等等。
// 签名, 用私钥
var signature = decrypt.sign(message, CryptoJS.SHA256, 'sha256')
console.log('签名', signature)
// 验签  用公钥
var uncrypted = encrypt.verify(message, signature, CryptoJS.SHA256)
console.log('验签', uncrypted)

image.png

  1. 加密解密
// 加密
let en_message = encrypt.encrypt(message)
console.log('加密结果:', en_message)
let de_message = decrypt.decrypt(en_message)
console.log('解密结果:', de_message)

image.png

完整代码实例

import JSEncrypt from 'jsencrypt'
import CryptoJS from 'crypto-js'
import { useEffect } from 'react'
export default function App() {
  let priv_key = `-----BEGIN RSA PRIVATE KEY-----
  MIICXAIBAAKBgQDtW5HtwZ37JXlwSBHRYuL/MrOJFokKzIFOO1feoGUPyzcerWVQ
  JYrvkOnpevlWQjqn7hy9cLlKEeo8BTwHRPFZa9ivbNQuiw3vt8HFY+v5jPx/Q9+c
  Fmsl/B/A9pmyjjuqMAZxxME77lyEodxgxH8DZsg9MTGYlcqI/6IckmzCdwIDAQAB
  AoGARABwFoXaFRHvcNO1ByAlmKeV+DiUmptskFVAH3AkhBnceNWEqSmYXHpQCaxJ
  swTWeTYm1b9t1mK7kOaPBCYkXsTO3jopQLD60ds1QGfoR6eTgZdwXrsmTpb6Rnvy
  +ldmo9pmfT4ssEtit9m4GVL9HvTN1xBsnM6+YZBgFZGkwsECQQD+QtRAO3UIj4bf
  pJypQ0Q0Nb5+svCnBs/vrzKz0vSmysNu7/Vi/9wN5gime5P8G4RpJELNDhVld51I
  w14rTPpbAkEA7vslVNo9deb5ZWD0aWNzk4Zh8YqbyhLxMNvrp1LtUcazCc8nyOoU
  nR9J9wQLWZbYFENI1w3YHN1xPVZtcf/7FQJAEv2s2stWF3iY61VhOidDDd9BxjbZ
  ULBqkY11bQcBrP+SD1Qu8OEJb6RR2xV53Se1ASFrN+OoZ3bCsa+d9f/+5wJAQY2g
  kuL+gu3lsVpkENiX5nqxOSl1THvfrzBUNuS3dnwTtngdiK41E1h22IxCdMO85+oA
  /ASvKFPR8SpZATFfdQJBANQ/D4h/8IZY6qQcZXnkY9eyoZhajKdt1lFEEj8WUUF5
  ybua/Z9A37LaH3W8LddIkToIaO94eB5aXI+fatfvNc8=
  -----END RSA PRIVATE KEY-----
  `
  let pub_key = `-----BEGIN PUBLIC KEY-----
  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDtW5HtwZ37JXlwSBHRYuL/MrOJ
  FokKzIFOO1feoGUPyzcerWVQJYrvkOnpevlWQjqn7hy9cLlKEeo8BTwHRPFZa9iv
  bNQuiw3vt8HFY+v5jPx/Q9+cFmsl/B/A9pmyjjuqMAZxxME77lyEodxgxH8DZsg9
  MTGYlcqI/6IckmzCdwIDAQAB
  -----END PUBLIC KEY-----
  `
  useEffect(() => {
    var encrypt = new JSEncrypt()
    encrypt.setPublicKey(pub_key)
    let message = 'hello world'
    var decrypt = new JSEncrypt()
    decrypt.setPrivateKey(priv_key)
    // 签名, 用私钥
    var signature = decrypt.sign(message, CryptoJS.SHA256, 'sha256')
    console.log('签名', signature)
    // 验签  用公钥
    var uncrypted = encrypt.verify(message, signature, CryptoJS.SHA256)
    console.log('验签', uncrypted)

    // 加密
    let en_message = encrypt.encrypt(message)
    console.log('加密结果:', en_message)
    let de_message = decrypt.decrypt(en_message)
    console.log('解密结果:', de_message)
  }, [])
  return (
    <div className="App">
      <h1>加密数据</h1>
    </div>
  )
}