RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密

这篇具有很好参考价值的文章主要介绍了RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章归档:https://www.yuque.com/u27599042/coding_star/cl4dl599pdmtllw1

依赖

  1. import JSEncrypt from ‘jsencrypt’
pnpm i jsencrypt
  1. import {stringIsNull} from “@/utils/string_utils.js”:https://www.yuque.com/u27599042/coding_star/slncupw7un3ce7cb
  2. import {isNumber} from “@/utils/number_utils.js”:https://www.yuque.com/u27599042/coding_star/tuwmm3ghf5lgo4bw

导入依赖

import JSEncrypt from 'jsencrypt'
import {stringIsNull} from "@/utils/string_utils.js"
import {isNumber} from "@/utils/number_utils.js"

内部变量

/**
 * RSA 加密算法获取密钥对中的公钥使用的 key
 *
 * @type {string}
 */
export const PUBLIC_KEY = 'RSAPublicKey'

/**
 * RSA 加密算法获取密钥对中的密钥使用的 key
 *
 * @type {string}
 */
export const PRIVATE_KEY = 'RSAPrivateKey'

/**
 * RSA 密钥对的 bit 数(密钥对的长度)。
 * 常用 1024、2048,密钥对的 bit 数,越大越安全,但是越大对服务器的消耗越大
 *
 * @type {number}
 */
let keySize = 1024

/**
 * keySize bit 数下的 RSA 密钥对所能够加密的最大明文大小。
 * RSA 算法一次能加密的明文长度与密钥长度(RSA 密钥对的 bit 数)成正比,
 * 默认情况下,Padding 方式为 OPENSSL_PKCS1_PADDING,RSA 算法会使
 * 用 11 字节的长度用于填充,所以默认情况下,RSA 所能够加密的最大明文大
 * 小为 (keySize / 8 - 11) byte
 *
 * @type {number}
 */
let maxEncryptPlainTextLen = 117

/**
 * keySize bit 数下的 RSA 密钥对所能够解密的最大密文大小。
 * (keySize / 8) byte
 *
 * @type {number}
 */
let maxDecryptCipherTextLen = 128

/**
 * 密钥长度为 1024 bit 下,通过公钥生成的密文字符串的长度
 *
 * @type {number}
 */
let cipherTextStrLen = 172

设置 RSA 密钥对的 bit 数

/**
 * 为 RSA 密钥对的 bit 数赋值,同时重新计算 keySize bit 数下的
 * RSA 密钥对所能够加密的最大明文大小、所能够解密的最大密文大小
 *
 * @param size RSA 密钥对的 bit 数
 */
export function setKeySize(size) {
    if (!isNumber(size) || size <= 0) {
        throw new TypeError("参数 {size} 需要是大于 0 的整数")
    }
    keySize = size
    maxEncryptPlainTextLen = keySize / 8 - 11
    maxDecryptCipherTextLen = keySize / 8
}

获取指定字符的 UTF8 字节大小

/**
 * 获取指定字符的 UTF8 字节大小
 * 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744
 *
 * @param charCode 字符编码
 * @return {number} 指定字符的 UTF8 字节大小
 */
export function getCharByteSizeUTF8(charCode) {
    if (!isNumber(charCode) || charCode < 0) {
        throw new TypeError("参数 {charCode} 需要是大于 0 的整数")
    }
    //字符代码在000000 – 00007F之间的,用一个字节编码
    if (charCode <= 0x007f) {
        return 1
    }
    //000080 – 0007FF之间的字符用两个字节
    else if (charCode <= 0x07ff) {
        return 2
    }
    //000800 – 00D7FF 和 00E000 – 00FFFF之间的用三个字节,注: Unicode在范围 D800-DFFF 中不存在任何字符
    else if (charCode <= 0xffff) {
        return 3
    }
    //010000 – 10FFFF之间的用4个字节
    else {
        return 4
    }
}

获取字符串的 UTF8 字节长度

/**
 * 获取字符串的 UTF8 字节长度
 * 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744
 *
 * @param str 字符串
 * @returns {number} 字符串的 UTF8 字节长度
 */
export function getStrByteLenUTF8(str) {
    if (stringIsNull(str)) {
        throw new TypeError("参数 {str} 需要非空字符串")
    }
    // 获取字符串的字符长度
    const strLen = str.length
    // 保存字符串的字节长度
    let strByteLen = 0
    // 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度
    for (let i = 0; i < strLen; i++) {
        // 获取当前遍历字符的编码
        let charCode = str.charCodeAt(i);
        // 获取并记录当前遍历字符的 UTF8 字节大小
        strByteLen += getCharByteSizeUTF8(charCode)
    }
    return strByteLen
}

获取字符串的 UTF8 字节长度, 同时获取按照指定的子字符串字节长度划分的子字符串数组

/**
 * 获取字符串的 UTF8 字节长度,同时获取按照指定的子字符串字节长度划分的子字符串数组
 * 代码参考: https://blog.csdn.net/csdn_yuan_/article/details/107428744
 *
 * @param str 字符串
 * @param subStrByteLen 子字符串字节长度
 * @return {[]} 按照指定的子字符串字节长度划分的子字符串数组
 */
export function getStrByteLenUTF8AndSubStrs(str, subStrByteLen) {
    if (stringIsNull(str)) {
        throw new TypeError("参数 {str} 需要非空字符串")
    }
    if (!isNumber(subStrByteLen) || subStrByteLen <= 0) {
        throw new TypeError("参数 {subStrByteLen} 需要是大于 0 的整数")
    }
    // 获取字符串的字符长度
    const strLen = str.length
    // 保存字符串的字节长度
    let strByteLen = 0
    // 记录上一次分隔的字符串的位置
    let preIdx = 0;
    // 记录当前子字符串的字节大小
    let subStrByteSize = 0;
    // 记录子字符串
    const subStrs = []
    // 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度
    for (let i = 0; i < strLen; i++) {
        // 获取当前遍历字符的编码
        let charCode = str.charCodeAt(i);
        // 获取并记录当前遍历字符的 UTF8 字节大小
        let charByteSizeUTF8 = getCharByteSizeUTF8(charCode)
        strByteLen += charByteSizeUTF8
        // 当前子字符串的字节大小
        subStrByteSize += charByteSizeUTF8
        // 子字符串达到切割长度
        if (subStrByteSize > subStrByteLen) {
            // 当前子字符串加入返回结果数组中
            subStrs.push(str.substring(preIdx, i))
            // 更新数据
            preIdx = i
            subStrByteSize = charByteSizeUTF8
        }
    }
    // 如果还有子字符串还为加入返回结果数组中
    if (subStrByteSize > 0) {
        subStrs.push(str.substring(preIdx))
    }
    return {
        strByteLen,
        subStrs
    }
}

使用公钥对明文进行加密(支持长文本)

/**
 * 使用公钥对明文进行加密(支持长文本)
 *
 * @param publicKey 公钥
 * @param plainText 明文
 * @returns {string} 明文加密后的密文
 */
export function encryptByPublicKey(publicKey, plainText) {
    if (stringIsNull(publicKey) || stringIsNull(plainText)) {
        throw new TypeError("参数 {publicKey} {plainText} 需要非空字符串")
    }
    // 获取明文字符串的字节大小和根据指定字节大小划分的子字符串数组
    const { strByteLen: plainTextByteSize, subStrs: plainTextSubStrArr } = getStrByteLenUTF8AndSubStrs(
        plainText,
        maxEncryptPlainTextLen
    )
    // 明文加密后的完整密文
    let cipherText = ""
    // 对明文进行分段加密
    plainTextSubStrArr.forEach(subStr => {
        // 获取加密解密器
        const encryptor = new JSEncrypt()
        // 设置公钥
        encryptor.setPublicKey(publicKey)
        // 加密
        cipherText += encryptor.encrypt(subStr)
    })
    return cipherText
}

使用私钥对密文进行解密(支持长文本)

注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密文章来源地址https://www.toymoban.com/news/detail-855643.html

/**
 * 使用私钥对密文进行解密(支持长文本)
 * 注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密
 *
 * @param privateKey 密钥
 * @param cipherText 密文
 * @return {string} 密文解密后的明文
 */
export function decryptByPrivateKey(privateKey, cipherText) {
    if (stringIsNull(privateKey) || stringIsNull(cipherText)) {
        throw new TypeError("参数 {privateKey} {cipherText} 需要非空字符串")
    }
    // 获取密文的字符长度
    let cipherTextLen = cipherText.length
    // 计算分段解密的次数, cipherTextStrLen 每段密文长度
    let decryptCount = cipherTextLen / cipherTextStrLen
    // 解密后的完整明文
    let plainText = ""
    // 对密文进行分段解密
    for (let i = 0; i < decryptCount; i++) {
        // 分段密文距离开始位置的偏移量
        let offSet = i * cipherTextStrLen
        let subCipherText = cipherText.substring(offSet, offSet + cipherTextLen)
        // 加密解密器
        const encryptor = new JSEncrypt()
        // 设置私钥
        encryptor.setPrivateKey(privateKey)
        // 解密
        plainText += encryptor.decrypt(subCipherText)
    }
    return plainText
}

与 RSAUtil 搭配的 Java 后端 RSAUtilInteractiveWithFrontEnd

完整源码

import JSEncrypt from 'jsencrypt'
import {stringIsNull} from "@/utils/string_utils.js"
import {isNumber} from "@/utils/number_utils.js"

/**
 * RSA 加密算法获取密钥对中的公钥使用的 key
 *
 * @type {string}
 */
export const PUBLIC_KEY = 'RSAPublicKey'

/**
 * RSA 加密算法获取密钥对中的密钥使用的 key
 *
 * @type {string}
 */
export const PRIVATE_KEY = 'RSAPrivateKey'

/**
 * RSA 密钥对的 bit 数(密钥对的长度)。
 * 常用 1024、2048,密钥对的 bit 数,越大越安全,但是越大对服务器的消耗越大
 *
 * @type {number}
 */
let keySize = 1024

/**
 * keySize bit 数下的 RSA 密钥对所能够加密的最大明文大小。
 * RSA 算法一次能加密的明文长度与密钥长度(RSA 密钥对的 bit 数)成正比,
 * 默认情况下,Padding 方式为 OPENSSL_PKCS1_PADDING,RSA 算法会使
 * 用 11 字节的长度用于填充,所以默认情况下,RSA 所能够加密的最大明文大
 * 小为 (keySize / 8 - 11) byte
 *
 * @type {number}
 */
let maxEncryptPlainTextLen = 117

/**
 * keySize bit 数下的 RSA 密钥对所能够解密的最大密文大小。
 * (keySize / 8) byte
 *
 * @type {number}
 */
let maxDecryptCipherTextLen = 128

/**
 * 密钥长度为 1024 bit 下,通过公钥生成的密文字符串的长度
 *
 * @type {number}
 */
let cipherTextStrLen = 172

/**
 * 为 RSA 密钥对的 bit 数赋值,同时重新计算 keySize bit 数下的
 * RSA 密钥对所能够加密的最大明文大小、所能够解密的最大密文大小
 *
 * @param size RSA 密钥对的 bit 数
 */
export function setKeySize(size) {
    if (!isNumber(size) || size <= 0) {
        throw new TypeError("参数 {size} 需要是大于 0 的整数")
    }
    keySize = size
    maxEncryptPlainTextLen = keySize / 8 - 11
    maxDecryptCipherTextLen = keySize / 8
}

/**
 * 获取指定字符的 UTF8 字节大小
 * 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744
 *
 * @param charCode 字符编码
 * @return {number} 指定字符的 UTF8 字节大小
 */
export function getCharByteSizeUTF8(charCode) {
    if (!isNumber(charCode) || charCode < 0) {
        throw new TypeError("参数 {charCode} 需要是大于 0 的整数")
    }
    //字符代码在000000 – 00007F之间的,用一个字节编码
    if (charCode <= 0x007f) {
        return 1
    }
    //000080 – 0007FF之间的字符用两个字节
    else if (charCode <= 0x07ff) {
        return 2
    }
    //000800 – 00D7FF 和 00E000 – 00FFFF之间的用三个字节,注: Unicode在范围 D800-DFFF 中不存在任何字符
    else if (charCode <= 0xffff) {
        return 3
    }
    //010000 – 10FFFF之间的用4个字节
    else {
        return 4
    }
}

/**
 * 获取字符串的 UTF8 字节长度
 * 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744
 *
 * @param str 字符串
 * @returns {number} 字符串的 UTF8 字节长度
 */
export function getStrByteLenUTF8(str) {
    if (stringIsNull(str)) {
        throw new TypeError("参数 {str} 需要非空字符串")
    }
    // 获取字符串的字符长度
    const strLen = str.length
    // 保存字符串的字节长度
    let strByteLen = 0
    // 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度
    for (let i = 0; i < strLen; i++) {
        // 获取当前遍历字符的编码
        let charCode = str.charCodeAt(i);
        // 获取并记录当前遍历字符的 UTF8 字节大小
        strByteLen += getCharByteSizeUTF8(charCode)
    }
    return strByteLen
}

/**
 * 获取字符串的 UTF8 字节长度,同时获取按照指定的子字符串字节长度划分的子字符串数组
 * 代码参考: https://blog.csdn.net/csdn_yuan_/article/details/107428744
 *
 * @param str 字符串
 * @param subStrByteLen 子字符串字节长度
 * @return {[]} 按照指定的子字符串字节长度划分的子字符串数组
 */
export function getStrByteLenUTF8AndSubStrs(str, subStrByteLen) {
    if (stringIsNull(str)) {
        throw new TypeError("参数 {str} 需要非空字符串")
    }
    if (!isNumber(subStrByteLen) || subStrByteLen <= 0) {
        throw new TypeError("参数 {subStrByteLen} 需要是大于 0 的整数")
    }
    // 获取字符串的字符长度
    const strLen = str.length
    // 保存字符串的字节长度
    let strByteLen = 0
    // 记录上一次分隔的字符串的位置
    let preIdx = 0;
    // 记录当前子字符串的字节大小
    let subStrByteSize = 0;
    // 记录子字符串
    const subStrs = []
    // 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度
    for (let i = 0; i < strLen; i++) {
        // 获取当前遍历字符的编码
        let charCode = str.charCodeAt(i);
        // 获取并记录当前遍历字符的 UTF8 字节大小
        let charByteSizeUTF8 = getCharByteSizeUTF8(charCode)
        strByteLen += charByteSizeUTF8
        // 当前子字符串的字节大小
        subStrByteSize += charByteSizeUTF8
        // 子字符串达到切割长度
        if (subStrByteSize > subStrByteLen) {
            // 当前子字符串加入返回结果数组中
            subStrs.push(str.substring(preIdx, i))
            // 更新数据
            preIdx = i
            subStrByteSize = charByteSizeUTF8
        }
    }
    // 如果还有子字符串还为加入返回结果数组中
    if (subStrByteSize > 0) {
        subStrs.push(str.substring(preIdx))
    }
    return {
        strByteLen,
        subStrs
    }
}

/**
 * 使用公钥对明文进行加密(支持长文本)
 *
 * @param publicKey 公钥
 * @param plainText 明文
 * @returns {string} 明文加密后的密文
 */
export function encryptByPublicKey(publicKey, plainText) {
    if (stringIsNull(publicKey) || stringIsNull(plainText)) {
        throw new TypeError("参数 {publicKey} {plainText} 需要非空字符串")
    }
    // 获取明文字符串的字节大小和根据指定字节大小划分的子字符串数组
    const { strByteLen: plainTextByteSize, subStrs: plainTextSubStrArr } = getStrByteLenUTF8AndSubStrs(
        plainText,
        maxEncryptPlainTextLen
    )
    // 明文加密后的完整密文
    let cipherText = ""
    // 对明文进行分段加密
    plainTextSubStrArr.forEach(subStr => {
        // 获取加密解密器
        const encryptor = new JSEncrypt()
        // 设置公钥
        encryptor.setPublicKey(publicKey)
        // 加密
        cipherText += encryptor.encrypt(subStr)
    })
    return cipherText
}

/**
 * 使用私钥对密文进行解密(支持长文本)
 * 注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密
 *
 * @param privateKey 密钥
 * @param cipherText 密文
 * @return {string} 密文解密后的明文
 */
export function decryptByPrivateKey(privateKey, cipherText) {
    if (stringIsNull(privateKey) || stringIsNull(cipherText)) {
        throw new TypeError("参数 {privateKey} {cipherText} 需要非空字符串")
    }
    // 获取密文的字符长度
    let cipherTextLen = cipherText.length
    // 计算分段解密的次数, cipherTextStrLen 每段密文长度
    let decryptCount = cipherTextLen / cipherTextStrLen
    // 解密后的完整明文
    let plainText = ""
    // 对密文进行分段解密
    for (let i = 0; i < decryptCount; i++) {
        // 分段密文距离开始位置的偏移量
        let offSet = i * cipherTextStrLen
        let subCipherText = cipherText.substring(offSet, offSet + cipherTextLen)
        // 加密解密器
        const encryptor = new JSEncrypt()
        // 设置私钥
        encryptor.setPrivateKey(privateKey)
        // 解密
        plainText += encryptor.decrypt(subCipherText)
    }
    return plainText
}

到了这里,关于RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 前端开发之jsencrypt加密解密的使用方法和使用示例

    前端开发之jsencrypt加密解密的使用方法和使用示例

    jsencrypt官方文档 公钥私钥生成网址 jsencrypt就是一个基于rsa加解密的js库,常用在向后台发送数据的时候 本文是通过node.js的window.btoa和window.atob配合jsencrypt进行加密

    2024年02月16日
    浏览(27)
  • 前端RSA加密方法jsencrypt以及encryptlong

    jsencrypt和encryptlong都是rsa加密,加密的对象一定要是字符串。 简单数据用前者,如果加密的是对象并且数据还挺多的,比如含有token 用后者。 生成密钥: RSA会产生两个密钥,其中公钥公开用于加密,私钥不公开用于解密。点击生成公钥密钥 NPM安装: jsencrypt NPM地址 encryptlo

    2024年02月15日
    浏览(13)
  • RSA之前端加密后端解密

    RSA之前端加密后端解密

    RSA加密解密方式有: (1)公钥加密,私钥解密; (2)私钥加密,公钥解密; 此文章中以下我使用的是 前端公钥加密,后端私钥解密 ; http://web.chacuo.net/netrsakeypair 生成对应的公钥和私钥 前端加密js文件 : 链接: https://pan.baidu.com/s/1NIMayTcmjbMOf7BqPhPQoA 提取码: t7an 下载js文件并

    2024年02月21日
    浏览(16)
  • vue前端RSA加密java后端解密的方法

    最近安全测试的总是测出安全漏洞来,让开发改。 想了想干脆把请求参数都加密下,前端加密后端解密,这样总差不多了。 看了下AES加密,是对称的,前后端用这个不太行。 于是想到用RSA加密,是非对称的,可以前端加密后端解密。 1.前端是vue项目,使用时,需要先执行:

    2023年04月21日
    浏览(10)
  • 前端js使用jsrsasign,生成RSA秘钥,获取一系列信息(公钥,私钥,模数,指数等)进行加密解密

    前言: 之前的项目里用的RSA加解密的时候是生成固定的公钥(模数,指数)和私钥放在代码里进行数据的解密。现在要修改成前端自己生成(模数和指数)传给后台。后台加密数据返回给我。我在用私钥解密。 后面查了很多,开始的window.crypto里的方法可以生成公钥和私钥,

    2024年02月16日
    浏览(66)
  • RSA 加密解密算法实现(简单,易懂)!!!

    RSA 加密解密算法实现(简单,易懂)!!!

    目录 一、什么是RSA算法 1.对称加密 2.非对称加密 3.非对称加密的应用 二、RSA算法的基础操作步骤 1.生成公钥和私钥 2.用公钥加密信息  3.用私钥解密信息 三、AC代码 六、RSA算法的测试  七、共勉     在计算机中常用的加密算法分为两类: 对称加密算法和非对称加密算法。

    2024年01月20日
    浏览(15)
  • RSA加密,公钥、私钥的生成,前端使用公钥加密,JSEncrypt返回值为false的原因以及解决方法,XML转换Pkcs1、8

    RSA加密,公钥、私钥的生成,前端使用公钥加密,JSEncrypt返回值为false的原因以及解决方法,XML转换Pkcs1、8

    非对称加密算法,两个且不同的Key,一个公开,一个私密,公开加密,私密解密。 特点: 原文短,加密后密文长 生成相对较慢 安全性超强 我们使用.net进行生成公钥、私钥。 使用RSA.ToXmlString(Boolean) 方法生成公钥以及私钥,方法中接收一个参数, true  表示同时包含 RSA 公钥

    2024年01月21日
    浏览(47)
  • Java代码实现RSA算法加密解密文件功能

    Java代码实现RSA算法加密解密文件功能

    底层算法不做赘述,想要了解自行百度。 RSA属于非对称加密,非对称加密有公钥和私钥两个概念,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密: 签名:使用私钥加密,公钥解密。用于让所有公钥所有者验证私钥所有者的身份

    2024年02月12日
    浏览(15)
  • js实现rsa密钥的加密、解密与生成

    今天想用js实现rsa的加解密的,在网上找了好久,下载啊什么的,十分麻烦,今天我也不bb的直接放代码 rsa.html 生成完了后,可以去在线rsa网站上检测一下,RSA在线加解密 下载链接: rsa.zip - 蓝奏云 备用下载链接: 百度网盘 密码1234 参考文献: travist/jsencrypt: (github.com)

    2024年02月16日
    浏览(51)
  • RSA加密解密(无数据大小限制,php、go、java互通实现)

    RSA加解密中必须考虑到的**长度、明文长度和密文长度问题。明文长度需要小于**长度,而密文长度则等于**长度。因此当加密内容长度大于**长度时,有效的RSA加解密就需要对内容进行分段。 这是因为,RSA算法本身要求加密内容也就是明文长度m必须0m**长度n。如果小于这个长

    2024年02月15日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包