星期五, 6月 16, 2006

java security備忘記

在SDI(http://www2.cpttm.org.mo/cyberlab/SDI/2005-001/index.html.en)的開發的過程中.
我覺得比較值得記錄下來的是security的部份,這裡只記下generate keys及一些測試程式.
而原本的PKCS12 storetype , 我把它改成 JKS.
在security方面,Applet 及 Web communication的部份我覺得比較容易,就沒有記下來.


開始備忘記:
首先要安裝jdk.


產生keystore:
[joeyta]$keytool -genkey -alias joeyta -keystore joeyta.ks -keyalg RSA -sigalg SHA1withRSA
( 在 java 裡, 預設的 keystore type 為 JKS )
其他的看需要輸入,但下面這兩個password就要記住
keystore password 輸入 123456
key password 輸入 234567
就會產生 joeyta.ks


顯示keystore list
輸入 keystore password 為 123456
[joeyta]$keytool -list -v -keystore joeyta.ks


產生certificate request file
[joeyta]$keytool -certreq -alias joeyta -keystore joeyta.ks -file joeyta.csr
輸入 keystore password 為 123456
輸入 key password 234567
就會產生 joeyta.ks


安裝openssl,
windows os 在
http://www.openssl.org/related/binaries.html 下載
( windows os 下需設 environment parameter 為 set RANDFILE=rand )
本人使用 Fedora Core release 3 (Heidelberg), 預設已安裝
輸入
[joeyta]$rpm -qa grep openssl
出現:
openssl-0.9.7a-20.2
openssl-devel-0.9.7a-20.2
如果沒有顯示,即沒有安裝,那就可以到
http://search.rpmseek.com/search.html 去找一下
( rpm -ivh
http://rpmpath ]


產生CA自簽的private key
[joeyta]$openssl req -new -keyout cakey.pem -out careq.pem
輸入 PEM pass phrase 為 capassword
其他的看需要輸入.
就會產生 cakey.pem 及 careq.pem


找出openssl設定檔:
[joeyta]$rpm -ql openssl grep cnf
出現:
/usr/share/ssl/openssl.cnf
( windows os 則在安裝目錄下的bin\openssl.cnf , 如 c:\OpenSSL\bin\openssl.cnf )


產生自簽certificate:
[joeyta]$openssl x509 -signkey cakey.pem -req -days 365 -in careq.pem -out cacert.pem -extfile /usr/share/ssl/openssl.cnf -extensions v3_ca
輸入 pass phrase 為 capassword
就會產生 cacert.pem


產生serial file:
[joeyta]$echo 02 > cacert.srl


產生CA sign certificate:
[joeyta]$openssl x509 -CA cacert.pem -CAkey cakey.pem -CAserial cacert.srl -req -in joeyta.csr -out joeyta.cer -days 365
輸入 pass phrase 為 capassword
就會產生 joeyta.cert


Import trusted CA certificate:
( 如果keystore type為 PKCS12 則不能 import trusted certificate, 因為 PKCS12 只能儲存 private keys )
[joeyta]$keytool -import -alias testCA -file cacert.pem -keystore joeyta.ks
keystore password 輸入 123456
Trust this certificate? [no]: 輸入 yes
[joeyta]$keytool -list -v -keystore joeyta.ks


這裡有不錯的文檔供查詢.
http://download.java.net/jdk6/docs/guide/security/jsse/JSSERefGuide.html
http://www.openssl.org/docs/



產生所有需要的 keystore 後, 可以開始進入寫程式了.
本人使用 Eclipse IDE
建立 java project, 命名為 javasecurity
點選 javasecurity > properties > Java Build Path
進入 Source 面版
點選 Add Foler 為 src
進入 Libraries 面版
點選 Add Extenals JARs , 將 junit_3.8.1.jar 加入來 (可在eclipse plugin目錄下找到), 然後按 ok
將剛剛產生的所有 keys 丟進 src 目錄下.


程式:
KeyManager.java // 主程式
KeyManagerTest.java // 測試程式



/* KeyManager.java */
package testca;


import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;


public class KeyManager {
private static String signAlgorithm = "SHA1withRSA";
private static KeyManager keyManager;

public String getSignAlgorithm() {
return signAlgorithm;
}


public PrivateKey loadPrivateKey(InputStream inputStream, String alias,
char[] keyStorePassword, char[] privatePassword)
throws KeyStoreException, NoSuchAlgorithmException,
CertificateException, IOException, UnrecoverableKeyException {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(inputStream, keyStorePassword);
return (PrivateKey) ks.getKey(alias, privatePassword);
}


public PublicKey loadPublicKey(InputStream inputStream, String alias,
char[] keyStorePassword) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(inputStream, keyStorePassword);
return (PublicKey) ks.getCertificate(alias).getPublicKey();
}


public byte[] sign(byte[] data, PrivateKey privateKey)
throws NoSuchAlgorithmException, InvalidKeyException,
SignatureException {
Signature s = Signature.getInstance(getSignAlgorithm());
s.initSign(privateKey);
s.update(data);
return s.sign();
}


public boolean verify(byte[] data, PublicKey publicKey, byte[] signature)
throws NoSuchAlgorithmException, InvalidKeyException,
SignatureException {
Signature s = Signature.getInstance(getSignAlgorithm());
s.initVerify(publicKey);
s.update(data);
return s.verify(signature);
}


private KeyManager(){

}
public static KeyManager getInstance(){
if (keyManager == null) {
keyManager = new KeyManager();
}
return keyManager;

}

}
/* KeyManager.java */



/* KeyManagerTest.java */
package testca;


import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;


import junit.framework.TestCase;


public class KeyManagerTest extends TestCase {
public void testSuccessSignature() throws Exception {
KeyManager keyManager = KeyManager.getInstance();
String data = "this is the plain text";
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("joeyta.ks");
PrivateKey privateKey = keyManager.loadPrivateKey(inputStream,
"joeyta", "123456".toCharArray(), "234567".toCharArray());
byte[] signData = keyManager.sign(data.getBytes(), privateKey);
inputStream = getClass().getClassLoader().getResourceAsStream(
"joeyta.ks");
PublicKey publicKey = keyManager.loadPublicKey(inputStream, "joeyta",
"123456".toCharArray());
assertTrue(keyManager.verify(data.getBytes(), publicKey, signData));
}


public void testFailSignature() throws Exception {
KeyManager keyManager = KeyManager.getInstance();
String data = "this is the plain text";
String data2 = "This is the plain fail text";
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("joeyta.ks");
PrivateKey privateKey = keyManager.loadPrivateKey(inputStream,
"joeyta", "123456".toCharArray(), "234567".toCharArray());
byte[] signData = keyManager.sign(data.getBytes(), privateKey);
inputStream = getClass().getClassLoader().getResourceAsStream(
"joeyta.ks");
PublicKey publicKey = keyManager.loadPublicKey(inputStream, "joeyta",
"123456".toCharArray());
assertFalse(keyManager.verify(data2.getBytes(), publicKey, signData));
}


}
/* KeyManagerTest.java */


// 我覺得這些程式非常簡單, 所以沒有作詳細的解釋
/* Explanation 1 */
public PrivateKey loadPrivateKey(InputStream inputStream, String alias,
char[] keyStorePassword, char[] privatePassword)
throws KeyStoreException, NoSuchAlgorithmException,
CertificateException, IOException, UnrecoverableKeyException { // 此method 返回 private key
KeyStore ks = KeyStore.getInstance("JKS"); // 定義 keystore type 為 JKS
ks.load(inputStream, keyStorePassword); // load keystore, keyStorePassword 為 當初設定的 123456
return (PrivateKey) ks.getKey(alias, privatePassword);
}

public PublicKey loadPublicKey(InputStream inputStream, String alias,
char[] keyStorePassword) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException { // 與上面類似, 但返回 public key
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(inputStream, keyStorePassword);
return (PublicKey) ks.getCertificate(alias).getPublicKey();
}
/* Explanation 1 */



/* Explanation 2 */
public byte[] sign(byte[] data, PrivateKey privateKey)
throws NoSuchAlgorithmException, InvalidKeyException,
SignatureException { // 此method 返回sign完的signature
Signature s = Signature.getInstance(getSignAlgorithm());
s.initSign(privateKey);
s.update(data);
return s.sign();
}


public boolean verify(byte[] data, PublicKey publicKey, byte[] signature)
throws NoSuchAlgorithmException, InvalidKeyException,
SignatureException { // 此method 返回是否verify
Signature s = Signature.getInstance(getSignAlgorithm());
s.initVerify(publicKey);
s.update(data);
return s.verify(signature);
}


private KeyManager(){}

public static KeyManager getInstance(){ // 這只是singleton
if (keyManager == null) {
keyManager = new KeyManager();
}
return keyManager;

}
/* Explanation 2 */



/* Explanation 3 */
public void testSuccessSignature() throws Exception {
KeyManager keyManager = KeyManager.getInstance();
String data = "this is the plain text";
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("joeyta.ks"); // 返回keystore
PrivateKey privateKey = keyManager.loadPrivateKey(inputStream,
"joeyta", "123456".toCharArray(), "234567".toCharArray()); // 返回private key
byte[] signData = keyManager.sign(data.getBytes(), privateKey); // 返回signature data
inputStream = getClass().getClassLoader().getResourceAsStream(
"joeyta.ks");
PublicKey publicKey = keyManager.loadPublicKey(inputStream, "joeyta", // 返回public key
"123456".toCharArray());
assertTrue(keyManager.verify(data.getBytes(), publicKey, signData)); // 檢查是否verify
}
/* Explanation 3 */

使用 KeyStore Explorer 瀏覽:
運行 KeyStore Explorer jre 必須 1.5 或以上版本.

其功能為:
KeyStore saving.
Key pair export.
Private key export.
CSR signing.
JAR file signing.
MIDlet signing.


下載10天試用期版本 kse-30-manual.zip :
http://www.lazgosoftware.com/kse/downloads.html
按步驟輸入 email, 就會從 email 取得 download path 如下:
http://www.lazgosoftware.com/kse/downloads/44b2f9e3-2fe40575/kse-30-manual.zip


解壓至 D:\kse 下, 執行:
java -jar D:\kse\kse.jar
就會出現如下畫面:


選擇 File -> Open 搜尋 joeyta.ks,
輸入上面已設定的 keystore password:123456
就能以 GUI 的形式修改 keystore 內容.


下面有一些官方的教學:
http://www.lazgosoftware.com/kse/support-start.html

沒有留言: