JKS和PKCS#12
今天来点实际工作中的硬通货!
与计费系统打交道,少不了用到加密/解密实现。为了安全起见,通过非对称加密交换对称加密密钥更是不可或缺。那么需要通过什么载体传递非对称算法公钥/私钥信息?数字证书是公钥的载体,而密钥库可以包含公钥、私钥信息。
JKS和PKCS#12都是比较常用的两种密钥库格式/标准。对于前者,搞Java开发,尤其是接触过HTTPS平台的朋友,并不陌生。JKS文件(通常为*.jks或*.keystore,扩展名无关)可以通过Java原生工具——KeyTool生成;而后者PKCS#12文件(通常为*.p12或*.pfx,意味个人信息交换文件),则是通过更为常用的OpenSSL工具产生。
当然,这两者之间是可以通过导入/导出的方式进行转换的!当然,这种转换需要通过KeyTool工具进行!
回归正题,计费同事遇到一个难题:合作方交给他们一个*.pfx文件,需要他们从中提取密钥,然后进行加密交互。其实,通过Java直接操作密钥库文件(或个人信息交换文件)对于一般Java开发人员来说,这都是个冷门。不接触数字安全,根本不知所云。况且,Java原生的密钥库文件格式为JKS,如何操作*.pfx文件?密钥库操作需要获知密钥库别名,*.pfx别名是什么?!接下来就解决这些问题!
方案:
- 通过keytool密钥库导入命令importkeystore,将密钥库格式由PKCS#12转换为JKS。
- 检索新生成的密钥库文件,提取别名信息。
- 由密钥库文件导出数字证书(这里将用到别名)。
- 通过代码提取公钥/私钥、签名算法等
先看格式转换:
- echo 格式转换
- keytool -importkeystore -v -srckeystore zlex.pfx -srcstoretype pkcs12 -srcstorepass 123456 -destkeystore zlex.keystore -deststoretype jks -deststorepass 123456
-importkeystore导入密钥库,通过格式设定,我们可以将PKCS#12文件转换为JKS格式。
-v显示详情
-srckeystore源密钥库,这里是zlex.pfx
-srcstoretype源密钥库格式,这里为pkcs12
-srcstorepass源密钥库密码,这里为123456
-destkeystore目标密钥库,这里为zlex.keystore
-deststoretype目标密钥库格式,这里为jks,默认值也如此
-deststorepass目标密钥库密码,这里为123456
通过这个操作,我们能够获得所需的密钥库文件zlex.keystore。
这时,我们已经获得了密钥库文件,只要确定对应的别名信息,就可以提取公钥/私钥,以及数字证书,进行加密交互了!
- echo 查看证书
- keytool -list -keystore zlex.keystore -storepass 123456 -v
-list列举密钥库
-keystore密钥库,这里是zlex.keystore
-storepass密钥库密码,这里是123456
-v显示详情
这里需要细致观察一下别名信息!!!就是红框中的数字1!!!
现在,我们把证书导出!
- echo 导出证书
- keytool -exportcert -alias 1 -keystore zlex.keystore -file zlex.crt -storepass 123456
-exportcert导出证书
-alias别名,这里是1
-keystore密钥库,这里是zlex.keystore
-file证书文件,这里是zlex.crt
-storepass密钥库密码,这里是123456
现在证书也导出了,我们可以提取公钥/私钥,进行加密/解密,签名/验证操作了!当然,即便没有证书,我们也能够通过密钥库(JKS格式)文件获得证书,以及公钥/私钥、签名算法等。
补充代码, 其实就是对Java加密技术(八)的修改!
- /**
- * 2010-8-11
- */
- import java.io.FileInputStream;
- import java.security.KeyStore;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.Signature;
- import java.security.cert.Certificate;
- import java.security.cert.CertificateFactory;
- import java.security.cert.X509Certificate;
- import java.util.Date;
- import javax.crypto.Cipher;
- /**
- * 证书操作类
- *
- * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
- * @since 1.0
- */
- public class CertificateCoder {
- /**
- * Java密钥库(Java Key Store,JKS)KEY_STORE
- */
- public static final String KEY_STORE = "JKS";
- public static final String X509 = "X.509";
- /**
- * 由 KeyStore获得私钥
- *
- * @param keyStorePath
- * @param keyStorePassword
- * @param alias
- * @param aliasPassword
- * @return
- * @throws Exception
- */
- private static PrivateKey getPrivateKey(String keyStorePath,
- String keyStorePassword, String alias, String aliasPassword)
- throws Exception {
- KeyStore ks = getKeyStore(keyStorePath, keyStorePassword);
- PrivateKey key = (PrivateKey) ks.getKey(alias,
- aliasPassword.toCharArray());
- return key;
- }
- /**
- * 由 Certificate获得公钥
- *
- * @param certificatePath
- * @return
- * @throws Exception
- */
- private static PublicKey getPublicKey(String certificatePath)
- throws Exception {
- Certificate certificate = getCertificate(certificatePath);
- PublicKey key = certificate.getPublicKey();
- return key;
- }
- /**
- * 获得Certificate
- *
- * @param certificatePath
- * @return
- * @throws Exception
- */
- private static Certificate getCertificate(String certificatePath)
- throws Exception {
- CertificateFactory certificateFactory = CertificateFactory
- .getInstance(X509);
- FileInputStream in = new FileInputStream(certificatePath);
- Certificate certificate = certificateFactory.generateCertificate(in);
- in.close();
- return certificate;
- }
- /**
- * 获得Certificate
- *
- * @param keyStorePath
- * @param keyStorePassword
- * @param alias
- * @return
- * @throws Exception
- */
- private static Certificate getCertificate(String keyStorePath,
- String keyStorePassword, String alias) throws Exception {
- KeyStore ks = getKeyStore(keyStorePath, keyStorePassword);
- Certificate certificate = ks.getCertificate(alias);
- return certificate;
- }
- /**
- * 获得KeyStore
- *
- * @param keyStorePath
- * @param password
- * @return
- * @throws Exception
- */
- private static KeyStore getKeyStore(String keyStorePath, String password)
- throws Exception {
- FileInputStream is = new FileInputStream(keyStorePath);
- KeyStore ks = KeyStore.getInstance(KEY_STORE);
- ks.load(is, password.toCharArray());
- is.close();
- return ks;
- }
- /**
- * 私钥加密
- *
- * @param data
- * @param keyStorePath
- * @param keyStorePassword
- * @param alias
- * @param aliasPassword
- * @return
- * @throws Exception
- */
- public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
- String keyStorePassword, String alias, String aliasPassword)
- throws Exception {
- // 取得私钥
- PrivateKey privateKey = getPrivateKey(keyStorePath, keyStorePassword,
- alias, aliasPassword);
- // 对数据加密
- Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
- cipher.init(Cipher.ENCRYPT_MODE, privateKey);
- return cipher.doFinal(data);
- }
- /**
- * 私钥解密
- *
- * @param data
- * @param keyStorePath
- * @param alias
- * @param keyStorePassword
- * @param aliasPassword
- * @return
- * @throws Exception
- */
- public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
- String alias, String keyStorePassword, String aliasPassword)
- throws Exception {
- // 取得私钥
- PrivateKey privateKey = getPrivateKey(keyStorePath, keyStorePassword,
- alias, aliasPassword);
- // 对数据加密
- Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
- cipher.init(Cipher.DECRYPT_MODE, privateKey);
- return cipher.doFinal(data);
- }
- /**
- * 公钥加密
- *
- * @param data
- * @param certificatePath
- * @return
- * @throws Exception
- */
- public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
- throws Exception {
- // 取得公钥
- PublicKey publicKey = getPublicKey(certificatePath);
- // 对数据加密
- Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
- cipher.init(Cipher.ENCRYPT_MODE, publicKey);
- return cipher.doFinal(data);
- }
- /**
- * 公钥解密
- *
- * @param data
- * @param certificatePath
- * @return
- * @throws Exception
- */
- public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
- throws Exception {
- // 取得公钥
- PublicKey publicKey = getPublicKey(certificatePath);
- // 对数据加密
- Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
- cipher.init(Cipher.DECRYPT_MODE, publicKey);
- return cipher.doFinal(data);
- }
- /**
- * 验证Certificate
- *
- * @param certificatePath
- * @return
- */
- public static boolean verifyCertificate(String certificatePath) {
- return verifyCertificate(new Date(), certificatePath);
- }
- /**
- * 验证Certificate是否过期或无效
- *
- * @param date
- * @param certificatePath
- * @return
- */
- public static boolean verifyCertificate(Date date, String certificatePath) {
- boolean status = true;
- try {
- // 取得证书
- Certificate certificate = getCertificate(certificatePath);
- // 验证证书是否过期或无效
- status = verifyCertificate(date, certificate);
- } catch (Exception e) {
- status = false;
- }
- return status;
- }
- /**
- * 验证证书是否过期或无效
- *
- * @param date
- * @param certificate
- * @return
- */
- private static boolean verifyCertificate(Date date, Certificate certificate) {
- boolean status = true;
- try {
- X509Certificate x509Certificate = (X509Certificate) certificate;
- x509Certificate.checkValidity(date);
- } catch (Exception e) {
- status = false;
- }
- return status;
- }
- /**
- * 签名
- *
- * @param keyStorePath
- * @param alias
- * @param keyStorePassword
- * @param aliasPassword
- * @return
- * @throws Exception
- */
- public static byte[] sign(byte[] sign, String keyStorePath, String alias,
- String keyStorePassword, String aliasPassword) throws Exception {
- // 获得证书
- X509Certificate x509Certificate = (X509Certificate) getCertificate(
- keyStorePath, keyStorePassword, alias);
- // 取得私钥
- PrivateKey privateKey = getPrivateKey(keyStorePath, keyStorePassword,
- alias, aliasPassword);
- // 构建签名
- Signature signature = Signature.getInstance(x509Certificate
- .getSigAlgName());
- signature.initSign(privateKey);
- signature.update(sign);
- return signature.sign();
- }
- /**
- * 验证签名
- *
- * @param data
- * @param sign
- * @param certificatePath
- * @return
- * @throws Exception
- */
- public static boolean verify(byte[] data, byte[] sign,
- String certificatePath) throws Exception {
- // 获得证书
- X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
- // 获得公钥
- PublicKey publicKey = x509Certificate.getPublicKey();
- // 构建签名
- Signature signature = Signature.getInstance(x509Certificate
- .getSigAlgName());
- signature.initVerify(publicKey);
- signature.update(data);
- return signature.verify(sign);
- }
- /**
- * 验证Certificate
- *
- * @param keyStorePath
- * @param keyStorePassword
- * @param alias
- * @return
- */
- public static boolean verifyCertificate(Date date, String keyStorePath,
- String keyStorePassword, String alias) {
- boolean status = true;
- try {
- Certificate certificate = getCertificate(keyStorePath,
- keyStorePassword, alias);
- status = verifyCertificate(date, certificate);
- } catch (Exception e) {
- status = false;
- }
- return status;
- }
- /**
- * 验证Certificate
- *
- * @param keyStorePath
- * @param keyStorePassword
- * @param alias
- * @return
- */
- public static boolean verifyCertificate(String keyStorePath,
- String keyStorePassword, String alias) {
- return verifyCertificate(new Date(), keyStorePath, keyStorePassword,
- alias);
- }
- }
相信上述代码已经帮朋友们解决了相当多的问题!
给出测试类:
- import static org.junit.Assert.*;
- import java.util.Date;
- import org.apache.commons.codec.binary.Hex;
- import org.junit.Test;
- /**
- * 证书操作验证类
- *
- * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
- * @version 1.0
- * @since 1.0
- */
- public class CertificateCoderTest {
- private String certificatePath = "zlex.crt";
- private String keyStorePath = "zlex.keystore";
- private String keyStorePassword = "123456";
- private String aliasPassword = "123456";
- private String alias = "1";
- @Test
- public void test() throws Exception {
- System.err.println("公钥加密——私钥解密");
- String inputStr = "Ceritifcate";
- byte[] data = inputStr.getBytes();
- byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
- certificatePath);
- byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
- keyStorePath, alias, keyStorePassword, aliasPassword);
- String outputStr = new String(decrypt);
- System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
- // 验证数据一致
- assertArrayEquals(data, decrypt);
- // 验证证书有效
- assertTrue(CertificateCoder.verifyCertificate(certificatePath));
- }
- @Test
- public void testSign() throws Exception {
- System.err.println("私钥加密——公钥解密");
- String inputStr = "sign";
- byte[] data = inputStr.getBytes();
- byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
- keyStorePath, keyStorePassword, alias, aliasPassword);
- byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
- certificatePath);
- String outputStr = new String(decodedData);
- System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
- assertEquals(inputStr, outputStr);
- System.err.println("私钥签名——公钥验证签名");
- // 产生签名
- byte[] sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
- keyStorePassword, aliasPassword);
- System.err.println("签名:\r" + Hex.encodeHexString(sign));
- // 验证签名
- boolean status = CertificateCoder.verify(encodedData, sign,
- certificatePath);
- System.err.println("状态:\r" + status);
- assertTrue(status);
- }
- @Test
- public void testVerify() throws Exception {
- System.err.println("密钥库证书有效期验证");
- boolean status = CertificateCoder.verifyCertificate(new Date(),
- keyStorePath, keyStorePassword, alias);
- System.err.println("证书状态:\r" + status);
- assertTrue(status);
- }
- }
第一个测试方法,用于提取公钥/私钥进行加密/解密操作。
第二个测试方法,用于提取签名算法进行签名/验证操作。
第三个测试方法,用于测试密钥库该别名对应的证书,当前日期下,是否有效。
OK,任务完成,密钥成功提取,剩下的都是代码基本功了!
JKS和PKCS#12的更多相关文章
- PKCS#12
http://blog.csdn.net/cuiran/article/details/7816696 数字证书介绍 一.什么是数字证书 数字证书就是互联网通讯中标志通讯各方身份信息的一系列数据,提供 ...
- BouncyCastle产生一个PKCS#12规范的PFX/p12证书
RT,在C#中实现,依赖.netFramework2.0 BouncyCastle中提供了PKCS12Store,Pkcs12StoreBuilder,AsymmetricKeyEntry,X509C ...
- RSA私钥和公钥文件格式 (pkcs#1, pkcs#8, pkcs#12, pem)
RSA私钥和公钥文件格式 (pkcs#1, pkcs#8, pkcs#12, pem) 2018年03月07日 11:57:22 阅读数:674 Format Name Description PKC ...
- C#使用BouncyCastle生成PKCS#12数字证书
背景 生成数字证书用于PDF文档数字签名 数字证书需要考虑环境兼容性,如linux.windows 网上资料不全或版本多样 本文章主要介绍了在C#中使用BouncyCastle生成PKCS#12个人信 ...
- SSL证书请求文件(CSR)生成指南 - Tomcat
SSL证书请求文件(CSR)生成指南 - Tomcat http://www.zhenssl.com/support/CSRgen/tomcat_CSR.htm 重要注意事项 An Importa ...
- 移动互联网实战--Apple的APNS桩推送服务的实现(1)
前记: 相信大家在搞IOS推送服务的开发时, 会直接使用javapns api来简单实现, 调试也直连Apple的APNS服务(产品/测试版)来实现. 很少有人会写个APNS的桩服务, 事实也是如此. ...
- openssl命令
author:JevonWei 版权声明:原创作品 1.构建根证书 构建根证书前,需要构建随机数文件(.rand),完整命令如 openssl rand -out private/.rand 1000 ...
- An annotation based command line parser
Java命令行选项解析之Commons-CLI & Args4J & JCommander http://rensanning.iteye.com/blog/2161201 JComm ...
- java-信息安全(十七)-*.PFX(*.p12)&个人信息交换文件
原文地址 http://snowolf.iteye.com/blog/735294 与计费系统打交道,少不了用到加密/解密实现.为了安全起见,通过非对称加密交换对称加密密钥更是不可或缺.那么需要通过什 ...
随机推荐
- 【转】用JitPack发布开源库时附加文档和源码
来自:http://www.gcssloop.com/course/jitpack-sources-javadoc 用JitPack发布开源库时附加文档和源码 很早之前写过一篇用JitPack发布An ...
- 海康威视,大华,宇视 的视频监控iOS Demo
原谅我只提供一个链接,我在这里写了两遍,最后加个链接页面卡死了,下面的demo,最好真机调试.(写博客还是在别的地方写复制到这里比较好!) 一个画面可以做,4个,9个,16个画面原理是一样的,集合到自 ...
- Dojo: Quick Start
1.Dojo学习地址 2.Dojo快速开始 2.1.Dojo引入 2.2.指定Dojo模块的位置 2.3.模块加载require 3.查找Dom节点 3.1.根据id查找dom节点 3.2.根据c ...
- 关于Oracle的疑问
索引范围扫描(index range scan) select empno,ename from emp where empno > 1 order by empno 这种情况下不会使用索引范围 ...
- MySQL排序原理与案例分析
前言 排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Group by语句,Distinct ...
- 安卓虚拟机adb shell sqlite3数据库
adb shell 连接: //http://www.cnblogs.com/xiaobo-Linux/ Android把数据都存放在data/data目录下. 我们使用cd命令转到data/data ...
- 不透明度opacity进阶
一.opacity属性 1.opacity 习惯上说“透明度”,其实应该叫“不透明度”.opacity 意思:不透明,而背景色的默认值:transparent意思才是“透明的”.所以opacity用来 ...
- Python学习实践-----打印日历
使用python语言实现在控制台打印日历 输入年.月.日 输出对应日历,指定的日数输出为'--' 程序没有做严格的输入验证,故输入整数即可. 以下为没有优化的源码: print_calendar.py ...
- java.lang.String.getBytes(String charsetName)方法实例
java.lang.String.getBytes(String charsetName) 方法编码将此String使用指定的字符集的字节序列,并将结果存储到一个新的字节数组. 声明 以下是java. ...
- [LeetCode] Frog Jump 青蛙过河
A frog is crossing a river. The river is divided into x units and at each unit there may or may not ...