
vi/vim鍵盤圖,希望給正在學習vim的同學帶來些幫助。
要不是公司同事的分享,我到現在還不知道有這么好的一個東西。其實網絡資源是豐富的,但是我(我們)就是缺乏發現沒的眼光。06年5月份就出品的東西,直到現在才被發現。可悲可嘆。
其實,自己用linux的時間也不短了,對VI也有一定的了解,但是就是沒有總結分享。
選擇了linux,選擇了開源,也要有分享的精神。
最后,感謝作者的精心制作 :)
本文通過模擬場景,介紹SSL雙向認證的java實現
默認的情況下,我認為讀者已經對SSL原理有一定的了解,所以文章中對SSL的原理,不做詳細的介紹。
如果有這個需要,那么通過GOOGLE,可以搜索到很多這樣的文章。
模擬場景:
Server端和Client端通信,需要進行授權和身份的驗證,即Client只能接受Server的消息,Server只能接受Client的消息。
實現技術:
JSSE(Java Security Socket Extension
)
是Sun為了解決在Internet上的安全通訊而推出的解決方案。它實現了SSL和TSL(傳輸層安全)協議。在JSSE中包含了數據加密,服務器驗證,消息完整性和客戶端驗證等技術。通過使用JSSE,開發人員可以在客戶機和服務器之間通過TCP/IP協議安全地傳輸數據
為了實現消息認證。
Server需要:
1)KeyStore: 其中保存服務端的私鑰
2)Trust KeyStore:其中保存客戶端的授權證書
同樣,Client需要:
1)KeyStore:其中保存客戶端的私鑰
2)Trust KeyStore:其中保存服務端的授權證書
我們可以使用Java自帶的keytool命令,去生成這樣信息文件
1)生成服務端私鑰,并且導入到服務端KeyStore文件中
keytool -genkey -alias serverkey -keystore kserver.keystore
過程中,分別需要填寫,根據需求自己設置就行
keystore密碼:123456
名字和姓氏:stone
組織單位名稱:eulic
組織名稱:eulic
城市或區域名稱:HZ
州或省份名稱:ZJ
國家代碼:CN
serverkey私鑰的密碼,不填寫和keystore的密碼一致:123456
就可以生成kserver.keystore文件
server.keystore是給服務端用的,其中保存著自己的私鑰
2)根據私鑰,導出服務端證書
keytool -export -alias serverkey -keystore kserver.keystore -file server.crt
server.crt就是服務端的證書
3)將服務端證書,導入到客戶端的Trust KeyStore中
keytool -import -alias serverkey -file server.crt -keystore tclient.keystore
tclient.keystore是給客戶端用的,其中保存著受信任的證書
采用同樣的方法,生成客戶端的私鑰,客戶端的證書,并且導入到服務端的Trust KeyStore中
1)keytool -genkey -alias clientkey -keystore kclient.keystore
2)keytool -export -alias clientkey -keystore kclient.keystore -file client.crt
3)keytool -import -alias clientkey -file client.crt -keystore tserver.keystore
如此一來,生成的文件分成兩組
服務端保存:kserver.keystore tserver.keystore
客戶端保存:kclient.keystore tclient.kyestore
接下來,就采用JSSE,分別生成SSLServerSocket,SSLSocket
服務端,生成SSLServerSocket代碼
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("data/kserver.keystore"), SERVER_KEY_STORE_PASSWORD.toCharArray());
tks.load(new FileInputStream("data/tserver.keystore"), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());
kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
客戶端,生成SSLSocket的代碼,大同小異
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("data/kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
tks.load(new FileInputStream("data/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return (SSLSocket) ctx.getSocketFactory().createSocket(DEFAULT_HOST, DEFAULT_PORT);
如此,就完成了服務端和客戶端之間的基于身份認證的交互。
client采用kclient.keystore中的clientkey私鑰進行數據加密,發送給server
server采用tserver.keystore中的client.crt證書(包含了clientkey的公鑰)對數據解密,如果解密成功,證明消息來自client,進行邏輯處理
server采用kserver.keystore中的serverkey私鑰進行數據叫米,發送給client
client采用tclient.keystore中的server.crt證書(包含了serverkey的公鑰)對數據解密,如果解密成功,證明消息來自server,進行邏輯處理
如果過程中,解密失敗,那么證明消息來源錯誤。不進行邏輯處理。這樣就完成了雙向的身份認證。
下面我附上簡單的SSLServer.java SSLClient.java,供大家演示用。
啟動服務端的時候,大家不妨采用telnet 127.0.0.1 7777連接,看看能不能實現消息傳遞。
ssl demo
備注:
demo是采用maven構建項目的
demo文件的編碼是用utf8,為了避免中文亂碼,請把workspace設置成utf8編碼
本文介紹常見的算法(MD5/SHA,DSA,RSA,DES)的應用場景,以及在java上的使用方法.
1) MD5/SHA
MessageDigest是一個數據的數字指紋.即對一個任意長度的數據進行計算,產生一個唯一指紋號.
MessageDigest的特性:
A) 兩個不同的數據,難以生成相同的指紋號
B) 對于指定的指紋號,難以逆向計算出原始數據
代表:MD5/SHA
Java實現:
MD5:
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Constant.DATA.getBytes());
byte[] result = md.digest();

SHA:
MessageDigest md = MessageDigest.getInstance("SHA");

md.update(Constant.DATA.getBytes());

byte[] result = md.digest();
2) DES
單密鑰算法,是信息的發送方采用密鑰A進行數據加密,信息的接收方采用同一個密鑰A進行數據解密.
單密鑰算法是一個對稱算法.
缺點:由于采用同一個密鑰進行加密解密,在多用戶的情況下,密鑰保管的安全性是一個問題.
代表:DES
Java實現:
首先,需要生成一個密鑰,這邊的做法,是把生成的密鑰,保存到某個文件中.
KeyGenerator gen = KeyGenerator.getInstance("DES");
Key key = gen.generateKey();
File keyFile = new File(Constant.CRYPT_KEY_FILE);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(keyFile));
out.writeObject(key);
out.close();

在生成key的時候,可以通過SecureRandom產生一個可信任的隨機數源
KeyGenerator gen = KeyGenerator.getInstance("DES");
gen.init(new SecureRandom(seed));
Key key = gen.generateKey();
加密:
Key key = gen.getKey(Constant.CRYPT_KEY_FILE);//從文件中得到密鑰
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key); //指定是加密模式
cipher.update(Constant.DATA.getBytes());
byte[] result = cipher.doFinal();
解密:
由于DES是一個對稱算法,所以解密代碼跟加密代碼幾乎一致
key = gen.getKey(Constant.CRYPT_KEY_FILE);
cipher.init(Cipher.DECRYPT_MODE, key); //指定是解密模式
cipher.update(result);
byte[] data = cipher.doFinal();
由于采用了同一個密鑰(key),所以兩端代碼中
Constant.DATA.getBytes()和 data 的值是一致的.
3) DSA
所謂數字簽名是指發送方從發送報文中抽取特征數據(稱為數字指紋或摘要),然后用發送方的私鑰對數字指紋使用加密算法進行算法操作,接受方使用發送方已經公開的公鑰解密并驗證報文.
數字簽名用戶驗證發送方身份或者發送方信息的完整性
代表:DSA
Java實現:
同樣,首先需要生成一個公鑰和私鑰,我們也把它保存到相應的文件中
KeyPairGenerator gen = KeyPairGenerator.getInstance(“DSA”);

//以指定的長度初始化KeyPairGenerator對象,如果沒有初始化系統以1024長度默認設置

//參數:keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數

gen.initialize(1024);

KeyPair pair = gen.generateKeyPair();

File pubkeyFile = new File(Constant.PUB_KEY_FILE);

File prikeyFile = new File(Constant.PRI_KEY_FILE);

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(pubkeyFile));

out.writeObject(pair.getPublic());

out.close();

out = new ObjectOutputStream(new FileOutputStream(prikeyFile));

out.writeObject(pair.getPrivate());

out.close();

簽名:
PrivateKey prikey = (PrivateKey) gen.getKey(Constant.PRI_KEY_FILE); //從文件得到私鑰

// 用私鑰對數據簽名

Signature signature = Signature.getInstance("DSA");

signature.initSign(prikey);

signature.update(Constant.DATA.getBytes());

byte[] bytes = signature.sign();


把原始數據和簽名發送給接收方
驗證:
用公鑰對原始數據和簽名進行驗證
PublicKey pubkey = (PublicKey) gen.getKey(Constant.PUB_KEY_FILE);//從文件得到公鑰

Signature check = Signature.getInstance("DSA");

check.initVerify(pubkey);

check.update(Constant.DATA.getBytes());

//驗證數據的完整性


if (check.verify(bytes))
{

System.out.println("OK");


} else
{

System.out.println("ERROR");

}
4) RSA
公鑰密碼體制:為了解決單密鑰保管安全性的問題,提供了公鑰密碼體制的概念.在公鑰體制中,加密密鑰不同于解密密鑰,加密密鑰公之于眾,誰都可以使用;解密密鑰只有解密人自己知道。它們分別稱為公開密鑰(Public key)和秘密密鑰(Private key)。
代表:RSA
Java實現:
同樣,需要生成公鑰和私鑰,并且保存到相應的文件中
KeyPairGenerator gen = KeyPairGenerator.getInstance(“RSA”);

//以指定的長度初始化KeyPairGenerator對象,如果沒有初始化系統以1024長度默認設置

//參數:keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數

gen.initialize(1024);

KeyPair pair = gen.generateKeyPair();

File pubkeyFile = new File(Constant.PUB_KEY_FILE);

File prikeyFile = new File(Constant.PRI_KEY_FILE);

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(pubkeyFile));

out.writeObject(pair.getPublic());

out.close();

out = new ObjectOutputStream(new FileOutputStream(prikeyFile));

out.writeObject(pair.getPrivate());

out.close();


加密:
采用公鑰進行加密:
PublicKey pubkey = (PublicKey) gen.getKey(Constant.PUB_KEY_FILE);//從文件中得到公鑰

Cipher cipher = Cipher.getInstance("RSA");

cipher.init(Cipher.ENCRYPT_MODE, pubkey);//指定加密模式

byte[] bytes = cipher.doFinal(Constant.DATA.getBytes());

解密:
采用私鑰進行解密:
PrivateKey prikey = (PrivateKey) gen.getKey(Constant.PRI_KEY_FILE);//從文件中得到私鑰

Cipher c = Cipher.getInstance("RSA");

c.init(Cipher.DECRYPT_MODE, prikey);//指定解密模式

byte[] data = c.doFinal(bytes);

兩段代碼中, Constant.DATA.getBytes()和data的值是一致的.
以上,對常見的算法,對了簡單的介紹.一般情況下,可以滿足我們日常的需求了.
附件是中java實現代碼:
java code