參考文章:http://jingyan.baidu.com/article/f3e34a12ad7acff5ea653569.html
http://bijian1013.iteye.com/blog/2339874
工作中需要使用非對稱加密rsa來進行消息摘要生産和驗證,但無法通過keytool工具來提取私鑰。
那怎麼獲得私鑰、公鑰?
以java為例:通過keystore類getentry() 或者getkey()來提取私鑰;通過certificate類getpublickey()擷取公鑰。
一.keytool生成keystore檔案
cmd代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1coRXYwNWaw91dfB3Lc12bj5SZ5VGdp5yMxATMuFWaqlmYvw1LcpDc0RHaiojIsJye.png)
-- 生成密碼倉庫test.store
eytool -genkey -v -alias test -dname "cn=test,ou=he,o=cui,l=shengzhen,st=guangdong,c=cn" -keyalg rsa -keysize 2048 -keypass 5201314 -keystore test.store -storepass 5201314 -validity 10000 -storetype jceks
-- 導出證書test.crt
eytool -exportcert -alias test -file test.crt -keystore test.store -storepass 5201314 -rfc -storetype jceks
運作後在f盤的key目錄下将産生如下兩個檔案。
二.生成私鑰、公鑰
keystorehelper.java
java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1coRXYwNWaw91dfB3Lc12bj5SZ5VGdp5yMxATMuFWaqlmYvw1LcpDc0RHaiojIsJye.png)
package com.bijian.keystore;
import java.io.fileinputstream;
import java.io.filenotfoundexception;
import java.io.fileoutputstream;
import java.io.inputstream;
import java.io.objectoutputstream;
import java.security.keystore;
import java.security.privatekey;
import java.security.publickey;
import java.security.cert.certificate;
import java.security.cert.certificateexception;
import java.security.cert.certificatefactory;
import sun.misc.base64encoder;
public class keystorehelper {
public static void main(string[] args) throws exception {
string privatepath = "f:/key/testpri.key"; // 準備導出的私鑰
string publicpath = "f:/key/testpub.key"; // 準備導出的公鑰
privatekey privatekey = getprivatekeyfromstore();
createkeyfile(privatekey, privatepath);
publickey publickey = getpublickeyfromcrt();
createkeyfile(publickey, publicpath);
byte[] publickeybytes = publickey.getencoded();
byte[] privatekeybytes = privatekey.getencoded();
string publickeybase64 = new base64encoder().encode(publickeybytes);
string privatekeybase64 = new base64encoder().encode(privatekeybytes);
system.out.println("publickeybase64.length():" + publickeybase64.length());
system.out.println("publickeybase64:" + publickeybase64);
system.out.println("privatekeybase64.length():" + privatekeybase64.length());
system.out.println("privatekeybase64:" + privatekeybase64);
}
private static privatekey getprivatekeyfromstore() throws exception {
string alias = "test"; // keytool中生成keystore時設定的alias
string storetype = "jceks"; // keytool中生成keystore時設定的storetype
char[] pw = "5201314".tochararray(); // keytool中生成keystore時設定的storepass
string storepath = "f:/key/test.store"; // keytool中已生成的keystore檔案
storetype = null == storetype ? keystore.getdefaulttype() : storetype;
keystore keystore = keystore.getinstance(storetype);
inputstream is = new fileinputstream(storepath);
keystore.load(is, pw);
// 由密鑰庫擷取密鑰的兩種方式
// keystore.privatekeyentry pkentry = (keystore.privatekeyentry) keystore.getentry(alias, new keystore.passwordprotection(pw));
// return pkentry.getprivatekey();
return (privatekey) keystore.getkey(alias, pw);
private static publickey getpublickeyfromcrt() throws certificateexception, filenotfoundexception {
string crtpath = "f:/key/test.crt"; // keytool中已生成的證書檔案
certificatefactory cf = certificatefactory.getinstance("x.509");
fileinputstream in = new fileinputstream(crtpath);
certificate crt = cf.generatecertificate(in);
publickey publickey = crt.getpublickey();
return publickey;
private static void createkeyfile(object key, string filepath) throws exception {
fileoutputstream fos = new fileoutputstream(filepath);
objectoutputstream oos = new objectoutputstream(fos);
oos.writeobject(key);
oos.flush();
oos.close();
}
運作上面的代碼後,将在f盤的key目錄下新産生testpub.key、testpri.key公私鑰檔案。
并在控制台輸出如下内容:
到此為止,公私鑰已生成。
三.驗證上面生成的公私鑰
1.私鑰加簽公鑰驗簽,進行驗證
digestutil.java
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1coRXYwNWaw91dfB3Lc12bj5SZ5VGdp5yMxATMuFWaqlmYvw1LcpDc0RHaiojIsJye.png)
public class digestutil {
/**
* 位元組轉為十六進制字元串
* @param位元組
* @return 十六進制字元串
*/
public static string byte2hex(byte[] b) {
string hs = "";
string stmp = "";
for (int n = 0; b != null && n < b.length; n++) {
stmp = (java.lang.integer.tohexstring(b[n] & 0xff));
if (stmp.length() == 1)
hs = hs + "0" + stmp;
else
hs = hs + stmp;
}
return hs;
* 十六進制字元轉為位元組
* @param 十六進制字元
* @return 位元組
public static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0)
throw new illegalargumentexception("byte length is not correct");
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2) {
string item = new string(b, n, 2);
b2[n / 2] = (byte) integer.parseint(item, 16);
return b2;
* 字元串轉換成十六進制值
* @param bin string 我們看到的要轉換成十六進制的字元串
* @return
*/
public static string bin2hex(string bin) {
char[] digital = "0123456789abcdef".tochararray();
stringbuffer sb = new stringbuffer("");
byte[] bs = bin.getbytes();
int bit;
for (int i = 0; i < bs.length; i++) {
bit = (bs[i] & 0x0f0) >> 4;
sb.append(digital[bit]);
bit = bs[i] & 0x0f;
return sb.tostring();
signutil.java
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1coRXYwNWaw91dfB3Lc12bj5SZ5VGdp5yMxATMuFWaqlmYvw1LcpDc0RHaiojIsJye.png)
import java.security.keyfactory;
import java.security.spec.pkcs8encodedkeyspec;
import org.apache.commons.codec.binary.base64;
public class signutil {
//#prikeytext
private final static string prikeytext = "miievqibadanbgkqhkig9w0baqefaascbkcwggsjageaaoibaqchxmxapt6qg+xtiqacg1czekwgpbky/qs5xgnx4hotnggum2n/5fdztshzofjwsnuukpza+bynhng0e0qn4xrp0wsi+z5lgdewt7dea0b5cky386mewwc11asa+sumir5xfujxdwrmqx5e7wvrcbuoq7a8qbfm3i8f4pdmokhlmviwhlngkorwvkobe8cya25jv2fzgxv1nzvz7zygao60a49x/naa2poe5ob9zxbfsa8kfhl0b+smqmd38uvrtciqs2kabw6egttoezk55i+hhg7nqmlum7xtw8z/t1fpetkgsnkanph7eqrhvhmjudphidx3bitaarw07mviq1lhagmbaaecggeadjpddju4o6nmintidzp78equxd3c09ink293imusqmpz840eueegn2o6w6+vp7oyox3aqk7ctoi5x7vitqmizxkakwnjpzdtjlbpvj4bjgx7fmrshczihxufchdbqc53wunrx5llpahniypoc88fhvv8xhxszxgikh8ip0juyhrs38tdvccrizkclssy9ct3kyhvdpkfweegsb0qj7j4vxk7eve6yqd0/ujqb9j54ts418dsehnozpdf6pfgngl585aqz3kpeurfsx3ryglhug+gqd+bkkdexa7vjlw5v1cf7kr1t/xk9gjqrbrbjtzly0mue11ips3om5lyknv/eqkbgqduwd+i64aladxerejahwu8sqjzgmzyhlmhxfq8rsalj490br3joz2+khxd7ydmvtuj0ifre99bcb7hi9sx0joojys8+rz7bw02bdnwjbva5syg3xojqdeokgl5nfn67rl762jgsdg2y5/hvee/vxmh9swb/ovqz10if3p5oj/jcwkbgqctunl1iwn57xhzqdqqeimlcskgrxelmydu/jtadltt27dgsjzbgw5gggmectvddxyadyb93vuutvz4evhxawo3cepdujs4jtkgzeaanmcer6doiyxpfrsxhmxrn4ngg70yea5u7ifyfa1dugldwjddg4ru122ftqum2ucwaabjwwkbgqc9r9wrufxpioudf4y0qkp7vosgsaybvogeosprqcmfuyt73c5zjg/fyj/sagxymgqxmw70mwur5kzbldit9zqgb9g3owaofgsjxi2fr5iupjjpdnpgqqxt7fohn/yb7ic6k7ojxp1ukt35jonszyktdwi/ogrvskctdrmav1wyvqkbgbzd6qxt/xi5dwjreyzcoixjbwgd1bqkd7eoc64xs8p2lxnktiswrnzrs0//c1i0huv80ogd5eptptutg1o2rsjbsnhbj3zglzmonh1bhc24cr4c/ef4vdycsltguv7iuxaz71a6lfzhho8bibych6covfx5usdysr1c0e1c1fjpaogaxq4hz7/apq/v1wmkznplgchbxefqixvhdzwuviay6samypare3frjd3sflgxhog48cq59a0p3dqjkja8u7eqa6c6qw9ci4f/ccehcdgnh6fokqihmdn6sr0/sinbvp0kqu25y+abrdjjwyzgtmweqmdfura+mvk9befn+ha3zak=";
//#pubkeytext
private final static string pubkeytext = "miibijanbgkqhkig9w0baqefaaocaq8amiibcgkcaqeaov5swj7ekipl04qmghtxgrcsbj2ysv0locrjceb6lz4bldnp/+rxwbuh2ahyvrdvfcqwwvgcp4tynbnej+f66dfkovmes4a3se+w3gng+qpmt/ojbfshndqlgvkrjikevxvi13vqzef+ro8fuxg7qkuwpeax5t4vbed3tkjiztl4sis54cjq1lsqgxphmgnusb9hwymb9tc1we88hmjutgupv/zwgnqahutgfc1wx7gvjhx5dg/rdedhd/lla7qikrnigavuhbk06hs5oeyvor4o56jc7pu17cpm/09x6rlsoljygdaye3qkr1r5o1a6r4ncdwykwak8nozfskts4qidaqab";
private final static string character_encoding_utf_8 = "utf-8";
public static void main(string[] args) {
string signstring = "bijian 您好!";
try {
// 加簽
string localsignature = signutil.sign(prikeytext.getbytes(character_encoding_utf_8), signstring);
system.out.println(localsignature);
//驗簽
boolean verifyresult = signutil.verify(pubkeytext.getbytes(character_encoding_utf_8), signstring, localsignature);
system.out.println("verifyresult:" + verifyresult);
} catch (exception e) {
// todo auto-generated catch block
e.printstacktrace();
* rsa私鑰加簽
* @param prikeytext經過base64處理後的私鑰
* @param plaintext明文内容
* @return 十六進制的簽名字元串
* @throws exception
public static string sign(byte[] prikeytext, string plaintext) throws exception {
pkcs8encodedkeyspec pripkcs8 = new pkcs8encodedkeyspec(base64.decodebase64(prikeytext));
keyfactory keyf = keyfactory.getinstance("rsa");
privatekey prikey = keyf.generateprivate(pripkcs8);
// 用私鑰對資訊生成數字簽名
java.security.signature signet = java.security.signature.getinstance("sha256withrsa");
signet.initsign(prikey);
signet.update(plaintext.getbytes("utf-8"));
return digestutil.byte2hex(signet.sign());
throw e;
* 公鑰驗簽
* @param pubkeytext經過base64處理後的公鑰
* @param signtext十六進制的簽名字元串
* @return 驗簽結果 true驗證一緻 false驗證不一緻
public static boolean verify(byte[] pubkeytext, string plaintext, string signtext) {
// 解密由base64編碼的公鑰,并構造x509encodedkeyspec對象
java.security.spec.x509encodedkeyspec bobpubkeyspec = new java.security.spec.x509encodedkeyspec(
base64.decodebase64(pubkeytext));
// rsa算法
java.security.keyfactory keyfactory = java.security.keyfactory.getinstance("rsa");
// 取公鑰匙對象
java.security.publickey pubkey = keyfactory.generatepublic(bobpubkeyspec);
// 十六進制數字簽名轉為位元組
byte[] signed = digestutil.hex2byte(signtext.getbytes("utf-8"));
java.security.signature signaturechecker = java.security.signature.getinstance("sha256withrsa");
signaturechecker.initverify(pubkey);
signaturechecker.update(plaintext.getbytes("utf-8"));
// 驗證簽名是否正常
return signaturechecker.verify(signed);
} catch (throwable e) {
return false;
運作結果如下,驗簽通過。
2.将f:\key下生成公私鑰驗證加解密
将f:\key下的testpub.key、testpri.key拷貝至工程中
運作如下代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1coRXYwNWaw91dfB3Lc12bj5SZ5VGdp5yMxATMuFWaqlmYvw1LcpDc0RHaiojIsJye.png)
import java.io.ioexception;
import java.io.objectinputstream;
import java.security.key;
import javax.crypto.cipher;
import sun.misc.base64decoder;
public class rsautil2 {
/** 指定加密算法為rsa */
private static final string algorithm = "rsa";
/** 指定公鑰存放檔案 */
private static string public_key_file = "testpub.key";
/** 指定私鑰存放檔案 */
private static string private_key_file = "testpri.key";
string source = "深圳,你好!";// 要加密的字元串
system.out.println("準備用公鑰加密的字元串為:" + source);
string cryptograph = encrypt(source);// 生成的密文
system.out.print("用公鑰加密後的結果為:" + cryptograph);
system.out.println();
string target = decrypt(cryptograph);// 解密密文
system.out.println("用私鑰解密後的字元串為:" + target);
system.out.println();
* 加密方法
* @param source 源資料
* @throws exception
public static string encrypt(string source) throws exception {
key publickey = getkey(public_key_file);
/** 得到cipher對象來實作對源資料的rsa加密 */
cipher cipher = cipher.getinstance(algorithm);
cipher.init(cipher.encrypt_mode, publickey);
byte[] b = source.getbytes();
/** 執行加密操作 */
byte[] b1 = cipher.dofinal(b);
base64encoder encoder = new base64encoder();
return encoder.encode(b1);
* 解密算法
* @param cryptograph 密文
public static string decrypt(string cryptograph) throws exception {
key privatekey = getkey(private_key_file);
/** 得到cipher對象對已用公鑰加密的資料進行rsa解密 */
cipher.init(cipher.decrypt_mode, privatekey);
base64decoder decoder = new base64decoder();
byte[] b1 = decoder.decodebuffer(cryptograph);
/** 執行解密操作 */
byte[] b = cipher.dofinal(b1);
return new string(b);
private static key getkey(string filename) throws exception, ioexception {
key key;
objectinputstream ois = null;
/** 将檔案中的私鑰對象讀出 */
ois = new objectinputstream(new fileinputstream(filename));
key = (key) ois.readobject();
throw e;
} finally {
ois.close();
return key;
運作結果:
附:sun.misc.base64encoder找不到jar包的解決方法
在myeclipse中編寫java代碼時,用到了base64decoder,import sun.misc.base64decoder;可是eclipse提示:
access restriction: the type base64decoder is not accessible due to restriction on required library c:\program
files\java\jre6\lib\rt.jar
access restriction : the constructor base64decoder() is not accessible due to restriction on required library c:\program files\java\jre6\lib\rt.jar
解決方案1(推薦):
隻需要在project build path中先移除jre system library,再添加庫jre system library,重新編譯後就一切正常了。
解決方案2:
右鍵項目->屬性->java bulid path->jre system library->access rules->resolution選擇accessible,下面填上**,點選确定即可!!!
大小: 43.8 kb
大小: 32.1 kb
大小: 58.7 kb
大小: 5.9 kb
大小: 1.6 kb
大小: 11 kb