美文网首页
基于RSA实现的客户端数据加密,服务端数据解密

基于RSA实现的客户端数据加密,服务端数据解密

作者: JSoon | 来源:发表于2018-12-21 16:12 被阅读0次

    不废话了,直接上正文,年底心好累。。。

    开发环境

    客户端:web浏览器
    服务端:node

    工具库

    jsencrypt.js

    一个运行在浏览器端的JS库,能够进行OpenSSL RSA的加解密,以及公钥&私钥的生成。

    node-rsa

    一个运行在node环境下的RSA模块,若配合 browserify 也能够运行在浏览器端,与jsencrypt.js的作用相同。

    适用场景

    对前端敏感信息进行公钥加密,增加攻击成本。

    兼容性

    客户端:所有主流现代浏览器
    服务端:同 node-rsa

    准备工作

    使用OpenSSL生成一对公钥和密钥。
    拿基于Unix OS的终端举例,运行如下代码:

    // 生成一把1024 bit的私钥
    openssl genrsa -out rsa_1024_priv.pem 1024
    // 根据该私钥再生成一把对应的公钥
    openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem
    

    到此为止,我们完成了公密钥的生成工作。

    客户端代码实现

    rsa.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>基于RSA实现的客户端数据加密,服务端数据解密</title>
    
        <style>
            body {
                margin: 20% 30%;
                font-size: 24px;
                font-weight: bold;
            }
            .encrypted-msg {
                word-break: break-all;
            }
        </style>
    </head>
    
    <body>
        <!-- 公钥rsa_1024_pub.pem中的key字串 -->
        <textarea name="" id="J_PublicKey" cols="30" rows="10" hidden>
    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8asrfSaoOb4je+DSmKdriQJKW
    VJ2oDZrs3wi5W67m3LwTB9QVR+cE3XWU21Nx+YBxS0yun8wDcjgQvYt625ZCcgin
    2ro/eOkNyUOTBIbuj9CvMnhUYiR61lC1f1IGbrSYYimqBVSjpifVufxtx/I3exRe
    ZosTByYp4Xwpb1+WAQIDAQAB
    -----END PUBLIC KEY-----
        </textarea>
        <div>
            加密前数据:<input id="J_Msg" type="text">
        </div>
        <div>
            <button id="J_EncryptBtn" type="button">客户端加密</button>
            <button id="J_DecryptBtn" type="button">服务端解密</button>
        </div>
        <hr>
        <p>加密后数据:</p>
        <div id="J_EncryptedMsg" class="encrypted-msg"></div>
        <p>解密后后数据:</p>
        <div id="J_DecryptedMsg" class="decrypted-msg"></div>
    
        <script src="/jquery/dist/jquery.js"></script>
        <script src="./jsencrypt.js"></script>
        <script src="./rsa.js"></script>
    </body>
    
    </html>
    

    rsa.js

    //#region 客户端加密
    
    $('#J_EncryptBtn').click(function () {
    
        // 使用公匙对明文进行加密
        var encrypt = new JSEncrypt();
        var publicKey = $.trim($('#J_PublicKey').val());
        
        var msg = $.trim($('#J_Msg').val());
        if (!msg) {
            return;
        }
        encrypt.setPublicKey(publicKey);
        var encryptedMsg = encrypt.encrypt(msg);
        $('#J_EncryptedMsg').html(encryptedMsg);
    
    });
    
    //#endregion
    
    //#region 服务端解密
    
    $('#J_DecryptBtn').click(function () {
    
        $.ajax({
            method: 'POST',
            url: '/rsa/decrypt',
            data: {
                msg: $('#J_EncryptedMsg').html()
            }
        }).then(function (res) {
            if (!res || !res.success) {
                return;
            }
    
            $('#J_DecryptedMsg').html(res.decryptedMsg);
        }, function () {
    
        });
    
    });
    
    //#endregion
    

    服务端代码实现

    考虑到文章内容的冗余度,直接进行接口的代码展示。

    var express = require('express');
    var router = express.Router();
    var NodeRSA = require('node-rsa');
    var fs = require('fs');
    var path = require('path');
    
    router.post('/decrypt', function (req, res, next) {
        var body = req.body;
        console.log(body);
    
        // 读取私钥
        fs.readFile(path.join(__dirname, "./private.pem"), (err, data) => {
            if (err) {
                res.status(500).json({
                    success: false
                });
                return;
            }
    
            // 创建私钥对象
            var privateKey = new NodeRSA(data.toString());
            privateKey.setOptions({
                // 这里需要指定RSA padding模式为pkcs1,这是因为前端jsencrypt库采用了pkcs1,而后端node-rsa默认使用的pkcs1_oaep
                // https://stackoverflow.com/questions/33837617/node-rsa-errors-when-trying-to-decrypt-message-with-private-key
                encryptionScheme: 'pkcs1'
            });
    
            // 对数据进行解密
            var decryptedMsg = privateKey.decrypt(body.msg, 'utf8');
    
            res.json({
                success: true,
                encryptedMsg: body.msg,
                decryptedMsg: decryptedMsg
            });
        });
    });
    
    module.exports = router;
    

    总结

    综上所述,实现了一个简洁的对明文数据进行加解密的过程,总结步骤如下:

    1. 生成两个配对的公钥(KE)和私钥(KD
    2. 使用公钥对明文(S)进行加密,生成密文(R),算法描述如下:

    R = E(S, KE)

    1. 使用私钥(KD)对密文(R)进行解密(即逆向计算),最终得到加密前的明文(S),算法描述如下:

    S = D(R, KD)

    参考文献

    https://github.com/travist/jsencrypt
    https://www.npmjs.com/package/node-rsa
    http://www.cnblogs.com/leoo2sk/archive/2010/10/01/hash-and-encrypt.html
    https://www.cnblogs.com/o--ok/p/4827580.html

    相关文章

      网友评论

          本文标题:基于RSA实现的客户端数据加密,服务端数据解密

          本文链接:https://www.haomeiwen.com/subject/gggmkqtx.html