• JAVA+Node/JavaScript 前后端通讯 RSA 加解密实现


    实际项目中,前后端或跨语言加密通讯的场景十分常见。这里以 JavaNode.js(兼容浏览器)两种开发语言为例,实现 RSA 加解密通讯。

    JAVA端加解密

    此代码采用分段加解密,理论上支持无限长度的文本内容

    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.security.*;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    
    public final class RSAProvider {
    
        private final static String RSA = "RSA";
        private final static String SHA256WithRSA = "SHA256WithRSA";
        private final static int MAX = 117;
    
        private String privateKey;
        private String publicKey;
    
        /**
         * 创建 RSA 工具类,自动生成公私钥(字符串格式)
         * @throws Exception
         */
        public RSAProvider() throws Exception {
            //自动生成密钥
            KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA);
            generator.initialize(1024, new SecureRandom());
            KeyPair keyPair = generator.genKeyPair();
    
            Base64.Encoder encoder = Base64.getEncoder();
            initKey(
                    encoder.encodeToString(keyPair.getPublic().getEncoded()),
                    encoder.encodeToString(keyPair.getPrivate().getEncoded())
            );
        }
    
        /**
         * 使用特定公私钥初始化工具类
         * @param pubKey
         * @param priKey
         */
        public RSAProvider(String pubKey, String priKey){
            initKey(pubKey, priKey);
        }
    
        private void initKey(String pubKey, String priKey){
            this.privateKey = priKey;
            this.publicKey = pubKey;
        }
    
        private PrivateKey buildPriKey() throws Exception {
            if(privateKey == null || privateKey.isEmpty())  throw new RuntimeException("PRIVATE KEY is empty!");
    
            return KeyFactory.getInstance(RSA)
                    .generatePrivate(
                            new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))
                    );
        }
    
        private PublicKey buildPubKey() throws Exception {
            if(publicKey == null || publicKey.isEmpty())  throw new RuntimeException("PUBLIC KEY is empty!");
    
            return KeyFactory.getInstance(RSA)
                    .generatePublic(
                            new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))
                    );
        }
    
        /**
         * 使用私钥签名
         * @param content
         * @return
         */
        public String sign(String content) throws Exception {
            Signature signature = Signature.getInstance(SHA256WithRSA);
            signature.initSign(buildPriKey());
            signature.update(content.getBytes());
            return Base64.getEncoder().encodeToString(signature.sign());
        }
    
        /**
         * 公钥验签
         * @param message
         * @param signed
         * @return
         * @throws Exception
         */
        public boolean verifySign(String message, String signed) throws Exception {
            Signature signature = Signature.getInstance(SHA256WithRSA);
            signature.initVerify(buildPubKey());
            signature.update(message.getBytes());
            return signature.verify(Base64.getDecoder().decode(signed));
        }
    
    
        /**
         * 使用公钥加密
         * @param content 任意长度的字符
         * @return
         */
        public String encrypt(String content) throws Exception {
            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.ENCRYPT_MODE, buildPubKey());
            //此方法只能加密长度小于 117 bytes
    //        return Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes()));
    
            byte[] bytes = content.getBytes();
            ByteArrayOutputStream bops = new ByteArrayOutputStream();
            int offLen = 0;
    
            while (bytes.length - offLen > 0){
                bops.write(cipher.doFinal(bytes, offLen, Math.min(bytes.length - offLen, MAX)));
                offLen += MAX;
            }
            bops.close();
            return Base64.getEncoder().encodeToString(bops.toByteArray());
        }
    
        /**
         * 使用私钥解密
         * @param data 任意长度的密文(分段解密)
         * @return
         * @throws Exception
         */
        public String decrypt(String data) throws Exception {
            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.DECRYPT_MODE, buildPriKey());
            // 此方法报错:Data must not be longer than 128 bytes
    //        return new String(cipher.doFinal(Base64.getDecoder().decode(data)));
    
            byte[] bytes =  Base64.getDecoder().decode(data);
            ByteArrayOutputStream bops = new ByteArrayOutputStream();
            int offLen = 0;
    
            while (bytes.length - offLen > 0){
                bops.write(cipher.doFinal(bytes, offLen, Math.min(bytes.length - offLen, 128)));
                offLen += 128;
            }
            bops.close();
            return bops.toString();
        }
    
        public String getPrivateKey() {
            return privateKey;
        }
        public String getPublicKey() {
            return publicKey;
        }
    }
    
    • 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
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    使用示例:

    RSAProvider().also {
        println("公钥:${it.publicKey}")
        println("私钥:${it.privateKey}")
    
        val text = "Hello,集成显卡!!"
        val miwen = it.encrypt(text)
        println("密文:${miwen}")
        println("解码:${it.decrypt(miwen)}")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Node/JavaScript 加解密

    // 请先执行 npm i node-rsa
    const NodeRSA = require("node-rsa")
    
    const encryptionScheme = "pkcs1"
    module.exports = {
        encrypt (data, publicKey) {
            const pubKey = new NodeRSA(publicKey, 'pkcs8-public')
            //设置与后端一致的加密方式 pkcs1
            pubKey.setOptions({ encryptionScheme })
            return pubKey.encrypt(Buffer.from(data), 'base64')
        },
    
        decrypt (data, privateKey){
            const priKey = new NodeRSA(privateKey, 'pkcs8-private')
            priKey.setOptions({ encryptionScheme })
            return priKey.decrypt(Buffer.from(data, 'base64'), 'utf8')
        },
    
        sign (data, privateKey){
            const priKey = new NodeRSA(privateKey, 'pkcs8-private')
            return priKey.sign(Buffer.from(data)).toString('base64')
        },
    
        verify (data, signature, publicKey){
            const pubKey = new NodeRSA(publicKey, 'pkcs8-public')
            return pubKey.verify(data, Buffer.from(signature, 'base64'))
        }
    }
    
    
    • 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
  • 相关阅读:
    网络编程day04(网络属性函数、广播、组播、TCP并发)
    Linux_一款好用的查看系统信息的桌面软件_包名hardinfo、软件名system profiler and Benchmark
    RocketMQ 4.5.1安装教程
    【节能学院】Acrel5000web能耗系统在某学院的应用
    齿轮减速机设备类网站pbootcms模板(PC端+手机端自适应)
    网络层哪些事?
    算法60天目录
    【无标题】
    吴恩达deeplearning.ai:Tensorflow训练一个神经网络
    爬虫----记录某新闻详情页app逆向过程(app逆向初学第一次实战)
  • 原文地址:https://blog.csdn.net/ssrc0604hx/article/details/133903909