当前位置:天才代写 > tutorial > JAVA 教程 > 将Java加密技能同Windows团结起来

将Java加密技能同Windows团结起来

2017-11-11 08:00 星期六 所属: JAVA 教程 浏览:604

副标题#e#

民众钥匙加密技能需要一个空间来存储数字证书和私钥。通过将钥匙和证书存储到一个文件中(称为keystore),Java Security Architecture实现了独立于平台的加密技能。

Microsoft Windows把钥匙和证书存储到Windows注册表和文件系统中。这就是说,在Windows系统上运行安详的Java措施的用户必需在Java和Microsoft的钥匙和证书库之间输入和输出钥匙和证书。好动静是,你可以“使用”Java应用措施通过Microsoft当地函数来运用Microsoft的证书和钥匙库。

通过将你的Java应用措施同Windows 钥匙/证书库团结起来,你固然牺牲了平台独立性,但你获得了四个长处:淘汰了打点和支持的本钱、更利便用户利用、更好的证书除掉校验、以及更好的钥匙和证书打点东西。

一个Java措施必需通过四个差异的类实现与Windows加密术的集成: · TrustManager Provider:用这个类来实现与Windows证书库的集成并实现安详计策。

· KeyManager Provider:用这个类来实现与Windows私钥库的集成。

· RSA Signature Provider:数字签名需要会见私钥库。假如Java措施不能读取私钥(好比,假如私钥存在一个加密了的智能卡上了),那么签名操纵就必需在Windows中举办。

· RSA Cipher Provider:解密RSA加密的数据(如加密套接字协议层(SSL)对称的钥匙)需要会见私钥库。假如Java措施不能读取私钥(好比,假如私钥存在一个加密了的智能卡上了),那么RSA解密操纵就必需在Windows中举办。

我将报告与Windows平台集成的TrustManager Provider、KeyManager Provider、RSA Signature Provider和RSA Cipher Provider的用法。TrustManager和KeyManager可以让你构建可运行的Windows支持的Java Secure Socket Extension(JSSE)应用措施。JSSE典型措施——EchoServer和EchoClient可以证明这一点。你不能包围JSSE的内置的RSA Cipher Provider,所以,只有当私钥可以从Windows钥匙库中输出时,JSSE应用措施才可以运行。

假如你在编写一个运用RSA签名或RSA加密的Java应用措施,那么你可以运用Windows支持的RSA Signature Provider和Cipher Provider。这不需要从Windows钥匙库中输出私钥。对付其它三个提供者(provider),你可以单独利用每一个。

该代码是用 beta版JDK 1.4.0-rc开拓的,很不变。不外,我们规划将该代码作为一个框架,举办进一步的开拓。在将该代码用于出产情况前,你应该改造异常处理惩罚,确信在当地代码中没有内存泄露,并使密钥的袒露低落到最小。为了测试代码,你需要一个RSA数字证书。你可以从VeriSign网站www.verisign.com/client/enrollment获得一个姑且证书,有效期是60天。详细操纵请遵循该站点上的指南。不要选定标为“Protect your Private Key”的框。因为没有选定这个框,你的私钥就可以输出。

下面的代码初试化了四个提供者:

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");


#p#副标题#e#

所有的四个提供者都挪用了10个当地的Microsoft函数:

· MSgetCACerts()从Microsoft证书库返回一列认证授权中心(Certificate Authority (CA))签发的证书。

· 假如一个证书没有被除掉,MSVerifyCertRevocation()返回true。

· MSgetPrivateKey()为一个特定的别名(alias )返回私钥。(这里所说的一个体名就是带有一个RSA私钥和证书的一个身份。)钥匙从Microsoft钥匙库中输出。

· MSgetCert()为一个特定的别名从Microsoft证书库中返回一个证书。

· MSgetAliases()返回一组别名(带有私钥的一个身份的名字)。Microsoft钥匙库中的每个私钥都有一个体名。

· MSrsaSignHash()返回哈希数据(hashed data)的RSA签名。

· MSrsaDecrypt()用RSA算法来解密一个先前加密了的数据块。

· MSrsaEncrypt()用Microsoft RSA provider来加密一个数据块。

· MSrsaGetKeysize()返回Microsoft钥匙库中一个钥匙的RSA钥匙巨细。

· MSgetCRL()将一个证书除掉清单(Certificate Revocation List(CRL))下载到Microsoft Internet缓存中。

一个约500行的用C语言代码编写的源文件mscryptofunctions.c中包括了所有这些函数。该代码可以在Windows 98/NT4/2000/XP上运行。

民众钥匙加密算法

#p#分页标题#e#

民众钥匙加密有两个目标:加密和数字签名。民众钥匙加密运用一个包括两部门的钥匙(或一对钥匙):一个私钥和一个公钥。公钥带有开始和终止日期、一个序号、一个身份(称为Subject Distinguished Name)、和一个CA的签名(见列表1)。RSA是最常用的民众钥匙加密算法。

民众钥匙加密运用一个公钥和一个私钥。一个数字证书(如下所示)包括公钥、开始和竣事日期、一个序号、一个身份和一个证书授权中心(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 = [email protected],
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

#p#副标题#e#

民众钥匙加密中的加密是用公钥来完成的,解密是用私钥完成的。民众钥匙加密对付大量的加密来说运算很巨大,但它却被遍及用来分派密钥。密钥,或对称加密算法,如DES和RC4,凡是用于大量的加密,可是密钥加密算法需要一些保密的要领来互换用于大量加密的钥匙。一种技能是生成一个随机数,用民众钥匙加密算法来加密谁人随机数,然后将加密了的随机数发送给远端的伙伴。发送者用远端伙伴的公钥来加密随机数。吸收者用它本身的私钥来解密这个随机数。任何截取了加密的随机数的第三方都不能解密谁人随机数,因为他没有私钥。

在数字签名中,用私钥来完成签名,用公钥来完成确认。被签名了的文件凡是是颠末哈希算法处理惩罚过的。哈希算法是一个单向算法,它可以减小文件的巨细。运用MD5哈希算法,文件被简小到16字节。运用SHA1哈希算法,文件被简小到20字节。然后,就用签名流的私钥对经哈希算法处理惩罚过的文件举办加密。任何人都可以用签名流的公钥来解密哈希文件。

你必需很是小心地掩护私钥。Windows将私钥以有些令人疑惑的形式存储在文件系统中。一个恶意的加害者可以进入到你的计较机并找到你的私钥。任何获得了你的私钥的人都可以化妆成你,在你不知道的环境下做出签署文件等行为。一种掩护私钥的要领就是用一个加密的智能卡,该卡上存储了私钥。运用一个加密的智能卡,用户仍然可以举办公钥加密和签名勾当,但没有人——甚至用户——可以读取私钥。智能卡有一个RSA加密和签名处理惩罚器,只有这个RSA处理惩罚器有权利用私钥。

当一个SSL处事器向一个SSL客户端确认身份时,客户端必需按照下面这些尺度来确定处事器的证书是否有效:

· 证书必需有一个信任链,其根CA必需是客户端信任的。

· 处事器证书,和信任链中所有的CA证书必需有有效的签名。每个证书都是由下面更高级的CA来签署的,除了根CA外,它签名本身的证书。

· 当前的日期和时间必需在处事器证书的有效期内,并且也在信任链中所有证书的有效期内。每个证书都有一个有效期(证书可以有效利用的一个开始日期和时间以及竣事日期和时间)。

· 每个CA应该打点和发布一个CRL。客户端必需可以从信任链中的每个CA获得CRLs,来查察处事器证书或部属CA的一个证书是否已被其下面更高级的CA除掉了。

· 证书必需可以有效用于其目标。钥匙的用途界说在证书中。譬喻,CA核准的仅用于数字签名的一个钥匙就不能用于SSL钥匙互换。

#p#分页标题#e#

Java安详实现情况中不举办证书除掉确认,就是说,它不举办CRL处理惩罚。我将向你展示如何运用Microsoft Windows的当地加密函数来查抄证书信任链中的CRLs,从而为Java实现一个TrustManager和KeyManager。

TrustManager

javax.net.ssl.X509TrustManager有三个要领,你可以在MSTrustManagerlmpl.java中找到: · getAcceptedIssuers()为Microsoft证书库中的所有CAs返回一组证书。

· checkClientTrusted()执行处事器的安详计策。

· checkServerTrusted()执行客户端的安详计策。

一个典范的TCP网络安详计策是:

· 客户端开始毗连。假设客户端只毗连到“安详的”处事器。客户端应该要求处事器用一个数字证书向客户端证明身份。通过确认处事器的证书(信任链、签名是有效的,有效期、证书没有被除掉,并且证书是核准用于RSA钥匙互换的),客户端确认处事器的真实性。客户端通过有效的证书来信任处事器。

· 处事器吸收来自所有客户端的TCP毗连,有些客户端大概是恶意的。处事器可以要求客户端用一个数字证书向处事器证明身份。那样的话,客户端的身份就可以被确认,并且多种信任级别也可以实现了。假如处事器不要求客户端证明身份,处事器应该假设所有的客户端都是恶意的。

你可以在checkServerTrusted()中看到,实现客户端安详计策是很容易的。CheckServerTrusted()查抄签名、信任链中证书的有效日期和CRLs。(我在后头会探讨证书除掉处理惩罚。)checkClientTrusted()要领与checkServerTrusted()是一样的。一般来说,这个安详计策对处事器来说并不足。一种加强处事器安详状态的要领就是要求客户端用数字证书来证明身份,只接管由一个特定的CA(如VeriSign CA)宣布的证书,而且检讨证书的Subject Distinguished Name中的非凡字段(如0=sun.com)。只需要几行Java代码就可以把这个进程添加到checkClientTrusted()中了。你需要定制checkClientTrusted()来实现你的安详计策(见列表2)。

checkClientTrusted()要领查抄签名、信任链中证书的有效日期和CRLs。可是,对处事器来说,这个安详函数并不足。你可以通过定制checkClientTrusted()来加强安详计策。
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提供了几个与证书链处理惩罚相关的类,在Java Certification Path API Programmer’s Guide中有进一步说明。我对它们做过尝试,最后抉择不消它们,因为我认为它们太巨大了。

TrustManager有第三个要领getAcceptedIssuers()。该要领为Microsoft证书库中所有CAs返回一组证书。Microsoft将这些证书存储在Registry中;你可以通过启动REGEDIT措施并查察HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\Root\Certificates找到它们。GetAcceptedIssuers()要领执行了Microsoft的当地函数CertEnumCertificateslnStore()。CA证书被作为一组base64位编码的字符串传回到Java要领。Java.security.cert.CertificateFactory将base64编码的证书转换成Java证书。

#p#副标题#e#

证书除掉

有两种除掉证书的要领:Online Certificate Status Protocol(OCSP)和CRL。OCSP(见RFC2560)并没有获得遍及的支持,所以我只探讨用来确认一个证书的除掉状况的CRLs。CAs按期发布一个CRL(见RFC2459)。CRL是一列证书序号,由CA签署。假如一个证书的序号列在CRL中,谁人证书就被除掉了,不再有效了。大大都证书在宣布时,都有一个称为CRL Distribution Point(CDP)的扩展名。CDP凡是是一个HTTP或Lightweight Directory Access Protocol(LDAP)URL,它指明该CRL存储在那边。我的VeriSign证书的CDP是http://crl.verisign.com/class1.crl。该CRL有500多K,所以需要花些时间来下载。

Java简直提供了类java.security.cert.LDAPCertStoreParameters,它可以用来从一个LDAP目次获取一个CRL,但这并不合用于VeriSign CRL(因为谁人CRL存在一个Web处事器上,而不是一个LDAP处事器上)。Microsoft有一个比Java更富厚的API用来打点证书除掉。假如你欣赏一个安详的网站(HTTPS),IE将会检讨处事器的证书是否已被除掉(假设处事器的证书有一个CDP)。IE将从证书链中的CAs获取CRLs并把它们缓存到IE的Temporary Internet Files(姑且Internet文件)目次中。在下一次需要来自谁人CA的CRL时,IE将首先查抄缓存。假如它在缓存中找到该CRL,IE会查抄该CRL是否逾期。(CRLs也有有效的from/to期限。VeriSign运用一个10天的有效期限。)假如CRL已经逾期,IE将获取一个新的CRL。

#p#分页标题#e#

我思量开拓一个只用于Java的CRL获取、缓存和除掉确认进程——可是那样会需要大量的Java代码,需要支持几个URL协议(HTTP、LDAP、FTP、文件),需要用一个文件来存储CRL缓存,并且需要复制Microsoft提供的底层框架。目标是运用IE的证书除掉底层框架。

Microsoft提供了一个函数CertVerifyRevocation(),它与IE缓存团结起来了并按需要下载和处理惩罚CRLs。我琢磨了好几周除掉进程,最后获得了一个靠得住的算法。当CertVerifyRecocation()下载一个CRL时,下载有时会间断。这就使CertVerifyRevocation()返回假的、很难规复的错误状况。我实现的进程显示在图1中。

将Java加密技术同Windows连合起来

图1. 证书除掉流程表

其诀窍就是挪用函数CryptRetrieveObjectByUrl()来从LDAP、HTTP或FTP处事器预取CRL到IE缓存中,然后挪用CertVerifyRevocation()来查抄这个证书是否已被除掉。固然CryptRetrieveObjectByUrl()下载仍然要受到网络的影响,造成毗连间断,但运用CryptRetrieveObjectByUrl()的长处就是你可以识别问题,陈诉一个有意义的错误信息,而且(假如你需要)可以提示用户接管或拒绝该证书。不幸的是,只有Windows 2000或更高版本中有CryptRetrieveObjectByUrl()。假如措施要在Windows 98或Windows NT4上运行,你就不能预取CRL。

我也实验运用Microsoft函数来下载CRLs,然后在Java中处理惩罚CRL。对付一个大的CRL(好比VeriSign CRL),这种方法很慢。

列表3显示关于isCertRevoked()要领的Java代码片断。IsCertRevoked()要领挪用了两个当地函数,MSgetCRL()和MSVerifyCertRevocation()。MSgetCRL()挪用Microsoft函数CryptRetrieveObjectByURL(),假如CRL不在缓存中,它可以使CRL被下载。你不需要把CRL通报到Java中,因为它从来不消在Java中。函数MSCertVerifyRevocation()挪用Microsoft函数CertVerifyRevocatoin()来确定一个证书是否被除掉了。列表4显示关于MSgetCRL()和MSVerifyCertRevocation()的代码片断。告诫:当我第一次在Windows 2000 Server PC上测试CertVerifyRevocation()时,它没有运行。在我将PC进级到Service Pack 2后,从头测试就很乐成。

我们简直认措施中的isCertRevoked()要领挪用了两个当地函数: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);
}

#p#副标题#e#

函数MSgetCRL()和MSVerifyCertRevocation()由要领isCertRevoked()挪用(如列表3所示)。MSgetCRL()挪用Microsoft函数CryptRetrieveObjectByURL(),假如在缓存中没有CRL,可以用该函数来下载它。函数MSVerifyCertRevocation()挪用Microsoft函数CertVerifyRevocation()来查察一个证书是否已被除掉。

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有六个要领:

· getClientAliases()返回一组客户端别名。(这里的一个体名就是带有一个RSA私钥和证书的一个身份。)

· getServerAliases()返回一组处事器别名。

· chooseClientAlias()从一组别名中选择一个客户端别名。

· chooseServerAlias()从一组别名中选择一个处事器别名。

· getCertificateChain()为一个证书返回有序的证书链。

· getPrivateKey()为一个体名返回私钥。

#p#副标题#e#

#p#分页标题#e#

Microsoft将私钥和它们相关的证书存储在文件系统中。我的私钥和证书存储在目次C:\Documents和Settings\Administrator\Application Data\Microsoft中。你不需要知道钥匙存储在那边,因为Microsoft提供了一个API用来会见钥匙和证书库。

KeyManager的getClientAliases()和getServerAliases()要领执行Microsoft当地的函数CertEnumCertificateslnStore(),查察Microsoft的“My”证书库中的所有证书。“My”证书库中的证书应该有一个与它们相关系的私钥。每个证书/私钥组合都有一个非凡的标识符,称为CONTAINER;这就相当于Java中的“别名”(见列表5)。

CertEnumCertificatesInStore()要领查察Microsoft中“My”证书库中所有的证书;每个证书都有一个相关的私钥。每个证书/私钥组合都有一个标识符,称为CONTAINER,这就相当于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()从一列别名中返回一个客户端(或处事器)别名。假如只有一个体名,在选择别名时就不会有歧义。因为Java的首创人对付选择运用哪个体名并没有提供任何非凡的指导,我就选择了清单中第一个体名。另一个选择符合的客户端别名的要领就是提示用户从一列大概的别名中选择一个体名。(在SSL客户端,你凡是可以这么做,但在处事器上不可。)

KeyManager的getCertificateChain()要领为一个证书返回有序的证书链。该要领通过挪用getAcceptedIssuers()要领获得一列可信任的证书签发者。首先我们找到证书签发者的Distinguished Name(DN),然后我们查察是否有哪个可信任的签发者有谁人DN。几个签发者可以有同一个DN。对付具有签发者DN的每个证书,我们提取公钥并实验在原始证书上确认签名。假如没有一个签发者有正确的DN和正确的公钥,证书链就被粉碎了,呈现一个异常。假如我们找到了正确的签发者签发的证书,我们就反复上述进程来查找和确认谁人证书的签发者。反复该进程,直到我们到达根CA。对付一个根CA,Subject DN和签发者DN是一样的(见列表6)。

要领getCertChain()为一个证书返回有序的证书链。
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;
}

#p#副标题#e#

#p#分页标题#e#

getPrivateKey()要领为一个体名返回私钥,假设私钥可以从Microsoft钥匙库中输出。记着,有时私钥是不能输出的。(譬喻,假如你用了一个加密了的智能卡,那么就没人可以从智能卡上读取私钥了。)假如不能输出私钥,getPrivateKey()就返回一个虚拟的私钥。所以,假如getPrivateKey()不能获得私钥,我们就骗Java,让它认为获得了私钥。getPrivateKey()也缓存别名,所以,当一个Java措施试图执行一个RSA数字签名函数时,我们就会知道运用哪个私钥了(缓存的别名),并且Microsoft加密提供者就可以执行我们想要的RSA签名或解密函数了(见列表7)。

要领getPrivateKey()为一个体名返回私钥,假设私钥可以从Windows钥匙库中输出。
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/8; i++) {
modblob[i] = keyblob[19-i+(keysize/16)*2];
expblob[i] = keyblob[19-i+(keysize/16)*9];
}
mod = new BigInteger(1, modblob);
exp = new BigInteger(1, expblob);
}
RSAPrivateKeySpec privKeySpec =
new RSAPrivateKeySpec(mod, exp);
KeyFactory kf = KeyFactory.getInstance("RSA");
privkey = kf.generatePrivate(privKeySpec);
return privkey;
}

RSA Signature Provider

java.security.SignatureSpi类有五个要领:

· engineInitSign()为签名初试化RSA签名引擎。

· engineInitVerify()为确认一个签名初试化RSA签名引擎。

· engineUpdate()增加数据到签名或确认操纵。

· engineSign()完成签名操纵并返回数字签名。

· engineVerify()完成签名-确认进程,假如签名是正确的,返回true。

记着,数字签名需要私钥,确认一个数字签名需要公钥。假如我们有权利用Microsoft的私钥——即,私钥是可输出的——就没须要在Microsoft当地代码中执行RSA签名操纵了。可是在有些环境下(譬喻,假如我们运用一个加密了的智能卡),我们无权利用私钥。假如私钥是不能输出的,我们必需用Microsoft当地代码举办数字签名。

假如Java措施运用KeyManager的要领getPrivateKey()来获取私钥,私钥的别名就被缓存起来。当RSA Signature Provider举办签名时,我们就重用缓存的别名,并挪用Microsoft当地函数来执行签名操纵而不消袒露私钥。(这听起来有些虚假,但确实可行。)留意,在engineInitSign()中没有用私钥。我用Java JCE哈希函数来举办运算,然后用Microsoft Cryptographic Provider从哈希文件中生成RSA签名。

通过添加一个engineInitSign(字符串别名)要领,可以改造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;
}

#p#副标题#e#

我们可以在Microsoft当地代码中实现签名-确认,但这么做没有优势。在实现进程中,我们运用了JSSE提供者在Java中执行确认:

#p#分页标题#e#

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个要领:

· engineInit()初试化暗码提供者(cipher provider)。

· engineUpdate()继承一个由多个部门构成的加密或解密操纵。

· engineDoFinal()加密或解密一个单一操纵中的数据,或完成一个由多个部门构成的操纵。

· engineGetBlockSize()返回字区巨细(以字节形式)。

· engineGetIV()返回初试化向量。它不消于RSA暗码。

· engineGetKeySize()返回一个特定的钥匙工具的钥匙巨细。

· engineGetOutputSize()以字节形式返回输出长度,输出缓冲器需要这个长度来生存下一个update或doFinal操纵的功效,输入长度已假定。

· engineGetParameters()返回这个暗码运用的参数。

· engineSetMode()配置暗码的模式(加密或解密)。

· engineSetPadding()配置这个暗码的填充机制(当前只支持PKCS1填充)。

· engineWrap()封装一个钥匙(未实现)。

· engineUnwrap()解开一个钥匙(未实现)。

RSA加密进程需要公钥;RSA解密需要私钥。假如我们有权利用Microsoft钥匙库中的RSA私钥——即,私钥是可以输出的——那么就没须要在Microsoft当地代码中执行RSA暗码操纵。但在有些环境下(譬喻,假如我们运用一个加密了的智能卡),我们就无权利用私钥。假如私钥是不能输出的,我们必需用Microsoft当地代码举办RSA解密。

RSA暗码在Windows当地代码中的实现很简朴。本质的解密进程如下:

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;
}

#p#副标题#e#

加密险些是一样的。因为RSA加密只需要公钥,加密模式可以在Java中执行。我选择在Windows当地代码中实现RSA加密息争密,因为这很容易。

RSA暗码是一个美国当局节制的加密算法。假如你想将RSA cipher provider同Sun JCE团结起来运用,你必需建设一个JAR文件,用一个DSA钥匙签署它,然后添加一个由Sun Microsystems签发的证书。为了利便,我已经把所有的mscrypto-class文件放在了一个单一的包中(com.boyter.mscrypto)。在签署的JAR文件中,只需要有MSRSACipherProvider.class和MSRSACipherFactoryImpl.class。用来建设和签名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.”(见资源)的第五步找到关于从Sun获取一个JCE代码签署的证书的说明。假如你想制止JCE的范围性(如美国当局的输出节制),你可以用一个clean-room式的实现情况(如BeeJCE)来取代JCE。我提供了一个称为msrsatest.java的措施,可以用来测试Microsoft 加密的RSA签名和RSA暗码提供者。为此,你必需在Microsoft Windows中安装一个RSA私钥和证书。

有按照的运用来由

将Java安详特征同当地Microsoft Windows安详平台团结起来有很多好的来由,包罗淘汰了的打点用度、CRL确认和与智能卡的兼容。将Java JCE同Windows证书和钥匙库团结起来的另一个来由是用来打点Java证书和钥匙库的Java东西很贫苦。Microsoft平台有一个更好的图形用户界面(GUI)用来打点Windows钥匙和证书库。你可以通过运行CERTMGR.EXT措施(与Windows平台SDK在一起)来启动GUI,可能你可以从IE窗口来启动:运用下拉菜单Tools | Internet Option,选择Content键,然后选择Certificates。

在将Microsoft 加密支持的KeyManager和TrustManager用于JSSE时,你不会有什么问题。Microsoft 加密支持的RSA Signature Provider和RSA Cipher Provider也可以运行,但不能用于JSSE。

资源

The Factory design pattern:

The SSL specification-JSSE (Java Secure Sockets Extension):

Instructions for installing JSSE:

"Build secure network applications with SSL and the JSSE API"

Clean-room Java implementation of RSA signing and encryption:

"How to Implement a Provider for the Java Cryptography Extension 1.2.1"

BeeJCE, Virtual Unlimited’s cleanroom implementation of JCE:

Microsoft SDK Crypto API Reference:

Java Certification Path API Programmer’s Guide:

Internet X.509 Public Key Infrastructure Certificate and CRL Profile:

关于作者:

#p#分页标题#e#

Brian Boyter做过20年的部队情报军官,还曾是Air Force Information Warfare Center、Cisco Systems和Digital Defense的安详参谋。此刻,他是Avaya Inc.的高级安详参谋。你可以通过[email protected]接洽他。

 

    关键字:

天才代写-代写联系方式