- 实验设计要求:
模块:
- 用户认证:数字签名方案
- 信息加密:公钥加密方案
- 信息隐藏: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();