zoukankan      html  css  js  c++  java
  • JKS和PKCS#12

    今天来点实际工作中的硬通货!
    与计费系统打交道,少不了用到加密/解密实现。为了安全起见,通过非对称加密交换对称加密密钥更是不可或缺。那么需要通过什么载体传递非对称算法公钥/私钥信息?数字证书是公钥的载体,而密钥库可以包含公钥、私钥信息。
    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  -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。

    这时,我们已经获得了密钥库文件,只要确定对应的别名信息,就可以提取公钥/私钥,以及数字证书,进行加密交互了!

    Cmd代码  收藏代码
    1. echo 查看证书  
    2. keytool -list -keystore zlex.keystore -storepass 123456 -v  


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

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


    现在,我们把证书导出!

    Cmd代码  收藏代码
    1. echo 导出证书  
    2. 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加密技术(八)的修改!

    Java代码  收藏代码
    1. /** 
    2.  * 2010-8-11 
    3.  */  
    4.   
    5. import java.io.FileInputStream;  
    6. import java.security.KeyStore;  
    7. import java.security.PrivateKey;  
    8. import java.security.PublicKey;  
    9. import java.security.Signature;  
    10. import java.security.cert.Certificate;  
    11. import java.security.cert.CertificateFactory;  
    12. import java.security.cert.X509Certificate;  
    13. import java.util.Date;  
    14.   
    15. import javax.crypto.Cipher;  
    16.   
    17. /** 
    18.  * 证书操作类 
    19.  *  
    20.  * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a> 
    21.  * @since 1.0 
    22.  */  
    23. public class CertificateCoder {  
    24.     /** 
    25.      * Java密钥库(Java Key Store,JKS)KEY_STORE 
    26.      */  
    27.     public static final String KEY_STORE = "JKS";  
    28.   
    29.     public static final String X509 = "X.509";  
    30.   
    31.     /** 
    32.      * 由 KeyStore获得私钥 
    33.      *  
    34.      * @param keyStorePath 
    35.      * @param keyStorePassword 
    36.      * @param alias 
    37.      * @param aliasPassword 
    38.      * @return 
    39.      * @throws Exception 
    40.      */  
    41.     private static PrivateKey getPrivateKey(String keyStorePath,  
    42.             String keyStorePassword, String alias, String aliasPassword)  
    43.             throws Exception {  
    44.         KeyStore ks = getKeyStore(keyStorePath, keyStorePassword);  
    45.         PrivateKey key = (PrivateKey) ks.getKey(alias,  
    46.                 aliasPassword.toCharArray());  
    47.         return key;  
    48.     }  
    49.   
    50.     /** 
    51.      * 由 Certificate获得公钥 
    52.      *  
    53.      * @param certificatePath 
    54.      * @return 
    55.      * @throws Exception 
    56.      */  
    57.     private static PublicKey getPublicKey(String certificatePath)  
    58.             throws Exception {  
    59.         Certificate certificate = getCertificate(certificatePath);  
    60.         PublicKey key = certificate.getPublicKey();  
    61.         return key;  
    62.     }  
    63.   
    64.     /** 
    65.      * 获得Certificate 
    66.      *  
    67.      * @param certificatePath 
    68.      * @return 
    69.      * @throws Exception 
    70.      */  
    71.     private static Certificate getCertificate(String certificatePath)  
    72.             throws Exception {  
    73.         CertificateFactory certificateFactory = CertificateFactory  
    74.                 .getInstance(X509);  
    75.         FileInputStream in = new FileInputStream(certificatePath);  
    76.   
    77.         Certificate certificate = certificateFactory.generateCertificate(in);  
    78.         in.close();  
    79.   
    80.         return certificate;  
    81.     }  
    82.   
    83.     /** 
    84.      * 获得Certificate 
    85.      *  
    86.      * @param keyStorePath 
    87.      * @param keyStorePassword 
    88.      * @param alias 
    89.      * @return 
    90.      * @throws Exception 
    91.      */  
    92.     private static Certificate getCertificate(String keyStorePath,  
    93.             String keyStorePassword, String alias) throws Exception {  
    94.         KeyStore ks = getKeyStore(keyStorePath, keyStorePassword);  
    95.         Certificate certificate = ks.getCertificate(alias);  
    96.   
    97.         return certificate;  
    98.     }  
    99.   
    100.     /** 
    101.      * 获得KeyStore 
    102.      *  
    103.      * @param keyStorePath 
    104.      * @param password 
    105.      * @return 
    106.      * @throws Exception 
    107.      */  
    108.     private static KeyStore getKeyStore(String keyStorePath, String password)  
    109.             throws Exception {  
    110.         FileInputStream is = new FileInputStream(keyStorePath);  
    111.         KeyStore ks = KeyStore.getInstance(KEY_STORE);  
    112.         ks.load(is, password.toCharArray());  
    113.         is.close();  
    114.         return ks;  
    115.     }  
    116.   
    117.     /** 
    118.      * 私钥加密 
    119.      *  
    120.      * @param data 
    121.      * @param keyStorePath 
    122.      * @param keyStorePassword 
    123.      * @param alias 
    124.      * @param aliasPassword 
    125.      * @return 
    126.      * @throws Exception 
    127.      */  
    128.     public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,  
    129.             String keyStorePassword, String alias, String aliasPassword)  
    130.             throws Exception {  
    131.         // 取得私钥  
    132.         PrivateKey privateKey = getPrivateKey(keyStorePath, keyStorePassword,  
    133.                 alias, aliasPassword);  
    134.   
    135.         // 对数据加密  
    136.         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());  
    137.         cipher.init(Cipher.ENCRYPT_MODE, privateKey);  
    138.   
    139.         return cipher.doFinal(data);  
    140.   
    141.     }  
    142.   
    143.     /** 
    144.      * 私钥解密 
    145.      *  
    146.      * @param data 
    147.      * @param keyStorePath 
    148.      * @param alias 
    149.      * @param keyStorePassword 
    150.      * @param aliasPassword 
    151.      * @return 
    152.      * @throws Exception 
    153.      */  
    154.     public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,  
    155.             String alias, String keyStorePassword, String aliasPassword)  
    156.             throws Exception {  
    157.         // 取得私钥  
    158.         PrivateKey privateKey = getPrivateKey(keyStorePath, keyStorePassword,  
    159.                 alias, aliasPassword);  
    160.   
    161.         // 对数据加密  
    162.         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());  
    163.         cipher.init(Cipher.DECRYPT_MODE, privateKey);  
    164.   
    165.         return cipher.doFinal(data);  
    166.   
    167.     }  
    168.   
    169.     /** 
    170.      * 公钥加密 
    171.      *  
    172.      * @param data 
    173.      * @param certificatePath 
    174.      * @return 
    175.      * @throws Exception 
    176.      */  
    177.     public static byte[] encryptByPublicKey(byte[] data, String certificatePath)  
    178.             throws Exception {  
    179.   
    180.         // 取得公钥  
    181.         PublicKey publicKey = getPublicKey(certificatePath);  
    182.         // 对数据加密  
    183.         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());  
    184.         cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
    185.   
    186.         return cipher.doFinal(data);  
    187.   
    188.     }  
    189.   
    190.     /** 
    191.      * 公钥解密 
    192.      *  
    193.      * @param data 
    194.      * @param certificatePath 
    195.      * @return 
    196.      * @throws Exception 
    197.      */  
    198.     public static byte[] decryptByPublicKey(byte[] data, String certificatePath)  
    199.             throws Exception {  
    200.         // 取得公钥  
    201.         PublicKey publicKey = getPublicKey(certificatePath);  
    202.   
    203.         // 对数据加密  
    204.         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());  
    205.         cipher.init(Cipher.DECRYPT_MODE, publicKey);  
    206.   
    207.         return cipher.doFinal(data);  
    208.   
    209.     }  
    210.   
    211.     /** 
    212.      * 验证Certificate 
    213.      *  
    214.      * @param certificatePath 
    215.      * @return 
    216.      */  
    217.     public static boolean verifyCertificate(String certificatePath) {  
    218.         return verifyCertificate(new Date(), certificatePath);  
    219.     }  
    220.   
    221.     /** 
    222.      * 验证Certificate是否过期或无效 
    223.      *  
    224.      * @param date 
    225.      * @param certificatePath 
    226.      * @return 
    227.      */  
    228.     public static boolean verifyCertificate(Date date, String certificatePath) {  
    229.         boolean status = true;  
    230.         try {  
    231.             // 取得证书  
    232.             Certificate certificate = getCertificate(certificatePath);  
    233.             // 验证证书是否过期或无效  
    234.             status = verifyCertificate(date, certificate);  
    235.         } catch (Exception e) {  
    236.             status = false;  
    237.         }  
    238.         return status;  
    239.     }  
    240.   
    241.     /** 
    242.      * 验证证书是否过期或无效 
    243.      *  
    244.      * @param date 
    245.      * @param certificate 
    246.      * @return 
    247.      */  
    248.     private static boolean verifyCertificate(Date date, Certificate certificate) {  
    249.         boolean status = true;  
    250.         try {  
    251.             X509Certificate x509Certificate = (X509Certificate) certificate;  
    252.             x509Certificate.checkValidity(date);  
    253.         } catch (Exception e) {  
    254.             status = false;  
    255.         }  
    256.         return status;  
    257.     }  
    258.   
    259.     /** 
    260.      * 签名 
    261.      *  
    262.      * @param keyStorePath 
    263.      * @param alias 
    264.      * @param keyStorePassword 
    265.      * @param aliasPassword 
    266.      * @return 
    267.      * @throws Exception 
    268.      */  
    269.     public static byte[] sign(byte[] sign, String keyStorePath, String alias,  
    270.             String keyStorePassword, String aliasPassword) throws Exception {  
    271.         // 获得证书  
    272.         X509Certificate x509Certificate = (X509Certificate) getCertificate(  
    273.                 keyStorePath, keyStorePassword, alias);  
    274.   
    275.         // 取得私钥  
    276.         PrivateKey privateKey = getPrivateKey(keyStorePath, keyStorePassword,  
    277.                 alias, aliasPassword);  
    278.   
    279.         // 构建签名  
    280.         Signature signature = Signature.getInstance(x509Certificate  
    281.                 .getSigAlgName());  
    282.         signature.initSign(privateKey);  
    283.         signature.update(sign);  
    284.         return signature.sign();  
    285.     }  
    286.   
    287.     /** 
    288.      * 验证签名 
    289.      *  
    290.      * @param data 
    291.      * @param sign 
    292.      * @param certificatePath 
    293.      * @return 
    294.      * @throws Exception 
    295.      */  
    296.     public static boolean verify(byte[] data, byte[] sign,  
    297.             String certificatePath) throws Exception {  
    298.         // 获得证书  
    299.         X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);  
    300.         // 获得公钥  
    301.         PublicKey publicKey = x509Certificate.getPublicKey();  
    302.         // 构建签名  
    303.         Signature signature = Signature.getInstance(x509Certificate  
    304.                 .getSigAlgName());  
    305.         signature.initVerify(publicKey);  
    306.         signature.update(data);  
    307.   
    308.         return signature.verify(sign);  
    309.   
    310.     }  
    311.   
    312.     /** 
    313.      * 验证Certificate 
    314.      *  
    315.      * @param keyStorePath 
    316.      * @param keyStorePassword 
    317.      * @param alias 
    318.      * @return 
    319.      */  
    320.     public static boolean verifyCertificate(Date date, String keyStorePath,  
    321.             String keyStorePassword, String alias) {  
    322.         boolean status = true;  
    323.         try {  
    324.             Certificate certificate = getCertificate(keyStorePath,  
    325.                     keyStorePassword, alias);  
    326.             status = verifyCertificate(date, certificate);  
    327.         } catch (Exception e) {  
    328.             status = false;  
    329.         }  
    330.         return status;  
    331.     }  
    332.   
    333.     /** 
    334.      * 验证Certificate 
    335.      *  
    336.      * @param keyStorePath 
    337.      * @param keyStorePassword 
    338.      * @param alias 
    339.      * @return 
    340.      */  
    341.     public static boolean verifyCertificate(String keyStorePath,  
    342.             String keyStorePassword, String alias) {  
    343.         return verifyCertificate(new Date(), keyStorePath, keyStorePassword,  
    344.                 alias);  
    345.     }  
    346. }  


    相信上述代码已经帮朋友们解决了相当多的问题!
    给出测试类:

    Java代码  收藏代码
    1. import static org.junit.Assert.*;  
    2.   
    3. import java.util.Date;  
    4.   
    5. import org.apache.commons.codec.binary.Hex;  
    6. import org.junit.Test;  
    7.   
    8. /** 
    9.  * 证书操作验证类 
    10.  *  
    11.  * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a> 
    12.  * @version 1.0 
    13.  * @since 1.0 
    14.  */  
    15. public class CertificateCoderTest {  
    16.     private String certificatePath = "zlex.crt";  
    17.     private String keyStorePath = "zlex.keystore";  
    18.     private String keyStorePassword = "123456";  
    19.     private String aliasPassword = "123456";  
    20.     private String alias = "1";  
    21.   
    22.     @Test  
    23.     public void test() throws Exception {  
    24.         System.err.println("公钥加密——私钥解密");  
    25.         String inputStr = "Ceritifcate";  
    26.         byte[] data = inputStr.getBytes();  
    27.   
    28.         byte[] encrypt = CertificateCoder.encryptByPublicKey(data,  
    29.                 certificatePath);  
    30.   
    31.         byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,  
    32.                 keyStorePath, alias, keyStorePassword, aliasPassword);  
    33.         String outputStr = new String(decrypt);  
    34.   
    35.         System.err.println("加密前: " + inputStr + " " + "解密后: " + outputStr);  
    36.   
    37.         // 验证数据一致  
    38.         assertArrayEquals(data, decrypt);  
    39.   
    40.         // 验证证书有效  
    41.         assertTrue(CertificateCoder.verifyCertificate(certificatePath));  
    42.   
    43.     }  
    44.   
    45.     @Test  
    46.     public void testSign() throws Exception {  
    47.         System.err.println("私钥加密——公钥解密");  
    48.   
    49.         String inputStr = "sign";  
    50.         byte[] data = inputStr.getBytes();  
    51.   
    52.         byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,  
    53.                 keyStorePath, keyStorePassword, alias, aliasPassword);  
    54.   
    55.         byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,  
    56.                 certificatePath);  
    57.   
    58.         String outputStr = new String(decodedData);  
    59.         System.err.println("加密前: " + inputStr + " " + "解密后: " + outputStr);  
    60.         assertEquals(inputStr, outputStr);  
    61.   
    62.         System.err.println("私钥签名——公钥验证签名");  
    63.         // 产生签名  
    64.         byte[] sign = CertificateCoder.sign(encodedData, keyStorePath, alias,  
    65.                 keyStorePassword, aliasPassword);  
    66.         System.err.println("签名: " + Hex.encodeHexString(sign));  
    67.   
    68.         // 验证签名  
    69.         boolean status = CertificateCoder.verify(encodedData, sign,  
    70.                 certificatePath);  
    71.         System.err.println("状态: " + status);  
    72.         assertTrue(status);  
    73.     }  
    74.   
    75.     @Test  
    76.     public void testVerify() throws Exception {  
    77.         System.err.println("密钥库证书有效期验证");  
    78.         boolean status = CertificateCoder.verifyCertificate(new Date(),  
    79.                 keyStorePath, keyStorePassword, alias);  
    80.         System.err.println("证书状态: " + status);  
    81.         assertTrue(status);  
    82.     }  
    83. }  


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



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

  • 相关阅读:
    约瑟夫问题
    十点半
    鹊桥相会
    C语言实验——数日子
    汉诺塔
    读入字符串
    C语言实验——各位数字之和排序
    数据结构实验之链表五:单链表的拆分
    C语言实验——分割整数
    大一上学期
  • 原文地址:https://www.cnblogs.com/kabi/p/6232966.html
Copyright © 2011-2022 走看看