• java-信息安全(十七)-*.PFX(*.p12)&个人信息交换文件


    原文地址

    http://snowolf.iteye.com/blog/735294

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

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

    cmd:

    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);  
        }  
    }  
    View Code

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

    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 + "
    
    " + "解密后: " + 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 + "
    
    " + "解密后: " + outputStr);  
            assertEquals(inputStr, outputStr);  
      
            System.err.println("私钥签名——公钥验证签名");  
            // 产生签名  
            byte[] sign = CertificateCoder.sign(encodedData, keyStorePath, alias,  
                    keyStorePassword, aliasPassword);  
            System.err.println("签名:
    " + Hex.encodeHexString(sign));  
      
            // 验证签名  
            boolean status = CertificateCoder.verify(encodedData, sign,  
                    certificatePath);  
            System.err.println("状态:
    " + status);  
            assertTrue(status);  
        }  
      
        @Test  
        public void testVerify() throws Exception {  
            System.err.println("密钥库证书有效期验证");  
            boolean status = CertificateCoder.verifyCertificate(new Date(),  
                    keyStorePath, keyStorePassword, alias);  
            System.err.println("证书状态:
    " + status);  
            assertTrue(status);  
        }  
    }  
    View Code

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

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

  • 相关阅读:
    golang ---cron
    Maven私库安装与配置
    Java8新特性之重复注解(repeating annotations)浅析
    String split
    如何将xml转为python中的字典
    json字符串和dict互转
    为什么空格拷贝到linux 会变成两个
    python之socket编程
    ntpdate设置
    Nginx配置ssl证书
  • 原文地址:https://www.cnblogs.com/bjlhx/p/6565839.html
Copyright © 2020-2023  润新知