什么是keytool注整?
keytool是JDK自帶的一個密鑰庫管理工具能曾。這里只用到了keytool的部分功能度硝,包括生成密鑰對,導(dǎo)出公鑰等寿冕。keytool生成的公鑰/私鑰對存放到一個到了一個文件中蕊程,這個文件有密碼保護,通稱為keystore蚂斤。
生成密鑰對
$ keytool -genkeypair \
-alias config-server \
-keystore config-server.keystore \
-validity 1800 \
-keyalg RSA \
-dname "CN=yxx, OU=company, O=org, L=city, ST=province, C=china" \
-keypass 222222 \
-storepass 111111
上面是創(chuàng)建密鑰對的命令,具體參數(shù)如下:
*alias 別名
*keystore 密鑰庫名稱
*validity 有效時間
*keyalg 密鑰對方式
*dname 基本信息
*keypass 密鑰口令
*storepass 密鑰庫口令
執(zhí)行上面的命令槐沼,會有一個提示曙蒸,如下:
JKS 密鑰庫使用專用格式。
建議使用 "keytool -importkeystore -srckeystore config-server.keystore
-destkeystore config-server.keystore -deststoretype pkcs12" 遷移到行業(yè)標(biāo)準(zhǔn)格式 PKCS12岗钩。
可以根據(jù)自己的情況看是否需要轉(zhuǎn)P12纽窟。
查看密鑰對
$ keytool -list -keystore examplestanstore -v
列出了config-server.keystore密鑰庫的中所有密鑰對。-v參數(shù)表示詳細(xì)信息兼吓,詳細(xì)信息中有證書的失效時間臂港。
導(dǎo)出公鑰證書
$ keytool -export -keystore config-server.keystore \
-alias config-server -file config-server.cer
導(dǎo)出的公鑰存放在當(dāng)前目錄的StanSmith.cer文件中,是個二進制文件视搏。
java簽名和驗證
參考了java安全官方教程审孽。
在該官方教程中,GenSig.java類生成密鑰對浑娜,對輸入的文件進行簽名佑力,輸出了一個簽名結(jié)果文件sig和公鑰suepk。
VerSig.java類接受三個參數(shù):公鑰文件名(suepk)筋遭、簽名文件(sig)打颤、被簽名的源文件名(hello.txt)。
該教程解釋了兩個類的原理漓滔,并附加有源碼。將源碼下載并編譯透且。創(chuàng)建一個hello.txt的文件作為被簽名的目標(biāo)文件豁鲤,里面隨便放點字符串畅形。然后執(zhí)行:
$ java GenSig hello.txt (生成文件sig和suepk)
$ java VerSig suepk sig hello.txt
signature verifies: true
注意:上面的代碼在一個單獨目錄中執(zhí)行
在實際使用時,密鑰對不可能每次在程序中重新生成棍厌。而keytool恰好可以生成并相對安全保存密鑰對耘纱。所以下面結(jié)合了keytool和java實現(xiàn)的功能。
結(jié)合keytool與java簽名/驗證
密鑰對由keytool生成并保存到keystore中保護起來(keystore有密碼)艳馒。公鑰也從keystore中導(dǎo)出弄慰。GenSig.java類只需要從keystore中取得私鑰進行簽名即可蝶锋。
VerSig.java也要做適當(dāng)?shù)男薷摹C菜埔驗閺膋eystore中導(dǎo)出的是證書而不是公鑰慌闭,兩者的封裝格式估計有差異驴剔。
具體步驟
1.利用keytool -genkey生成密鑰對保存在keystore中(庫文件是config-server.keystore)
2.利用`keytool -export’從keystore中導(dǎo)出公鑰證書(StanSmith.cer)
3.利用新類GenSig2.java生成簽名(文件名是sig)粥庄,GenSig2.java會從keystore中取私鑰
4.將公鑰(StanSmith.cer)飒赃、簽名(sig)、被簽名文件(hello.txt)發(fā)給驗證方
5.驗證方利用VerSig2.java進行驗證
下面是GenSig2.java和VerSig2.java的源碼和執(zhí)行方式炒事。
GenSig2.java
import java.io.*;
import java.security.*;
class GenSig2 {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Usage: java GenSig2 <nameOfFileToSign>");
}
else try{
/*create key paire use keytool:
$ keytool -genkey -alias signLegal -keystore examplestanstore -validity 1800*/
// read keystore file
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream ksfis = new FileInputStream("config-server.keystore");
BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
// open keystore and get private key
// alias is 'signLeal', kpasswd/spasswd is 'vagrant'
ks.load(ksbufin, "vagrant".toCharArray());
PrivateKey priv = (PrivateKey) ks.getKey("signLegal", "vagrant".toCharArray());
/* Create a Signature object and initialize it with the private key */
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initSign(priv);
/* Update and sign the data */
FileInputStream fis = new FileInputStream(args[0]);
BufferedInputStream bufin = new BufferedInputStream(fis);
byte[] buffer = new byte[1024];
int len;
while (bufin.available() != 0) {
len = bufin.read(buffer);
dsa.update(buffer, 0, len);
};
bufin.close();
/* Now that all the data to be signed has been read in,
generate a signature for it */
byte[] realSig = dsa.sign();
/* Save the signature in a file */
FileOutputStream sigfos = new FileOutputStream("sig");
sigfos.write(realSig);
sigfos.close();
/* public key file can export from keystore use keytool:
$ keytool -export -keystore examplestanstore -alias signLegal -file StanSmith.cer */
} catch (Exception e) {
System.err.println("Caught exception " + e.toString());
}
};
編譯后,這樣運行:
$ java GenSig2 hello.txt
會生成簽名文件sig姑躲。
VerSig2.java
import java.io.*;
import java.security.*;
import java.security.spec.*;
class VerSig2 {
public static void main(String[] args) {
/* Verify a DSA signature */
if (args.length != 3) {
System.out.println("Usage: VerSig publickeyfile signaturefile datafile");
}
else try{
/* import encoded public cert */
FileInputStream certfis = new FileInputStream(args[0]);
java.security.cert.CertificateFactory cf =
java.security.cert.CertificateFactory.getInstance("X.509");
java.security.cert.Certificate cert = cf.generateCertificate(certfis);
PublicKey pubKey = cert.getPublicKey();
/* input the signature bytes */
FileInputStream sigfis = new FileInputStream(args[1]);
byte[] sigToVerify = new byte[sigfis.available()];
sigfis.read(sigToVerify );
sigfis.close();
/* create a Signature object and initialize it with the public key */
Signature sig = Signature.getInstance("SHA1withDSA", "SUN");
sig.initVerify(pubKey);
/* Update and verify the data */
FileInputStream datafis = new FileInputStream(args[2]);
BufferedInputStream bufin = new BufferedInputStream(datafis);
byte[] buffer = new byte[1024];
int len;
while (bufin.available() != 0) {
len = bufin.read(buffer);
sig.update(buffer, 0, len);
};
bufin.close();
boolean verifies = sig.verify(sigToVerify);
System.out.println("signature verifies: " + verifies);
} catch (Exception e) {
System.err.println("Caught exception " + e.toString());
};
}
}
編譯后卖怜,這樣運行(StanSmith.cer是利用keytool導(dǎo)出的公鑰證書马靠,見前文):
$ java VerSig2 StanSmith.cer sig hello.txt
signature verifies: true
學(xué)習(xí)交流,請加群:64691032