# Secure-Communicate **Repository Path**: wenzhao299/Secure-Communicate ## Basic Information - **Project Name**: Secure-Communicate - **Description**: 基于互联网的多对多网络即时通讯工具,实现登录、注册、消息加解密、密钥保护与签名认证。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2021-09-11 - **Last Updated**: 2023-06-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Secure Communicate ## 一、项目介绍 基于互联网的多对多网络即时通讯工具,实现登录、注册、消息加解密、密钥保护与签名认证。 ## 二、开发环境与工具 1、开发环境:Windows10,Java15,MySQL 5.7,phpMyAdmin 5.6.6 2、开发工具:IntelliJ IDEA 2020.3 ## 三、设计原理 1、Socket是什么 套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上的进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口。 2、Socket如何进行通信 要通过互联网进行通信,至少需要一对套接字,其中一个运行于客户端,我们称之为 Client Socket,另一个运行于服务器端,我们称之为 Server Socket 。 根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤: (1)服务器监听 服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。 (2)客户端请求 由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端接字提出连接请求。 (3)连接确认 当服务器端套接字监听到或者说接收到客户端套接字的连接请求,就会响应客户端套接字的请求,建立一个新的线程,并把服务器端套接字的描述发送给客户端。一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,接收其他客户端套接字的连接请求。 图1 Socket运行图 3、Socket的类型 (1)流套接字(SOCK_STREAM) 流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。 (2)数据报套接字(SOCK_DGRAM) 数据报套接字提供一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP( User DatagramProtocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。 (3)原始套接字(SOCK_RAW) 原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接。 ## 四、系统功能描述及软件模块划分 1、系统功能 (1)基于互联网的多对多即时通讯; (2)提供登录、注册功能; (3)提供消息的加解密、密钥保护与签名认证。 2、模块划分 (1)Login:实现登录、注册功能; (2)Server:服务器界面,提供收发消息功能; (3)Client:客户端界面,提供收发消息功能; (4)AESUtil:提供AES加解密功能; (5)DESUtil:提供DES加解密功能; (6)ThreeDESUtil:提供3DES加解密功能; (7)RSAUtil:提供加解密的密钥保护与签名认证功能。 ## 五、设计步骤 1、Login 2、Server (1)开启监听,等待客户端连接 (2)发送信息 (3)转发客户端消息 (4)接收消息 3、Client 代码部分与Server端大同小异,故不再赘述。 4、通信双方的消息由四部分组成 (1)接收方端口号; (2)发送方使用私钥对明文信息摘要的签名,长度172位Base64编码; (3)对消息加密后的密文,长度根据发送消息长短变化的Base64编码; (4)使用接收方公钥对密钥种子加密后的密文,长度172位Base64编码。 图5 消息组成示例 5、消息发送过程 (1)输入接收方端口号toPort; (2)输入需要发送的消息say,随机生成长度位n位的十六进制数作为密钥种子randomkey(DES与AES,n=16;3DES,n=48),并使用密钥种子生成密钥,使用密钥对say加密得到密文encryptData; (3)发送端使用自己的RSA私钥对消息摘签名得到Signature; (4)发送端使用接收端的公钥对randomkey加密得到PubKeyEncrypt; (5)将toPort、Signature、encryptData、PubKeyEncrypt四者连接,组成一次通信所传输的信息,发送完成。 6、消息接收过程 (1)服务器收到消息,截取信息头部的端口号,若为server_port,则表明此信息由服务器接收;若不为server_port,则表明此信息由服务器转发。 (1)截取消息最后172位PubKeyEncrypt,使用自己的私钥进行解密得到密钥种子randomkey,以此生成密钥; (2)截取前后去除了172位的信息encryptData,使用刚生成的密钥解密得到明文decryptData; (3)截取消息前172位Signature,使用发送端的公钥解密,解密成功得以认证是发送端发送的消息,并得到消息摘要,将此摘要与解密得到的消息形成的摘要对比,对比无误,说明消息没有被篡改,接收完成。 图6 整体框架图 7、数据库 将MySQL 5.7搭建在阿里云应用服务器上,并配置phpMyAdmin 5.6.6使用图形化界面。创建名为LAN的数据库,内含两个表:ServerUser和ClientUser,分别存储服务器与客户端的用户名与密码,均为VARCHAR(8)格式,其中用户名为主键,以确保唯一性。 图7 ServerUser表 图8 ClientUser表 ## 六、关键问题及其解决方法 关键问题:如何让服务器与客户端、客户端与客户端之间进行多对多通信。 解决方法: (1)服务器与客户端之间多对多通信 服务器端使用套接字组,一组套接字对应一个客户端,服务器与多个客户端之间的通信建立在独立的套接字上。 ```java Socket[] socket_server = new Socket[10]; ServerSocket[] server = new ServerSocket[10]; ``` (2)客户端与客户端之间多对多通信 服务器端维护一个port\_map,将各个客户端的端口信息存储维护,当客户端与客户端之间进行通信时,只需选择想要通信的客户端的端口号,即可通过服务器转发,实现客户端与客户端之间的多对多通信。 ## 七、设计结果 1、登录注册界面 图9 登录注册界面 输入用户名和密码后,可选择:登录服务器、登录客户端、注册客户端。 登录时,若输入用户名和密码与数据库不匹配,则提示登录失败,如图10: 图10 登录失败 注册时,若输入的用户名已存在于数据库,则提示用户名已存在,如图11: 图11 用户名已存在 注册时,若注册用户名未存在于数据库,则提示注册成功,如图12: 图12 注册成功 2、运行界面 成功登录后,界面如图13(以一个服务器、一个客户端为例): 图13 运行界面 服务器端输入端口号并开启监听,各个客户端输入服务器监听的端口号与服务器IP地址进行连接,连接后如图14(以服务器和1号客户端为例): 图14 连接成功 3、服务器与客户端之间通信,通信双方选择对方的端口号后,即可进行通信(服务器端口号默认为0),如图15(以服务器和1号客户端为例): 图15 服务器与1号客户端通信 4、客户端与客户端之间通信,通信双方选择对方的端口号后,即可进行通信,如图16(以2号客户端和3号客户端为例): 图16 2号客户端与3号客户端通信 此时服务器会显示转发内容,如图17最下方两行: 图17 服务器转发 5、系统运行过程中,所有加解密、签名认证过程都在后台运行,如图18: 图18 后台运行过程 6、设计思考题的分析和解答: 1、上述设计的内容,在支持一对一的客户端与服务器双向通信的同时,能否支持多个客户端同时与服务器通信?若不能,如何改造程序结构,使其支持这种模式? 答:可以支持多个客户端同时与服务器进行通信。除此之外,还能够实现客户端与客户端之间的通信。 2、上述客户端、服务器端成对使用,它们发送的信息、接收的信息应整合在一个程序中实现,以增加适用性。 答:通过IDEA将程序打包成jar包,然后通过exe4j将jar包、外部引用包以及jre环境打包成exe,即使在没有安装Java环境的机器上也能正常运行。 ## 八、软件使用说明 1、登录注册 输入正确的用户名和密码后,点击登录服务器、登录客户端,或进行客户端注册,注册成功后再进行登录。注意:服务器只能登录一次,客户端上限为十个。 2、服务器监听与客户端连接 服务器输入需要绑定监听的端口号,点击开始,进行监听; 客户端输入需要连接的端口号与服务器的IP地址,连接到服务器。 3、多对多通信 通信双方输入对方的端口号后,在消息框内输入要发送的消息,点击发送即可进行通信。 ## 九、参考资料 [1] 高传善等. 计算机网络教程. 高等教育出版社,2013. [2] 谢希仁. 计算机网络. 电子工业出版社,2017. ## 十、设计体会 完成项目的过程是艰难的,编程过程中我遇到了很多问题。 第一个问题就是mysql-connector-java.jar和bcprov-jdk12-166.jar第三方包的导入,一开始我直接导入到模块路径下了,运行总是报错,在网上找了很多方法,有的帖子说要放到jre目录下,然后我发现jdk12版本没有jre文件夹,折腾了好久,最后才发现是IDEA导入时没有放到类路径下。 第二个问题是实现多对多通信,这里困扰了我很久,最终选择使用套接字组来进行客户端区分,不同的客户端与服务器使用不同的端口进行通信,以此进行区分,实现多对多的通信。另外,通过代码与数据库连接的时候,总是报错,通过网络查询后的方法也都没有奏效。最终,我新建了一个数据库用户,才能够成功连接到数据库,在代码里使用root用户却无法连接到数据库,我想这应该是数据库的权限保护机制吧。 另外就是java.security.spec无法使用,搜索报错原因,发现是编译器一致性级别不适用,将级别从11改为1.8后才能够运行。 还有一个比较头疼的问题是RSA产生公钥和私钥的部分,我为密钥产生函数加了一个种子,种子以Server和Client命名,目的是取得两者的公钥和私钥,但是在服务器、客户机两端界面获取密钥的时候,两者获得的对方的公钥与自己的私钥不是同一个密钥对,导致接收端解密不成功,这里也困扰我很久,最后我把两者获得的密钥全部打印出来比较,才发现密钥对不匹配,修改后成功运行。 最后在打包成可执行文件的时候,也遇到了困难。因为我的程序使用了外部jar包,在使用exe4j打包成exe文件后,会报jar包签名错误,经过查询大量资料后,我选择在打包成jar时,不将外部jar包一起打包,而是在exe4j内打包,终于解决了问题。还有一些小问题就不一一列举了,最终我通过自己的努力完成了作品,还是很有成就感的。 谈到展望,目前系统只实现了服务器和客户机多对多的文字通信,后续尝试增加文件传输的功能。另外,如果有可能,我想实现一个简单的通讯软件,类似QQ或者微信,正好我还有个阿里云的服务器,借此机会尝试一下,多接触一些新东西。只有自己动手的时候,才知道自己有哪些知识掌握得并不牢固,才能有针对性地进行学习。