Skip to content
This repository has been archived by the owner on Sep 25, 2023. It is now read-only.

在不支持libpomelo2的设备中(如windows phone)使用 DH + RC4 算法提供通信加密功能 #768

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
13 changes: 13 additions & 0 deletions lib/common/service/sessionService.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var EventEmitter = require('events').EventEmitter;
var crypto = require('crypto')
var util = require('util');
var logger = require('pomelo-logger').getLogger('pomelo', __filename);
var utils = require('../../util/utils');
Expand Down Expand Up @@ -514,6 +515,10 @@ Session.prototype.get = function(key) {
* @param {Object} msg final message sent to client
*/
Session.prototype.send = function(msg) {
if(!!this.__socket__.__serverSecret){
var cipher = crypto.createCipher('rc4', this.__socket__.__serverSecret);
msg = cipher.update(msg);
}
this.__socket__.send(msg);
};

Expand All @@ -523,6 +528,14 @@ Session.prototype.send = function(msg) {
* @param {Array} msgs list of message
*/
Session.prototype.sendBatch = function(msgs) {
if(!!this.__socket__.__serverSecret){
for(var i = 0; i < msgs.length; i ++){
var msg = msgs[i];
var cipher = crypto.createCipher('rc4', this.__socket__.__serverSecret);
msg = cipher.update(msg);
msgs[i] = msg;
}
}
this.__socket__.sendBatch(msgs);
};

Expand Down
5 changes: 5 additions & 0 deletions lib/components/connector.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var crypto = require('crypto')
var logger = require('pomelo-logger').getLogger('pomelo', __filename);
var taskManager = require('../common/manager/taskManager');
var pomelo = require('../pomelo');
Expand Down Expand Up @@ -216,6 +217,10 @@ var bindEvents = function(self, socket) {

// new message
socket.on('message', function(msg) {
if(!!socket.__serverSecret){
var decipher = crypto.createDecipher('rc4', socket.__serverSecret);
msg.body = decipher.update(msg.body);
}
var dmsg = msg;
if(self.decode) {
dmsg = self.decode.call(self, msg, session);
Expand Down
21 changes: 21 additions & 0 deletions lib/connectors/commands/handshake.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var pomelo = require('../../pomelo');
var Package = require('pomelo-protocol').Package;
var crypto = require('crypto')

var CODE_OK = 200;
var CODE_USE_ERROR = 500;
Expand Down Expand Up @@ -27,6 +28,7 @@ var Command = function(opts) {
this.useDict = opts.useDict;
this.useProtobuf = opts.useProtobuf;
this.useCrypto = opts.useCrypto;
this.useCrypto2 = opts.useCrypto2;
};

module.exports = Command;
Expand Down Expand Up @@ -85,6 +87,25 @@ Command.prototype.handle = function(socket, msg) {
pomelo.app.components.__connector__.setPubKey(socket.id, msg.sys.rsa);
}

if(this.useCrypto2){
if(!msg.sys.clientKey || 'string' !== typeof msg.sys.clientKey || msg.sys.clientKey.trim().length === 0){
return processError(socket, CODE_USE_ERROR);
}
var clientKey = msg.sys.clientKey;
var challenge = crypto.randomBytes(8).toString('base64');
var serverDiff = crypto.getDiffieHellman('modp1');
serverDiff.generateKeys();
var serverKey = serverDiff.getPublicKey('base64');
var serverSecret = serverDiff.computeSecret(clientKey, 'base64', 'base64');
opts.crypto2 = true;
opts.serverKey = serverKey;
opts.challenge = challenge;
socket.__serverSecret = serverSecret;
var cipher = crypto.createCipher('rc4', serverSecret);
var rc4 = cipher.update(challenge, 'utf8', 'base64');
rc4 += cipher.final('base64');
socket.__challenge = rc4;
}
if(typeof this.userHandshake === 'function') {
this.userHandshake(msg, function(err, resp) {
if(err) {
Expand Down
11 changes: 11 additions & 0 deletions lib/connectors/common/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ var handleHandshakeAck = function(socket, pkg) {
return;
}
socket.state = ST_WORKING;
if(socket.__serverSecret){
try{
var body = JSON.parse(protocol.strdecode(pkg.body));
if(!body || body.challenge !== socket.__challenge){
return socket.emit('error', new Error('challenge failed'))
}
}catch(e){
return socket.emit('error', new Error('challenge failed'))
}
delete socket.__challenge;
}
socket.emit('heartbeat');
};

Expand Down