山东大学软件学院项目实训-创新实训-SDUMeeting(八)

山东大学软件学院项目实训-创新实训-SDUMeeting(八)

n方diffie-hellman密钥交换

import { ChannelType, MessageKind } from "@/common/constants";
import { ISignedPbk, IRoomUser, IUpdateMessage } from "@/common/interface";
import Long from "long";
import { setImmediatelyInterval, UidList } from "@/common/util";
import {
  generateG,
  generatePrime,
  generatePrivateKey,
  quickMod,
} from "@/lib/diffie-hellman/diffie-hellman";
import { RpcEventDispatcher } from "@/lib/stream/rpc";
import * as proto from "@/proto";
import electron from "electron";

首先是状态维护,维护自身加入退出会议的状态。通过心跳检测被其他的用户知道自己的状态

export default class PeerRpcDispatcher extends RpcEventDispatcher {
private uidList: UidList;
static NEGOTIATE_PBK_TIMEOUT = 3000; // 3000ms
private negotiateTimer: any;
private heartbeatTimer: any;
constructor(webContents, ipcMain: Electron.IpcMain = electron.ipcMain) {
  super(webContents, ipcMain);
  this.uidList = new UidList(this.uid, 1000);
  this.pbkInfo = null;
  this.uidList.emitter.on(UidList.EVENT_UID_OUTDATE, (uid) => {
    this.log(`${uid}退出了会议`);
  });
  this.uidList.emitter.on(UidList.EVENT_UID_NEW, (uid) => {
    this.log(`${uid}加入了会议`);
  });
  this.negotiateTimer = null;
  this.heartbeatTimer = null;
}

流加密函数

//流加密函数
encodeRpcUpdateMessageChunk(kind: MessageKind, ...args: any): Buffer {
  if (kind === MessageKind.BROADCAST_TEXT) {
    return this.encodeProto(proto.ChatText, args[0]);
  }
  if (kind === MessageKind.SIGN_PBK) {
    return this.encodeProto(proto.SignedPbk, args[0]);
  }
  return Buffer.from(args[0]);
}

流解密函数

 //流解密函数
 decodeRpcUpdateMessageChunk(kind: MessageKind, chunk: Buffer): any {
   if (kind === MessageKind.BROADCAST_TEXT) {
     return this.decodeProto(proto.ChatText, chunk);
   }
   if (kind === MessageKind.SIGN_PBK) {
     return this.decodeProto(proto.SignedPbk, chunk);
   }
   return Buffer.from(chunk).toString("utf8");
 }

接入会议,进行密钥协商

 onDispatchCall(kind: MessageKind, chunk: Buffer): [MessageKind, ...any[]] {
   switch (kind) {
     case MessageKind.DEMAND_STATUS_PBK:
       this.startNegotiatePbk();
       this.dispatchRsp(MessageKind.DEMAND_STATUS_PBK);
       break;
   }
   return [kind, chunk];
 }
 onDispatchRsp(
   kind: MessageKind,
   src: string,
   chunk: any
 ): [MessageKind, ...any[]] {
   switch (kind) {
     case MessageKind.BROADCAST_LOG:
       this.log(Buffer.from(chunk).toString("utf8"));
       break;
     case MessageKind.BROADCAST_HEARTBEAT:
       this.uidList.update(chunk);
       this.updateRenderUids();
       break;
     case MessageKind.DEMAND_STATUS_PBK:
       this.startNegotiatePbk();
       break;
     case MessageKind.SIGN_PBK:
       const signedPbk: ISignedPbk = chunk;
       if (src === this.uidList.leftPeer) {
         this.negotiatePbk(
           this.uidList.uids,
           Long.fromBytes(Array.from(Uint8Array.from(signedPbk.pbk)), false),
           signedPbk.uids
         );
       }
       break;
   }
   return [kind, chunk];
 }
 updateRenderUids() {
   this.sendToIpcRender(ChannelType.UPDATE_UIDS, this.uidList.uids);
 }

开始密钥协商,首先更新自己的私钥,调用密钥协商函数,判断协商状态。

  startNegotiatePbk() {
    this.updatePrivateKey();//首先更新自己的私钥
    process.nextTick(() => {
      this.pbkInfo = null;
      this.negotiatePbk(this.uidList.uids);//调用密钥协商函数
      if (this.negotiateTimer !== null) {//判断协商状态
        clearTimeout(this.negotiateTimer);
      }
      this.negotiateTimer = setTimeout(() => {
        if (this.pbkInfo === null) {
          this.log(
            `协商密钥超时(${PeerRpcDispatcher.NEGOTIATE_PBK_TIMEOUT}ms),请重试!!!`
          );
          this.dispatchCall(MessageKind.DEMAND_STATUS_CHAT);
        }
        this.negotiateTimer = null;
      }, PeerRpcDispatcher.NEGOTIATE_PBK_TIMEOUT);
    });
  }

协商过程,假设一共有n方,则协商轮数是n-1,利用心跳检测中得到的在线用户数n,循环m-1次,每次交换receive_data^private_key mod p 即quickMod(currentPbk, this.privateKey, generatePrime());

  negotiatePbk(//协商过程,假设一共有n方,则协商轮数是n-1,利用心跳检测中得到的在线用户数n,循环m-1次,每次交换receive_data^private_key mod p 即quickMod(currentPbk, this.privateKey, generatePrime());
    uids: string[],
    currentPbk: Long = generateG(),
    currentUids: string[] = []
  ) {
    if (currentPbk && !currentUids.includes(this.uid)) {
      currentPbk = quickMod(currentPbk, this.privateKey, generatePrime());
      currentUids.push(this.uid);
      this.log(
        `密钥协商${currentUids.length}/${uids.length}, PBK ${currentPbk}`
      );
      const pbkInfo: ISignedPbk = {
        pbk: Buffer.from(currentPbk.toBytes()),
        uids: currentUids,
      };
      if (currentUids.length < uids.length) {
        this.dispatchCall(MessageKind.SIGN_PBK, pbkInfo);
      } else {
        this.pbkInfo = pbkInfo;
        this.sendToIpcRender(
          ChannelType.UPDATE_PBK,
          Buffer.from(currentPbk.toBytes()).toString("base64")
        );
        this.log(`密钥协商结束, 请使用密钥${currentPbk}加密聊天`);
        this.dispatchCall(MessageKind.DEMAND_STATUS_CHAT);
        clearTimeout(this.negotiateTimer);
        this.negotiateTimer = null;
      }
    }
  }
  updatePrivateKey() {
    this.privateKey = generatePrivateKey();
    this.log(`请勿泄露!!!私钥为${this.privateKey}`);
  }

这里调用心跳检测,用于检测用户是否在线,并且维护一个在线用户队列

  startHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
    }
    this.heartbeatTimer = setImmediatelyInterval(() => {
      this.dispatchCall(MessageKind.BROADCAST_HEARTBEAT, this.uid);
    }, 500);
    this.sendToIpcRender(ChannelType.UPDATE_UIDS, []);
  }
  stopHeartbeat() {
    clearInterval(this.heartbeatTimer);
    this.heartbeatTimer = null;
    this.sendToIpcRender(ChannelType.UPDATE_UIDS, []);
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值