日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

論Java加密技術(shù)與Windows的結(jié)合

系統(tǒng) 3600 0

  公共鑰匙加密技術(shù)需要一個(gè)空間來(lái)存儲(chǔ)數(shù)字證書和私鑰。通過(guò)將鑰匙和證書存儲(chǔ)到一個(gè)文件中(稱為keystore),Java Security Architecture實(shí)現(xiàn)了獨(dú)立于平臺(tái)的加密技術(shù)。

  Microsoft Windows把鑰匙和證書存儲(chǔ)到Windows注冊(cè)表和文件系統(tǒng)中。這就是說(shuō),在Windows系統(tǒng)上運(yùn)行安全的Java程序的用戶必須在Java和Microsoft的鑰匙和證書庫(kù)之間輸入和輸出鑰匙和證書。好消息是,你可以“哄騙”Java應(yīng)用程序通過(guò)Microsoft本地函數(shù)來(lái)運(yùn)用Microsoft的證書和鑰匙庫(kù)。

  通過(guò)將你的Java應(yīng)用程序同Windows 鑰匙/證書庫(kù)結(jié)合起來(lái),你雖然犧牲了平臺(tái)獨(dú)立性,但你得到了四個(gè)好處:減少了管理和支持的成本、更方便用戶使用、更好的證書撤消校驗(yàn)、以及更好的鑰匙和證書管理工具。

  一個(gè)Java程序必須通過(guò)四個(gè)不同的類實(shí)現(xiàn)與Windows加密術(shù)的集成: · TrustManager Provider:用這個(gè)類來(lái)實(shí)現(xiàn)與Windows證書庫(kù)的集成并實(shí)現(xiàn)安全策略。

  · KeyManager Provider:用這個(gè)類來(lái)實(shí)現(xiàn)與Windows私鑰庫(kù)的集成。
  · RSA Signature Provider:數(shù)字簽名需要訪問(wèn)私鑰庫(kù)。如果Java程序不能讀取私鑰(比如,如果私鑰存在一個(gè)加密了的智能卡上了),那么簽名操作就必須在Windows中進(jìn)行。
  · RSA Cipher Provider:解密RSA加密的數(shù)據(jù)(如加密套接字協(xié)議層(SSL)對(duì)稱的鑰匙)需要訪問(wèn)私鑰庫(kù)。如果Java程序不能讀取私鑰(比如,如果私鑰存在一個(gè)加密了的智能卡上了),那么RSA解密操作就必須在Windows中進(jìn)行。

  我將講述與Windows平臺(tái)集成的TrustManager Provider、KeyManager Provider、RSA Signature Provider和RSA Cipher Provider的用法。TrustManager和KeyManager可以讓你構(gòu)建可運(yùn)行的Windows支持的Java Secure Socket Extension(JSSE)應(yīng)用程序。JSSE范例程序——EchoServer和EchoClient可以證明這一點(diǎn)。你不能覆蓋JSSE的內(nèi)置的RSA Cipher Provider,所以,只有當(dāng)私鑰可以從Windows鑰匙庫(kù)中輸出時(shí),JSSE應(yīng)用程序才可以運(yùn)行。

  如果你在編寫一個(gè)運(yùn)用RSA簽名或RSA加密的Java應(yīng)用程序,那么你可以運(yùn)用Windows支持的RSA Signature Provider和Cipher Provider。這不需要從Windows鑰匙庫(kù)中輸出私鑰。對(duì)于其它三個(gè)提供者(provider),你可以單獨(dú)使用每一個(gè)。

  該代碼是用 beta版JDK 1.4.0-rc開(kāi)發(fā)的,很穩(wěn)定。不過(guò),我們打算將該代碼作為一個(gè)框架,進(jìn)行進(jìn)一步的開(kāi)發(fā)。在將該代碼用于生產(chǎn)環(huán)境前,你應(yīng)該改進(jìn)異常處理,確信在本地代碼中沒(méi)有內(nèi)存泄露,并使密鑰的暴露降低到最小。為了測(cè)試代碼,你需要一個(gè)RSA數(shù)字證書。你可以從VeriSign網(wǎng)站www.verisign.com/client/enrollment得到一個(gè)臨時(shí)證書,有效期是60天。具體操作請(qǐng)遵循該站點(diǎn)上的指南。不要選定標(biāo)為“Protect your Private Key”的框。因?yàn)闆](méi)有選定這個(gè)框,你的私鑰就可以輸出。

  下面的代碼初試化了四個(gè)提供者:

MSTrustMgrProvider.install();
MSKeyMgrProvider.install();
MSRSASignProvider.install();
MSRSACipherProvider.install();
kmf = KeyManagerFactory
.getInstance("MSKMF");
tmf = TrustManagerFactory.
getInstance("MSTMF");
Cipher cipher =
Cipher.getInstance(
"RSA/ECB/PKCS1Padding");
Signature rsa =
Signature.getInstance(
"SHA1withRSA");

  所有的四個(gè)提供者都調(diào)用了10個(gè)本地的Microsoft函數(shù):

  · MSgetCACerts()從Microsoft證書庫(kù)返回一列認(rèn)證授權(quán)中心(Certificate Authority (CA))簽發(fā)的證書。
  · 如果一個(gè)證書沒(méi)有被撤消,MSVerifyCertRevocation()返回true。
  · MSgetPrivateKey()為一個(gè)特定的別名(alias )返回私鑰。(這里所說(shuō)的一個(gè)別名就是帶有一個(gè)RSA私鑰和證書的一個(gè)身份。)鑰匙從Microsoft鑰匙庫(kù)中輸出。
  · MSgetCert()為一個(gè)特定的別名從Microsoft證書庫(kù)中返回一個(gè)證書。
  · MSgetAliases()返回一組別名(帶有私鑰的一個(gè)身份的名字)。Microsoft鑰匙庫(kù)中的每個(gè)私鑰都有一個(gè)別名。
  · MSrsaSignHash()返回哈希數(shù)據(jù)(hashed data)的RSA簽名。
  · MSrsaDecrypt()用RSA算法來(lái)解密一個(gè)先前加密了的數(shù)據(jù)塊。
  · MSrsaEncrypt()用Microsoft RSA provider來(lái)加密一個(gè)數(shù)據(jù)塊。
  · MSrsaGetKeysize()返回Microsoft鑰匙庫(kù)中一個(gè)鑰匙的RSA鑰匙大小。
  · MSgetCRL()將一個(gè)證書撤消清單(Certificate Revocation List(CRL))下載到Microsoft Internet緩存中。

  一個(gè)約500行的用C語(yǔ)言代碼編寫的源文件mscryptofunctions.c中包含了所有這些函數(shù)。該代碼可以在Windows 98/NT4/2000/XP上運(yùn)行。

公共鑰匙加密算法

  公共鑰匙加密有兩個(gè)目的:加密和數(shù)字簽名。公共鑰匙加密運(yùn)用一個(gè)包含兩部分的鑰匙(或一對(duì)鑰匙):一個(gè)私鑰和一個(gè)公鑰。公鑰帶有開(kāi)始和終止日期、一個(gè)序號(hào)、一個(gè)身份(稱為Subject Distinguished Name)、和一個(gè)CA的簽名(見(jiàn)列表1)。RSA是最常用的公共鑰匙加密算法。

公共鑰匙加密運(yùn)用一個(gè)公鑰和一個(gè)私鑰。一個(gè)數(shù)字證書(如下所示)包含公鑰、開(kāi)始和結(jié)束日期、一個(gè)序號(hào)、一個(gè)身份和一個(gè)證書授權(quán)中心(CA)的簽名。
Serial number:
6822 3C33 7945 3AC8 F8C5 398B 7469 94E1
Signature algorithm: md5RSA
Issuer: CN = VeriSign Class 1 CA Individual
Subscriber-Persona Not Validated,
OU = www.verisign.com/repository/RPA Incorp.
By Ref.,LIAB.LTD(c)98,
OU = VeriSign Trust Network, O = VeriSign, Inc.
Valid from: Wednesday, May 30, 2001 7:00:00 PM
Valid to: Monday, July 30, 2001 6:59:59 PM
Subject: E = boyter@txdirect.net,
CN = Brian Boyter,
OU = Digital ID Class 1 </? Microsoft,
OU = Persona Not Validated,
OU = www.verisign.com/repository/RPA Incorp.
by ref.,LIAB.LTD(c)98,
OU = VeriSign Trust Network, O = VeriSign, Inc.
Public key: 3081 8902 8181 00BA B459 0F39 156E
C69E C238 BFD0 401D DBB9 D207 DFA4 5DBD 09F3
5CE6 B5E6 C357 88DD 808B 0699 5F68 A2A4 6A8A
3B21 6D3D D0A1 1E5F DAB1 FB8E F835 F84F 849B
29A4 6943 8D59 0669 7C81 1D00 03B7 1A02 4E7A
8596 11BD 7CC4 07A3 D7E5 9FF6 5684 B853 04F0
0938 A11E 5218 F9AB F034 070D C8C4 6652 C19B
4C57 E435 EFDC 85D4 B269 07B7 0102 0301 0001
Basic constraints: Subject Type=End Entity,
Path Length Constraint=None
Certificate policy:
Policy Qualifier Id=CPS Qualifier:
https://www.verisign.com/CPS
Policy Qualifier Info:
Organization=VeriSign, Inc.,
Notice Number=1
CRL Distribution Point Distribution Point Name:
Full Name:
URL=http://crl.verisign.com/class1.crl
Thumbprint algorithm: sha1
Thumbprint: 74A8 9F07 43AA 8FFC C4D5 AB09 3773 3AFF F7E7 DFFC

  公共鑰匙加密中的加密是用公鑰來(lái)完成的,解密是用私鑰完成的。公共鑰匙加密對(duì)于大量的加密來(lái)說(shuō)運(yùn)算很復(fù)雜,但它卻被廣泛用來(lái)分配密鑰。密鑰,或?qū)ΨQ加密算法,如DES和RC4,通常用于大量的加密,但是密鑰加密算法需要一些保密的方法來(lái)交換用于大量加密的鑰匙。一種技術(shù)是生成一個(gè)隨機(jī)數(shù),用公共鑰匙加密算法來(lái)加密那個(gè)隨機(jī)數(shù),然后將加密了的隨機(jī)數(shù)發(fā)送給遠(yuǎn)端的同伴。發(fā)送者用遠(yuǎn)端同伴的公鑰來(lái)加密隨機(jī)數(shù)。接收者用它自己的私鑰來(lái)解密這個(gè)隨機(jī)數(shù)。任何截取了加密的隨機(jī)數(shù)的第三方都不能解密那個(gè)隨機(jī)數(shù),因?yàn)樗麤](méi)有私鑰。

  在數(shù)字簽名中,用私鑰來(lái)完成簽名,用公鑰來(lái)完成確認(rèn)。被簽名了的文件通常是經(jīng)過(guò)哈希算法處理過(guò)的。哈希算法是一個(gè)單向算法,它可以減小文件的大小。運(yùn)用MD5哈希算法,文件被簡(jiǎn)小到16字節(jié)。運(yùn)用SHA1哈希算法,文件被簡(jiǎn)小到20字節(jié)。然后,就用簽名人的私鑰對(duì)經(jīng)哈希算法處理過(guò)的文件進(jìn)行加密。任何人都可以用簽名人的公鑰來(lái)解密哈希文件。

  你必須非常小心地保護(hù)私鑰。Windows將私鑰以有些令人迷惑的形式存儲(chǔ)在文件系統(tǒng)中。一個(gè)惡意的侵犯者可以進(jìn)入到你的計(jì)算機(jī)并找到你的私鑰。任何得到了你的私鑰的人都可以化裝成你,在你不知道的情況下做出簽署文件等行為。一種保護(hù)私鑰的方法就是用一個(gè)加密的智能卡,該卡上存儲(chǔ)了私鑰。運(yùn)用一個(gè)加密的智能卡,用戶仍然可以進(jìn)行公鑰加密和簽名活動(dòng),但沒(méi)有人——甚至用戶——可以讀取私鑰。智能卡有一個(gè)RSA加密和簽名處理器,只有這個(gè)RSA處理器有權(quán)使用私鑰。

  當(dāng)一個(gè)SSL服務(wù)器向一個(gè)SSL客戶端確認(rèn)身份時(shí),客戶端必須根據(jù)下面這些標(biāo)準(zhǔn)來(lái)確定服務(wù)器的證書是否有效:
  · 證書必須有一個(gè)信任鏈,其根CA必須是客戶端信任的。
  · 服務(wù)器證書,和信任鏈中所有的CA證書必須有有效的簽名。每個(gè)證書都是由下面更高級(jí)的CA來(lái)簽署的,除了根CA外,它簽名自己的證書。
  · 當(dāng)前的日期和時(shí)間必須在服務(wù)器證書的有效期內(nèi),而且也在信任鏈中所有證書的有效期內(nèi)。每個(gè)證書都有一個(gè)有效期(證書可以有效使用的一個(gè)開(kāi)始日期和時(shí)間以及結(jié)束日期和時(shí)間)。
  · 每個(gè)CA應(yīng)該管理和公布一個(gè)CRL。客戶端必須可以從信任鏈中的每個(gè)CA得到CRLs,來(lái)查看服務(wù)器證書或下屬CA的一個(gè)證書是否已被其下面更高級(jí)的CA撤消了。
  · 證書必須可以有效用于其目的。鑰匙的用途定義在證書中。例如,CA批準(zhǔn)的僅用于數(shù)字簽名的一個(gè)鑰匙就不能用于SSL鑰匙交換。

  Java安全實(shí)現(xiàn)環(huán)境中不進(jìn)行證書撤消確認(rèn),就是說(shuō),它不進(jìn)行CRL處理。我將向你展示如何運(yùn)用Microsoft Windows的本地加密函數(shù)來(lái)檢查證書信任鏈中的CRLs,從而為Java實(shí)現(xiàn)一個(gè)TrustManager和KeyManager。

TrustManager

  javax.net.ssl.X509TrustManager有三個(gè)方法,你可以在MSTrustManagerlmpl.java中找到: · getAcceptedIssuers()為Microsoft證書庫(kù)中的所有CAs返回一組證書。
  · checkClientTrusted()執(zhí)行服務(wù)器的安全策略。
  · checkServerTrusted()執(zhí)行客戶端的安全策略。

  一個(gè)典型的TCP網(wǎng)絡(luò)安全策略是:

  · 客戶端開(kāi)始連接。假設(shè)客戶端只連接到“安全的”服務(wù)器。客戶端應(yīng)該要求服務(wù)器用一個(gè)數(shù)字證書向客戶端證明身份。通過(guò)確認(rèn)服務(wù)器的證書(信任鏈、簽名是有效的,有效期、證書沒(méi)有被撤消,而且證書是批準(zhǔn)用于RSA鑰匙交換的),客戶端確認(rèn)服務(wù)器的真實(shí)性。客戶端通過(guò)有效的證書來(lái)信任服務(wù)器。
  · 服務(wù)器接收來(lái)自所有客戶端的TCP連接,有些客戶端可能是惡意的。服務(wù)器可以要求客戶端用一個(gè)數(shù)字證書向服務(wù)器證明身份。那樣的話,客戶端的身份就可以被確認(rèn),而且多種信任級(jí)別也可以實(shí)現(xiàn)了。如果服務(wù)器不要求客戶端證明身份,服務(wù)器應(yīng)該假設(shè)所有的客戶端都是惡意的。

  你可以在checkServerTrusted()中看到,實(shí)現(xiàn)客戶端安全策略是很容易的。CheckServerTrusted()檢查簽名、信任鏈中證書的有效日期和CRLs。(我在后面會(huì)探討證書撤消處理。)checkClientTrusted()方法與checkServerTrusted()是一樣的。一般來(lái)說(shuō),這個(gè)安全策略對(duì)服務(wù)器來(lái)說(shuō)并不夠。一種增強(qiáng)服務(wù)器安全狀態(tài)的方法就是要求客戶端用數(shù)字證書來(lái)證明身份,只接受由一個(gè)特定的CA(如VeriSign CA)發(fā)布的證書,并且檢驗(yàn)證書的Subject Distinguished Name中的特殊字段(如0=sun.com)。只需要幾行Java代碼就可以把這個(gè)過(guò)程添加到checkClientTrusted()中了。你需要定制checkClientTrusted()來(lái)實(shí)現(xiàn)你的安全策略(見(jiàn)列表2)。

checkClientTrusted()方法檢查簽名、信任鏈中證書的有效日期和CRLs。但是,對(duì)服務(wù)器來(lái)說(shuō),這個(gè)安全函數(shù)并不夠。你可以通過(guò)定制checkClientTrusted()來(lái)增強(qiáng)安全策略。
public void checkClientTrusted(
X509Certificate chain[]) {
// DontKnowFlag indicates what to do if we're
// not sure if the certificate is revoked
// int DontKnowFlag=0; // reject the cert
// int DontKnowFlag=1; // accept the cert
int DontKnowFlag=2; // ask the user

// check for revoked certs in the cert chain
if (com.boyter.mscrypto.MSValidCertificate.
isCertChainValid(chain, DontKnowFlag))
return;

// client cert is not trusted
System.out.println("Client Certificate is not Trusted - aborting");
System.exit(2);
}

  Java提供了幾個(gè)與證書鏈處理相關(guān)的類,在Java Certification Path API Programmer's Guide中有進(jìn)一步說(shuō)明。我對(duì)它們做過(guò)實(shí)驗(yàn),最后決定不用它們,因?yàn)槲艺J(rèn)為它們太復(fù)雜了。

  TrustManager有第三個(gè)方法getAcceptedIssuers()。該方法為Microsoft證書庫(kù)中所有CAs返回一組證書。Microsoft將這些證書存儲(chǔ)在Registry中;你可以通過(guò)啟動(dòng)REGEDIT程序并查看HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/SystemCertificates/Root/Certificates找到它們。GetAcceptedIssuers()方法執(zhí)行了Microsoft的本地函數(shù)CertEnumCertificateslnStore()。CA證書被作為一組base64位編碼的字符串傳回到Java方法。Java.security.cert.CertificateFactory將base64編碼的證書轉(zhuǎn)換成Java證書。

證書撤消

  有兩種撤消證書的方法:Online Certificate Status Protocol(OCSP)和CRL。OCSP(見(jiàn)RFC2560)并沒(méi)有得到廣泛的支持,所以我只探討用來(lái)確認(rèn)一個(gè)證書的撤消狀況的CRLs。CAs定期公布一個(gè)CRL(見(jiàn)RFC2459)。CRL是一列證書序號(hào),由CA簽署。如果一個(gè)證書的序號(hào)列在CRL中,那個(gè)證書就被撤消了,不再有效了。大多數(shù)證書在發(fā)布時(shí),都有一個(gè)稱為CRL Distribution Point(CDP)的擴(kuò)展名。CDP通常是一個(gè)HTTP或Lightweight Directory Access Protocol(LDAP)URL,它指明該CRL存儲(chǔ)在哪里。我的VeriSign證書的CDP是http://crl.verisign.com/class1.crl。該CRL有500多K,所以需要花些時(shí)間來(lái)下載。

  Java的確提供了類java.security.cert.LDAPCertStoreParameters,它可以用來(lái)從一個(gè)LDAP目錄獲取一個(gè)CRL,但這并不適用于VeriSign CRL(因?yàn)槟莻€(gè)CRL存在一個(gè)Web服務(wù)器上,而不是一個(gè)LDAP服務(wù)器上)。Microsoft有一個(gè)比Java更豐富的API用來(lái)管理證書撤消。如果你瀏覽一個(gè)安全的網(wǎng)站(HTTPS),IE將會(huì)檢驗(yàn)服務(wù)器的證書是否已被撤消(假設(shè)服務(wù)器的證書有一個(gè)CDP)。IE將從證書鏈中的CAs獲取CRLs并把它們緩存到IE的Temporary Internet Files(臨時(shí)Internet文件)目錄中。在下一次需要來(lái)自那個(gè)CA的CRL時(shí),IE將首先檢查緩存。如果它在緩存中找到該CRL,IE會(huì)檢查該CRL是否過(guò)期。(CRLs也有有效的from/to期限。VeriSign運(yùn)用一個(gè)10天的有效期限。)如果CRL已經(jīng)過(guò)期,IE將獲取一個(gè)新的CRL。

  我考慮開(kāi)發(fā)一個(gè)只用于Java的CRL獲取、緩存和撤消確認(rèn)過(guò)程——但是那樣會(huì)需要大量的Java代碼,需要支持幾個(gè)URL協(xié)議(HTTP、LDAP、FTP、文件),需要用一個(gè)文件來(lái)存儲(chǔ)CRL緩存,而且需要復(fù)制Microsoft提供的底層框架。目的是運(yùn)用IE的證書撤消底層框架。

  Microsoft提供了一個(gè)函數(shù)CertVerifyRevocation(),它與IE緩存結(jié)合起來(lái)了并按需要下載和處理CRLs。我琢磨了好幾周撤消過(guò)程,最后得到了一個(gè)可靠的算法。當(dāng)CertVerifyRecocation()下載一個(gè)CRL時(shí),下載有時(shí)會(huì)中斷。這就使CertVerifyRevocation()返回假的、很難恢復(fù)的錯(cuò)誤狀況。我實(shí)現(xiàn)的過(guò)程顯示在圖1中。

論Java加密技術(shù)與Windows的結(jié)合

圖1. 證書撤消流程表

  其訣竅就是調(diào)用函數(shù)CryptRetrieveObjectByUrl()來(lái)從LDAP、HTTP或FTP服務(wù)器預(yù)取CRL到IE緩存中,然后調(diào)用CertVerifyRevocation()來(lái)檢查這個(gè)證書是否已被撤消。雖然CryptRetrieveObjectByUrl()下載仍然要受到網(wǎng)絡(luò)的影響,造成連接中斷,但運(yùn)用CryptRetrieveObjectByUrl()的好處就是你可以識(shí)別問(wèn)題,報(bào)告一個(gè)有意義的錯(cuò)誤信息,并且(如果你需要)可以提示用戶接受或拒絕該證書。不幸的是,只有Windows 2000或更高版本中有CryptRetrieveObjectByUrl()。如果程序要在Windows 98或Windows NT4上運(yùn)行,你就不能預(yù)取CRL。

  我也嘗試運(yùn)用Microsoft函數(shù)來(lái)下載CRLs,然后在Java中處理CRL。對(duì)于一個(gè)大的CRL(比如VeriSign CRL),這種方式很慢。

  列表3顯示關(guān)于isCertRevoked()方法的Java代碼片段。IsCertRevoked()方法調(diào)用了兩個(gè)本地函數(shù),MSgetCRL()和MSVerifyCertRevocation()。MSgetCRL()調(diào)用Microsoft函數(shù)CryptRetrieveObjectByURL(),如果CRL不在緩存中,它可以使CRL被下載。你不需要把CRL傳遞到Java中,因?yàn)樗鼜膩?lái)不用在Java中。函數(shù)MSCertVerifyRevocation()調(diào)用Microsoft函數(shù)CertVerifyRevocatoin()來(lái)確定一個(gè)證書是否被撤消了。列表4顯示關(guān)于MSgetCRL()和MSVerifyCertRevocation()的代碼片段。警告:當(dāng)我第一次在Windows 2000 Server PC上測(cè)試CertVerifyRevocation()時(shí),它沒(méi)有運(yùn)行。在我將PC升級(jí)到Service Pack 2后,重新測(cè)試就很成功。

我們的確認(rèn)程序中的isCertRevoked()方法調(diào)用了兩個(gè)本地函數(shù):MSgetCRL()和MSVerifyCertRevocation() (如列表4所示)。
boolean isCertRevoked(X509Certificate cert,
int DontKnowFlag) {
byte[] certblob = cert.getEncoded();

// Does the cert have a CDP (
// CRL distribution point)???
byte[] CDPblob = cert.getExtensionValue(
"2.5.29.31");

// yes there is a CDP - ASN parse the CDP
String[] URLarray = MSF.MSparseCDP(CDPblob);
for (int i=0; i<URLARRAY.LENGTH; i++) String URL = URLarray[i];
// go fetch that CRL
if (MSF.MSgetCRL(URL)) {
// url was fetched correctly
break;
}

// is the cert revoked???
int revocationStatus =
MSF.MSVerifyCertRevocation(certblob);
switch (revocationStatus) {
case 0: // cert is revoked
return AskUserWhatHeWantsToDo(DontKnowFlag);
case 1: // cert is not revoked
return false;
default:
}

// processing error - cannot determine
// if cert is revoked
return AskUserWhatHeWantsToDo(DontKnowFlag);
}


函數(shù)MSgetCRL()和MSVerifyCertRevocation()由方法isCertRevoked()調(diào)用(如列表3所示)。MSgetCRL()調(diào)用Microsoft函數(shù)CryptRetrieveObjectByURL(),如果在緩存中沒(méi)有CRL,可以用該函數(shù)來(lái)下載它。函數(shù)MSVerifyCertRevocation()調(diào)用Microsoft函數(shù)CertVerifyRevocation()來(lái)查看一個(gè)證書是否已被撤消。
MSgetCRL(jstring jurl)
{
if (!CryptRetrieveObjectByUrl(
url, CONTEXT_OID_CRL, 0, timeout*1000,
(LPVOID)&crl, NULL, NULL, NULL, NULL)) {
printf("CryptRetrieveObjectByUrl failed/n");
// cached url is corrupted
DeleteUrlCacheEntry(url);
return JNI_FALSE;
}
return JNI_TRUE;
}


MSVerifyCertRevocation (jbyteArray jCert)
{
rgpvContext[0] = (PVOID)pCertContext;
if (CertVerifyRevocation(X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE, 1, rgpvContext,
0, NULL, &status)) {
return 1; // cert is not revoked
}

if (status.dwError == CRYPT_E_REVOKED)
return 0; // cert is revoked

return -2; // processing error
}


KeyManager

  javax.net.ssl.X509KeyManager有六個(gè)方法:
  · getClientAliases()返回一組客戶端別名。(這里的一個(gè)別名就是帶有一個(gè)RSA私鑰和證書的一個(gè)身份。)
  · getServerAliases()返回一組服務(wù)器別名。
  · chooseClientAlias()從一組別名中選擇一個(gè)客戶端別名。
  · chooseServerAlias()從一組別名中選擇一個(gè)服務(wù)器別名。
  · getCertificateChain()為一個(gè)證書返回有序的證書鏈。
  · getPrivateKey()為一個(gè)別名返回私鑰。

  Microsoft將私鑰和它們相關(guān)的證書存儲(chǔ)在文件系統(tǒng)中。我的私鑰和證書存儲(chǔ)在目錄C:/Documents和Settings/Administrator/Application Data/Microsoft中。你不需要知道鑰匙存儲(chǔ)在哪里,因?yàn)镸icrosoft提供了一個(gè)API用來(lái)訪問(wèn)鑰匙和證書庫(kù)。

  KeyManager的getClientAliases()和getServerAliases()方法執(zhí)行Microsoft本地的函數(shù)CertEnumCertificateslnStore(),查看Microsoft的“My”證書庫(kù)中的所有證書。“My”證書庫(kù)中的證書應(yīng)該有一個(gè)與它們相關(guān)連的私鑰。每個(gè)證書/私鑰組合都有一個(gè)特殊的標(biāo)識(shí)符,稱為CONTAINER;這就相當(dāng)于Java中的“別名”(見(jiàn)列表5)。

CertEnumCertificatesInStore()方法查看Microsoft中“My”證書庫(kù)中所有的證書;每個(gè)證書都有一個(gè)相關(guān)的私鑰。每個(gè)證書/私鑰組合都有一個(gè)標(biāo)識(shí)符,稱為CONTAINER,這就相當(dāng)于Java中的別名。
JobjectArray MSgetAliases (jstring jcertStore) {

// open Microsoft certificate store
hSystemStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0, 0, CERT_SYSTEM_STORE_CURRENT_USER,
certStore);

// read all the certificates
while(pCertContext=
CertEnumCertificatesInStore(
hSystemStore, pCertContext)) {

// get the cert key container name
CertGetCertificateContextProperty(
pCertContext, CERT_KEY_PROV_INFO_PROP_ID,
alias, &propLen);

// add to list of aliases
AddDataToList(&list, alias, strlen(alias)+1);
}
return jaliases;
}


列表5

  方法chooseClientAlias()和chooseServerAlias()從一列別名中返回一個(gè)客戶端(或服務(wù)器)別名。如果只有一個(gè)別名,在選擇別名時(shí)就不會(huì)有歧義。因?yàn)镴ava的創(chuàng)始人對(duì)于選擇運(yùn)用哪個(gè)別名并沒(méi)有提供任何特殊的指導(dǎo),我就選擇了清單中第一個(gè)別名。另一個(gè)選擇合適的客戶端別名的方法就是提示用戶從一列可能的別名中選擇一個(gè)別名。(在SSL客戶端,你通常可以這么做,但在服務(wù)器上不行。)

  KeyManager的getCertificateChain()方法為一個(gè)證書返回有序的證書鏈。該方法通過(guò)調(diào)用getAcceptedIssuers()方法得到一列可信任的證書簽發(fā)者。首先我們找到證書簽發(fā)者的Distinguished Name(DN),然后我們查看是否有哪個(gè)可信任的簽發(fā)者有那個(gè)DN。幾個(gè)簽發(fā)者可以有同一個(gè)DN。對(duì)于具有簽發(fā)者DN的每個(gè)證書,我們提取公鑰并嘗試在原始證書上確認(rèn)簽名。如果沒(méi)有一個(gè)簽發(fā)者有正確的DN和正確的公鑰,證書鏈就被破壞了,出現(xiàn)一個(gè)異常。如果我們找到了正確的簽發(fā)者簽發(fā)的證書,我們就重復(fù)上述過(guò)程來(lái)查找和確認(rèn)那個(gè)證書的簽發(fā)者。重復(fù)該過(guò)程,直到我們達(dá)到根CA。對(duì)于一個(gè)根CA,Subject DN和簽發(fā)者DN是一樣的(見(jiàn)列表6)。

方法getCertChain()為一個(gè)證書返回有序的證書鏈。
MSCryptoFunctions MSF = new MSCryptoFunctions();
X509Certificate[] getCertChain(
X509Certificate cert) {

try {
getCACerts();

Principal subject = cert.getSubjectDN();
Principal issuer = cert.getIssuerDN();
CertChainList.add(cert);

// stop if issuer==subject (root CA)
while (!(issuer.equals(subject))) {

match = false;
X509CertSelector xcs =
new X509CertSelector();
xcs.setCertificateValid(new Date());

Collection certcollection =
CACerts.getCertificates(xcs);

//
// the next 7 lines are inserted to work
// around a problem with X509CertSelector.
// we should be able to do this with
// xcs.setSubject(issuer.toString());
//
Iterator iter = certcollection.iterator();
while ( iter.hasNext() ) {
X509Certificate cacert =
(X509Certificate) (iter.next());
if (!cacert.getSubjectDN().equals(issuer))
iter.remove();
}

issuerArray =
new X509Certificate[
certcollection.size()];
issuerArray = (X509Certificate[])
certcollection.toArray(issuerArray);

for (int i=0; i</<>issuerArray.length; i++)
if (verifySignature(issuerArray[i], cert)){
match = true;
cert = issuerArray[i];
subject = cert.getSubjectDN();
issuer = cert.getIssuerDN();
CertChainList.add(cert);
break;
}
if (!match) {
return null; // cert chain broken
}
}
} catch (Exception e) {
e.printStackTrace();
}

X509Certificate[] CertChain =
new X509Certificate[CertChainList.size()];
CertChainList.toArray(CertChain);

return CertChain;
}

  getPrivateKey()方法為一個(gè)別名返回私鑰,假設(shè)私鑰可以從Microsoft鑰匙庫(kù)中輸出。記住,有時(shí)私鑰是不能輸出的。(例如,如果你用了一個(gè)加密了的智能卡,那么就沒(méi)人可以從智能卡上讀取私鑰了。)如果不能輸出私鑰,getPrivateKey()就返回一個(gè)虛擬的私鑰。所以,如果getPrivateKey()不能得到私鑰,我們就騙Java,讓它認(rèn)為得到了私鑰。getPrivateKey()也緩存別名,所以,當(dāng)一個(gè)Java程序試圖執(zhí)行一個(gè)RSA數(shù)字簽名函數(shù)時(shí),我們就會(huì)知道運(yùn)用哪個(gè)私鑰了(緩存的別名),而且Microsoft加密提供者就可以執(zhí)行我們想要的RSA簽名或解密函數(shù)了(見(jiàn)列表7)。

方法getPrivateKey()為一個(gè)別名返回私鑰,假設(shè)私鑰可以從Windows鑰匙庫(kù)中輸出。
MSCryptoFunctions MSF = new MSCryptoFunctions();
public PrivateKey getPrivateKey(String alias) {

// get the private key from MS Windows for
// this alias
byte[] keyblob = MSF.MSgetPrivateKey(alias);

if (keyblob == null) { // generate a dummy key
byte[] modblob = new byte[128];
for(i=0; i<128; i++)
modblob[i] = 127;
mod = new BigInteger(modblob);
exp = mod;

} else { // use the key that got exported
for(i=0; i<keysize><br i>modblob[i] = keyblob[19-i+(keysize/16)*2];<br>expblob[i] = keyblob[19-i+(keysize/16)*9];<br>}<br>mod = new BigInteger(1, modblob);<br>exp = new BigInteger(1, expblob);<br>}<br>RSAPrivateKeySpec privKeySpec = <br>new RSAPrivateKeySpec(mod, exp);<br>KeyFactory kf = KeyFactory.getInstance("RSA");<br>privkey = kf.generatePrivate(privKeySpec);<br>return privkey;<br>}</keysize>


RSA Signature Provider

  java.security.SignatureSpi類有五個(gè)方法:
  · engineInitSign()為簽名初試化RSA簽名引擎。
  · engineInitVerify()為確認(rèn)一個(gè)簽名初試化RSA簽名引擎。
  · engineUpdate()增加數(shù)據(jù)到簽名或確認(rèn)操作。
  · engineSign()完成簽名操作并返回?cái)?shù)字簽名。
  · engineVerify()完成簽名-確認(rèn)過(guò)程,如果簽名是正確的,返回true。

  記住,數(shù)字簽名需要私鑰,確認(rèn)一個(gè)數(shù)字簽名需要公鑰。如果我們有權(quán)使用Microsoft的私鑰——即,私鑰是可輸出的——就沒(méi)必要在Microsoft本地代碼中執(zhí)行RSA簽名操作了。但是在有些情況下(例如,如果我們運(yùn)用一個(gè)加密了的智能卡),我們無(wú)權(quán)使用私鑰。如果私鑰是不能輸出的,我們必須用Microsoft本地代碼進(jìn)行數(shù)字簽名。

  如果Java程序運(yùn)用KeyManager的方法getPrivateKey()來(lái)獲取私鑰,私鑰的別名就被緩存起來(lái)。當(dāng)RSA Signature Provider進(jìn)行簽名時(shí),我們就重用緩存的別名,并調(diào)用Microsoft本地函數(shù)來(lái)執(zhí)行簽名操作而不用暴露私鑰。(這聽(tīng)起來(lái)有些虛假,但確實(shí)可行。)注意,在engineInitSign()中沒(méi)有用私鑰。我用Java JCE哈希函數(shù)來(lái)進(jìn)行運(yùn)算,然后用Microsoft Cryptographic Provider從哈希文件中生成RSA簽名。

  通過(guò)添加一個(gè)engineInitSign(字符串別名)方法,可以改進(jìn)Java Signature類:

MSCryptoFunctions MSF =
new MSCryptoFunctions();
protected void engineInitSign(
PrivateKey privateKey) {
MSF.MSrsaSignInit((byte[])null,
"MD5");
}

protected byte[] engineSign() {
byte[] hash = MD5.digest();
byte[] mssig =
MSF.MSrsaSignHash(hash,
(byte[])null, "MD5");
return mssig;
}

  我們可以在Microsoft本地代碼中實(shí)現(xiàn)簽名-確認(rèn),但這么做沒(méi)有優(yōu)勢(shì)。在實(shí)現(xiàn)過(guò)程中,我們運(yùn)用了JSSE提供者在Java中執(zhí)行確認(rèn):

protected void engineInitVerify(
PublicKey publicKey) {
jsse = Signature.getInstance(
"MD5withRSA", "SunJSSE");
jsse.initVerify(publicKey);
}

protected boolean engineVerify(
byte[] sigBytes) {
boolean verifyresult=false;
verifyresult =
jsse.verify(sigBytes);
return verifyresult;
}

RSA Cipher Provider

  javax.Crypto.CipherSpi類有12個(gè)方法:
  · engineInit()初試化密碼提供者(cipher provider)。
  · engineUpdate()繼續(xù)一個(gè)由多個(gè)部分組成的加密或解密操作。
  · engineDoFinal()加密或解密一個(gè)單一操作中的數(shù)據(jù),或完成一個(gè)由多個(gè)部分組成的操作。
  · engineGetBlockSize()返回字區(qū)大小(以字節(jié)形式)。
  · engineGetIV()返回初試化向量。它不用于RSA密碼。
  · engineGetKeySize()返回一個(gè)特定的鑰匙對(duì)象的鑰匙大小。
  · engineGetOutputSize()以字節(jié)形式返回輸出長(zhǎng)度,輸出緩沖器需要這個(gè)長(zhǎng)度來(lái)保存下一個(gè)update或doFinal操作的結(jié)果,輸入長(zhǎng)度已假定。
  · engineGetParameters()返回這個(gè)密碼運(yùn)用的參數(shù)。
  · engineSetMode()設(shè)置密碼的模式(加密或解密)。
  · engineSetPadding()設(shè)置這個(gè)密碼的填充機(jī)制(當(dāng)前只支持PKCS1填充)。
  · engineWrap()封裝一個(gè)鑰匙(未實(shí)現(xiàn))。
  · engineUnwrap()解開(kāi)一個(gè)鑰匙(未實(shí)現(xiàn))。

  RSA加密過(guò)程需要公鑰;RSA解密需要私鑰。如果我們有權(quán)使用Microsoft鑰匙庫(kù)中的RSA私鑰——即,私鑰是可以輸出的——那么就沒(méi)必要在Microsoft本地代碼中執(zhí)行RSA密碼操作。但在有些情況下(例如,如果我們運(yùn)用一個(gè)加密了的智能卡),我們就無(wú)權(quán)使用私鑰。如果私鑰是不能輸出的,我們必須用Microsoft本地代碼進(jìn)行RSA解密。

  RSA密碼在Windows本地代碼中的實(shí)現(xiàn)很簡(jiǎn)單。本質(zhì)的解密過(guò)程如下:

MSrsaDecrypt (jstring jpadalg,
jbyteArray jdata) {
CryptAcquireContext(
&hDecryptProv, alias, NULL,
PROV_RSA_FULL,0);
CryptGetUserKey(hDecryptProv,
AT_KEYEXCHANGE, &hDecryptKey);
CryptDecrypt(hDecryptKey, 0,
TRUE, 0, encryptblob, &ndata);
return decryptblob;
}

  加密幾乎是一樣的。因?yàn)镽SA加密只需要公鑰,加密模式可以在Java中執(zhí)行。我選擇在Windows本地代碼中實(shí)現(xiàn)RSA加密和解密,因?yàn)檫@很容易。

  RSA密碼是一個(gè)美國(guó)政府控制的加密算法。如果你想將RSA cipher provider同Sun JCE結(jié)合起來(lái)運(yùn)用,你必須創(chuàng)建一個(gè)JAR文件,用一個(gè)DSA鑰匙簽署它,然后添加一個(gè)由Sun Microsystems簽發(fā)的證書。為了方便,我已經(jīng)把所有的mscrypto-class文件放在了一個(gè)單一的包中(com.boyter.mscrypto)。在簽署的JAR文件中,只需要有MSRSACipherProvider.class和MSRSACipherFactoryImpl.class。用來(lái)創(chuàng)建和簽名JAR文件的Windows命令是:

jar cvf mscrypto.jar com
jarsigner -keystore keystore
-storepass foobar mscrypto.jar
jcesigner

  你可以從“How to Implement a Provider for the Java Cryptography Extension 1.2.1.”(見(jiàn)資源)的第五步找到關(guān)于從Sun獲取一個(gè)JCE代碼簽署的證書的說(shuō)明。如果你想避免JCE的局限性(如美國(guó)政府的輸出控制),你可以用一個(gè)clean-room式的實(shí)現(xiàn)環(huán)境(如BeeJCE)來(lái)代替JCE。我提供了一個(gè)稱為msrsatest.java的程序,可以用來(lái)測(cè)試Microsoft 加密的RSA簽名和RSA密碼提供者。為此,你必須在Microsoft Windows中安裝一個(gè)RSA私鑰和證書。

有根據(jù)的運(yùn)用理由

  將Java安全特征同本地Microsoft Windows安全平臺(tái)結(jié)合起來(lái)有許多好的理由,包括減少了的管理費(fèi)用、CRL確認(rèn)和與智能卡的兼容。將Java JCE同Windows證書和鑰匙庫(kù)結(jié)合起來(lái)的另一個(gè)理由是用來(lái)管理Java證書和鑰匙庫(kù)的Java工具很麻煩。Microsoft平臺(tái)有一個(gè)更好的圖形用戶界面(GUI)用來(lái)管理Windows鑰匙和證書庫(kù)。你可以通過(guò)運(yùn)行CERTMGR.EXT程序(與Windows平臺(tái)SDK在一起)來(lái)啟動(dòng)GUI,或者你可以從IE窗口來(lái)啟動(dòng):運(yùn)用下拉菜單Tools | Internet Option,選擇Content鍵,然后選擇Certificates。

  在將Microsoft 加密支持的KeyManager和TrustManager用于JSSE時(shí),你不會(huì)有什么問(wèn)題。Microsoft 加密支持的RSA Signature Provider和RSA Cipher Provider也可以運(yùn)行,但不能用于JSSE。

論Java加密技術(shù)與Windows的結(jié)合


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

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

您的支持是博主寫作最大的動(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ì)您有幫助就好】

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

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 广德县| 岳阳市| 陕西省| 寿宁县| 文昌市| 尤溪县| 酒泉市| 林芝县| 株洲县| 巨鹿县| 定陶县| 德格县| 砀山县| 桂阳县| 天峨县| 昆明市| 青海省| 长葛市| 勃利县| 巴林左旗| 平顶山市| 靖江市| 琼中| 台山市| 玉溪市| 侯马市| 宣汉县| 高州市| 青阳县| 登封市| 千阳县| 广河县| 读书| 桑日县| 银川市| 白朗县| 兴化市| 仙居县| 灵丘县| 彭州市| 台南县|