• 前(jsencrypt)后(node-rsa/crypto)端 RSA 加密与解密


    前端使用 jsencrypt 进行加密,服务端使用 node-rsa 或 crypto 进行解密。

    jsencrypt 加密

    需要注意的是 RSA 加密的数据长度是有限制的,过长的数据可能导致解密失败。允许的数据长度与密钥长度成正比。

    import JSEncrypt from 'jsencrypt';
    
    // 通过 node-rsa 或 crypto 生成的公钥,也可以其他方式生成,只要与私钥成对即可
    const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
    MIIBIjA
    ......
    owIDAQAB
    -----END PUBLIC KEY-----
    `;
    
    /**
     * 对数据进行 RSA 加密,加密失败时会返回 false。
     *
     * JSEncrypt 只能加密字符串数据,因此使用 JSON.stringify 对要加密的数据进行序列化
     *
     * 但此时需要注意一些 JSON.stringify 的问题
     *
     *      比如:JSON.stringify(undefined) => undefined // 这不是一个字符串
     *      比如:JSON.stringify({ prop: undefined }) => '{}'
     *      比如:JSON.stringify(NaN) => 'null'
     *
     * @param {string | number | Object | Array} data 需要加密的数据
     * @param {string} publicKey 公钥,可选
     * @returns {string | false} 密文
     */
    export const EncryptByRSA = (data, publicKey = PUBLIC_KEY) => {
        const encrypt = new JSEncrypt();
    
        encrypt.setPublicKey(publicKey);
    
        return encrypt.encrypt(JSON.stringify(data));
    };
    
    /**
     * 对密文进行 RSA 解密,秘钥不对会返回 false,数据不是加密后的密文会返回 null。
     *
     * 会使用 JSON.parse 对解密后数据进行反序列化
     *
     * @param {string} secretText 待解密的字符串
     * @param {string} privateKey 私钥
     * @returns {any} 解密后的数据
     */
    export const DecryptByAES = (secretText, privateKey) => {
        const decrypt = new JSEncrypt();
    
        decrypt.setPrivateKey(privateKey);
    
        return JSON.parse(decrypt.decrypt(secretText));
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    crypto 解密

    需要注意的是解密时需要设置正确的 padding,否则可能无法对 jsencrypt 加密的数据进行解密。

    import crypto from 'crypto';
    
    /**
     * 生成 RSA 公私钥对
     * @return {Object} { publicKey, privateKey }
     */
    export const generateRSAKeyPair = () => {
        const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
            modulusLength: 2048, // 秘钥长度
    
            // 秘钥配置,详见 https://nodejs.cn/dist/latest-v18.x/docs/api/crypto.html#keyobjectexportoptions
            publicKeyEncoding: {
                type: 'spki', // 编码类型
                format: 'pem' // 编码格式
            },
            privateKeyEncoding: {
                type: 'pkcs8',
                format: 'pem'
            }
        });
        return { publicKey, privateKey };
    };
    
    /**
     * 使用公钥进行加密,加密出错会抛出异常
     * @param {any} data 需要加密的数据,会使用 JSON.stringify 序列化
     * @param {string} publicKey
     * @return {string} 加密后的密文
     */
    export const encrypt = (data, publicKey) => {
        const dataJSON = JSON.stringify(data);
        return crypto.publicEncrypt(publicKey, Buffer.from(dataJSON, 'utf-8')).toString('base64');
    };
    
    /**
     * 使用私钥进行解密,解密出错会抛出异常
     * @param {string} secretText 密文
     * @param {string} privateKey 私钥
     * @return {String} 解密后的明文,会使用 JSON.parse 反序列化
     */
    export const decrypt = (secretText, privateKey) => {
        const dataStr = crypto
            .privateDecrypt(
                {
                    key: privateKey,
    
                    // padding 的值需要与公钥的编码类型相对应
                    padding: crypto.constants.RSA_PKCS1_PADDING
                },
                Buffer.from(secretText, 'base64')
            )
            .toString('utf-8');
        return JSON.parse(dataStr);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    node-rsa 解密

    import NodeRSA from 'node-rsa';
    
    /**
     * 生成 RSA 公私钥对
     * @return {Object} { publicKey, privateKey }
     */
    export const generateRSAKeyPair = () => {
        const key = new NodeRSA({ b: 512 }); // 指定密钥长度
    
        key.setOptions({ encryptionScheme: 'pkcs1' }); // 指定加密格式
    
        const publicKey = key.exportKey('pkcs8-public-pem'); //制定输出格式
        const privateKey = key.exportKey('pkcs8-private-pem');
    
        return { publicKey, privateKey };
    };
    
    /**
     * 使用公钥进行加密,加密出错会抛出异常
     * @param {any} data 需要加密的数据,会使用 JSON.stringify 序列化
     * @param {string} publicKey
     * @return {string} 加密后的密文
     */
    export const encrypt = (data, publicKey) => {
        const encrypt = new NodeRSA(publicKey, 'pkcs8-public-pem');
        encrypt.setOptions({ encryptionScheme: 'pkcs1' });
    
        return encrypt.encrypt(JSON.stringify(data), 'base64');
    };
    
    /**
     * 对密文进行 RSA 解密。如果解密失败,则抛出异常
     * @param {string} secretText 密文
     * @param {string} privateKey 私钥
     * @return {String} 解密后的明文,会使用 JSON.parse 反序列化
     */
    export const decrypt = (secretText, privateKey) => {
        const decrypt = new NodeRSA(privateKey, 'pkcs8-private-pem');
        
        // jsencrypt 自身使用的是 pkcs1 加密方案,所以这里设置为 pkcs1
        decrypt.setOptions({ encryptionScheme: 'pkcs1' });
    
        return JSON.parse(decrypt.decrypt(secretText, 'utf8'));
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
  • 相关阅读:
    计算机毕业设计ssm大学生课外学习系统m65wl系统+程序+源码+lw+远程部署
    使用python来访问Hadoop HDFS存储实现文件的操作
    新库上线 | CnOpenData交通运输、仓储和邮政业工商注册企业基本信息数据
    BE节点经常挂掉:[IO_ERROR]failed to list /proc/27349/fd/: No such file or directory
    KNN算法分类问题实现介绍和使用
    vue项目使用highlight.js 代码高亮插件,并给它添加行数
    flannel的vxlan的工作过程
    论文超详细精读|八千字:AS-GCN
    【ACM学习】【STL】顺序容器的基本功能
    MySQL之查询性能优化(五)
  • 原文地址:https://blog.csdn.net/dark_cy/article/details/133603332