?? ssl_with_signature.java
字號:
/****************************************************************
* 軟件:Java簽名協議擴展 (Java Signature Protocol Extension, JSPE)
* 版本:V1.0
* 軟件功能:實現SSL簽名協議
* 模塊: 私有類ProtocolVersion
* 私有類SSLSignatureType
* 私有類Signature_Alert_type
* 公共類SSL_with_signature
* 私有類SSLsignature_reply
*-----------------------------------------------------------------
* 版權所有:中山大學軟件研究所 2002
* Programmed by 佛山張峰嶺 fszfl@21cn.com
* 2002.4 - 2002.5
*****************************************************************/
package com.zsusoft.zfl;
import java.util.*;
import java.security.*;
import java.security.KeyStore;
import java.net.*;
import javax.net.*;
import javax.net.ssl.*;
//import com.sun.net.ssl.*;
import java.io.*;
import java.lang.*;
/**
* SSL_with_signature類的私有類,定義SSL簽名協議版本號。
**/
class ProtocolVersion{
/**
* 主版本號
**/
public static final byte major=1;
/**
* 次版本號
**/
public static final byte minor=0;
}
/**
* SSL_with_signature類的私有類,定義SSL簽名協議中的消息類型。
**/
class SSLSignatureType{
/**
* 簽名請求
**/
public static final byte signature_request=1;
/**
* 簽名響應
**/
public static final byte signature_reply=2;
/**
* 簽名警告
**/
public static final byte signature_alert=3;
}
/**
* SSL_with_signature類的私有類,定義SSL簽名協議中的警告類型。
**/
class Signature_Alert_type{
/**
* 簽名值無法通過校驗,可能是非法或損壞的簽名值
**/
public static final byte Illegal_Signature=1;
/**
* 簽名響應方拒絕簽名
**/
public static final byte Reject_To_Signature=2;
/**
* 非法隨機數
**/
public static final byte Illegal_random=3;
/**
* 沒有簽名能力,簽名響應方可能沒有具備簽名能力的私人數字證書
**/
public static final byte No_signature_ability=4;
/**
* 系統內部故障
**/
public static final byte System_interal_error=5;
/**
* 用戶自定義的警告類型
**/
public static final byte User_define_alert=6;
/**
* 消息格式錯誤
**/
public static final byte Format_error=7;
}
/**********
* 使用用戶指定的私鑰庫和證書庫初始化SSL會話;
* 實現了Unix Socket API格式的通信調用方法;
* 通過創建簽名回應對象(SSLsignature_reply)啟動對簽名請求的監聽;
* 提供簽名請求功能調用方法;
* 提供一些如字符串輸入,記日志文件之類的功能調用方法。
* 類中的main方法實現了SSL簽名協議功能的演示和調試。
**********/
public class SSL_with_signature {
//可以公共訪問的成員
/**
* 自己的證書
**/
public java.security.cert.X509Certificate my_certificate;
//private javax.security.cert.Certificate my_certificate;
// 注:javax.security.cert.Certificate 是JSSE中,專用于SSL
// java.security.cert.Certificate 是Java自帶的,不知為什么兩者不兼容
// X509Certificate 是Certificate的子類
/**
* 用于創建服務器Socket
**/
public SSLServerSocketFactory ssf= null;
/**
* 用于創建客戶機Socket
**/
public SSLSocketFactory sf= null;
/**
* SSL版本,來自SSLContext.getProtocol()
**/
public String SSL_version = null;
//public static final String BYTE_ENCODING ="8859_1"; //傳送信息時的編碼方式
/**
* 傳送信息時的編碼方式
**/
public static final String BYTE_ENCODING ="GBK";
//public static final String BYTE_ENCODING ="ASCII7"; //傳送信息時的編碼方式
/**
* 本人證書中的Suject Distinguished Name
**/
public String my_SubjectDN = "";
/**
* 調用Message_Box.inputString()顯示輸入窗口并提示用戶輸入信息
**/
public static Message_Box message_box = new Message_Box();
//私有成員,不能被公開訪問
/**
* 簽名響應方監聽對方連接的端口常數定義
**/
private static final int SSLsignature_listen_port=9008;
private static boolean debug_mode = false; //調試模式
/**
* 這個對象用獨立的線程監聽請求簽名的連接
**/
private SSLsignature_reply sslsignature_reply=null;
private PrivateKey my_privatekey; //自己的私鑰
private SSLSignature_Log Log_Object=null; //用于記錄日志
/**************
* 構造函數的作用:
* 1 裝置自己的私鑰庫和對方的信任證書庫
* 2 生成可以創建SSL socket的socket 工廠
* 參數說明:
* my_keystore存放自己的私鑰
* alias:密鑰證書庫中的alias名,缺省為mykey(JKS的缺省)
* my_password為訪問私鑰的密碼
* cert_keystore存放信任的證書
* LogFileName為保存記錄日志的文件名
**/
public SSL_with_signature(KeyStore my_keystore,String alias,String my_password,KeyStore cert_keystore,String LogFileName)
throws Exception
{
//final String ALIASNAME ="mykey"; //密鑰證書庫中的alias名,缺省為mykey(JKS的缺省)
try {
/*本段代碼用于產生SSL socket工廠*/
// kmf 為SSL使用的本方私鑰和證書
// tmf 為SSL使用對方證書 ,注意 tmf 中可以保存很多證書,也就是一個SSL_with_signature對象可以同時與許多其他機器聯系
// sf 為 SSL client 的socket factory
// ssf 為 SSL server 的 serversocke factory
Security.addProvider(new com.sun.rsajca.Provider());
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
if(debug_mode){
Show_Debug_Message("以下是Java安全平臺SSL提供商的資料:");
ListProviderInfo(new com.sun.rsajca.Provider());
ListProviderInfo(new com.sun.net.ssl.internal.ssl.Provider());
}
TrustManagerFactory tmf;
KeyManagerFactory kmf;
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLS");
SSL_version = sslContext.getProtocol();
tmf=TrustManagerFactory.getInstance("SunX509");
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(my_keystore, my_password.toCharArray());
tmf.init(cert_keystore);
//使用隨機數加強加密強度
SecureRandom srand=SecureRandom.getInstance("SHA1PRNG","SUN");
srand.setSeed((new Date()).getTime());
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), srand);
sf = sslContext.getSocketFactory();
ssf = sslContext.getServerSocketFactory();
if(my_keystore.isKeyEntry(alias) == false) //不是保存私鑰
throw new KeyStoreException(alias+" entry is not a key entry");
/*取自己的私鑰*/
my_privatekey=(PrivateKey)my_keystore.getKey(alias,my_password.toCharArray()); //裝入自己私鑰
/*取自己的證書和Subject distinguished name*/
my_certificate=(java.security.cert.X509Certificate)my_keystore.getCertificate(alias);
my_certificate.checkValidity(); //檢查證書是否仍然有效
my_SubjectDN=my_certificate.getSubjectDN().getName();
/*設置日志對象*/
if(LogFileName == null)
{
int begin=my_SubjectDN.indexOf("CN="); //定位CN域頭
int end=my_SubjectDN.indexOf(",",begin); //定位CN域尾
String my_SubjectDN_CN = null;
if(end<0){
my_SubjectDN_CN=my_SubjectDN.substring(begin+3);
}
else{
my_SubjectDN_CN=my_SubjectDN.substring(begin+3,end);
}
Log_Object=new SSLSignature_Log(my_SubjectDN_CN+"_signature.log"); //缺省使用Subject Distinguish name中的CN字段
}
else
Log_Object=new SSLSignature_Log(LogFileName);
} catch (Exception e) {
System.err.println("無法創建SSL_with_signature對象: " +
e.getMessage());
e.printStackTrace();
throw e;
//System.exit(-1);
}
}
/*
* 顯示Java安全方案SSL提供商提供的Java安全類信息
**/
private static void ListProviderInfo(java.security.Provider p){
Show_Debug_Message("---------------Provider name:"+p.getName()+"-------------------");
Show_Debug_Message("Provider version:"+p.getVersion());
Show_Debug_Message("Provider information:"+p.getInfo());
}
/**
* 顯示我的證書信息
**/
public void Show_My_Certificate()
{
Show_Message("個人證書信息:");
Show_Message(my_certificate.toString());
}
/**
* 顯示SSL的信息
**/
public void Show_SSL_information()
{
Show_Message("SSL的信息:");
Show_Message("版本:"+SSL_version);
String[] supportedCipherSuites = sf.getSupportedCipherSuites();
Show_Message("支持的加密算法為:");
for(int i=0;i<supportedCipherSuites.length;++i)Show_Message(supportedCipherSuites[i]);
String[] defaultCipherSuites=sf.getDefaultCipherSuites();
Show_Message("缺省的加密算法為:");
for(int i=0;i<defaultCipherSuites.length;++i)Show_Message(defaultCipherSuites[i]);
}
/**
* 獲取SSL會話的信息
* socket: 使用的socket
* 返回SSL會話的信息
**/
public static String getSSLsessionMessage(Socket socket)
{
String SSLMessage = null;
try{
SSLSession sslsession = ((SSLSocket)socket).getSession(); //SSL會話
SSLMessage = "SSL Session id :" + sslsession.toString() + "\r\n";
SSLMessage += " 對方主機:" + sslsession.getPeerHost() + "\r\n"; //獲取對方的主機名
try{
javax.security.cert.Certificate partner_cert=(javax.security.cert.Certificate)(sslsession.getPeerCertificateChain()[0]); //對方的證書
SSLMessage += " 對方證書:\r\n";
SSLMessage += partner_cert.toString()+"\r\n";
} catch (Exception ie) {
SSLMessage += " 對方沒有證書!\r\n";
}
SSLMessage += "SSL會話使用的加密算法:"+ sslsession.getCipherSuite() + "\r\n";
SSLMessage += "SSL會話創建的時間:"+ (new Date(sslsession.getCreationTime())).toString() +"\r\n";
SSLMessage += "SSL會話最近使用的時間:"+ (new Date(sslsession.getLastAccessedTime())).toString() +"\r\n";
SSLMessage += "SSL會話綁定的對象:";
String ObjectName[] = sslsession.getValueNames();
for(int i=0;i<ObjectName.length;i++)SSLMessage += ObjectName[0]+" ";
SSLMessage += "\r\n";
} catch (Exception e){
SSLMessage = "無法獲取SSL信息,可能不是使用SSL連接\r\n";
SSLMessage += "出錯原因:"+e.getMessage()+"\r\n";
}
return SSLMessage;
}
/**
* 創建ServerSocket,在指定端口監聽SSL連接
* 參數說明:
* listen_port為監聽連接的端口
* 調用返回服務器Socket
**/
public ServerSocket listen(int listen_port)
{
try {
//通訊使用SSL加密
ServerSocket ss = ssf.createServerSocket(listen_port);
((SSLServerSocket)ss).setNeedClientAuth(true); //需要認證對方
return ss;
} catch (IOException e) {
System.err.println("無法創建服務器Socket,原因: " +
e.getMessage());
e.printStackTrace();
return null;
}
}
/**
* 通過SSL的socket發送數據,本方法也通用于TCP socket
* 參數說明:
* s:使用的socket
* but:緩沖區
* length:發送字節長度
* 返回實際發送長度
* -1 表示出錯
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -