首页 > 解决方案 > 函数包装器如何交互?

问题描述

我正在研究这个项目:rsa-aes-client-server ,我无法理解它们如何与文件夹“\componnets\”和“\static\js\”中的包装函数(aes-wrapper 和 rsa-wrapper)交互?以及这些函数如何与 index.js 文件交互?静态\js\rsa-wrapper.js:

(function () {

    'use strict';

    var crypto = window.crypto.subtle;
    var rsaParams =  {name:"RSA-OAEP", hash: {name: "SHA-1"}};

    function importPublicKey(keyInPemFormat){
        return new Promise(function(resolve, reject){
            var key = converterWrapper.convertPemToBinary2(keyInPemFormat);
            key = converterWrapper.base64StringToArrayBuffer(key);

            crypto.importKey('spki', key, rsaParams, false, ["encrypt"])
                .then(function(cryptokey) {
                    resolve(cryptokey);
                });
        });
    }

    function importPrivateKey(keyInPemFormat){

        var key = converterWrapper.convertPemToBinary2(keyInPemFormat);
        key = converterWrapper.base64StringToArrayBuffer(key);

        return new Promise(function(resolve, reject){
            crypto.importKey('pkcs8', key, rsaParams, false, ["decrypt"])
                .then(function(cryptokey) {
                    resolve(cryptokey);
                });
        });
    }

    function publicEncrypt(keyInPemFormat, message) {
        return new Promise(function(resolve, reject){
            importPublicKey(keyInPemFormat).then(function (key) {
                crypto.encrypt(rsaParams, key, converterWrapper.str2abUtf8(message))
                    .then(function(encrypted){
                        resolve(converterWrapper.arrayBufferToBase64String(encrypted));
                    });
            })
        });
    }

    function privateDecrypt(keyInPemFormat, encryptedBase64Message) {
        return new Promise(function(resolve, reject){
            importPrivateKey(keyInPemFormat).then(function (key) {
                crypto.decrypt(rsaParams, key, converterWrapper.base64StringToArrayBuffer(encryptedBase64Message))
                    .then(function(decrypted){
                        resolve(converterWrapper.arrayBufferToUtf8(decrypted));
                    });
            });
        });
    }

    window.rsaWrapper = {
        importPrivateKey: importPrivateKey,
        importPublicKey: importPublicKey,
        privateDecrypt: privateDecrypt,
        publicEncrypt: publicEncrypt
    }

}());

组件\rsa-wrapper.js

const path = require('path');
const rsaWrapper = {};
const fs = require('fs');
const NodeRSA = require('node-rsa');
const crypto = require('crypto');

// load keys from file
rsaWrapper.initLoadServerKeys = (basePath) => {
    rsaWrapper.serverPub = fs.readFileSync(path.resolve(basePath, 'keys', 'server.public.pem'));
    rsaWrapper.serverPrivate = fs.readFileSync(path.resolve(basePath, 'keys', 'server.private.pem'));
    rsaWrapper.clientPub = fs.readFileSync(path.resolve(basePath, 'keys', 'client.public.pem'));
};

rsaWrapper.generate = (direction) => {
    let key = new NodeRSA();
    key.generateKeyPair(2048, 65537);
    fs.writeFileSync(path.resolve(__dirname, 'keys', direction + '.private.pem'), key.exportKey('pkcs8-private-pem'));
    fs.writeFileSync(path.resolve(__dirname, 'keys', direction + '.public.pem'), key.exportKey('pkcs8-public-pem'));

    return true;
};

rsaWrapper.serverExampleEncrypt = () => {
    console.log('Server public encrypting');

    let enc = rsaWrapper.encrypt(rsaWrapper.serverPub, 'Server init hello');
    console.log('Encrypted RSA string ', '\n', enc);
    let dec = rsaWrapper.decrypt(rsaWrapper.serverPrivate, enc);
    console.log('Decrypted RSA string ...');
    console.log(dec);
};

rsaWrapper.encrypt = (publicKey, message) => {
    let enc = crypto.publicEncrypt({
        key: publicKey,
        padding: crypto.RSA_PKCS1_OAEP_PADDING
    }, Buffer.from(message));

    return enc.toString('base64');
};

rsaWrapper.decrypt = (privateKey, message) => {
    let enc = crypto.privateDecrypt({
        key: privateKey,
        padding: crypto.RSA_PKCS1_OAEP_PADDING
    }, Buffer.from(message, 'base64'));

    return enc.toString();
};

module.exports = rsaWrapper;

index.js

const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const rsaWrapper = require('./components/rsa-wrapper');
const aesWrapper = require('./components/aes-wrapper');

rsaWrapper.initLoadServerKeys(__dirname);
rsaWrapper.serverExampleEncrypt();

// middleware for static processing
app.use(express.static(__dirname + '/static'));

// web socket connection event
io.on('connection', function(socket){

    // Test sending to client dummy RSA message
    let encrypted = rsaWrapper.encrypt(rsaWrapper.clientPub, 'Hello RSA message from client to server');
    socket.emit('rsa server encrypted message', encrypted);

    // Test accepting dummy RSA message from client
    socket.on('rsa client encrypted message', function (data) {
        console.log('Server received RSA message from client');
        console.log('Encrypted message is', '\n', data);
        console.log('Decrypted message', '\n', rsaWrapper.decrypt(rsaWrapper.serverPrivate, data));
    });

    // Test AES key sending
    const aesKey = aesWrapper.generateKey();
    let encryptedAesKey = rsaWrapper.encrypt(rsaWrapper.clientPub, (aesKey.toString('base64')));
    socket.emit('send key from server to client', encryptedAesKey);

    // Test accepting dummy AES key message
    socket.on('aes client encrypted message', function (data) {
        // console.log('Server received AES message from client', '\n', 'Encrypted message is', '\n', data);
        console.log('Decrypted message', '\n', aesWrapper.decrypt(aesKey, data));

        // Test send client dummy AES message
        let message = aesWrapper.createAesMessage(aesKey, 'Server AES message');
        socket.emit('aes server encrypted message', message);
    });
});

http.listen(3000, function(){
    console.log('listening on *:3000');
});

标签: javascriptnode.jsweb

解决方案


file 下的static/js文件在客户端加载并公开一个全局变量,例如在rsa-wrapper此代码中将添加一个全局变量rsaWrapper,该变量将用于index.html

window.rsaWrapper = {
        importPrivateKey: importPrivateKey,
        importPublicKey: importPublicKey,
        privateDecrypt: privateDecrypt,
        publicEncrypt: publicEncrypt
    }

中的文件在componnets服务器端使用并加载了require语句。
客户端服务器交互是使用socket.io库进行的,该库为两种客户端服务器交互提供了一种方式。
呼叫完成socket.emit以发送消息和socket.on收听消息


推荐阅读