zoukankan      html  css  js  c++  java
  • Java加密与解密笔记(四) 高级应用

    术语列表:

    CA:证书颁发认证机构(Certificate Authority)

    PEM:隐私增强邮件(Privacy Enhanced Mail),是OpenSSL使用的一种密钥文件。

    PKI:公钥基础设施(Public Key Infrastructure),可以理解成是一种平台标准。事实上所有的数字证书都符合PIK平台下的X.509标准。正式这个原因,我们才可以在之前的解析数字证书的时候可以用X509Certificate类。即使在X.509的大标准下,仍然存在不同编码格式的数字证书如CER、BER、DER和PICS(包括PKCS7、PKCS10、PKCS12等)

    CSR:证书签发申请(Certificate Siging Request),是一种文件,内容包含了“我是谁”以及“我需要什么样的证书(算法名称,密钥长度等)”

    数字证书

    数字证书的本质其实还是非对称加密。数字证书中KeyStore充当着PrivateKey的角色(其实KeyStore中包含完整的秘钥对),Certificate充当着PublicKey的角色。

    相对于普通的非对称加密算法,数字证书新增了哪些功能?

    //TODO 

    可以用工具keytool来生成KeyStore文件,这个工具存放在在Java的bin目录中。详细说明参考官方说明:http://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html

    可以用下面的命令来生成KeyStore文件:

    keytool -genkey -validity 30 -alias www.example.com -keyalg RSA -keystore d:demo.keystore  

    参数说明:

    genkey:表示生成密钥 
    validity:证书有效期,单位:天
    alias:证书别名
    keyalg:(非对称加密)算法名称
    keystore:KeyStore文件存储位置

    执行过程中会要求输入相关信息:

    输入keystore密码:  
    再次输入新密码:  
    您的名字与姓氏是什么?  
      [Unknown]:  hu
    您的组织单位名称是什么?  
      [Unknown]:  huqiao
    您的组织名称是什么?  
      [Unknown]:  huqiao
    您所在的城市或区域名称是什么?  
      [Unknown]:  Beijing
    您所在的州或省份名称是什么?  
      [Unknown]:  Beijing
    该单位的两字母国家代码是什么  
      [Unknown]:  CN  
    CN=huqiao, OU=huqiao, O=hu, L=Beijing, ST=Beijing, C=CN 正确吗?  
      [否]:  Y  
      
    输入<tomcat>的主密码  
            (如果和 keystore 密码相同,按回车):  
    再次输入新密码:  

    执行完成之后,会在指定位置生成一个.keystore的文件。这个文件中包含了密钥对等其他信息,二进制内容,所以无法用文本编辑器打开。是服务器用的。

    用keytool查看keystore文件信息:

    keytool -list  -v -keystore xxxx.keystore -storepass 密码

    同样用keytool工具,来生成客户端用的cer文件:

    keytool -export -keystore d:demo.keystore -alias www.example.com -file d:demo.cer -rfc  

    这就是颁发给客户端的证书文件:

    可以用Java来读取证书的内容:

        public static void main(String[] args) throws Exception{
            
            X509Certificate cer = (X509Certificate) getCertificate("D:\demo.cer");  
            
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            
            System.out.println("版本:"+cer.getVersion());
            System.out.println("序列号:"+Integer.toHexString(cer.getSerialNumber().intValue()));
            System.out.println("签名算法:"+cer.getSigAlgName());
            System.out.println("颁发者:"+cer.getIssuerDN());
            System.out.println("有限期从:" + sdf.format(cer.getNotBefore()) + "到" + sdf.format(cer.getNotAfter()));
            System.out.println("使用者:" + cer.getSubjectDN());
            
        }
        
        private static Certificate getCertificate(String certificatePath)throws Exception {  
            CertificateFactory certificateFactory = CertificateFactory  
                    .getInstance("X.509");  
            FileInputStream in = new FileInputStream(certificatePath);  
      
            Certificate certificate = certificateFactory.generateCertificate(in);  
            in.close();  
      
            return certificate;  
        } 

     读取到的内容:

    版本:3
    序列号:61cb1ded
    签名算法:SHA256withRSA
    颁发者:CN=hu, OU=huqiao, O=huqiao, L=Beijing, ST=Beijing, C=CN
    有限期从:2017-10-19 11:16:02到2116-05-13 11:16:02
    使用者:CN=hu, OU=huqiao, O=huqiao, L=Beijing, ST=Beijing, C=CN

     同样,读取KeyStore的方法如下:

        /**
         * 从文件读取KeyStore文件 
         * @param keyStoreFilePath
         * @param pwd
         * @return
         * @throws Exception
         */
        public static KeyStore getKeyStore(String keyStoreFilePath,String pwd)throws Exception{
            KeyStore keyStore = KeyStore.getInstance("jks");
            InputStream in = new FileInputStream(keyStoreFilePath);
            keyStore.load(in, pwd.toCharArray());
            return keyStore;
        }

    在KeyStore中,既能拿到私钥也能拿到公钥:

            String pwd = "123456";
            String alias = "www.example.me";
            KeyStore keyStore = getKeyStore("D:\demo.keystore", pwd);
            
            PrivateKey priKey = (PrivateKey)keyStore.getKey(alias, pwd.toCharArray());
            
            
            Certificate cer2 = keyStore.getCertificate(alias);
            PublicKey pubKey = cer2.getPublicKey();
            System.out.println("-------------Private Key-----------------");
            System.out.println(Base64Util.encode(priKey.getEncoded()));
            System.out.println("-------------Public Key-----------------");
            System.out.println(Base64Util.encode(pubKey.getEncoded()));
    -------------Private Key-----------------
    MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRd0QlcJcrImkD5xLkjh7hQRU+
    8Qi1n55k9fhKu+Ee5GTx958XGifX1zWv0IajiWcOCly9SdAWja6afNQZsXAvcoQEouwtwpOQ4KZB
    vipH9aWtU5JLRvPwFER2TDddb1L3fDqhozl8WSDRVLFOgYJdzKp1SblVeGfbOWEz8t4NiUlvB0f0
    srHubafPHy08ZDPvCy72ywuomc6kiwn/IXBRQrFBTanMxWu3mqF4XwawQ+EJlPQIBauHwCaC1N5B
    YQPgNbia6GmfQlATAGt94Vn/e44MZ69e/E9bnWcpSDWZ+y72DdR1YypT/Ey8ercl1Hj0tYuX67vd
    BoEJw/vOTPN3AgMBAAECggEAD+G0GAaeX5XfUn1tsEiaTMfrfXc3CtZMYylHJxtxqS71/Gai+FRy
    WuolVuw/mRys5KKif3OeRGd/qpT2W/BZKi/LlLJpp9qN57kwweFSQVx9sFOazvxVOInA2xtSQ1JS
    fxM7OtAuZqA3XcfHHcWyBbyj2/q4A6P6c+O43AB5F5uDBgWQT7FgMgtuh4A6U0bYaglGX6LEqztj
    ENw6hP1VSEQomw+EAvCTOa0xqDBN8KWJQmEqweq8loVlGr1h8bDsNFRLRUrWFAKqRYBxZ1m+c08m
    1e7rRG8Pj9OcuS2SZBtzmh9NSiWDK0u/zp/A9m6yaLD6qpyfi61+1LkZzcPEAQKBgQDt8zqJ+tBS
    akZMOhStrdzaFu6/USnIfufmj/U/DV66gyCXaTGGw3wG2pPsqmi+XnPVWcHZ/yaILFPXVE59/eox
    IDiAih61U088RKhtzR/4yBZvv9AnSfz5EDC/dt6yv9ptOnaj6dPa7alN0m5lwV+qkEbuNug7azRE
    8Ngd0FO5dwKBgQDhWuZu4W29KCjFTbL5yU23dgi8Dg1v/BjuGG8VBJ/RSSOM0wDT7jVyjflLRea3
    jXKYIhKeOqpbMN5xsVvwuF5bXdGneMzT8AAmFjpfR2P8PE9RdB61TELGtz7gov4dh6dJ+Nokxo9L
    PIvQ/cBL6/hKvX06VAQPcm/2BQnTBn8WAQKBgHaKiqo8mlXEffrxoGWZzQGVFSGYhJFOr6bMJuhf
    d8bBFpZ3oGW7s2kSsUjg6EeWdGxgR9Obag3Cz43hgS0BNw98NsnKhVveAgZLSgFRhFEDFTJcw40f
    LfjCWRa5WF6Cd4Wc74ffMFzLs2GCqN7mhAtLzxpTnkQjtyl1NqU7qMonAoGAVfKYPiPF+cWuPwnS
    P8gR1u2yiR6G63XngC9bdlWsKmLNpzD2eN26DrWtJZNEWi8dTH56QVS4kk0CGbR+D0IR4qDWjBvb
    at13AQ+rNZmBvbq2uaci6xxpv2Y2GfCwIE0TdXfuouYD0rsFzDBrPcmCiebZMvzGC6omn1ruk0hA
    AgECgYB2Ub/V5jlBtNDYjROJ1cHWKlg9uTHv6ovRiDO4jcaXwEKuoBQGgjkyxBTsIItz4GAUHVYc
    AxOnNCaJ94zyLzWI85/0+QBOqkgS6zdkmIcBk5Lj9P+Yk7/YVlNNGp9Mv9peHRqF8dRSHtqqUWMy
    vDs4ZprpdLHXNcnDvtSseQ5lBA==
    -------------Public Key-----------------
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0XdEJXCXKyJpA+cS5I4e4UEVPvEItZ+e
    ZPX4SrvhHuRk8fefFxon19c1r9CGo4lnDgpcvUnQFo2umnzUGbFwL3KEBKLsLcKTkOCmQb4qR/Wl
    rVOSS0bz8BREdkw3XW9S93w6oaM5fFkg0VSxToGCXcyqdUm5VXhn2zlhM/LeDYlJbwdH9LKx7m2n
    zx8tPGQz7wsu9ssLqJnOpIsJ/yFwUUKxQU2pzMVrt5qheF8GsEPhCZT0CAWrh8AmgtTeQWED4DW4
    muhpn0JQEwBrfeFZ/3uODGevXvxPW51nKUg1mfsu9g3UdWMqU/xMvHq3JdR49LWLl+u73QaBCcP7
    zkzzdwIDAQAB

    有效期验证:

        /**
         * 有限期验证
         * @param cer
         * @param date
         * @return
         */
        public static boolean verifyDate(Certificate cer,Date date){
             X509Certificate x509Certificate = (X509Certificate) cer;  
             try {
                x509Certificate.checkValidity(date);
                return true;
            } catch (Exception e) {
                return false;
            }  
            
        }

    签名和验证签名:

        /**
         * 签名
         * @param data
         * @param cer
         * @return
         */
        public static String sign(String data,KeyStore keyStore,String alias,String pwd)throws Exception{
            PrivateKey privateKey = getPrivateKey(keyStore, alias, pwd);
            X509Certificate cer = (X509Certificate)keyStore.getCertificate(alias);
            Signature signature = Signature.getInstance(cer.getSigAlgName());
            signature.initSign(privateKey);
            signature.update(data.getBytes("UTF-8"));
            return Base64Util.encode(signature.sign());
        }
        
        /**
         * 验证签名
         * @param sign
         * @param cer
         * @return
         */
        public static boolean signVerify(String data,String sign,Certificate cer)throws Exception{
            byte[] signData = Base64Util.decode(sign);
            PublicKey publicKey = cer.getPublicKey();
            Signature signature = Signature.getInstance(((X509Certificate)cer).getSigAlgName());
            signature.initVerify(publicKey);
            signature.update(data.getBytes());
            return signature.verify(signData);
        }
        

    需要注意的是签名算法应该从证书里拿,而不是密钥你拿。

    加密和解密:

        /**
         * 加密
         * @param data
         * @param cer
         * @return
         */
        public static String encrypt(String data,Certificate cer)throws Exception{
            PublicKey publicKey = cer.getPublicKey();
            Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encrypedData = cipher.doFinal(data.getBytes("UTF-8"));
            return Base64Util.encode(encrypedData);
        }
        
        /**
         * 解密
         * @param data
         * @param cer
         * @return
         */
        public static String decrypt(String data,KeyStore keyStore,String alias,String pwd)throws Exception{
            PrivateKey privteKey = getPrivateKey(keyStore, alias, pwd);
            Cipher cipher = Cipher.getInstance(privteKey.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privteKey);
            byte[] decrypedData = cipher.doFinal(Base64Util.decode(data));
            return new String(decrypedData,"UTF-8");
        }

    测试:

    public static void main(String[] args) throws Exception{
            
            X509Certificate cer = (X509Certificate) getCertificate("D:\test.cer");  
            
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            
            System.out.println("版本:"+cer.getVersion());
            System.out.println("序列号:"+Integer.toHexString(cer.getSerialNumber().intValue()));
            System.out.println("签名算法:"+cer.getSigAlgName());
            System.out.println("颁发者:"+cer.getIssuerDN());
            System.out.println("有限期从:" + sdf.format(cer.getNotBefore()) + "到" + sdf.format(cer.getNotAfter()));
            System.out.println("使用者:" + cer.getSubjectDN());
            
            String pwd = "123456";
            String alias = "blog.huqiao.me";
            KeyStore keyStore = getKeyStore("D:\test.keystore", pwd);
            
            PrivateKey priKey = (PrivateKey)keyStore.getKey(alias, pwd.toCharArray());
            
            
            Certificate cer2 = keyStore.getCertificate(alias);
            PublicKey pubKey = cer2.getPublicKey();
            System.out.println("-------------Private Key-----------------");
            System.out.println(Base64Util.encode(priKey.getEncoded()));
            System.out.println("-------------Public Key-----------------");
            System.out.println(Base64Util.encode(pubKey.getEncoded()));
            
            String data = "Hello,Certificate";
            System.out.println("原文:" + data);
            
            String sign = sign(data, keyStore, alias, pwd);
            System.out.println("签名:" + sign);
            
            boolean signVerify = signVerify(data, sign,(Certificate)cer);
            System.out.println("签名验证:" + signVerify);
            
            String encryptData = encrypt(data, cer);
            System.out.println("加密后:" + encryptData);
            
            String decryptData = decrypt(encryptData, keyStore, alias, pwd);
            System.out.println("解密后:" + decryptData);
            
        }
    -------------Private Key-----------------
    MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRd0QlcJcrImkD5xLkjh7hQRU+
    8Qi1n55k9fhKu+Ee5GTx958XGifX1zWv0IajiWcOCly9SdAWja6afNQZsXAvcoQEouwtwpOQ4KZB
    vipH9aWtU5JLRvPwFER2TDddb1L3fDqhozl8WSDRVLFOgYJdzKp1SblVeGfbOWEz8t4NiUlvB0f0
    srHubafPHy08ZDPvCy72ywuomc6kiwn/IXBRQrFBTanMxWu3mqF4XwawQ+EJlPQIBauHwCaC1N5B
    YQPgNbia6GmfQlATAGt94Vn/e44MZ69e/E9bnWcpSDWZ+y72DdR1YypT/Ey8ercl1Hj0tYuX67vd
    BoEJw/vOTPN3AgMBAAECggEAD+G0GAaeX5XfUn1tsEiaTMfrfXc3CtZMYylHJxtxqS71/Gai+FRy
    WuolVuw/mRys5KKif3OeRGd/qpT2W/BZKi/LlLJpp9qN57kwweFSQVx9sFOazvxVOInA2xtSQ1JS
    fxM7OtAuZqA3XcfHHcWyBbyj2/q4A6P6c+O43AB5F5uDBgWQT7FgMgtuh4A6U0bYaglGX6LEqztj
    ENw6hP1VSEQomw+EAvCTOa0xqDBN8KWJQmEqweq8loVlGr1h8bDsNFRLRUrWFAKqRYBxZ1m+c08m
    1e7rRG8Pj9OcuS2SZBtzmh9NSiWDK0u/zp/A9m6yaLD6qpyfi61+1LkZzcPEAQKBgQDt8zqJ+tBS
    akZMOhStrdzaFu6/USnIfufmj/U/DV66gyCXaTGGw3wG2pPsqmi+XnPVWcHZ/yaILFPXVE59/eox
    IDiAih61U088RKhtzR/4yBZvv9AnSfz5EDC/dt6yv9ptOnaj6dPa7alN0m5lwV+qkEbuNug7azRE
    8Ngd0FO5dwKBgQDhWuZu4W29KCjFTbL5yU23dgi8Dg1v/BjuGG8VBJ/RSSOM0wDT7jVyjflLRea3
    jXKYIhKeOqpbMN5xsVvwuF5bXdGneMzT8AAmFjpfR2P8PE9RdB61TELGtz7gov4dh6dJ+Nokxo9L
    PIvQ/cBL6/hKvX06VAQPcm/2BQnTBn8WAQKBgHaKiqo8mlXEffrxoGWZzQGVFSGYhJFOr6bMJuhf
    d8bBFpZ3oGW7s2kSsUjg6EeWdGxgR9Obag3Cz43hgS0BNw98NsnKhVveAgZLSgFRhFEDFTJcw40f
    LfjCWRa5WF6Cd4Wc74ffMFzLs2GCqN7mhAtLzxpTnkQjtyl1NqU7qMonAoGAVfKYPiPF+cWuPwnS
    P8gR1u2yiR6G63XngC9bdlWsKmLNpzD2eN26DrWtJZNEWi8dTH56QVS4kk0CGbR+D0IR4qDWjBvb
    at13AQ+rNZmBvbq2uaci6xxpv2Y2GfCwIE0TdXfuouYD0rsFzDBrPcmCiebZMvzGC6omn1ruk0hA
    AgECgYB2Ub/V5jlBtNDYjROJ1cHWKlg9uTHv6ovRiDO4jcaXwEKuoBQGgjkyxBTsIItz4GAUHVYc
    AxOnNCaJ94zyLzWI85/0+QBOqkgS6zdkmIcBk5Lj9P+Yk7/YVlNNGp9Mv9peHRqF8dRSHtqqUWMy
    vDs4ZprpdLHXNcnDvtSseQ5lBA==
    -------------Public Key-----------------
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0XdEJXCXKyJpA+cS5I4e4UEVPvEItZ+e
    ZPX4SrvhHuRk8fefFxon19c1r9CGo4lnDgpcvUnQFo2umnzUGbFwL3KEBKLsLcKTkOCmQb4qR/Wl
    rVOSS0bz8BREdkw3XW9S93w6oaM5fFkg0VSxToGCXcyqdUm5VXhn2zlhM/LeDYlJbwdH9LKx7m2n
    zx8tPGQz7wsu9ssLqJnOpIsJ/yFwUUKxQU2pzMVrt5qheF8GsEPhCZT0CAWrh8AmgtTeQWED4DW4
    muhpn0JQEwBrfeFZ/3uODGevXvxPW51nKUg1mfsu9g3UdWMqU/xMvHq3JdR49LWLl+u73QaBCcP7
    zkzzdwIDAQAB
    原文:Hello,Certificate
    签名:0NxD/FHk9CIdfoLIN7/TrQkFhEMGJzJr6E/do7aR8mgUAJjEHNg9NhXT1eaI8hszuofFPj8PhN+w
    fE2N2YqB8ozBbNhvMvUbeMaAK2gFrMCBsw+ihbtPwTVoc3sxY3FQSDmEgLBY2IBtmvji9XdrclNY
    D/IJJhg5DwlXpIoYPRIf2Ct+JkvY4sM/6xNm1ZyKb0CZbKJTAZQ57BuXU4vvs5wvB6TAK/ilR5yV
    TFhKlzLRS68FPCREukdiB/eITXPugfEBTCyIUQhrF2qaxdKOwyTN7dCWI16QVtAYKT9SG2Dbs5bu
    bBRsYlwhrLYunBER8QCvX7gHLLZIiCheQg3VaQ==
    签名验证:true
    加密后:rkiHwkuAdS1WikNq7bogqdmR+alDc7anV/RGcKbX9LmBJoUyQcV+Iu2K1bhc44yddnxfGy0uRqKM
    9rsfPM/O1epB09oz5QdeOj8BP1Em8WEjhsG6LxU9oCPj3jypV/z6gH6fOg1idz0nS+sDuXqHqj/t
    rNx0n3SgztG2Ek5S/Px2STHmS+G7FghPP4ZbW0IeKSOpRbErKW82aA4AF3Rsn7e6eSzHZT+2WMs/
    2oTfzwfYguimLZA4TUTJwTXJ2lK3XRkIkaBo27er81BX7IaT44bYn7y7ujiWmGEbdgOgck+FNqny
    gSVvYUvDvli8w5HB+0cEa7VpUDIqw3MFJ+Z2HQ==
    解密后:Hello,Certificate

    小结:数字证书就是在非对称加密的基础上增加了一些其他的信息,具体的加密也解密,签名也签名验证在与之前的RSA没有什么差别。

    HTTPS

    HTTPS是使用SSL/TLS加密的HTTP协议。

    客户端与服务器通信用的是数字证书(非对称加密),客户端拿到服务器的证书,用这个证书的公钥进行数据加密,然后将数据发送给服务器。

    加密通信没问题了,通信过程不会被别人窃听和篡改。但是还是有一个问题,就是如何确定服务器是否被冒牌了。

    确定服务器是否是“真的”服务器时,客户端和服务器两方说了都不算数,得需要第三方来证明。这就是CA(证书颁发验证机构)。

    CA负责注册服务器,记录服务器的详细信息,并给服务器颁发证书。

    那么怎么确保CA的可靠性。从理论上讲无法确认,于是只能人为地构建认证机构,比如Symantec、VeriSign、GeoTrust等。这些机构向全球提供证书服务。我们的浏览器或系统内置了这些机构的证书,所以在访问这些机构或子机构认证的服务器时可以正常通过验证。

    我们可以不用公共的CA服务,自己给服务器搞一个证书,但是浏览器不会认,需要手动把这些证书导入到本地系统才行。

    其他相关文章:
     
     

    参考:

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

    https://zhuanlan.zhihu.com/p/24854237

  • 相关阅读:
    venv(virtual environment)的使用
    Pytest 失败重运行机制
    Python 中方法和函数的区别
    手机移动端WEB资源整合
    Sass学习日志
    1、vue基础使用复习
    vscode配置笔记
    vue兼容IE浏览器、对低版本IE下的友好提示
    关闭eslint校验
    vue实现吸顶的效果
  • 原文地址:https://www.cnblogs.com/at0x7c00/p/7691817.html
Copyright © 2011-2022 走看看