zoukankan      html  css  js  c++  java
  • Java加密技术(八)——数字证书

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

    请大家在阅读本篇内容时先阅读 Java加密技术(四),预先了解RSA加密算法。 

    在构建Java代码实现前,我们需要完成证书的制作。 
    1.生成keyStroe文件 
    在命令行下执行以下命令: 

    Shell代码  收藏代码
    1. keytool -genkey -validity 36000 -alias www.zlex.org -keyalg RSA -keystore d:zlex.keystore  



    其中 
    -genkey表示生成密钥 
    -validity指定证书有效期,这里是36000天 
    -alias指定别名,这里是www.zlex.org 
    -keyalg指定算法,这里是RSA 
    -keystore指定存储位置,这里是d:zlex.keystore 

    在这里我使用的密码为 123456 

    控制台输出: 

    Console代码  收藏代码
    1. 输入keystore密码:  
    2. 再次输入新密码:  
    3. 您的名字与姓氏是什么?  
    4.   [Unknown]:  www.zlex.org  
    5. 您的组织单位名称是什么?  
    6.   [Unknown]:  zlex  
    7. 您的组织名称是什么?  
    8.   [Unknown]:  zlex  
    9. 您所在的城市或区域名称是什么?  
    10.   [Unknown]:  BJ  
    11. 您所在的州或省份名称是什么?  
    12.   [Unknown]:  BJ  
    13. 该单位的两字母国家代码是什么  
    14.   [Unknown]:  CN  
    15. CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗?  
    16.   [否]:  Y  
    17.   
    18. 输入<tomcat>的主密码  
    19.         (如果和 keystore 密码相同,按回车):  
    20. 再次输入新密码:  


    这时,在D盘下会生成一个zlex.keystore的文件。 

    2.生成自签名证书 
    光有keyStore文件是不够的,还需要证书文件,证书才是直接提供给外界使用的公钥凭证。 
    导出证书: 

    Shell代码  收藏代码
    1. keytool -export -keystore d:zlex.keystore -alias www.zlex.org -file d:zlex.cer -rfc  



    其中 
    -export指定为导出操作 
    -keystore指定keystore文件 
    -alias指定导出keystore文件中的别名 
    -file指向导出路径 
    -rfc以文本格式输出,也就是以BASE64编码输出 
    这里的密码是 123456 

    控制台输出: 

    Console代码  收藏代码
    1. 输入keystore密码:  
    2. 保存在文件中的认证 <d:zlex.cer>  



    当然,使用方是需要导入证书的! 
    可以通过自签名证书完成CAS单点登录系统的构建! 

    Ok,准备工作完成,开始Java实现! 

    通过java代码实现如下:Coder类见 Java加密技术(一) 

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



    再给出一个测试类: 

    Java代码  收藏代码
    1. import static org.junit.Assert.*;  
    2.   
    3. import org.junit.Test;  
    4.   
    5. /** 
    6.  *  
    7.  * @author 梁栋 
    8.  * @version 1.0 
    9.  * @since 1.0 
    10.  */  
    11. public class CertificateCoderTest {  
    12.     private String password = "123456";  
    13.     private String alias = "www.zlex.org";  
    14.     private String certificatePath = "d:/zlex.cer";  
    15.     private String keyStorePath = "d:/zlex.keystore";  
    16.   
    17.     @Test  
    18.     public void test() throws Exception {  
    19.         System.err.println("公钥加密——私钥解密");  
    20.         String inputStr = "Ceritifcate";  
    21.         byte[] data = inputStr.getBytes();  
    22.   
    23.         byte[] encrypt = CertificateCoder.encryptByPublicKey(data,  
    24.                 certificatePath);  
    25.   
    26.         byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,  
    27.                 keyStorePath, alias, password);  
    28.         String outputStr = new String(decrypt);  
    29.   
    30.         System.err.println("加密前: " + inputStr + " " + "解密后: " + outputStr);  
    31.   
    32.         // 验证数据一致  
    33.         assertArrayEquals(data, decrypt);  
    34.   
    35.         // 验证证书有效  
    36.         assertTrue(CertificateCoder.verifyCertificate(certificatePath));  
    37.   
    38.     }  
    39.   
    40.     @Test  
    41.     public void testSign() throws Exception {  
    42.         System.err.println("私钥加密——公钥解密");  
    43.   
    44.         String inputStr = "sign";  
    45.         byte[] data = inputStr.getBytes();  
    46.   
    47.         byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,  
    48.                 keyStorePath, alias, password);  
    49.   
    50.         byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,  
    51.                 certificatePath);  
    52.   
    53.         String outputStr = new String(decodedData);  
    54.         System.err.println("加密前: " + inputStr + " " + "解密后: " + outputStr);  
    55.         assertEquals(inputStr, outputStr);  
    56.   
    57.         System.err.println("私钥签名——公钥验证签名");  
    58.         // 产生签名  
    59.         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,  
    60.                 password);  
    61.         System.err.println("签名: " + sign);  
    62.   
    63.         // 验证签名  
    64.         boolean status = CertificateCoder.verify(encodedData, sign,  
    65.                 certificatePath);  
    66.         System.err.println("状态: " + status);  
    67.         assertTrue(status);  
    68.   
    69.     }  
    70. }  



    控制台输出: 

    Console代码  收藏代码
    1. 公钥加密——私钥解密  
    2. 加密前: Ceritificate  
    3.   
    4. 解密后: Ceritificate  
    5.   
    6. 私钥加密——公钥解密  
    7. 加密前: sign  
    8.   
    9. 解密后: sign  
    10. 私钥签名——公钥验证签名  
    11. 签名:  
    12. pqBn5m6PJlfOjH0A6U2o2mUmBsfgyEY1NWCbiyA/I5Gc3gaVNVIdj/zkGNZRqTjhf3+J9a9z9EI7  
    13. 6F2eWYd7punHx5oh6hfNgcKbVb52EfItl4QEN+djbXiPynn07+Lbg1NOjULnpEd6ZhLP1YwrEAuM  
    14. OfvX0e7/wplxLbySaKQ=  
    15.   
    16. 状态:  
    17. true  



    由此完成了证书验证体系! 

    同样,我们可以对代码做签名——代码签名! 
    通过工具JarSigner可以完成代码签名。 
    这里我们对tools.jar做代码签名,命令如下: 

    Shell代码  收藏代码
    1. jarsigner -storetype jks -keystore zlex.keystore -verbose tools.jar www.zlex.org  


    控制台输出: 

    Console代码  收藏代码
    1. 输入密钥库的口令短语:  
    2.  正在更新: META-INF/WWW_ZLEX.SF  
    3.  正在更新: META-INF/WWW_ZLEX.RSA  
    4.   正在签名: org/zlex/security/Security.class  
    5.   正在签名: org/zlex/tool/Main$1.class  
    6.   正在签名: org/zlex/tool/Main$2.class  
    7.   正在签名: org/zlex/tool/Main.class  
    8.   
    9. 警告:  
    10. 签名者证书将在六个月内过期。  



    此时,我们可以对签名后的jar做验证! 
    验证tools.jar,命令如下: 

    Shell代码  收藏代码
    1. jarsigner -verify -verbose -certs tools.jar  


    控制台输出: 

    Console代码  收藏代码
    1.          402 Sat Jun 20 16:25:14 CST 2009 META-INF/MANIFEST.MF  
    2.          532 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.SF  
    3.          889 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.RSA  
    4. sm       590 Wed Dec 10 13:03:42 CST 2008 org/zlex/security/Security.class  
    5.   
    6.       X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN  
    7.       [证书将在 09-9-18 下午3:27 到期]  
    8.   
    9. sm       705 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$1.class  
    10.   
    11.       X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN  
    12.       [证书将在 09-9-18 下午3:27 到期]  
    13.   
    14. sm       779 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$2.class  
    15.   
    16.       X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN  
    17.       [证书将在 09-9-18 下午3:27 到期]  
    18.   
    19. sm     12672 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main.class  
    20.   
    21.       X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN  
    22.       [证书将在 09-9-18 下午3:27 到期]  
    23.   
    24.   
    25.   s = 已验证签名  
    26.   m = 在清单中列出条目  
    27.   k = 在密钥库中至少找到了一个证书  
    28.   i = 在身份作用域内至少找到了一个证书  
    29.   
    30. jar 已验证。  
    31.   
    32. 警告:  
    33. 此 jar 包含签名者证书将在六个月内过期的条目。  



    代码签名认证的用途主要是对发布的软件做验证,支持 Sun Java .jar (Java Applet) 文件(J2SE)和 J2ME MIDlet Suite 文件。 
     



    相关链接: 
    Java加密技术(一)——BASE64与单向加密算法MD5&SHA&MAC 
    Java加密技术(二)——对称加密DES&AES 
    Java加密技术(三)——PBE算法 
    Java加密技术(四)——非对称加密算法RSA 
    Java加密技术(五)——非对称加密算法的由来 
    Java加密技术(六)——数字签名算法DSA 
    Java加密技术(七)——非对称加密算法最高ECC 
    Java加密技术(八)——数字证书 
    Java加密技术(九)——初探SSL 
    Java加密技术(十)——单向认证 
    Java加密技术(十一)——双向认证 
    Java加密技术(十二)——*.PFX(*.p12)&个人信息交换文件 

  • 相关阅读:
    51 Nod 1068 Bash游戏v3
    51 Nod Bash 游戏v2
    51 Nod 1073 约瑟夫环
    UVA 12063 Zeros and ones 一道需要好好体会的好题
    51 Nod 1161 Partial sums
    2018中国大学生程序设计竞赛
    UVA 11971 Polygon
    UVA 10900 So do you want to be a 2^n-aire?
    UVA 11346 Possibility
    python with as 的用法
  • 原文地址:https://www.cnblogs.com/shihaiming/p/7614325.html
Copyright © 2011-2022 走看看