密码学课程设计——多人加密聊天系统

  • 实验设计要求:

模块:

  1. 用户认证:数字签名方案
  2. 信息加密:公钥加密方案
  3. 信息隐藏:LSB方案

要求:

实现登陆验证,信息发送和接收(文本和图片),信息加密解密,信息签名和签名验证

 

  • 关键代码解释说明:

1.数字签名:使用java security包中的keypairgenerator 生成rsa秘钥对,长度为512:

2.获取秘钥对中的publicexponent,modulus,privateexponent:

3.加密代码:

其中,输入要加密的信息后,转成byte[],通过取模运算,产生加密信息,转成字节。

4.解密代码:

同解密过程一样。

5.数字签名验证:

通过登录用户输入的姓名,在数据库中查找到对应的e和n(即公钥),通过用户输入的私钥d,对“yaxin”用私钥加密后,服务端用公钥进行解密,内容为yaxin即为验证成功。

6.数据库查找代码:

Resultset集存储客户的e,n,d 返回arraylist可供查找。

8.客户注册代码:

若客户为新注册用户,选择注册按钮,生成新的秘钥对,用户自行保留私钥d,新生成的用户信息将被存储在数据库chatroom1中:

7.客户登陆代码:

客户需要输入昵称和私钥d进行数字签名登陆验证。

8.客户私聊消息加密:通过被传输消息的客户在数据库系统中存储的公钥,传输消息方将数据进行加密,被传输消息方先将数据解密,在显示出来,客户端只会看到解密的消息,非被传输方会看到加密后的信息,但是无法解出。

三、代码展示:

Server类:
package MyChatRoom;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.ihep.Mysqllink;
import com.ihep.RSADemo;


public class Server {
	
	private ServerSocket sc;
	private ExecutorService threadpool;
	private List<PrintWriter> pws;
	private Map<String,PrintWriter> maps;
	
	
	public Server() {
		try {
			sc= new ServerSocket(8088);
		} catch (IOException e) {
			e.printStackTrace();
		}
		threadpool 
		   = Executors.newFixedThreadPool(100);
		pws = new ArrayList<PrintWriter>();
		maps = new HashMap<String,PrintWriter>();
		RSADemo rsa=new RSADemo();	
			Mysqllink msq=new Mysqllink();
			//msq.Mysqllinkstart();
	}
	
	public void start() {
		int count = 0;
		while(true) {
			
			System.out.println("wait..");
			try {
				Socket s= sc.accept();
				ClientHandle hc 
				  = new ClientHandle(s);
				threadpool.execute(hc);
				
			} catch (IOException e) {
				e.printStackTrace();
			}
			count++;
			System.out.println
			   ("第"+count+"个客户连接成功!");
		}
	}
	//自定义方法
	//遍历map集合,将所有在线的好友name拼接成字符串,
	//并返回
	public String findAll(){
		synchronized (maps) {
		//1.遍历map集合,拿到所有在线人的name
			Set<String> names = maps.keySet();
		//2. 遍历set集合,拿到所有人的name
			String nms="";
			Iterator<String> it =  names.iterator();
			while(it.hasNext()){
				String nm = it.next();
				nms +=nm;//重新赋值 拼接每一个在线好友的name
				nms +=",";
			}
		
			return nms;
		}
	}

	//创建ClientHandle类(助教模板类)
	class  ClientHandle implements Runnable{
		Socket s;
		PrintWriter pw;
		String name;
		public ClientHandle(Socket s) {
			this.s=s;
		
			
		}
		public void run() {
			//获取该客户端的输入流,读取该客户端的消息
			try {
				InputStream is 
				  = s.getInputStream();
				InputStreamReader isr 
				 = new InputStreamReader(is);
				BufferedReader br 
				  = new BufferedReader(isr);
				//从socket中获取该客户端的输出流
				OutputStream os = s.getOutputStream();
				OutputStreamWriter osw
					= new OutputStreamWriter(os);
				pw
				  = new PrintWriter(osw,true);
								//在读消息之前,先读客户端发来的 昵称
				name = br.readLine();
				
				//将name和name对应的pw存入map集合中
				synchronized (maps) {
					maps.put(name,pw);
				}		
				pw.println("欢迎你,"
				    +name+",当前在线人数【"+(pws.size()+1)+"】人!");
				//服务器告诉刚上线的客户端都有哪些人在线
				String nms = findAll();
				//至此,所有在线的name都在nms字符串中
				pw.println("当前在线好友:"+nms);
				sendToAll(name+
						"上线了!当前在线人数【"
						+(pws.size()+1)+"】人!");
				
				sendToAll("当前在线好友:"+nms);
				
				//将该客户端的输出流加入到集合中存储起来
				synchronized (pws) {
					pws.add(pw);
				}
				
		SimpleDateFormat sdf 
			 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			Date d = null;
			while(true) {
					String str = br.readLine();//阻塞
					d = new Date(); //当前时间
					String time = sdf.format(d);
					
					System.out.println(name+":"+str);//输出在控制台
					if(str.startsWith("@")){
						//单聊
						//1. 解析出要单聊的name,也就是截取@和:之间的name
						String to_name = str.substring(1, str.indexOf(":"));
						//2. 根据第一步解析出的人名从map中获取到
						//   该人名所对应的pw
						
						PrintWriter to_pw = maps.get(to_name);
						//3. 解析出单聊的消息,也就是截取:之后的内容
						
						String msg = str.substring(str.indexOf(":")+1);
						
					    Mysqllink msq=new Mysqllink();
						ArrayList<String> list=msq.selectsj(to_name);
						//System.out.println(list.get(0).toString()+'\n'+list.get(1).toString()+'\n'+list.get(2).toString());
					   
						RSADemo rsa=new RSADemo();
						
						byte[] mesag=rsa.encrypt((msg.trim()).getBytes(), list.get(0).toString(), list.get(1).toString());
						
						System.out.println("加密过后的消息:"+mesag);
						
						byte[] msg_afterde=rsa.decrypt(mesag, list.get(2).toString(), list.get(1).toString());
						
						String msg_afterde1=new String(msg_afterde);
						
						System.out.println("解密后的消息"+msg_afterde1);						
						//4. 使用第2步获得的pw将第3步解析出的msg进行发送
						to_pw.println(time+"\n"+name+"悄悄对你说:"+msg_afterde1);
						//5. 消息也要返回给自己,不仅是给要单聊的那个人
						pw.println(time+"\n"+"我对"+to_name+"悄悄说:"+msg_afterde1);
						sendToAll(time+"\n"+name+":"+mesag.toString());
					}else{
						
						
						//群发
						sendToAll(time+"\n"+name+":"+str);
					}
				}
			}catch(Exception e) {
				//追踪一异常信息
				//e.printStackTrace();
  • 3
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值