=======================KDC.java,KDC密钥分配中心=======================
package first;
import java.awt.BorderLayout;
import java.awt.Container;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Random;
import javax.crypto.SecretKey;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* 密钥分配中心
*/
public class KDC extends JFrame{
private static final long serialVersionUID = 1L;
ServerSocket socket;
Socket connect;
ObjectInputStream in;
ObjectOutputStream out;
//保存用户与KDC共享的密钥
private HashMap<String,SecretKey> keys = new HashMap<String,SecretKey>();
private JTextArea textArea = new JTextArea();
public KDC() throws Exception{
super("密钥分配中心");
Container cp = this.getContentPane();
cp.add(new JScrollPane(textArea),BorderLayout.CENTER);
this.setSize(300,300);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
socket = new ServerSocket(10000,5);//KDC的Socket初始化,采用端口10000
Thread t = new Thread(new KDCThread());
t.start();//启动线程,接收用户的请求
}
//处理用户的请求
private void dealRequest(String data) throws Exception{
String[] msg = data.split(",");
textArea.append(msg[0]+" 请求与 "+msg[1]+" 通信/n本次业务标识符: "+msg[2]+" /n/n");
sendMsg(msg[0],msg[1],msg[2]);
}
/**
* KDC接收到用户的会话密钥请求后,应答对方
*
* @param ida
* 会话请求方ID
* @param idb
* 被请求会话方ID
* @param random
* 业务标识符
* @throws Exception
*/
private void sendMsg(String ida,String idb,String N1) throws Exception{
String ks = random();//产生一个随机数用于生成密钥
String strMsgToIda = ks+"/"+ida+"/"+idb+"/"+N1;//发送给会话请求方A的信息(未加密)
String strMsgToIdb = ks+","+ida;//发送给会话接收方B的信息(未加密)
byte[] byteMsgToIda = Provider.encrypt(keys.get(ida),strMsgToIda.getBytes());//发送给会话请求方A的信息(已加密)
byte[] byteMsgToIdb1 = Provider.encrypt(keys.get(idb),strMsgToIdb.getBytes());//发送给会话接收方B的信息(用B密钥加密,但未用A密钥加密)
byte[] byteMsgToIdb = Provider.encrypt(keys.get(ida),byteMsgToIdb1);//发送给会话接收方B的信息(已用A的密钥加密)
send(byteMsgToIda);
send(byteMsgToIdb);
connect.close();//关闭连接
}
public void addClient(String id,SecretKey SecretKey){
keys.put(id, SecretKey);
}
public void send(byte[] data) throws Exception{
int num = data.length;
out.writeInt(num);//发送字节数
out.flush();
out.write(data);//发送数据
out.flush();
}
private String random(){
Random r = new Random();
String id = Math.abs(r.nextInt()%10000)+"";
return id;
}
//用于接收用户请求的线程
private class KDCThread implements Runnable{
public void run() {
while(true){
try {
connect = socket.accept();//循环等待用户请求
out = new ObjectOutputStream(connect.getOutputStream());
in = new ObjectInputStream(connect.getInputStream());
//处理接收到的用户请求
dealRequest(in.readUTF());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
==================Provider.java,加密解密算法实现工具类=====================
package first;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class Provider {
/**
* 加密数据
*
* @param key
* @param data
* @return
* @throws Exception
*/
public static byte[] encrypt(SecretKey key,byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance("DES", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* 解密
*
* @param key
* 解密密钥
* @param data
* 待解密数据
* @return
* @throws Exception
*/
public static byte[] decrypt(SecretKey key,byte[] raw) throws Exception{
Cipher cipher = Cipher.getInstance("DES", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(raw);
}
/**
* 生成密钥
*
* @return
* 密钥
*/
public static Key generateKey(String str){
try {
KeyGenerator kg = KeyGenerator.getInstance("DES");
SecureRandom sr = new SecureRandom(str.getBytes());//随机数源
kg.init(sr);//初始化
Key key = kg.generateKey();//生成密钥
return key;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
*
* @param key
* @return
* @throws Exception
*/
public static SecretKey generateSecretKey(byte[] key) throws Exception{
SecretKeyFactory fac = null;
//创建一个密钥工厂
fac = SecretKeyFactory.getInstance("DES");
DESKeySpec spec = new DESKeySpec(key);//从原始密匙数据创建一个DESKeySpec对象
return fac.generateSecret(spec);
}
/**
* 转换16进制
*
* @param data
* @return
*/
public static byte[] getHexString(byte[] data){
String s = new String();
for(int i=0;i<data.length;i++){
s += Integer.toHexString(data[i]& 0xFF);
}
return s.getBytes();
}
}
=====================User.java,用户类=====================
package first;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import javax.crypto.SecretKey;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class User extends JFrame{
private static final long serialVersionUID = 1L;
private String id;//用户标识ID
private ServerSocket socket;
private Socket connect;
private ObjectInputStream in;
private ObjectOutputStream out;
private SecretKey key;//用户与KDC共享的密钥
private JTextArea textArea = new JTextArea();
private JButton btn = new JButton("发送");
private JTextField tf = new JTextField(5);
//构造函数
public User(KDC kdc,String id) throws Exception{
super("用户:"+id);
this.id = id;
socket = new ServerSocket(Integer.parseInt(id),5);
key = Provider.generateSecretKey(Provider.generateKey("hello").getEncoded());
kdc.addClient(id, key);//用户注册与KDC共享的密钥
Thread thread = new Thread(new Communicate());
thread.start();//启动线程,接收其他用户的通信请求
init();
}
/**
* 向KDC发出会话密钥请求
*
* @param idb
* 用户ID
* @throws Exception
*/
public void request(String msg,String idb) throws Exception{
//连接KDC
connect(10000);
//向KDC发送请求信息
String N1 = random();
String dialogRequest = id+","+idb+","+N1;//请求会话方发送给KDC的信息: IDa//IDb//N1
out.writeUTF(dialogRequest);
out.flush();
byte[] dataToA = receive();//接收KDC的应答
byte[] dataToB = receive();//接收KDC的应答
//解密
dataToA = Provider.decrypt(key,dataToA);//KDC给A应答的信息
dataToB = Provider.decrypt(key,dataToB);//KDC通过A转发给B的信息
String[] msgToA = new String(dataToA).split("/");
if(!msgToA[3].equals(N1)){//验证收到的N1是否相等
JOptionPane.showMessageDialog(this, "N1在传输过程中被修改,通信结束");
return;
}
//处理KDC的应答
dealWithResponse(msgToA,dataToB,msg);
}
/**
* 接受会话请求
* @param msg
* KDC转发的信息
* @throws Exception
*/
public void accept(byte[] msg) throws Exception{
byte[] data = Provider.decrypt(key,msg);//使用用户与KDC共享的密钥解密
String[] str = new String(data).split(",");
//生成会话密钥Ks
SecretKey ks = Provider.generateSecretKey(Provider.generateKey(str[0]).getEncoded());
//发送:EKs[N2]
String N2 = random()+"";
byte[] BToA = Provider.encrypt(ks,N2.getBytes());//加密N2
send(BToA);//发送N2
//接收EKs[f(N2)]
byte[] receiveFN2 = receive();
receiveFN2 = Provider.decrypt(ks,receiveFN2);
//判断接收到的f[N2]是否与原来的N2相等
if(new String(receiveFN2).equals(fn2(N2))){
String result = new String(receive());//相等则接收数据,否则不接收数据
textArea.setText(result.trim());
}
else
JOptionPane.showMessageDialog(null, "信息出错,"+id+"拒绝接收数据:");
}
//处理KDC的应答
private void dealWithResponse(String[] msgToA,byte[] dataToB,String msg) throws Exception{
//连接B
connect(Integer.parseInt(msgToA[2]));
//A转发KDC发送给B的信息
send(dataToB);
//A接收N2
byte[] receiveN2 = receive();
SecretKey ks = Provider.generateSecretKey(Provider.generateKey(msgToA[0]).getEncoded());//生成会话密钥Ks
receiveN2 = Provider.decrypt(ks,receiveN2);//用会话密钥Ks解密N2
//A发送:EKs[f(N2)]
String FN2 = fn2(new String(receiveN2));
byte[] sendFN2 = Provider.encrypt(ks,FN2.getBytes());//用会话密钥加密
send(sendFN2);
//A发送要传送的数据
byte[] data = msg.getBytes();
send(data);
//通信完成,关闭连接
connect.close();
}
//发送数据
public void send(byte[] data) throws Exception{
int num = data.length;
out.writeInt(num);//发送字节数
out.flush();
out.write(data);//发送数据
out.flush();
}
//连接通信方
private void connect(int port)throws Exception{
if(connect != null && connect.isConnected())
connect.close();
connect = new Socket(InetAddress.getByName("localhost"),port);
out = new ObjectOutputStream(connect.getOutputStream());
in = new ObjectInputStream(connect.getInputStream());
}
//接收数据
public byte[] receive(){
int num;
try {
num = in.readInt();
byte[] data = new byte[num];
in.read(data);
return data;
} catch (IOException e) {
return null;
}
}
private String fn2(String n2){
Integer i = Integer.parseInt(n2);
return i+1+"";
}
private String random(){
Random r = new Random();
String id = Math.abs(r.nextInt()%10000)+"";
return id;
}
//初始化界面
private void init(){
Container cp = getContentPane();
cp.add(new JScrollPane(textArea),BorderLayout.CENTER);
cp.add(btn,BorderLayout.SOUTH);
cp.add(tf,BorderLayout.NORTH);
textArea.setLineWrap(true);
tf.setText(id.equals("30000")?"20000":"30000");
this.setSize(300,400);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
try {
Thread t = new Thread(new SendThread(textArea.getText(),tf.getText().trim()));
t.start();//启动发送数据的线程
} catch (Exception e) {
}
}
}
);
}
/**
* 内隐类,线程,用于接收其他用户的通信请求
*
*/
private class Communicate implements Runnable{
public void run() {
while(true){
byte[] data;
try {
connect = socket.accept();
out = new ObjectOutputStream(connect.getOutputStream());
in = new ObjectInputStream(connect.getInputStream());
data = receive();
accept(data);//处理接收到的消息
Thread.sleep(300);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 发送数据的线程
*/
private class SendThread implements Runnable{
private String msg;
private String id;
public SendThread(String msg,String id){
this.msg = msg;
this.id = id;
}
public void run() {
try {
request(msg,id);
} catch (Exception e) {
//e.printStackTrace();
JOptionPane.showMessageDialog(null, "通信出错");
System.exit(0);
}
}
}
}
=======================test.java,测试类==============================
package first;
import java.io.IOException;
public class Test {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
KDC kdc = new KDC();
new User(kdc,"20000");
new User(kdc,"30000");
}
}