亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Java安全通信、數(shù)字證書(shū)及應(yīng)用實(shí)踐

系統(tǒng) 1751 0

摘要

  在本文中,我用詳細(xì)的語(yǔ)言和大量的 圖片 及完整的 程序 源碼向你展示了在 JAVA 中如何實(shí)現(xiàn)通過(guò)消息摘要、消息驗(yàn)證碼達(dá)到 安全 通信、以及用Java的工具生成數(shù)字證書(shū),和用程序給數(shù)字證書(shū)簽名、以及用簽名后的數(shù)學(xué)證書(shū)簽名applet突破applet的訪問(wèn)權(quán)限的過(guò)程,給出了全部例子的詳細(xì)代碼。

  通過(guò)本文中你可以學(xué)到以下知識(shí):

程序間如何安全通信

什么是 及 如何生成消息摘要

什么是 及 如何生成消息驗(yàn)證碼

如何使用 Java工具生成和維護(hù)數(shù)字證書(shū)庫(kù)

如何用程序給數(shù)字證書(shū)驗(yàn)證簽名

如何利用數(shù)字證書(shū)給 applet簽名突破applet的訪問(wèn)權(quán)限

關(guān)鍵字

  消息摘要、消息驗(yàn)證碼、指紋、加密、安全、 Java、數(shù)字簽名、applet、數(shù)字證書(shū)

一、基礎(chǔ)知識(shí)

  計(jì)算機(jī)安全通信過(guò)程中,常使用消息摘要和消息驗(yàn)證碼來(lái)保證傳輸?shù)臄?shù)據(jù)未曾被第三方修改。

  消息摘要是對(duì)原始數(shù)據(jù)按照一定算法進(jìn)行計(jì)算得到的結(jié)果,它主要檢測(cè)原始數(shù)據(jù)是否被修改過(guò)。消息摘要與加密不同,加密是對(duì)原始數(shù)據(jù)進(jìn)行變換,可以從變換后的數(shù)據(jù)中獲得原始數(shù)據(jù),而消息摘要是從原始數(shù)據(jù)中獲得一部分信息,它比原始數(shù)據(jù)少得多,因此消息摘要可以看作是原始數(shù)據(jù)的指紋。

  例:下面一段程序計(jì)算一段字符串的消息摘要

package com.messagedigest;
import java.security.*;
public class DigestPass {
 public static void main(String[] args) throws Exception{
  String str="Hello,I sent to you 80 yuan.";
  MessageDigest md = MessageDigest.getInstance("MD5");//常用的有MD5,SHA算法等
  md.update(str.getBytes("UTF-8"));//傳入原始字串
  byte[] re = md.digest();//計(jì)算消息摘要放入byte數(shù)組中
  //下面把消息摘要轉(zhuǎn)換為字符串
  String result = "";
  for(int i=0;i<re.length;i++){
   result += Integer.toHexString((0x000000ff&re[i])|0xffffff00).substring(6);
  }
  System.out.println(result);
 }
}


  當(dāng)我們有時(shí)需要對(duì)一個(gè)文件加密時(shí),以上方式不再適用。

  又例:下面一段程序計(jì)算從輸入(出)流中計(jì)算消息摘要。

package com.messagedigest;
import java.io.*;
import java.security.*;
public class DigestInput {
 public static void main(String[] args) throws Exception{
  String fileName = "test.txt";
  MessageDigest md = MessageDigest.getInstance("MD5");
  FileInputStream fin = new FileInputStream(fileName);
  DigestInputStream din = new DigestInputStream(fin,md);//構(gòu)造輸入流
  //DigestOutputStream dout = new DigestOutputStream(fout,md);
  //使用輸入(出)流可以自己控制何時(shí)開(kāi)始和關(guān)閉計(jì)算摘要
  //也可以不控制,將全過(guò)程計(jì)算
  //初始時(shí)是從開(kāi)始即開(kāi)始計(jì)算,如我們可以開(kāi)始時(shí)關(guān)閉,然后從某一部分開(kāi)始,如下:
  //din.on(false);
  int b;
  while((b=din.read())!=-1){
   //做一些對(duì)文件的處理
   //if(b=='$') din.on(true); //當(dāng)遇到文件中的符號(hào)$時(shí)才開(kāi)始計(jì)算
  }
  byte[] re = md.digest();//獲得消息摘要
  //下面把消息摘要轉(zhuǎn)換為字符串
  String result = "";
  for(int i=0;i<re.length;i++){
   result += Integer.toHexString((0x000000ff&re[i])|0xffffff00).substring(6);
  }
  System.out.println(result);
 }
}


  當(dāng)A和B通信時(shí),A將數(shù)據(jù)傳給B時(shí),同時(shí)也將數(shù)據(jù)的消息摘要傳給B,B收到后可以用該消息摘要驗(yàn)證A傳的消息是否正確。這時(shí)會(huì)產(chǎn)生問(wèn)題,即若傳遞過(guò)程中別人修改了數(shù)據(jù)時(shí),同時(shí)也修改了消息摘要。B就無(wú)法確認(rèn)數(shù)據(jù)是否正確。消息驗(yàn)證碼可以解決這一問(wèn)題。

  使用消息驗(yàn)證碼的前提是 A和B雙方有一個(gè)共同的密鑰,這樣A可以將數(shù)據(jù)計(jì)算出來(lái)的消息摘要加密后發(fā)給B,以防止消息摘要被改。由于使用了共同的密鑰,所以稱(chēng)為“驗(yàn)證碼”。

  例、下面的程序即可利用共同的密鑰來(lái)計(jì)算消息摘要的驗(yàn)證碼

package com.mac;
import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class MyMac {
 public static void main(String[] args) throws Exception{
  //這是一個(gè)消息摘要串
  String str="TestString";
  //共同的密鑰編碼,這個(gè)可以通過(guò)其它算法計(jì)算出來(lái)
  byte[] kb={11,105,-119,50,4,-105,16,38,-14,-111,21,-95,70,-15,76,-74,
    67,-88,59,-71,55,-125,104,42};
  //獲取共同的密鑰
  SecretKeySpec k = new SecretKeySpec(kb,"HMACSHA1");
  //獲取Mac對(duì)象
  Mac m = Mac.getInstance("HmacMD5");
  m.init(k);
  m.update(str.getBytes("UTF-8"));
  byte[] re = m.doFinal();//生成消息碼
  //下面把消息碼轉(zhuǎn)換為字符串
  String result = "";
  for(int i=0;i<re.length;i++){
   result += Integer.toHexString((0x000000ff&re[i])|0xffffff00).substring(6);
  }
  System.out.println(result);
 }
}


  使用以上兩種技術(shù)可以保證數(shù)據(jù)沒(méi)有經(jīng)過(guò)改變,但接收者還無(wú)法確定數(shù)據(jù)是否確實(shí)是某個(gè)人發(fā)來(lái)的。盡管消息碼可以確定數(shù)據(jù)是某個(gè)有同樣密鑰的人發(fā)來(lái)的,但這要求雙方具有共享的密鑰,若有一組用戶共享,我們就無(wú)法確定數(shù)據(jù)的來(lái)源了。

  數(shù)字簽名可以解決這一問(wèn)題。數(shù)字簽名利用非對(duì)稱(chēng)加密技術(shù),發(fā)送者使用私鑰加密數(shù)據(jù)產(chǎn)生的消息摘要(簽名),接收者使用發(fā)送者的公鑰解密消息摘要以驗(yàn)證簽名是否是某個(gè)人的。由于私鑰只有加密者才有,因此如果接收者用某個(gè)公鑰解密了某個(gè)消息摘要,就可以確定這段消息摘要必然是對(duì)應(yīng)的私鑰持有者發(fā)來(lái)的。

  使用數(shù)字簽名的前提是接收數(shù)據(jù)者能夠確信驗(yàn)證簽名時(shí)(用發(fā)送者的私鑰加密消息摘要)所用的公鑰確實(shí)是某個(gè)人的 (因?yàn)橛锌赡苡腥思俑婀€)。數(shù)字證書(shū)可以解決這個(gè)問(wèn)題。

  數(shù)字證書(shū)含有兩部分?jǐn)?shù)據(jù):一部分是對(duì)應(yīng)主體(單位或個(gè)人)的信息,另一部分是這個(gè)主體所對(duì)應(yīng)的公鑰。即數(shù)字證書(shū)保存了主體和它的公鑰的一一對(duì)應(yīng)關(guān)系。同樣,數(shù)字證書(shū)也有可能被假造,如何判定數(shù)字證書(shū)的內(nèi)容的真實(shí)性呢?所以,有效的數(shù)字證書(shū)必須經(jīng)過(guò)權(quán)威 CA的簽名,即權(quán)威CA驗(yàn)證數(shù)字證書(shū)的內(nèi)容的真實(shí)性,然后再在數(shù)字證書(shū)上使用自己的私鑰簽名(相當(dāng)于在證書(shū)加章確認(rèn))。

  這樣,當(dāng)用戶收到這樣的數(shù)字證書(shū)后,會(huì)用相應(yīng)的權(quán)威 CA的公鑰驗(yàn)證該證書(shū)的簽名(因?yàn)闄?quán)威的CA的公鑰在 操作系統(tǒng) 中己經(jīng)安裝)。根據(jù)非對(duì)稱(chēng)加密的原理,如果該證書(shū)不是權(quán)威CA簽名的,將不能通過(guò)驗(yàn)證,即該證書(shū)是不可靠的。

  若通過(guò)驗(yàn)證,即可證明此證書(shū)含的信息(發(fā)信人的公鑰和信息)是無(wú)誤的。于是可以信任該證書(shū),便可以通過(guò)該證書(shū)內(nèi)含的公鑰來(lái)確認(rèn)數(shù)據(jù)確實(shí)是發(fā)送者發(fā)來(lái)的。

  于是,雙方通信時(shí), A把數(shù)據(jù)的消息摘要用自己的私鑰加密(即簽名),然后把自己的數(shù)字證書(shū)和數(shù)據(jù)及簽名后的消息摘要一起發(fā)送給B,B處查看A的數(shù)字證書(shū),如果A的數(shù)字證書(shū)是經(jīng)過(guò)權(quán)威CA驗(yàn)證可靠的,便信任A,便可使用A的數(shù)字證書(shū)中附帶的A的公鑰解密消息摘要(這一過(guò)程同時(shí)確認(rèn)了發(fā)送數(shù)據(jù)的人又可以解密消息摘要),然后通過(guò)解密后的消息摘要驗(yàn)證數(shù)據(jù)是否正確無(wú)誤沒(méi)被修改。

  利用這一原理,我們可以突破 java的applet小程序在瀏覽器中的權(quán)限,由于默認(rèn)的applet權(quán)限控制不允許它訪問(wèn)操作系統(tǒng)級(jí)的一切。于是我們可以用我們數(shù)字證書(shū)來(lái)給 applet簽名,然后客戶端收到該applet時(shí),系統(tǒng)會(huì)自動(dòng)查看給該applet簽名的數(shù)字證書(shū)并提供給終端用戶判定是否信認(rèn)該數(shù)字證書(shū),如果用戶信認(rèn),則該applet便有了訪問(wèn)系統(tǒng)的權(quán)限。

?

二、 Java中的數(shù)字證書(shū)的生成及維護(hù)方法

  Java中的keytool.exe可以用來(lái)創(chuàng)建數(shù)字證書(shū),所有的數(shù)字證書(shū)是以一條一條(采用別名區(qū)別)的形式存入證書(shū)庫(kù)的中,證書(shū)庫(kù)中的一條證書(shū)包含該條證書(shū)的私鑰,公鑰和對(duì)應(yīng)的數(shù)字證書(shū)的信息。證書(shū)庫(kù)中的一條證書(shū)可以導(dǎo)出數(shù)字證書(shū)文件,數(shù)字證書(shū)文件只包括主體信息和對(duì)應(yīng)的公鑰。

  每一個(gè)證書(shū)庫(kù)是一個(gè)文件組成,它有訪問(wèn)密碼,在首次創(chuàng)建時(shí),它會(huì)自動(dòng)生成證書(shū)庫(kù),并要求指定訪問(wèn)證書(shū)庫(kù)的密碼。

  在創(chuàng)建證書(shū)的的時(shí)候,需要填寫(xiě)證書(shū)的一些信息和證書(shū)對(duì)應(yīng)的私鑰密碼。這些信息包括 CN=xx,OU=xx,O=xx,L=xx,ST=xx,C=xx,它們的意思是:

  CN(Common Name名字與姓氏)

  OU(Organization Unit組織單位名稱(chēng))

  O(Organization組織名稱(chēng))

  L(Locality城市或區(qū)域名稱(chēng))

  ST(State州或省份名稱(chēng))

  C(Country國(guó)家名稱(chēng))

  可以采用交互式讓工具提示輸入以上信息,也可以采用參數(shù)

-dname "CN=xx,OU=xx,O=xx,L=xx,ST=xx,C=xx"來(lái)自動(dòng)創(chuàng)建。

1、示例

  如下所示一句采用交互式創(chuàng)建一個(gè)證書(shū),指定證書(shū)庫(kù)為 abnerCALib,創(chuàng)建別名為abnerCA的一條證書(shū),它指定用RSA算法生成,

  且指定密鑰長(zhǎng)度為 1024,證書(shū)有效期為3650天:

C:/j2sdk1.4.1_01/mykeystore>keytool -genkey -alias abnerCA -keyalg RSA -keysize 1024 -keystore abnerCALib -validity 3650


  如下圖所示:


  上圖中最后一步,我們輸入的是 CN,代表中國(guó)的縮寫(xiě),也可以直接輸入“中國(guó)”兩個(gè)字。

2、證書(shū)的操作方法

證書(shū)的顯示

  如:

keytool –list –keystore abnerCALib


  將顯示 abnerCALib證書(shū)庫(kù)的的所有證書(shū)列表:如下圖示:


  又如: keytool -list -alias abnerCA -keystore abnerCALib

  將顯示 abnerCALib證書(shū)庫(kù)中別名為abnerCA的證書(shū)的信息。如下圖所示:


  又如: keytool -list -v -alias abnerCA -keystore abnerCALib

  將顯示證書(shū)的詳細(xì)信息( -v參數(shù))如下圖所示:



將證書(shū)導(dǎo)出到證書(shū)文件

  如: keytool -export -alias abnerCA -file abnerCA.cer -keystore abnerCALib
  將把證書(shū)庫(kù) abnerCALib中的別名為abnerCA的證書(shū)導(dǎo)出到abnerCA.cer證書(shū)文件中,

  它包含證書(shū)主體的信息及證書(shū)的公鑰,不包括私鑰,可以公開(kāi),如下圖所示 :


  上面導(dǎo)出的證書(shū)文件是以二進(jìn)制編碼文件,無(wú)法用文本編輯器正確顯示,因此不利用公布證書(shū),可以加上 -rfc參數(shù)以一種可打印的編者編碼輸出。

  如:

keytool -export -alias abnerCA -file abnerCA.cer -keystore abnerCALib -storepass 100200 –rfc


  這個(gè)命令在命令行中指定了證書(shū)庫(kù)的訪問(wèn)密碼,同時(shí)指定以可查看編碼的方式輸出。

3、通過(guò)證書(shū)文件查看證書(shū)的信息

  通過(guò)命令 :keytool –printcert –file abnerCA.cer可以查看證書(shū)文件的信息。

  也可以在 windows中雙擊產(chǎn)生的證書(shū)文件直接查看。

證書(shū)條目的刪除

  keytool的命令行參數(shù)-delete可以刪除密鑰庫(kù)中的條目,如:

keytool -delete -alias abnerCA -keystore abnerCALib


  這條命令將 abnerCALib庫(kù)中的abnerCA這一條證書(shū)刪除了。

證書(shū)條目口令的修改

  如:

keytool –keypasswd –alias abnerCA –keystore abnerCALib


  可以以交互的方式修改 abnerCALib證書(shū)庫(kù)中的條目為abnerCA的證書(shū)。

Keytool –keypasswd –alias abnerCA –keypass 123456 –new 200100 –storepass 1002 00 –keystore abnerCALib


  這一行命令以非交互式的方式修改庫(kù)中別名為 abnerCA的證書(shū)的密碼為新密碼123456,行中的200100是指該條證書(shū)的原密碼, 1002 00是指證書(shū)庫(kù)的密碼。

?

三、數(shù)字證書(shū)的簽發(fā)(簽名)

  我們?cè)谏厦鎰?chuàng)建好了數(shù)字證書(shū),但這些數(shù)字證書(shū)還沒(méi)有經(jīng)過(guò)權(quán)威 CA的證實(shí)(即簽名)。一般情況下,我們需要將這些證書(shū)發(fā)送給權(quán)威的CA,并申請(qǐng)其簽名以確認(rèn)數(shù)字證書(shū)讓客戶信任。

  下面我們將模仿自己是一個(gè)權(quán)威的數(shù)字證書(shū)認(rèn)證機(jī)構(gòu) CA,這個(gè)機(jī)構(gòu)將采用自己的私鑰來(lái)簽發(fā)其它的證書(shū)。這個(gè)簽發(fā)過(guò)程是這樣的:我們自己是CA,我們自己有一個(gè)自簽的數(shù)字證書(shū)存入數(shù)字證書(shū)庫(kù)中。在數(shù)字證書(shū)庫(kù)中的這個(gè)我們的CA數(shù)字證書(shū),它含有私鑰,公鑰和我們這個(gè)CA的主體信息。下面這一個(gè)指令可以創(chuàng)建一個(gè)CA的自簽的數(shù)字證書(shū):

   keytool –genkey –dname “CN=美森系統(tǒng)軟件有限公司,OU=美森系統(tǒng)軟件有限公司,O=美森系統(tǒng)軟件有限公司,L=成都市,ST=四川省,C=中國(guó)” –alias MissionCA –keyalg RSA –keysize 1024 –keystore abnerCALib –keypass 200100 –storepass 100200 –validity 3650

  上面,我們?cè)?abnerCALib這個(gè)數(shù)字證書(shū)庫(kù)中創(chuàng)建了一個(gè)別名為:missionCA、有效期為3650天、算法為RSA且密鑰長(zhǎng)度為1024的數(shù)字證書(shū),這條證書(shū)的私鑰密碼為:200100,證書(shū)庫(kù)的訪問(wèn)密碼為:100200。這條別名為missionCA的證書(shū)代表我們自己的權(quán)威CA即:美森系統(tǒng)軟件有限公司這個(gè)權(quán)威CA。以后我們將用這個(gè)證書(shū)來(lái)簽名其它的數(shù)字證書(shū)。

  現(xiàn)在我要給自己申請(qǐng)一個(gè)數(shù)字證書(shū),我可以這么做:先在數(shù)字證書(shū)庫(kù)中創(chuàng)建一條證書(shū):

keytool –genkey –dname “CN=柴政,OU=美森系統(tǒng)軟件有限公司,O=美森系統(tǒng)軟件有限公司,L=成都市,ST=四川省,C=中國(guó)” –alias abnerCA –keyalg RSA –keysize 1024 –keystore abnerCALib –keypass 200100 –storepass 100200 –validity 3650

  這樣創(chuàng)建了一個(gè)別名為 abnerCA的數(shù)字證書(shū),我們可以將它導(dǎo)出為cer文件(見(jiàn)前)。

  接著,我們可以用上一步生成的 CA的自簽證書(shū)來(lái)簽名我這個(gè)數(shù)字證書(shū)了。

  CA簽名數(shù)字證書(shū)的過(guò)程需用以下程序來(lái)進(jìn)行,這個(gè)程序是自解釋的:

package com.security;
import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import java.math.*;
import sun.security.x509.*;
/**
* <p>Description: 該程序根據(jù)簽發(fā)者(CA)的證書(shū)信息(即CA的私鑰)來(lái)對(duì)被簽發(fā)者
* 的證書(shū)進(jìn)行簽名,過(guò)程即是使用CA的證書(shū)和被簽證書(shū)來(lái)重構(gòu)形成一個(gè)新的證書(shū)</p>
* @author abnerchai
* @version 1.0
*/

 public class SignCert {
  public static void main(String[] args) throws Exception{
   char[] storepass = "100200".toCharArray();
   //存放CA證書(shū)和被簽證書(shū)的證書(shū)庫(kù)的訪問(wèn)密碼
   char[] cakeypass = "200100".toCharArray();//CA數(shù)字證書(shū)條目的訪問(wèn)密碼
   String alias = "missionCA";
   //CA證書(shū)在證書(shū)庫(kù)中的別名,這個(gè)CA的證書(shū)用來(lái)簽名其它的證書(shū)
   String name = "abnerCALib";//存放CA證書(shū)和被簽證書(shū)的證書(shū)庫(kù)的名字
   String newLib = "SignedLib";
   //新證書(shū)庫(kù)的名字,如果需要將簽名后的證書(shū)放入新庫(kù),這是新庫(kù)的名字
   char[] newLibPass = "100200".toCharArray();//設(shè)置新庫(kù)的訪問(wèn)密碼
   String cerFileName = "abnerCA.cer";//被簽證書(shū)的證書(shū)文件名
   String aliasName = "abnerCA";//被簽證書(shū)在證書(shū)庫(kù)中的alias別名
   char[] namePass = "200100".toCharArray();
   //被簽證書(shū)的條目在證書(shū)庫(kù)的私鑰密碼
   int n =3; //被簽證書(shū)的有效期,以年為單位,以當(dāng)前時(shí)間開(kāi)始計(jì)算
   int sn = 200406001;
   //序列號(hào)可自己定義,這里定義的意義為2004年6月簽發(fā),是本年度CA簽發(fā)的第多少個(gè)以001計(jì)算,要求唯一
   String afteraliasName = "abnerCA_Signed";
   //簽名后新產(chǎn)生的被簽過(guò)名的證書(shū)在庫(kù)中的別名
   char[] afterNewPass = "200100".toCharArray();
   //簽名后新產(chǎn)生的被簽過(guò)名的證書(shū)在庫(kù)的條目的私鑰的密碼
   //裝載證書(shū)庫(kù)
   FileInputStream in = new FileInputStream(name);
   KeyStore ks = KeyStore.getInstance("JKS");//JKS為證書(shū)庫(kù)的類(lèi)型
   ks.load(in,storepass);
   //從證書(shū)庫(kù)中讀出簽發(fā)者(CA)的證書(shū)
   java.security.cert.Certificate cl = ks.getCertificate(alias);
   //讀出一個(gè)CA證書(shū),這里的l是字母l不是數(shù)據(jù)字1
   PrivateKey privateKey = (PrivateKey)ks.getKey(alias,cakeypass);
   //根據(jù)別名和證書(shū)密碼讀出CA證書(shū)的私鑰
   in.close();
   //從證書(shū)庫(kù)中讀出的簽發(fā)者(CA)的證書(shū)中提取簽發(fā)者的信息
   byte[] encodl = cl.getEncoded();//提取證書(shū)的編碼,這里是字母l不是數(shù)據(jù)字1
   X509CertImpl cimpl = new X509CertImpl(encodl);
   //這里是字母l不是數(shù)據(jù)字1,根據(jù)證書(shū)的編碼創(chuàng)建X509CertImpl類(lèi)型的對(duì)象
   //根據(jù)上面的對(duì)象獲得X509CertInfo類(lèi)型的對(duì)象,該對(duì)象封裝了證書(shū)的全部?jī)?nèi)容。
   X509CertInfo cinfo_first =
    (X509CertInfo)cimpl.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
   //然后獲得X500Name類(lèi)型的簽發(fā)者信息
   X500Name issuer = (X500Name)
   cinfo_first.get(X509CertInfo.SUBJECT+"."+CertificateIssuerName.DN_NAME);
   //獲取待簽發(fā)的證書(shū),即獲取被簽發(fā)者的證書(shū)
   //可從密鑰庫(kù)中獲取,也可從導(dǎo)出的證書(shū)文件中獲取,這里給出兩種方式   ////////////////////////////////////////////////////////////////////////

//方式一、采用從導(dǎo)出的cer文件中獲取 start

///////////////////////////////////////////////////////////////////////////////

/*

  CertificateFactory cf = CertificateFactory.getInstance("X.509");
  //X.509是使用最多的一種數(shù)字證書(shū)標(biāo)準(zhǔn)

  FileInputStream in2 = new FileInputStream(cerFileName);//被簽證書(shū)文件

  java.security.cert.Certificate c2 = cf.generateCertificate(in2);
  //生成需要被簽的證書(shū)
  in2.close();
  byte[] encod2 = c2.getEncoded();
  X509CertImpl cimp2 = new X509CertImpl(encod2);

  //獲得被簽證書(shū)的詳細(xì)內(nèi)容,然后根據(jù)這個(gè)證書(shū)生成新證書(shū)

  X509CertInfo cinfo_second =
   (X509CertInfo)cimp2.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
*/

///////////////////////////////////////////////////////////////////////////////

//end 方式一

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

//方式二、從證書(shū)庫(kù)中讀出被簽的證書(shū) start

///////////////////////////////////////////////////////////////////////////////

  java.security.cert.Certificate c3 = ks.getCertificate(aliasName);
  //從證書(shū)庫(kù)中讀出被簽證書(shū),然后生成新的證書(shū)
  byte[] encod3 = c3.getEncoded();
  X509CertImpl cimp3 = new X509CertImpl(encod3);
  X509CertInfo cinfo_second =
   (X509CertInfo)cimp3.get(X509CertImpl.NAME+"."+X509CertImpl.INFO); ///////////////////////////////////////////////////////////////////////////

//end方式二

/////////////////////////////////////////////////////////////////////////// //設(shè)置新證書(shū)的有效期,使之為當(dāng)前向后n年有效,新證書(shū)的

  //截止日期不能超過(guò)CA證書(shū)的有效日期

  Date beginDate = new Date();
  Calendar cal = Calendar.getInstance();
  cal.setTime(beginDate);
  cal.add(cal.YEAR,n);
  Date endDate = cal.getTime();
  CertificateValidity cv = new CertificateValidity(beginDate,endDate);
  cinfo_second.set(X509CertInfo.VALIDITY,cv);
  //設(shè)置新證書(shū)的序列號(hào)

  CertificateSerialNumber csn = new CertificateSerialNumber(sn);
  cinfo_second.set(X509CertInfo.SERIAL_NUMBER,csn);
  //設(shè)置新證書(shū)的簽發(fā)者
  cinfo_second.set(X509CertInfo.ISSUER+"."+CertificateIssuerName.DN_NAME,issuer);
  //新的簽發(fā)者是CA的證書(shū)中讀出來(lái)的

  //設(shè)置新證書(shū)的算法,指定CA簽名該證書(shū)所使用的算法為md5WithRSA

  AlgorithmId algorithm = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
  cinfo_second.set(CertificateAlgorithmId.NAME+"."+
  CertificateAlgorithmId.ALGORITHM,algorithm);

  //創(chuàng)建新的簽名后的證書(shū)

  X509CertImpl newcert = new X509CertImpl(cinfo_second);

  //簽名,使用CA證書(shū)的私鑰進(jìn)行簽名,簽名使用的算法為MD5WithRSA

  newcert.sign(privateKey,"MD5WithRSA");//這樣便得到了經(jīng)過(guò)CA簽名后的證書(shū)

  //把新證書(shū)存入證書(shū)庫(kù)
  //把新生成的證書(shū)存入一個(gè)新的證書(shū)庫(kù),也可以存入原證書(shū)庫(kù),
  //存入新證書(shū)庫(kù),則新證書(shū)庫(kù)中不僅包含原證書(shū)庫(kù)中的所有條目,
  //而且新增加了一個(gè)這次產(chǎn)生的條目。注意,這時(shí),新產(chǎn)生的簽名后的證書(shū)只
  //包括公鑰和主體信息及簽名信息,不包括私鑰信息。這里給出兩種方式。
///////////////////////////////////////////////////////////////////////////

//方式一:存入新密鑰庫(kù)

///////////////////////////////////////////////////////////////////////////

/*

ks.setCertificateEntry(afteraliasName,newcert);
FileOutputStream out = new FileOutputStream(newLib);
//存入新庫(kù)signedLib,并設(shè)置新庫(kù)的庫(kù)訪問(wèn)密碼
ks.store(out,newLibPass);
out.close();
*/

///////////////////////////////////////////////////////////////////////////

//end 方式一

///////////////////////////////////////////////////////////////////////////

//也可以采用另外一種方式,存入原證書(shū)庫(kù)中

//存入原庫(kù)中,即在原證書(shū)庫(kù)中增加一條證書(shū),這個(gè)證書(shū)是原證書(shū)經(jīng)過(guò)簽名后的證書(shū)

//這個(gè)新證書(shū)含有私鑰和私鑰密碼

///////////////////////////////////////////////////////////////////////////

//方式二,存入原密鑰庫(kù)

///////////////////////////////////////////////////////////////////////////

//先在原庫(kù)中讀出被簽證書(shū)的私鑰

PrivateKey prk = (PrivateKey)ks.getKey(aliasName,namePass);
java.security.cert.Certificate[] cchain = {newcert};
//存入原來(lái)的庫(kù),第二個(gè)參數(shù)為原證書(shū)的私鑰,第三個(gè)參數(shù)為新證書(shū)的私鑰密碼,第三個(gè)參數(shù)為新證書(shū)

ks.setKeyEntry(afteraliasName,prk,afterNewPass,cchain); //用新密鑰替代原來(lái)的沒(méi)有簽名的證書(shū)的密碼

FileOutputStream out2 = new FileOutputStream(name);
ks.store(out2,storepass);//存入原來(lái)的庫(kù)中,第二個(gè)參數(shù)為該庫(kù)的訪問(wèn)密碼

///////////////////////////////////////////////////////////////////////////

//end 方式二

///////////////////////////////////////////////////////////////////////////

}

}


  運(yùn)行以上程序,即可運(yùn)用 MissionCA證書(shū)來(lái)簽發(fā)abnerCA證書(shū),運(yùn)行后在abnerCALib中增加一條別名為abnerCA_Signed的數(shù)字證書(shū),我們將它導(dǎo)出為cer文件(導(dǎo)出方法見(jiàn)前)。

  至此,我們己經(jīng)用 CA的證書(shū)以我們的數(shù)字證書(shū)簽名了。在windows中,雙擊導(dǎo)出的abnerCA_Signend.cer文件,出現(xiàn)如下圖所示:


  上圖中證書(shū)信息一欄顯示“不能驗(yàn)證該證書(shū)”,原因是因?yàn)椋覀兊倪@個(gè)數(shù)字證書(shū)的簽發(fā)者 missionCA證書(shū)沒(méi)有安裝到系統(tǒng)中。我們可以將證書(shū)庫(kù)中別名為missionCA的自簽數(shù)字證書(shū)導(dǎo)出為cer文件,然后安裝到系統(tǒng)中。再次查雙擊看此證書(shū),如下圖所示:



  到此,我們己經(jīng)獲得了一個(gè)由我們自己的 CA簽名頒發(fā)的個(gè)人數(shù)字證書(shū)。并且將我們自己的CA證書(shū)安裝到系統(tǒng)中成為系統(tǒng)信任的根證書(shū)。于是,以后只要是由我們的這個(gè)CA證書(shū)簽名頒發(fā)的數(shù)字證書(shū)都會(huì)受到系統(tǒng)的信任。

?

?

四、利用數(shù)字證書(shū)給 applet簽名

  現(xiàn)在假設(shè)我們公司給 xx公司做一個(gè)項(xiàng)目,這個(gè)項(xiàng)目中需要用到applet,且這些applet需要特權(quán)以實(shí)現(xiàn)一些特殊的功能(如讀出客戶端用戶系統(tǒng)中C:/winNT /system.ini文件中的內(nèi)容并顯示)。那么我們可以頒發(fā)一個(gè)數(shù)字證書(shū),并給這個(gè)數(shù)字證書(shū)簽名,然后用簽名后的這個(gè)數(shù)字證書(shū)來(lái)簽名我們的 applet,使客戶信任。具體過(guò)程如下:

  1、生成一個(gè)用于此項(xiàng)目簽名 applet 的數(shù)字證書(shū),別名定為: mission_water

  生成一個(gè)用于此項(xiàng)目簽名的數(shù)字證書(shū)如下:

  keytool –genkey –dname “CN=美森軟件-水公司項(xiàng)目,OU=美森系統(tǒng)軟件有限公司,O=美森系統(tǒng)軟件有限公司,L=成都市,ST=四川省,C=中國(guó)” –alias Mission_Water –keyalg RSA –keysize 1024 –keystore abnerCALib –keypass 200100 –storepass 100200 –validity 3650

  2、用我們的 CA(missinCA) 來(lái)簽發(fā)這個(gè)數(shù)字證書(shū)

  然后,運(yùn)行我們?cè)谇懊娴谌?jié)中給定的程序,注意:運(yùn)行此程序前,請(qǐng)修改以下參數(shù):

String cerFileName = "Mission_Water.cer";

String aliasName = "Mission_Water";

String afteraliasName = "Mission_Water_Signed";


  然后運(yùn)行,程序會(huì)在 abnerCALib證書(shū)庫(kù)中產(chǎn)生一個(gè)別名為:Mission_Water_Signed的數(shù)字證書(shū),這個(gè)證書(shū)是經(jīng)過(guò)我們的CA(MissionCA)簽發(fā)的。

  下面,我們用以下指令導(dǎo)出這個(gè)證書(shū):

keytool -export -alias Mission_Water_Signed -file Mission_Water_Signed.cer -keystore abnerCALib -rfc


  會(huì)生成一個(gè) Mission_Water_Signed.cer 文件。

  3、用簽發(fā)后的數(shù)字證書(shū)來(lái)簽名我們的 applet

  我們現(xiàn)在來(lái)做一個(gè)簡(jiǎn)單的 applet,它的代碼如下:

package com.applet;

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

import javax.swing.*;

import java.io.*;

public class ShowFileApplet extends JApplet {

private boolean isStandalone = false;

private String content = "文件的內(nèi)容是:"; //自定義的提示信息

private String fileName = "C://WINNT//system.ini";//讀出這個(gè)文件的內(nèi)容

private TextArea ta = new TextArea(10,80);//自定義的輸出框

public String getParameter(String key, String def) {

return isStandalone ? System.getProperty(key, def) :

(getParameter(key) != null ? getParameter(key) : def);

}

public ShowFileApplet() {

}

public void init() {

try {

jbInit();

myInit();//自己定義的方法

}

catch(Exception e) {

e.printStackTrace();

}

}

private void jbInit() throws Exception {

this.setSize(new Dimension(400,300));

}

/**

* 自定義的初始化方法,讀入系統(tǒng)中的一個(gè)文件的內(nèi)容并保存起來(lái),然后,增加一個(gè)

* 可視化的輸出框

*/

private void myInit(){

String s;

BufferedReader in;

try {

in = new BufferedReader(new FileReader(fileName));

while ( (s = in.readLine()) != null) {

content +=s + "/n";

}

}catch (IOException ex) {

ex.printStackTrace();

}

System.out.println(content);

ta.setText(content);

getContentPane().add(ta);

}

/*

*重載的方法,輸出內(nèi)容

**/

public void paint(Graphics g){

ta.setText(content);

}

public String getAppletInfo() {

return "Applet Information";

}

public String[][] getParameterInfo() {

return null;

}

//static initializer for setting look & feel

static {

try {

}

catch(Exception e) {

}

}

}


  好了,這個(gè) applet寫(xiě)好了,下面我們來(lái)把這個(gè)applet編譯打包成jar文件。

  編譯此 applet文件,會(huì)在當(dāng)前目錄(當(dāng)前目錄為classes目錄)下生成一個(gè)com/applet的目錄結(jié)構(gòu),在applet目錄下有一個(gè)ShowFileApplet.class,進(jìn)入當(dāng)前目錄,執(zhí)行:

jar cvf myapplet.jar com/applet/*.*


  于是在當(dāng)前目錄下產(chǎn)生一個(gè) myapplet.jar文件。

  然后再在當(dāng)前目錄(當(dāng)前目錄為 classes目錄)下新建一個(gè)applet目錄,專(zhuān)門(mén)存放applet的jar文件,把前面生成的數(shù)字證書(shū)庫(kù)abnerCALib這個(gè)文件也copy到 applet目錄下面來(lái),同時(shí)把剛才生成的myapplet.jar文件也移到applet目錄下面來(lái)。然后進(jìn)入該目錄執(zhí)行:

jarsigner -keystore abnerCALib myapplet.jar Mission_Water_Signed

Enter Passphrase for keystore: 100200

Enter key password for Mission_Water_Signed: 200100


  即用 Mission_Water_Signed這個(gè)我們的CA簽發(fā)的數(shù)字證書(shū)給這個(gè)applet簽名了。

4、運(yùn)行我們的 applet

  我們來(lái)寫(xiě)一個(gè) html文件來(lái)運(yùn)行這個(gè)簽名后的applet,內(nèi)容如下:

<!-- ShowFileApplet.html -->

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=GB2312">

<title>HTMLTestPage</title>

</head><body>

applet將會(huì)顯示,如果你的瀏覽器支持Java<br>

<applet

archive = "./applet/myapplet.jar"

code = "com.applet.ShowFileApplet.class"

name = "TestApplet"

width = "400"

height = "300"

hspace = "0"

vspace = "0"

align = "middle"



</applet>

</body>

</html>


  這個(gè) HTML文件可以運(yùn)行applet,但如果瀏覽器不支持Java,即沒(méi)有安裝JRE,它不會(huì)提示用戶去下載安裝。我們可以用Java自帶的 htmlconverter工具轉(zhuǎn)換一下這個(gè)HTML文件,轉(zhuǎn)換后的文件可以在支持JAVA2的瀏覽器中(不管該瀏覽器是否設(shè)置了使用java2運(yùn)行 applet,它都會(huì)在Java2環(huán)境中運(yùn)行applet,如果瀏覽器不支持Java2,則會(huì)自動(dòng)下載所需的文件。

  在 DOS方式下運(yùn)行htmlconverter,彈出如下圖所示畫(huà)框,按圖中所示選擇剛才的那個(gè)HTML文件,如下圖所示:



  點(diǎn)“轉(zhuǎn)換”,將會(huì)在當(dāng)前目錄下生成一個(gè) HTML文件,并把原來(lái)的HTML文件備份了。

  生成后的 HTML文件內(nèi)容如下所示:

<!-- ShowFileApplet.html -->

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=GB2312">

<title>HTMLTestPage</title>

</head>

<body>

applet將會(huì)顯示,如果你的瀏覽器支持Java<br>

<OBJECT

classid = "clsid:CAFEEFAC-0014-0001-0001-ABCDEFFEDCBA"

codebase = "http://java.sun.com/products/plugin/autodl/jinstall-1_4_1_01-windows-i586.cab#Version=1,4,1,1"

WIDTH = "400" HEIGHT = "300" NAME = "TestApplet" ALIGN = "middle" VSPACE = "0" HSPACE = "0" >

<PARAM NAME = CODE VALUE = "com.applet.ShowFileApplet.class" >

<PARAM NAME = ARCHIVE VALUE = "./applet/myapplet.jar" >

<PARAM NAME = NAME VALUE = "TestApplet" >

<PARAM NAME = "type" VALUE = "application/x-java-applet;jpi-version=1.4.1_01">

<PARAM NAME = "scriptable" VALUE = "false">

<COMMENT>

<EMBED

type = "application/x-java-applet;jpi-version=1.4.1_01"

CODE = "com.applet.ShowFileApplet.class"

ARCHIVE = "./applet/myapplet.jar"

NAME = "TestApplet"

WIDTH = "400"

HEIGHT = "300"

ALIGN = "middle"

VSPACE = "0"

HSPACE = "0"

scriptable = false

pluginspage = "http://java.sun.com/products/plugin/index.html#download">

<NOEMBED>

</NOEMBED>

</EMBED>

</COMMENT>

</OBJECT>

</body>

</html>


  雙擊打開(kāi)運(yùn)行這個(gè)文件或把這個(gè)文件及 applet目錄發(fā)布到WEB Server中去,可以訪問(wèn)運(yùn)行這個(gè)applet。運(yùn)行時(shí),彈出如下圖所示對(duì)話框:


  如果此時(shí)你點(diǎn)“是”,則在這次會(huì)話過(guò)程中,此 applet具有訪問(wèn)本地文件系統(tǒng)的權(quán)限,但下次運(yùn)行時(shí)還要提示此信息。如果你點(diǎn)“總是有效”則以后每次訪問(wèn)此類(lèi)含有由 Mission_Water_Signed數(shù)字證書(shū)簽發(fā)的applet頁(yè)面,都不會(huì)再?gòu)棾龃诉x擇框。因?yàn)椋耗氵x擇了總是有效,這樣,Java會(huì)在Java Plug-in中記錄這個(gè)信任的數(shù)字證書(shū),除非你把Java Plug-in中記錄的這個(gè)信任證書(shū)刪除。在win2k中,可以在“控制面版”->Java Plug-in中看到。如下圖所示:


  點(diǎn)選擇“總是有效”后,該程序運(yùn)行的結(jié)果如下圖所示:

Java安全通信、數(shù)字證書(shū)及應(yīng)用實(shí)踐


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 波多野结衣免费免费视频一区 | 99久久精品免费观看区一 | 免费亚洲成人 | 免费一级欧美片片线观看 | 自拍亚洲国产 | 4hutv四虎最新地址 | 日本人的色道www免费一区 | 久久国产精品免费 | 亚洲日本久久一区二区va | 日本精品久久久一区二区三区 | 视色视频在线 | 亚洲欧美在线视频免费 | 91国色| 久久成人精品免费播放 | 特片我不卡 | 日本高清一道本 | 日本欧美一区二区三区在线 | 精品一区二区久久 | 国产精品久久久久影院色 | 狠狠色丁香婷婷综合久久片 | 久草热在线 | 国产高清精品自在线看 | 深夜影院老司机69影院 | 男人的天堂欧美精品色偷偷 | 国产精品国产三级国产a | 99色视频在线 | 国产精品呦呦 | 天天摸天天舔天天操 | 国产在线19禁免费观看国产 | 青草青青在线视频观看 | 免费国产小视频在线观看 | 九九精品视频在线播放 | 天天操夜夜爽 | 国产精品午夜免费福利视频 | 国产第一综合另类色区奇米 | 在线观看自拍视频 | 国产精品成人四虎免费视频 | 免费在线观看h片 | 99视频全部看免费观 | 91网站国产 | 欧美日韩中文视频 |