RSA非對稱加密原理
RSA算法的核心是歐拉定理它浅,其安全性決定于下面的公式:
//其中d組成了私鑰译柏,如果d被計算出來那么算法被破解。n是一個隨機(jī)的大整數(shù)
(1)ed≡1 (mod φ(n))姐霍。只有知道e和φ(n)鄙麦,才能算出d。
(2)φ(n)=(p-1)(q-1)镊折。只有知道p和q胯府,才能算出φ(n)。
(3)n=pq恨胚。只有將n因數(shù)分解,才能算出p和q与纽。
可是侣签,大整數(shù)的因數(shù)分解,是一件非常困難的事情急迂。目前影所,除了暴力破解,還沒有發(fā)現(xiàn)別的有效方法僚碎。
維基百科這樣寫道:
“對極大整數(shù)做因數(shù)分解的難度決定了RSA算法的可靠性猴娩。換言之,對一極大整數(shù)做因數(shù)分解愈困難,RSA算法愈可靠卷中。
假如有人找到一種快速因數(shù)分解的算法矛双,那么RSA的可靠性就會極度下降。但找到這樣的算法的可能性是非常小的蟆豫。今天只有短的RSA密鑰才可能被暴力破解议忽。到2008年為止,世界上還沒有任何可靠的攻擊RSA算法的方式十减。
只要密鑰長度足夠長栈幸,用RSA加密的信息實際上是不能被解破的“锉伲”
RSA算法常用于非對稱加密速址,非對稱加密流程如下:
(1)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的由驹,任何人都可以獲得芍锚,私鑰則是保密的。
(2)甲方獲取乙方的公鑰蔓榄,然后用它對信息加密并炮。
(3)乙方得到加密后的信息,用私鑰解密润樱。
SSL雙向認(rèn)證的原理
具體過程:
① 瀏覽器發(fā)送一個連接請求給安全服務(wù)器渣触。
② 服務(wù)器將自己的證書,以及同證書相關(guān)的信息發(fā)送給客戶瀏覽器壹若。
③ 客戶瀏覽器檢查服務(wù)器送過來的證書是否是由自己信賴的 CA 中心所簽發(fā)的嗅钻。如果是,就繼續(xù)執(zhí)行協(xié)議店展;如果不是养篓,客戶瀏覽器就給客戶一個警告消息:警告客戶這個證書不是可以信賴的,詢問客戶是否需要繼續(xù)赂蕴。
④ 接著客戶瀏覽器比較證書里的消息柳弄,例如域名和公鑰,與服務(wù)器剛剛發(fā)送的相關(guān)消息是否一致概说,如果是一致的碧注,客戶瀏覽器認(rèn)可這個服務(wù)器的合法身份。
⑤ 服務(wù)器要求客戶發(fā)送客戶自己的證書糖赔。收到后萍丐,服務(wù)器驗證客戶的證書,如果沒有通過驗證放典,拒絕連接逝变;如果通過驗證基茵,服務(wù)器獲得用戶的公鑰。
⑥ 客戶瀏覽器告訴服務(wù)器自己所能夠支持的通訊對稱密碼方案壳影。
⑦ 服務(wù)器從客戶發(fā)送過來的密碼方案中拱层,選擇一種加密程度最高的密碼方案,用客戶的公鑰加過密后通知瀏覽器宴咧。
⑧ 瀏覽器針對這個密碼方案根灯,選擇一個通話密鑰,接著用服務(wù)器的公鑰加過密后發(fā)送給服務(wù)器掺栅。
⑨ 服務(wù)器接收到瀏覽器送過來的消息箱吕,用自己的私鑰解密,獲得通話密鑰柿冲。
⑩ 服務(wù)器、瀏覽器接下來的通訊都是用對稱密碼方案兆旬,對稱密鑰是加過密的假抄。
上面所述的是雙向認(rèn)證 SSL 協(xié)議的具體通訊過程,這種情況要求服務(wù)器和用戶雙方都有證書丽猬。
應(yīng)用
那么如何去做一個SSL雙向認(rèn)證的通信測試呢宿饱?一般制作雙向認(rèn)證相關(guān)證書有兩個工具openssl
和keytool
。
二者比較:
- openssl 適用范圍廣脚祟,使用的最多谬以。
- keytool 單獨針對 java application
需要安裝 jre 之后才會有 keytool
java只能用 Java Keystore,而它需要keytool 工具生成由桌。
keystore 可以把私鑰和證書放一起为黎,只用一個文件。
使用keytool
因為我使用java開發(fā)行您,所以就用keytool了铭乾,下面演示一個實例,注意這個實例中沒有使用CA娃循。
keytool命令說明:
- keytool -genkey 生成密鑰對
- keytool -export 導(dǎo)出證書
- keytool -import 導(dǎo)入證書或證書鏈
生成密鑰證書文件
服務(wù)器端:
1,生成服務(wù)器端的密鑰對
keytool -genkey -alias serverkey -keystore kserver.ks
密碼: serverpass
2, 導(dǎo)出證書
keytool -export -alias serverkey -keystore kserver.ks -file server.crt
3, 把證書導(dǎo)入炕檩,生成的tclient.ks交給客戶端,里面有公鑰信息
keytool -import -alias serverkey -file server.crt -keystore tclient.ks
密碼: serverpublicpass
同理生成客戶端:
1, 生成客戶端密鑰對
keytool -genkey -alias clientkey -keystore kclient.ks
密碼: clientpass
2, 導(dǎo)出證書
keytool -export -alias clientkey -keystore kclient.ks -file client.crt
3, 導(dǎo)入證書捌斧,生成的tserver.ks交給服務(wù)器笛质,里面有客戶端的公鑰信息
keytool -import -alias clientkey -file client.crt -keystore tserver.ks
密碼: clientpublicpass
關(guān)鍵代碼示例:
//客戶端:
public static void main(String[] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore tks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("cert/kclient.ks"), "clientpass".toCharArray());
tks.load(new FileInputStream("cert/tclient.ks"), "serverpublicpass".toCharArray());
kmf.init(ks, "clientpass".toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocket sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket("localhost", 8288);
InputStream input = sslSocket.getInputStream();
OutputStream output = sslSocket.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(input);
BufferedOutputStream bos = new BufferedOutputStream(output);
bos.write("Hello".getBytes());
bos.flush();
byte[] buffer = new byte[20];
int length = bis.read(buffer);
System.out.println(new String(buffer, 0, length));
sslSocket.close();
}
//服務(wù)器端:
public static void main(String[] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore tks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("cert/kserver.ks"), "serverpass".toCharArray());
tks.load(new FileInputStream("cert/tserver.ks"), "clientpublicpass".toCharArray());
kmf.init(ks, "serverpass".toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLServerSocket serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(8288);
serverSocket.setNeedClientAuth(true);
while (true) {
try {
Socket s = serverSocket.accept();
InputStream input = s.getInputStream();
OutputStream output = s.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(input);
BufferedOutputStream bos = new BufferedOutputStream(output);
byte[] buffer = new byte[20];
int length = bis.read(buffer);
System.out.println("Receive: " + new String(buffer, 0, length).toString());
bos.write("Hello".getBytes());
bos.flush();
s.close();
} catch (Exception e) {
System.out.println(e);
}
}
}