Skip to content

Commit

Permalink
私聊加入协商密钥机制:poop:但是代码写得很坏,需要调整架构和逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
ch1ny committed May 31, 2022
1 parent 3999fea commit b3f0387
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 56 deletions.
40 changes: 40 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Store = require('electron-store');
const store = new Store();
const fs = require('fs-extra');
const cp = require('child_process');
const crypto = require('crypto');

let loginWindow, mainWindow;
let tray;
Expand Down Expand Up @@ -399,6 +400,17 @@ function createMainWindow(userEmail) {
return mainWindow.isMinimized();
});

ipc.handle('DIFFIE_HELLMAN', (evt, ...args) => {
switch (args.length) {
case 1:
return diffieHellman.final(args[0]);
case 3:
return diffieHellman.answer(args[0], args[1], args[2]);
default:
return diffieHellman.offer();
}
});

mainWindow.on('closed', () => {
ipc.removeHandler('GET_USER_AUTH_TOKEN_AFTER_LOGIN');
ipc.removeAllListeners('EXCHANGE_MAIN_WINDOW_MAXIMIZED_STATUS');
Expand All @@ -412,6 +424,7 @@ function createMainWindow(userEmail) {
ipc.removeHandler('GET_MESSAGE_HISTORY');
ipc.removeHandler('DOWNLOADED_UPDATE_ZIP');
ipc.removeAllListeners('READY_TO_UPDATE');
ipc.removeHandler('DIFFIE_HELLMAN');
mainWindow = null;
});
});
Expand Down Expand Up @@ -487,3 +500,30 @@ function requestInstanceLock() {
});
}
}

const diffieHellmanClient = crypto.createDiffieHellman(256, 5);
const diffieHellman = {
offer() {
diffieHellmanClient.generateKeys();
const clientPublicKey = diffieHellmanClient.getPublicKey();
const global_p = diffieHellmanClient.getPrime().toString('hex');
const global_g = diffieHellmanClient.getGenerator().toString('hex');
return new Array(global_p, global_g, clientPublicKey.toString('hex'));
},
answer(global_p, global_g, clientPublicKey) {
console.log(global_p, global_g, clientPublicKey);
const global_p_buffer = Buffer.from(global_p, 'hex');
const global_g_buffer = Buffer.from(global_g, 'hex');
const clienPublicKeyBuffer = Buffer.from(clientPublicKey, 'hex');
const server = crypto.createDiffieHellman(global_p_buffer, global_g_buffer);
server.generateKeys();
const serverPublicKey = server.getPublicKey();
const serverSecret = server.computeSecret(clienPublicKeyBuffer);
return new Array(serverSecret.toString('hex'), serverPublicKey.toString('hex'));
},
final(serverPublicKey) {
const serverPublicKey_buffer = Buffer.from(serverPublicKey, 'hex');
const clientSecret = diffieHellmanClient.computeSecret(serverPublicKey_buffer);
return clientSecret.toString('hex');
},
};
1 change: 1 addition & 0 deletions public/electronAssets/preload.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron');
const crypto = require('crypto');

const _ipcRenderer = Object.assign(
{
Expand Down
159 changes: 103 additions & 56 deletions src/Components/ChatComponent/ChatRTC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { getDeviceStream, getMainContent } from 'Utils/Global';
import { AUDIO_TYPE, buildPropmt } from 'Utils/Prompt/Prompt';
import { setCallStatus, setNowChattingId, setNowWebrtcFriendId } from 'Utils/Store/actions';
import store from 'Utils/Store/store';
import { eWindow } from 'Utils/Types';
import { setupReceiverTransform, setupSenderTransform } from 'Utils/WebRTC/RtcEncrypt';

interface ChatRtcProps {
Expand All @@ -50,6 +51,7 @@ export class ChatRTC extends EventEmitter {
};
candidateQueue!: Array<any>;
useSecurity: boolean;
security: string;

constructor(props: ChatRtcProps) {
super();
Expand All @@ -61,6 +63,7 @@ export class ChatRTC extends EventEmitter {
this.localStream = null;
this.remoteStream = null;
this.useSecurity = false;
this.security = '';

this.socket.on('ON_PRIVATE_WEBRTC_OFFER', (msg) => {
this.sender = msg.sender;
Expand All @@ -79,13 +82,14 @@ export class ChatRTC extends EventEmitter {
eventBus.emit('GET_PRIVATE_CALLED');
this.answerAudioPrompt[0]();
store.dispatch(setNowChattingId(msg.sender));
const pgArr = JSON.parse(msg.security);
this.answerModal = Modal.confirm({
icon: msg.security ? <AlertOutlined /> : <ExclamationCircleOutlined />,
title: '视频通话邀请',
content: (
<span>
用户 {msg.senderName}(id: {msg.sender})向您发出视频通话请求,是否接受?
{msg.security ? (
{pgArr.length === 3 ? (
<span>
<br />
注意:对方启用了私聊视频会话加密功能,接受此会话可能会导致您的CPU占用被大幅度提高,请与对方确认后选择是否接受此会话
Expand All @@ -108,8 +112,11 @@ export class ChatRTC extends EventEmitter {
</>
),
onOk: () => {
this.useSecurity = msg.security;
this.createAnswer(msg.sender, msg.sdp);
this.useSecurity = pgArr.length === 3;
console.log(pgArr);

if (this.useSecurity) this.createAnswer(msg.sender, msg.sdp, pgArr);
else this.createAnswer(msg.sender, msg.sdp);
},
onCancel: () => {
rejectOffer(PRIVATE_WEBRTC_ANSWER_TYPE.REJECT);
Expand All @@ -124,40 +131,43 @@ export class ChatRTC extends EventEmitter {
} else rejectOffer(PRIVATE_WEBRTC_ANSWER_TYPE.BUSY);
});

this.socket.on('ON_PRIVATE_WEBRTC_ANSWER', ({ accept, sdp, sender, receiver }) => {
if (sender === this.sender && receiver === this.receiver) {
this.callAudioPrompt[1]();
if (this.offerModal) {
this.offerModal.destroy();
this.offerModal = null;
}
if (accept === PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT) {
this.receiveAnswer(sdp);
} else {
switch (accept) {
case PRIVATE_WEBRTC_ANSWER_TYPE.BUSY:
globalMessage.error({
content: '对方正在通话中',
duration: 1.5,
});
break;
case PRIVATE_WEBRTC_ANSWER_TYPE.NO_USER:
globalMessage.error({
content: '呼叫的用户不存在',
duration: 1.5,
});
break;
case PRIVATE_WEBRTC_ANSWER_TYPE.REJECT:
globalMessage.error({
content: '对方拒绝了您的通话邀请',
duration: 1.5,
});
break;
this.socket.on(
'ON_PRIVATE_WEBRTC_ANSWER',
({ accept, sdp, sender, receiver, security }) => {
if (sender === this.sender && receiver === this.receiver) {
this.callAudioPrompt[1]();
if (this.offerModal) {
this.offerModal.destroy();
this.offerModal = null;
}
if (accept === PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT) {
this.receiveAnswer(sdp, security);
} else {
switch (accept) {
case PRIVATE_WEBRTC_ANSWER_TYPE.BUSY:
globalMessage.error({
content: '对方正在通话中',
duration: 1.5,
});
break;
case PRIVATE_WEBRTC_ANSWER_TYPE.NO_USER:
globalMessage.error({
content: '呼叫的用户不存在',
duration: 1.5,
});
break;
case PRIVATE_WEBRTC_ANSWER_TYPE.REJECT:
globalMessage.error({
content: '对方拒绝了您的通话邀请',
duration: 1.5,
});
break;
}
this.onEnded();
}
this.onEnded();
}
}
});
);

this.socket.on('ON_PRIVATE_WEBRTC_CANDIDATE', this.handleCandidate.bind(this));

Expand Down Expand Up @@ -185,16 +195,15 @@ export class ChatRTC extends EventEmitter {
this.peer.addTrack(track, this.localStream);
}

// NOTE: 加密
if (this.useSecurity)
this.peer.getSenders().forEach((sender) => {
setupSenderTransform(sender);
});
else if (senderCodecs)
let pgArr: Array<string> = [];
if (this.useSecurity) {
pgArr = await eWindow.ipc.invoke('DIFFIE_HELLMAN');
} else if (senderCodecs) {
this.peer
.getTransceivers()
.find((t) => t.sender.track?.kind === 'video')
?.setCodecPreferences(senderCodecs);
}

this.peer
.createOffer({
Expand All @@ -209,13 +218,13 @@ export class ChatRTC extends EventEmitter {
sender: this.myId,
senderName: myName,
receiver: targetId,
security: this.useSecurity,
security: JSON.stringify(pgArr),
});
});
this.offerModal = offerModal;
}

async createAnswer(sender: number, remoteSdp: any) {
async createAnswer(sender: number, remoteSdp: any, pgArr?: Array<string>) {
this.peer = this.buildPeer();
store.dispatch(setCallStatus(CALL_STATUS_ANSWERING));
store.dispatch(setNowWebrtcFriendId(sender));
Expand All @@ -242,15 +251,40 @@ export class ChatRTC extends EventEmitter {
}

// NOTE: 加密
if (this.useSecurity)
let privateKey: string, publicKey: string;
if (pgArr) {
const serverArr = await eWindow.ipc.invoke(
'DIFFIE_HELLMAN',
pgArr[0],
pgArr[1],
pgArr[2]
);
privateKey = serverArr[0];
publicKey = serverArr[1];
this.security = privateKey;
this.peer.getSenders().forEach((sender) => {
setupSenderTransform(sender);
setupSenderTransform(sender, privateKey);
});
else if (senderCodecs)

this.remoteStream = new MediaStream();
// NOTE: 解密
if (this.useSecurity) {
this.peer.getReceivers().forEach((receiver) => {
setupReceiverTransform(receiver, privateKey);
this.remoteStream?.addTrack(receiver.track);
});
} else if (receiverCodecs)
this.peer
.getTransceivers()
.find((t) => t.receiver.track.kind === 'video')
?.setCodecPreferences(receiverCodecs);
this.emit('REMOTE_STREAM_READY', this.remoteStream);
} else if (senderCodecs) {
this.peer
.getTransceivers()
.find((t) => t.sender.track?.kind === 'video')
?.setCodecPreferences(senderCodecs);
}

this.peer
.createAnswer({
Expand All @@ -267,12 +301,22 @@ export class ChatRTC extends EventEmitter {
sdp: sdp.sdp,
sender: this.sender,
receiver: this.receiver,
security: this.useSecurity ? publicKey : '',
});
store.dispatch(setCallStatus(CALL_STATUS_CALLING));
});
}

receiveAnswer(remoteSdp: any) {
async receiveAnswer(remoteSdp: any, publicKey: string) {
// NOTE: 加密
if (this.useSecurity) {
const privateKey = await eWindow.ipc.invoke('DIFFIE_HELLMAN', publicKey);
this.security = privateKey;
this.peer.getSenders().forEach((sender) => {
setupSenderTransform(sender, privateKey);
});
}

this.peer.setRemoteDescription(
new RTCSessionDescription({
sdp: remoteSdp,
Expand Down Expand Up @@ -347,17 +391,19 @@ export class ChatRTC extends EventEmitter {
}
};
peer.ontrack = (evt) => {
// NOTE: 解密
if (this.useSecurity) setupReceiverTransform(evt.receiver);
else if (receiverCodecs)
peer.getTransceivers()
.find((t) => t.receiver.track.kind === 'video')
?.setCodecPreferences(receiverCodecs);
if (this.myId === this.sender) {
// NOTE: 解密
if (this.useSecurity) setupReceiverTransform(evt.receiver, this.security);
else if (receiverCodecs)
peer.getTransceivers()
.find((t) => t.receiver.track.kind === 'video')
?.setCodecPreferences(receiverCodecs);

this.remoteStream = this.remoteStream || new MediaStream();
this.remoteStream.addTrack(evt.track);
if (this.remoteStream.getTracks().length === 2)
this.emit('REMOTE_STREAM_READY', this.remoteStream);
this.remoteStream = this.remoteStream || new MediaStream();
this.remoteStream.addTrack(evt.track);
if (this.remoteStream.getTracks().length === 2)
this.emit('REMOTE_STREAM_READY', this.remoteStream);
}
};

// NOTE: 断连检测
Expand All @@ -381,6 +427,7 @@ export class ChatRTC extends EventEmitter {
this.sender = undefined;
this.receiver = undefined;
this.useSecurity = false;
this.security = '';
store.dispatch(setNowWebrtcFriendId(null));
this.localStream = null;
this.remoteStream = null;
Expand Down

0 comments on commit b3f0387

Please sign in to comment.