`
yanfaguanli
  • 浏览: 650654 次
文章分类
社区版块
存档分类
最新评论

Java加密技术(十二)——*.PFX(*.p12)&个人信息交换文件

 
阅读更多

今天来点实际工作中的硬通货!

与计费系统打交道,少不了用到加密/解密实现。为了安全起见,通过非对称加密交换对称加密密钥更是不可或缺。那么需要通过什么载体传递非对称算法公钥/私钥信息?数字证书是公钥的载体,而密钥库可以包含公钥、私钥信息。
JKSPKCS#12都是比较常用的两种密钥库格式/标准。对于前者,搞Java开发,尤其是接触过HTTPS平台的朋友,并不陌生。JKS文件(通常为*.jks或*.keystore,扩展名无关)可以通过Java原生工具——KeyTool生成;而后者PKCS#12文件(通常为*.p12或*.pfx,意味个人信息交换文件),则是通过更为常用的OpenSSL工具产生。
当然,这两者之间是可以通过导入/导出的方式进行转换的!当然,这种转换需要通过KeyTool工具进行!
回归正题,计费同事遇到一个难题:合作方交给他们一个*.pfx文件,需要他们从中提取密钥,然后进行加密交互。其实,通过Java直接操作密钥库文件(或个人信息交换文件)对于一般Java开发人员来说,这都是个冷门。不接触数字安全,根本不知所云。况且,Java原生的密钥库文件格式为JKS,如何操作*.pfx文件?密钥库操作需要获知密钥库别名,*.pfx别名是什么?!接下来就解决这些问题!

方案:
  1. 通过keytool密钥库导入命令importkeystore,将密钥库格式由PKCS#12转换为JKS。
  2. 检索新生成的密钥库文件,提取别名信息。
  3. 由密钥库文件导出数字证书(这里将用到别名)。
  4. 通过代码提取公钥/私钥、签名算法等

先看格式转换:
Cmd代码收藏代码
  1. echo格式转换
  2. keytool-importkeystore-v-srckeystorezlex.pfx-srcstoretypepkcs12-srcstorepass123456-destkeystorezlex.keystore-deststoretypejks-deststorepass123456

-importkeystore导入密钥库,通过格式设定,我们可以将PKCS#12文件转换为JKS格式。
-v显示详情
-srckeystore源密钥库,这里是zlex.pfx
-srcstoretype源密钥库格式,这里为pkcs12
-srcstorepass源密钥库密码,这里为123456
-destkeystore目标密钥库,这里为zlex.keystore
-deststoretype目标密钥库格式,这里为jks,默认值也如此
-deststorepass目标密钥库密码,这里为123456
通过这个操作,我们能够获得所需的密钥库文件zlex.keystore。

这时,我们已经获得了密钥库文件,只要确定对应的别名信息,就可以提取公钥/私钥,以及数字证书,进行加密交互了!
Cmd代码收藏代码
  1. echo查看证书
  2. keytool-list-keystorezlex.keystore-storepass123456-v

-list列举密钥库
-keystore密钥库,这里是zlex.keystore
-storepass密钥库密码,这里是123456
-v显示详情

这里需要细致观察一下别名信息!!!就是红框中的数字1!!!


现在,我们把证书导出!
Cmd代码收藏代码
  1. echo导出证书
  2. keytool-exportcert-alias1-keystorezlex.keystore-filezlex.crt-storepass123456

-exportcert导出证书
-alias别名,这里是1
-keystore密钥库,这里是zlex.keystore
-file证书文件,这里是zlex.crt
-storepass密钥库密码,这里是123456

现在证书也导出了,我们可以提取公钥/私钥,进行加密/解密,签名/验证操作了!当然,即便没有证书,我们也能够通过密钥库(JKS格式)文件获得证书,以及公钥/私钥、签名算法等。
补充代码, 其实就是对Java加密技术(八)的修改!
Java代码收藏代码
  1. /**
  2. *2010-8-11
  3. */
  4. importjava.io.FileInputStream;
  5. importjava.security.KeyStore;
  6. importjava.security.PrivateKey;
  7. importjava.security.PublicKey;
  8. importjava.security.Signature;
  9. importjava.security.cert.Certificate;
  10. importjava.security.cert.CertificateFactory;
  11. importjava.security.cert.X509Certificate;
  12. importjava.util.Date;
  13. importjavax.crypto.Cipher;
  14. /**
  15. *证书操作类
  16. *
  17. *@author<ahref="mailto:zlex.dongliang@gmail.com">梁栋</a>
  18. *@since1.0
  19. */
  20. publicclassCertificateCoder{
  21. /**
  22. *Java密钥库(JavaKeyStore,JKS)KEY_STORE
  23. */
  24. publicstaticfinalStringKEY_STORE="JKS";
  25. publicstaticfinalStringX509="X.509";
  26. /**
  27. *由KeyStore获得私钥
  28. *
  29. *@paramkeyStorePath
  30. *@paramkeyStorePassword
  31. *@paramalias
  32. *@paramaliasPassword
  33. *@return
  34. *@throwsException
  35. */
  36. privatestaticPrivateKeygetPrivateKey(StringkeyStorePath,
  37. StringkeyStorePassword,Stringalias,StringaliasPassword)
  38. throwsException{
  39. KeyStoreks=getKeyStore(keyStorePath,keyStorePassword);
  40. PrivateKeykey=(PrivateKey)ks.getKey(alias,
  41. aliasPassword.toCharArray());
  42. returnkey;
  43. }
  44. /**
  45. *由Certificate获得公钥
  46. *
  47. *@paramcertificatePath
  48. *@return
  49. *@throwsException
  50. */
  51. privatestaticPublicKeygetPublicKey(StringcertificatePath)
  52. throwsException{
  53. Certificatecertificate=getCertificate(certificatePath);
  54. PublicKeykey=certificate.getPublicKey();
  55. returnkey;
  56. }
  57. /**
  58. *获得Certificate
  59. *
  60. *@paramcertificatePath
  61. *@return
  62. *@throwsException
  63. */
  64. privatestaticCertificategetCertificate(StringcertificatePath)
  65. throwsException{
  66. CertificateFactorycertificateFactory=CertificateFactory
  67. .getInstance(X509);
  68. FileInputStreamin=newFileInputStream(certificatePath);
  69. Certificatecertificate=certificateFactory.generateCertificate(in);
  70. in.close();
  71. returncertificate;
  72. }
  73. /**
  74. *获得Certificate
  75. *
  76. *@paramkeyStorePath
  77. *@paramkeyStorePassword
  78. *@paramalias
  79. *@return
  80. *@throwsException
  81. */
  82. privatestaticCertificategetCertificate(StringkeyStorePath,
  83. StringkeyStorePassword,Stringalias)throwsException{
  84. KeyStoreks=getKeyStore(keyStorePath,keyStorePassword);
  85. Certificatecertificate=ks.getCertificate(alias);
  86. returncertificate;
  87. }
  88. /**
  89. *获得KeyStore
  90. *
  91. *@paramkeyStorePath
  92. *@parampassword
  93. *@return
  94. *@throwsException
  95. */
  96. privatestaticKeyStoregetKeyStore(StringkeyStorePath,Stringpassword)
  97. throwsException{
  98. FileInputStreamis=newFileInputStream(keyStorePath);
  99. KeyStoreks=KeyStore.getInstance(KEY_STORE);
  100. ks.load(is,password.toCharArray());
  101. is.close();
  102. returnks;
  103. }
  104. /**
  105. *私钥加密
  106. *
  107. *@paramdata
  108. *@paramkeyStorePath
  109. *@paramkeyStorePassword
  110. *@paramalias
  111. *@paramaliasPassword
  112. *@return
  113. *@throwsException
  114. */
  115. publicstaticbyte[]encryptByPrivateKey(byte[]data,StringkeyStorePath,
  116. StringkeyStorePassword,Stringalias,StringaliasPassword)
  117. throwsException{
  118. //取得私钥
  119. PrivateKeyprivateKey=getPrivateKey(keyStorePath,keyStorePassword,
  120. alias,aliasPassword);
  121. //对数据加密
  122. Ciphercipher=Cipher.getInstance(privateKey.getAlgorithm());
  123. cipher.init(Cipher.ENCRYPT_MODE,privateKey);
  124. returncipher.doFinal(data);
  125. }
  126. /**
  127. *私钥解密
  128. *
  129. *@paramdata
  130. *@paramkeyStorePath
  131. *@paramalias
  132. *@paramkeyStorePassword
  133. *@paramaliasPassword
  134. *@return
  135. *@throwsException
  136. */
  137. publicstaticbyte[]decryptByPrivateKey(byte[]data,StringkeyStorePath,
  138. Stringalias,StringkeyStorePassword,StringaliasPassword)
  139. throwsException{
  140. //取得私钥
  141. PrivateKeyprivateKey=getPrivateKey(keyStorePath,keyStorePassword,
  142. alias,aliasPassword);
  143. //对数据加密
  144. Ciphercipher=Cipher.getInstance(privateKey.getAlgorithm());
  145. cipher.init(Cipher.DECRYPT_MODE,privateKey);
  146. returncipher.doFinal(data);
  147. }
  148. /**
  149. *公钥加密
  150. *
  151. *@paramdata
  152. *@paramcertificatePath
  153. *@return
  154. *@throwsException
  155. */
  156. publicstaticbyte[]encryptByPublicKey(byte[]data,StringcertificatePath)
  157. throwsException{
  158. //取得公钥
  159. PublicKeypublicKey=getPublicKey(certificatePath);
  160. //对数据加密
  161. Ciphercipher=Cipher.getInstance(publicKey.getAlgorithm());
  162. cipher.init(Cipher.ENCRYPT_MODE,publicKey);
  163. returncipher.doFinal(data);
  164. }
  165. /**
  166. *公钥解密
  167. *
  168. *@paramdata
  169. *@paramcertificatePath
  170. *@return
  171. *@throwsException
  172. */
  173. publicstaticbyte[]decryptByPublicKey(byte[]data,StringcertificatePath)
  174. throwsException{
  175. //取得公钥
  176. PublicKeypublicKey=getPublicKey(certificatePath);
  177. //对数据加密
  178. Ciphercipher=Cipher.getInstance(publicKey.getAlgorithm());
  179. cipher.init(Cipher.DECRYPT_MODE,publicKey);
  180. returncipher.doFinal(data);
  181. }
  182. /**
  183. *验证Certificate
  184. *
  185. *@paramcertificatePath
  186. *@return
  187. */
  188. publicstaticbooleanverifyCertificate(StringcertificatePath){
  189. returnverifyCertificate(newDate(),certificatePath);
  190. }
  191. /**
  192. *验证Certificate是否过期或无效
  193. *
  194. *@paramdate
  195. *@paramcertificatePath
  196. *@return
  197. */
  198. publicstaticbooleanverifyCertificate(Datedate,StringcertificatePath){
  199. booleanstatus=true;
  200. try{
  201. //取得证书
  202. Certificatecertificate=getCertificate(certificatePath);
  203. //验证证书是否过期或无效
  204. status=verifyCertificate(date,certificate);
  205. }catch(Exceptione){
  206. status=false;
  207. }
  208. returnstatus;
  209. }
  210. /**
  211. *验证证书是否过期或无效
  212. *
  213. *@paramdate
  214. *@paramcertificate
  215. *@return
  216. */
  217. privatestaticbooleanverifyCertificate(Datedate,Certificatecertificate){
  218. booleanstatus=true;
  219. try{
  220. X509Certificatex509Certificate=(X509Certificate)certificate;
  221. x509Certificate.checkValidity(date);
  222. }catch(Exceptione){
  223. status=false;
  224. }
  225. returnstatus;
  226. }
  227. /**
  228. *签名
  229. *
  230. *@paramkeyStorePath
  231. *@paramalias
  232. *@paramkeyStorePassword
  233. *@paramaliasPassword
  234. *@return
  235. *@throwsException
  236. */
  237. publicstaticbyte[]sign(byte[]sign,StringkeyStorePath,Stringalias,
  238. StringkeyStorePassword,StringaliasPassword)throwsException{
  239. //获得证书
  240. X509Certificatex509Certificate=(X509Certificate)getCertificate(
  241. keyStorePath,keyStorePassword,alias);
  242. //取得私钥
  243. PrivateKeyprivateKey=getPrivateKey(keyStorePath,keyStorePassword,
  244. alias,aliasPassword);
  245. //构建签名
  246. Signaturesignature=Signature.getInstance(x509Certificate
  247. .getSigAlgName());
  248. signature.initSign(privateKey);
  249. signature.update(sign);
  250. returnsignature.sign();
  251. }
  252. /**
  253. *验证签名
  254. *
  255. *@paramdata
  256. *@paramsign
  257. *@paramcertificatePath
  258. *@return
  259. *@throwsException
  260. */
  261. publicstaticbooleanverify(byte[]data,byte[]sign,
  262. StringcertificatePath)throwsException{
  263. //获得证书
  264. X509Certificatex509Certificate=(X509Certificate)getCertificate(certificatePath);
  265. //获得公钥
  266. PublicKeypublicKey=x509Certificate.getPublicKey();
  267. //构建签名
  268. Signaturesignature=Signature.getInstance(x509Certificate
  269. .getSigAlgName());
  270. signature.initVerify(publicKey);
  271. signature.update(data);
  272. returnsignature.verify(sign);
  273. }
  274. /**
  275. *验证Certificate
  276. *
  277. *@paramkeyStorePath
  278. *@paramkeyStorePassword
  279. *@paramalias
  280. *@return
  281. */
  282. publicstaticbooleanverifyCertificate(Datedate,StringkeyStorePath,
  283. StringkeyStorePassword,Stringalias){
  284. booleanstatus=true;
  285. try{
  286. Certificatecertificate=getCertificate(keyStorePath,
  287. keyStorePassword,alias);
  288. status=verifyCertificate(date,certificate);
  289. }catch(Exceptione){
  290. status=false;
  291. }
  292. returnstatus;
  293. }
  294. /**
  295. *验证Certificate
  296. *
  297. *@paramkeyStorePath
  298. *@paramkeyStorePassword
  299. *@paramalias
  300. *@return
  301. */
  302. publicstaticbooleanverifyCertificate(StringkeyStorePath,
  303. StringkeyStorePassword,Stringalias){
  304. returnverifyCertificate(newDate(),keyStorePath,keyStorePassword,
  305. alias);
  306. }
  307. }

相信上述代码已经帮朋友们解决了相当多的问题!
给出测试类:
Java代码收藏代码
  1. importstaticorg.junit.Assert.*;
  2. importjava.util.Date;
  3. importorg.apache.commons.codec.binary.Hex;
  4. importorg.junit.Test;
  5. /**
  6. *证书操作验证类
  7. *
  8. *@author<ahref="mailto:zlex.dongliang@gmail.com">梁栋</a>
  9. *@version1.0
  10. *@since1.0
  11. */
  12. publicclassCertificateCoderTest{
  13. privateStringcertificatePath="zlex.crt";
  14. privateStringkeyStorePath="zlex.keystore";
  15. privateStringkeyStorePassword="123456";
  16. privateStringaliasPassword="123456";
  17. privateStringalias="1";
  18. @Test
  19. publicvoidtest()throwsException{
  20. System.err.println("公钥加密——私钥解密");
  21. StringinputStr="Ceritifcate";
  22. byte[]data=inputStr.getBytes();
  23. byte[]encrypt=CertificateCoder.encryptByPublicKey(data,
  24. certificatePath);
  25. byte[]decrypt=CertificateCoder.decryptByPrivateKey(encrypt,
  26. keyStorePath,alias,keyStorePassword,aliasPassword);
  27. StringoutputStr=newString(decrypt);
  28. System.err.println("加密前:"+inputStr+"\n\r"+"解密后:"+outputStr);
  29. //验证数据一致
  30. assertArrayEquals(data,decrypt);
  31. //验证证书有效
  32. assertTrue(CertificateCoder.verifyCertificate(certificatePath));
  33. }
  34. @Test
  35. publicvoidtestSign()throwsException{
  36. System.err.println("私钥加密——公钥解密");
  37. StringinputStr="sign";
  38. byte[]data=inputStr.getBytes();
  39. byte[]encodedData=CertificateCoder.encryptByPrivateKey(data,
  40. keyStorePath,keyStorePassword,alias,aliasPassword);
  41. byte[]decodedData=CertificateCoder.decryptByPublicKey(encodedData,
  42. certificatePath);
  43. StringoutputStr=newString(decodedData);
  44. System.err.println("加密前:"+inputStr+"\n\r"+"解密后:"+outputStr);
  45. assertEquals(inputStr,outputStr);
  46. System.err.println("私钥签名——公钥验证签名");
  47. //产生签名
  48. byte[]sign=CertificateCoder.sign(encodedData,keyStorePath,alias,
  49. keyStorePassword,aliasPassword);
  50. System.err.println("签名:\r"+Hex.encodeHexString(sign));
  51. //验证签名
  52. booleanstatus=CertificateCoder.verify(encodedData,sign,
  53. certificatePath);
  54. System.err.println("状态:\r"+status);
  55. assertTrue(status);
  56. }
  57. @Test
  58. publicvoidtestVerify()throwsException{
  59. System.err.println("密钥库证书有效期验证");
  60. booleanstatus=CertificateCoder.verifyCertificate(newDate(),
  61. keyStorePath,keyStorePassword,alias);
  62. System.err.println("证书状态:\r"+status);
  63. assertTrue(status);
  64. }
  65. }

第一个测试方法,用于提取公钥/私钥进行加密/解密操作。
第二个测试方法,用于提取签名算法进行签名/验证操作。
第三个测试方法,用于测试密钥库该别名对应的证书,当前日期下,是否有效。



OK,任务完成,密钥成功提取,剩下的都是代码基本功了!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics