Java证书体系

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

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 

控制台输出:

输入keystore密码:
再次输入新密码:
您的名字与姓氏是什么?
  [Unknown]:  www.zlex.org
您的组织单位名称是什么?
  [Unknown]:  zlex
您的组织名称是什么?
  [Unknown]:  zlex
您所在的城市或区域名称是什么?
  [Unknown]:  BJ
您所在的州或省份名称是什么?
  [Unknown]:  BJ
该单位的两字母国家代码是什么
  [Unknown]:  CN
CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗?
  [否]:  Y

输入<tomcat>的主密码
        (如果和 keystore 密码相同,按回车):
再次输入新密码:


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

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

keytool -export -keystore d:\zlex.keystore -alias www.zlex.org -file d:\zlex.cer -rfc



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

控制台输出:

输入keystore密码:
保存在文件中的认证 <d:\zlex.cer>



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

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

通过java代码实现如下:Coder类见

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



再给出一个测试类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import  static  org.junit.Assert.*;
 
import  org.junit.Test;
 
/**
 
  * @author 梁栋
  * @version 1.0
  * @since 1.0
  */
public  class  CertificateCoderTest {
     private  String password =  "123456" ;
     private  String alias =  "www.zlex.org" ;
     private  String certificatePath =  "d:/zlex.cer" ;
     private  String keyStorePath =  "d:/zlex.keystore" ;
 
     @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, password);
         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, alias, password);
 
         byte [] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                 certificatePath);
 
         String outputStr =  new  String(decodedData);
         System.err.println( "加密前: "  + inputStr +  "\n\r"  "解密后: "  + outputStr);
         assertEquals(inputStr, outputStr);
 
         System.err.println( "私钥签名——公钥验证签名" );
         // 产生签名
         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
                 password);
         System.err.println( "签名:\r"  + sign);
 
         // 验证签名
         boolean  status = CertificateCoder.verify(encodedData, sign,
                 certificatePath);
         System.err.println( "状态:\r"  + status);
         assertTrue(status);
 
     }
}



控制台输出:

公钥加密——私钥解密
加密前: Ceritificate

解密后: Ceritificate

私钥加密——公钥解密
加密前: sign

解密后: sign
私钥签名——公钥验证签名
签名:
pqBn5m6PJlfOjH0A6U2o2mUmBsfgyEY1NWCbiyA/I5Gc3gaVNVIdj/zkGNZRqTjhf3+J9a9z9EI7
6F2eWYd7punHx5oh6hfNgcKbVb52EfItl4QEN+djbXiPynn07+Lbg1NOjULnpEd6ZhLP1YwrEAuM
OfvX0e7/wplxLbySaKQ=

状态:
true



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

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

jarsigner -storetype jks -keystore zlex.keystore -verbose tools.jar www.zlex.org


控制台输出:

输入密钥库的口令短语:
 正在更新: META-INF/WWW_ZLEX.SF
 正在更新: META-INF/WWW_ZLEX.RSA
  正在签名: org/zlex/security/Security.class
  正在签名: org/zlex/tool/Main$1.class
  正在签名: org/zlex/tool/Main$2.class
  正在签名: org/zlex/tool/Main.class

警告:
签名者证书将在六个月内过期。



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

jarsigner -verify -verbose -certs tools.jar


控制台输出:

         402 Sat Jun 20 16:25:14 CST 2009 META-INF/MANIFEST.MF
         532 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.SF
         889 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.RSA
sm       590 Wed Dec 10 13:03:42 CST 2008 org/zlex/security/Security.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]

sm       705 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$1.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]

sm       779 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$2.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]

sm     12672 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main.class

      X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
      [证书将在 09-9-18 下午3:27 到期]


  s = 已验证签名
  m = 在清单中列出条目
  k = 在密钥库中至少找到了一个证书
  i = 在身份作用域内至少找到了一个证书

jar 已验证。

警告:
此 jar 包含签名者证书将在六个月内过期的条目。



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

    在中,我们模拟了一个基于RSA非对称加密网络的安全通信。现在我们深度了解一下现有的安全网络通信——SSL。 
    我们需要构建一个由CA机构签发的有效证书,这里我们使用上文中生成的自签名证书zlex.cer 
    这里,我们将证书导入到我们的密钥库。 

keytool -import -alias www.zlex.org -file d:/zlex.cer -keystore d:/zlex.keystore



其中 
-import表示导入 
-alias指定别名,这里是www.zlex.org 
-file指定算法,这里是d:/zlex.cer 
-keystore指定存储位置,这里是d:/zlex.keystore 
在这里我使用的密码为654321 

控制台输出:

输入keystore密码:
再次输入新密码:
所有者:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
签发人:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
序列号:4a1e48df
有效期: Thu May 28 16:18:39 CST 2009 至Wed Aug 26 16:18:39 CST 2009
证书指纹:
         MD5:19:CA:E6:36:E2:DF:AD:96:31:97:2F:A9:AD:FC:37:6A
         SHA1:49:88:30:59:29:45:F1:69:CA:97:A9:6D:8A:CF:08:D2:C3:D5:C0:C4
         签名算法名称:SHA1withRSA
         版本: 3
信任这个认证? [否]:  y
认证已添加至keystore中



OK,最复杂的准备工作已经完成。 

猜你喜欢

转载自blog.csdn.net/wjq008/article/details/49071849