=======================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");
}
}