 |
| 将Java加密技术同Windows结合起来(续) |
|
|
|
|
列表5 方法chooseClientAlias()和chooseServerAlias()从一列别名中返回一个客户端(或服务器)别名。如果只有一个别名,在选择别名时就不会有歧义。由于Java的开创人对于选择运用哪个别名并没有提供任何特别的领导,我就选择了清单中第一个别名。另一个选择适合的客户端别名的方法就是提醒用户从一列可能的别名中选择一个别名。(在SSL客户端,你通常可以这么做,但在服务器上不行。) KeyManager的getCertificateChain()方法为一个证书返回有序的证书链。该方法通过调用getAcceptedIssuers()方法得到一列可信赖的证书签发者。首先我们找到证书签发者的Distinguished Name(DN),然后我们查看是否有哪个可信赖的签发者有那个DN。几个签发者可以有同一个DN。对于具有签发者DN的每个证书,我们提取公钥并尝试在原始证书上确认签名。如果没有一个签发者有准确的DN和准确的公钥,证书链就被损坏了,呈现一个异常。如果我们找到了正确的签发者签发的证书,我们就反复上述过程来查找和确认那个证书的签发者。反复该过程,直到我们到达根CA。对于一个根CA,本周有机会涨20%的个股,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, cert)){ match = true; cert = issuerArray; 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()办法为一个别号返回私钥,假设私钥可以从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 = 127; mod = new BigInteger(modblob); exp = mod; } else { // use the key that got exported for(i=0; i modblob = keyblob[19-i+(keysize/16)*2]; expblob = 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; } 我们可以在Microsoft本地代码中实现签名-确认,但这么做没有上风。在实现进程中,我们应用了JSSE供给者在Java中履行确认: 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; } 加密几乎是一样的,静的深夜。由于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: 关于作者: Brian Boyter做过20年的部队情报军官,还曾是Air Force Information Warfare Center、Cisco Systems和Digital Defense的安全参谋。现在,他是Avaya Inc.的高等安全参谋。你可以通过bboyter@avaya.com接洽他。
|
|
|
|
|
| 完美世界,喜剧网游,网络游戏,3D网游,永久免费网游,完美时空,公会,魔族,游戏,MMOG,RPG,热门,流行,攻城,黄金装备,极品装备,戒指,聊天,PKwww.175zz.com |
|