各种Java加密算法

您的评价:
     
 
  如基本的单向加密算法:

  • BASE64 严格地说,属于编码格式,而非加密算法

  • MD5(Message Digest algorithm 5,信息摘要算法)

  • SHA(Secure Hash Algorithm,安全散列算法)

  • HMAC(Hash Message Authentication Code,散列消息鉴别码)

复杂的对称加密(DES、PBE)、非对称加密算法:

  • DES(Data Encryption Standard,数据加密算法)

  • PBE(Password-based encryption,基于密码验证)

  • RSA(算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman)

  • DH(Diffie-Hellman算法,密钥一致协议)

  • DSA(Digital Signature Algorithm,数字签名)

  • ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)

本篇内容简要介绍BASE64MD5SHAHMAC几种方法。 
    MD5SHAHMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法。我们通常只把他们作为加密的基础。单纯的以上三种的加密并不可靠。

BASE64 
按 照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.) 
常见于邮件、http加密,截取http信息,你就会发现登录操作的用户名、密码字段通过BASE64加密的。

通过java代码实现如下:

01 /**
02      * BASE64解密
03      
04      * @param key
05      * @return
06      * @throws Exception
07      */
08     public static byte[] decryptBASE64(String key) throws Exception {
09         return (new BASE64Decoder()).decodeBuffer(key);
10     }
11  
12     /**
13      * BASE64加密
14      
15      * @param key
16      * @return
17      * @throws Exception
18      */
19     public static String encryptBASE64(byte[] key) throws Exception {
20         return (new BASE64Encoder()).encodeBuffer(key);
21     }

主要就是BASE64Encoder、BASE64Decoder两个类,我们只需要知道使用对应的方法即可。另,BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充。

MD5 
MD5 -- message-digest algorithm 5 (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都 是MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友都见过下载链接旁边放着MD5的串。就是用来验证文 件是否一致的。

通过java代码实现如下:

01 /**
02      * MD5加密
03      
04      * @param data
05      * @return
06      * @throws Exception
07      */
08     public static byte[] encryptMD5(byte[] data) throws Exception {
09  
10         MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
11         md5.update(data);
12  
13         return md5.digest();
14  
15     }

通常我们不直接使用上述MD5加密。通常将MD5产生的字节数组交给BASE64再加密一把,得到相应的字符串。

SHA 
SHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了, 但是SHA仍然是公认的安全加密算法,较之MD5更为安全。

通过java代码实现如下:

01 /**
02      * SHA加密
03      
04      * @param data
05      * @return
06      * @throws Exception
07      */
08     public static byte[] encryptSHA(byte[] data) throws Exception {
09  
10         MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
11         sha.update(data);
12  
13         return sha.digest();
14  
15     }
16 }

HMAC 
HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个 标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证 等。

通过java代码实现如下:

01 /**
02      * 初始化HMAC密钥
03      
04      * @return
05      * @throws Exception
06      */
07     public static String initMacKey() throws Exception {
08         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
09  
10         SecretKey secretKey = keyGenerator.generateKey();
11         return encryptBASE64(secretKey.getEncoded());
12     }
13  
14     /**
15      * HMAC加密
16      
17      * @param data
18      * @param key
19      * @return
20      * @throws Exception
21      */
22     public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
23  
24         SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
25         Mac mac = Mac.getInstance(secretKey.getAlgorithm());
26         mac.init(secretKey);
27  
28         return mac.doFinal(data);
29  
30     }

给出一个完整类,如下:

001 import java.security.MessageDigest;
002  
003 import javax.crypto.KeyGenerator;
004 import javax.crypto.Mac;
005 import javax.crypto.SecretKey;
006  
007 import sun.misc.BASE64Decoder;
008 import sun.misc.BASE64Encoder;
009  
010 /**
011  * 基础加密组件
012  
013  * @author 梁栋
014  * @version 1.0
015  * @since 1.0
016  */
017 public abstract class Coder {
018     public static final String KEY_SHA = "SHA";
019     public static final String KEY_MD5 = "MD5";
020  
021     /**
022      * MAC算法可选以下多种算法
023      
024      * <pre>
025      * HmacMD5 
026      * HmacSHA1 
027      * HmacSHA256 
028      * HmacSHA384 
029      * HmacSHA512
030      * </pre>
031      */
032     public static final String KEY_MAC = "HmacMD5";
033  
034     /**
035      * BASE64解密
036      
037      * @param key
038      * @return
039      * @throws Exception
040      */
041     public static byte[] decryptBASE64(String key) throws Exception {
042         return (new BASE64Decoder()).decodeBuffer(key);
043     }
044  
045     /**
046      * BASE64加密
047      
048      * @param key
049      * @return
050      * @throws Exception
051      */
052     public static String encryptBASE64(byte[] key) throws Exception {
053         return (new BASE64Encoder()).encodeBuffer(key);
054     }
055  
056     /**
057      * MD5加密
058      
059      * @param data
060      * @return
061      * @throws Exception
062      */
063     public static byte[] encryptMD5(byte[] data) throws Exception {
064  
065         MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
066         md5.update(data);
067  
068         return md5.digest();
069  
070     }
071  
072     /**
073      * SHA加密
074      
075      * @param data
076      * @return
077      * @throws Exception
078      */
079     public static byte[] encryptSHA(byte[] data) throws Exception {
080  
081         MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
082         sha.update(data);
083  
084         return sha.digest();
085  
086     }
087  
088     /**
089      * 初始化HMAC密钥
090      
091      * @return
092      * @throws Exception
093      */
094     public static String initMacKey() throws Exception {
095         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
096  
097         SecretKey secretKey = keyGenerator.generateKey();
098         return encryptBASE64(secretKey.getEncoded());
099     }
100  
101     /**
102      * HMAC加密
103      
104      * @param data
105      * @param key
106      * @return
107      * @throws Exception
108      */
109     public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
110  
111         SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
112         Mac mac = Mac.getInstance(secretKey.getAlgorithm());
113         mac.init(secretKey);
114  
115         return mac.doFinal(data);
116  
117     }
118 }

再给出一个测试类:

01 import static org.junit.Assert.*;
02  
03 import org.junit.Test;
04  
05 /**
06  
07  * @author 梁栋
08  * @version 1.0
09  * @since 1.0
10  */
11 public class CoderTest {
12  
13     @Test
14     public void test() throws Exception {
15         String inputStr = "简单加密";
16         System.err.println("原文:\n" + inputStr);
17  
18         byte[] inputData = inputStr.getBytes();
19         String code = Coder.encryptBASE64(inputData);
20  
21         System.err.println("BASE64加密后:\n" + code);
22  
23         byte[] output = Coder.decryptBASE64(code);
24  
25         String outputStr = new String(output);
26  
27         System.err.println("BASE64解密后:\n" + outputStr);
28  
29         // 验证BASE64加密解密一致性
30         assertEquals(inputStr, outputStr);
31  
32         // 验证MD5对于同一内容加密是否一致
33         assertArrayEquals(Coder.encryptMD5(inputData), Coder
34                 .encryptMD5(inputData));
35  
36         // 验证SHA对于同一内容加密是否一致
37         assertArrayEquals(Coder.encryptSHA(inputData), Coder
38                 .encryptSHA(inputData));
39  
40         String key = Coder.initMacKey();
41         System.err.println("Mac密钥:\n" + key);
42  
43         // 验证HMAC对于同一内容,同一密钥加密是否一致
44         assertArrayEquals(Coder.encryptHMAC(inputData, key), Coder.encryptHMAC(
45                 inputData, key));
46  
47         BigInteger md5 = new BigInteger(Coder.encryptMD5(inputData));
48         System.err.println("MD5:\n" + md5.toString(16));
49  
50         BigInteger sha = new BigInteger(Coder.encryptSHA(inputData));
51         System.err.println("SHA:\n" + sha.toString(32));
52  
53         BigInteger mac = new BigInteger(Coder.encryptHMAC(inputData, inputStr));
54         System.err.println("HMAC:\n" + mac.toString(16));
55     }
56 }

控制台输出:

原文:
简单加密
BASE64加密后:
566A5Y2V5Yqg5a+GBASE64解密后:
简单加密
Mac密钥:
uGxdHC+6ylRDaik++leFtGwiMbuYUJ6mqHWyhSgF4trVkVBBSQvY/a22xU8XT1RUemdCWW155Bke
pBIpkd7QHg==MD5:
-550b4d90349ad4629462113e7934de56
SHA:
91k9vo7p400cjkgfhjh0ia9qthsjagfn
HMAC:
2287d192387e95694bdbba2fa941009a

注意 
编译时,可能会看到如下提示:

引用

警告:sun.misc.BASE64Decoder 是 Sun 的专用 API,可能会在未来版本中删除

import sun.misc.BASE64Decoder; 
               ^ 
警告:sun.misc.BASE64Encoder 是 Sun 的专用 API,可能会在未来版本中删除

import sun.misc.BASE64Encoder; 
               ^

BASE64Encoder 和BASE64Decoder是非官方JDK实现类。虽然可以在JDK里能找到并使用,但是在API里查不到。JRE 中 sun 和 com.sun 开头包的类都是未被文档化的,他们属于 java, javax 类库的基础,其中的实现大多数与底层平台有关,一般来说是不推荐使用的。

BASE64的加密解密是双向的,可以求反解。 
    MD5、SHA以及HMAC是单向加密,任何数据加密后只会产生唯一的一个加密串,通常用来校验数据在传输过程中是否被修改。其中HMAC算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。 
    单向加密的用途主要是为了校验数据在传输过程中是否被修改。

接下来我们介绍对称加密算法,最常用的莫过于DES数据加密算法。 
DES 
DES-Data Encryption Standard,即数据加密算法。是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中 Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密 或解密。 
        DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位。

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

001 import java.security.Key;
002 import java.security.SecureRandom;
003  
004 import javax.crypto.Cipher;
005 import javax.crypto.KeyGenerator;
006 import javax.crypto.SecretKey;
007 import javax.crypto.SecretKeyFactory;
008 import javax.crypto.spec.DESKeySpec;
009  
010  
011 /**
012  * DES安全编码组件
013  
014  * <pre>
015  * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
016  * DES                  key size must be equal to 56
017  * DESede(TripleDES)     key size must be equal to 112 or 168
018  * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
019  * Blowfish          key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
020  * RC2                  key size must be between 40 and 1024 bits
021  * RC4(ARCFOUR)      key size must be between 40 and 1024 bits
022  * 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
023  * </pre>
024  
025  * @author 梁栋
026  * @version 1.0
027  * @since 1.0
028  */
029 public abstract class DESCoder extends Coder {
030     /**
031      * ALGORITHM 算法 <br>
032      * 可替换为以下任意一种算法,同时key值的size相应改变。
033      
034      * <pre>
035      * DES                  key size must be equal to 56
036      * DESede(TripleDES)     key size must be equal to 112 or 168
037      * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
038      * Blowfish          key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
039      * RC2                  key size must be between 40 and 1024 bits
040      * RC4(ARCFOUR)      key size must be between 40 and 1024 bits
041      * </pre>
042      
043      * 在Key toKey(byte[] key)方法中使用下述代码
044      * <code>SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);</code> 替换
045      * <code>
046      * DESKeySpec dks = new DESKeySpec(key);
047      * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
048      * SecretKey secretKey = keyFactory.generateSecret(dks);
049      * </code>
050      */
051     public static final String ALGORITHM = "DES";
052  
053     /**
054      * 转换密钥<br>
055      
056      * @param key
057      * @return
058      * @throws Exception
059      */
060     private static Key toKey(byte[] key) throws Exception {
061         DESKeySpec dks = new DESKeySpec(key);
062         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
063         SecretKey secretKey = keyFactory.generateSecret(dks);
064  
065         // 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码
066         // SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
067  
068         return secretKey;
069     }
070  
071     /**
072      * 解密
073      
074      * @param data
075      * @param key
076      * @return
077      * @throws Exception
078      */
079     public static byte[] decrypt(byte[] data, String key) throws Exception {
080         Key k = toKey(decryptBASE64(key));
081  
082         Cipher cipher = Cipher.getInstance(ALGORITHM);
083         cipher.init(Cipher.DECRYPT_MODE, k);
084  
085         return cipher.doFinal(data);
086     }
087  
088     /**
089      * 加密
090      
091      * @param data
092      * @param key
093      * @return
094      * @throws Exception
095      */
096     public static byte[] encrypt(byte[] data, String key) throws Exception {
097         Key k = toKey(decryptBASE64(key));
098         Cipher cipher = Cipher.getInstance(ALGORITHM);
099         cipher.init(Cipher.ENCRYPT_MODE, k);
100  
101         return cipher.doFinal(data);
102     }
103  
104     /**
105      * 生成密钥
106      
107      * @return
108      * @throws Exception
109      */
110     public static String initKey() throws Exception {
111         return initKey(null);
112     }
113  
114     /**
115      * 生成密钥
116      
117      * @param seed
118      * @return
119      * @throws Exception
120      */
121     public static String initKey(String seed) throws Exception {
122         SecureRandom secureRandom = null;
123  
124         if (seed != null) {
125             secureRandom = new SecureRandom(decryptBASE64(seed));
126         else {
127             secureRandom = new SecureRandom();
128         }
129  
130         KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
131         kg.init(secureRandom);
132  
133         SecretKey secretKey = kg.generateKey();
134  
135         return encryptBASE64(secretKey.getEncoded());
136     }
137 }

延续上一个类的实现,我们通过MD5以及SHA对字符串加密生成密钥,这是比较常见的密钥生成方式。 
再给出一个测试类:

01 import static org.junit.Assert.*;
02  
03  
04 import org.junit.Test;
05  
06 /**
07  
08  * @author 梁栋
09  * @version 1.0
10  * @since 1.0
11  */
12 public class DESCoderTest {
13  
14     @Test
15     public void test() throws Exception {
16         String inputStr = "DES";
17         String key = DESCoder.initKey();
18         System.err.println("原文:\t" + inputStr);
19  
20         System.err.println("密钥:\t" + key);
21  
22         byte[] inputData = inputStr.getBytes();
23         inputData = DESCoder.encrypt(inputData, key);
24  
25         System.err.println("加密后:\t" + DESCoder.encryptBASE64(inputData));
26  
27         byte[] outputData = DESCoder.decrypt(inputData, key);
28         String outputStr = new String(outputData);
29  
30         System.err.println("解密后:\t" + outputStr);
31  
32         assertEquals(inputStr, outputStr);
33     }
34 }

得到的输出内容如下:

原文:    DES
密钥: f3wEtRrV6q0=加密后:   C6qe9oNIzRY=解密后:   DES

由控制台得到的输出,我们能够比对加密、解密后结果一致。这是一种简单的加密解密方式,只有一个密钥。 
    其实DES有很多同胞兄弟,如DESede(TripleDES)、AES、Blowfish、RC2、RC4(ARCFOUR)。这里就不过多阐述了,大同小异,只要换掉ALGORITHM换成对应的值,同时做一个代码替换SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);就可以了,此外就是密钥长度不同了。

1 /**
2  * DES          key size must be equal to 56
3  * DESede(TripleDES) key size must be equal to 112 or 168
4  * AES          key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
5  * Blowfish     key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
6  * RC2          key size must be between 40 and 1024 bits
7  * RC4(ARCFOUR) key size must be between 40 and 1024 bits
8  **/

除了DES,我们还知道有DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法——PBE 
PBE 
    PBE——Password-based encryption(基于密码加密)。其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。是一种简便的加密方式。 
通过java代码实现如下:Coder类见

001 import java.security.Key;
002 import java.util.Random;
003   
004 import javax.crypto.Cipher;
005 import javax.crypto.SecretKey;
006 import javax.crypto.SecretKeyFactory;
007 import javax.crypto.spec.PBEKeySpec;
008 import javax.crypto.spec.PBEParameterSpec;
009   
010 /**
011  * PBE安全编码组件
012  
013  * @author 梁栋
014  * @version 1.0
015  * @since 1.0
016  */
017 public abstract class PBECoder extends Coder {
018     /**
019      * 支持以下任意一种算法
020      
021      * <pre>
022      * PBEWithMD5AndDES 
023      * PBEWithMD5AndTripleDES 
024      * PBEWithSHA1AndDESede
025      * PBEWithSHA1AndRC2_40
026      * </pre>
027      */
028     public static final String ALGORITHM = "PBEWITHMD5andDES";
029   
030     /**
031      * 盐初始化
032      
033      * @return
034      * @throws Exception
035      */
036     public static byte[] initSalt() throws Exception {
037         byte[] salt = new byte[8];
038         Random random = new Random();
039         random.nextBytes(salt);
040         return salt;
041     }
042   
043     /**
044      * 转换密钥<br>
045      
046      * @param password
047      * @return
048      * @throws Exception
049      */
050     private static Key toKey(String password) throws Exception {
051         PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
052         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
053         SecretKey secretKey = keyFactory.generateSecret(keySpec);
054   
055         return secretKey;
056     }
057   
058     /**
059      * 加密
060      
061      * @param data 数据
062      * @param password 密码
063      * @param salt  盐
064      * @return
065      * @throws Exception
066      */
067     public static byte[] encrypt(byte[] data, String password, byte[] salt)
068             throws Exception {
069   
070         Key key = toKey(password);
071   
072         PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
073         Cipher cipher = Cipher.getInstance(ALGORITHM);
074         cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
075   
076         return cipher.doFinal(data);
077   
078     }
079   
080     /**
081      * 解密
082      
083      * @param data  数据
084      * @param password 密码
085      * @param salt  盐
086      * @return
087      * @throws Exception
088      */
089     public static byte[] decrypt(byte[] data, String password, byte[] salt)
090             throws Exception {
091   
092         Key key = toKey(password);
093   
094         PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
095         Cipher cipher = Cipher.getInstance(ALGORITHM);
096         cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
097   
098         return cipher.doFinal(data);
099   
100     }
101 }

再给出一个测试类:

01 import static org.junit.Assert.*;
02   
03 import org.junit.Test;
04   
05 /**
06  
07  * @author 梁栋
08  * @version 1.0
09  * @since 1.0
10  */
11 public class PBECoderTest {
12   
13     @Test
14     public void test() throws Exception {
15         String inputStr = "abc";
16         System.err.println("原文: " + inputStr);
17         byte[] input = inputStr.getBytes();
18   
19         String pwd = "efg";
20         System.err.println("密码: " + pwd);
21   
22         byte[] salt = PBECoder.initSalt();
23   
24         byte[] data = PBECoder.encrypt(input, pwd, salt);
25   
26         System.err.println("加密后: " + PBECoder.encryptBASE64(data));
27   
28         byte[] output = PBECoder.decrypt(data, pwd, salt);
29         String outputStr = new String(output);
30   
31         System.err.println("解密后: " + outputStr);
32         assertEquals(inputStr, outputStr);
33     }
34   
35 }

控制台输出:

原文: abc
密码: efg
加密后: iCZ0uRtaAhE=解密后: abc

后续我们会介绍非对称加密算法,如RSA、DSA、DH、ECC等。

接下来我们介绍典型的非对称加密算法——RSA

RSA 
    这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。 
    这种加密算法的特点主要是密钥的变化,上文我们看到DES只有一个密钥。相当于只有一把钥匙,如果这把钥匙丢了,数据也就不安全了。RSA同时有两把钥 匙,公钥与私钥。同时支持数字签名。数字签名的意义在于,对传输过来的数据进行校验。确保数据在传输工程中不被修改。

流程分析:

  1. 甲方构建密钥对儿,将公钥公布给乙方,将私钥保留。

  2. 甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。

  3. 乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。

按如上步骤给出序列图,如下:

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

001 import java.security.Key;
002 import java.security.KeyFactory;
003 import java.security.KeyPair;
004 import java.security.KeyPairGenerator;
005 import java.security.PrivateKey;
006 import java.security.PublicKey;
007 import java.security.Signature;
008 import java.security.interfaces.RSAPrivateKey;
009 import java.security.interfaces.RSAPublicKey;
010 import java.security.spec.PKCS8EncodedKeySpec;
011 import java.security.spec.X509EncodedKeySpec;
012  
013 import java.util.HashMap;
014 import java.util.Map;
015  
016 import javax.crypto.Cipher;
017  
018 /**
019  * RSA安全编码组件
020  
021  * @author 梁栋
022  * @version 1.0
023  * @since 1.0
024  */
025 public abstract class RSACoder extends Coder {
026     public static final String KEY_ALGORITHM = "RSA";
027     public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
028  
029     private static final String PUBLIC_KEY = "RSAPublicKey";
030     private static final String PRIVATE_KEY = "RSAPrivateKey";
031  
032     /**
033      * 用私钥对信息生成数字签名
034      
035      * @param data
036      *            加密数据
037      * @param privateKey
038      *            私钥
039      
040      * @return
041      * @throws Exception
042      */
043     public static String sign(byte[] data, String privateKey) throws Exception {
044         // 解密由base64编码的私钥
045         byte[] keyBytes = decryptBASE64(privateKey);
046  
047         // 构造PKCS8EncodedKeySpec对象
048         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
049  
050         // KEY_ALGORITHM 指定的加密算法
051         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
052  
053         // 取私钥匙对象
054         PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
055  
056         // 用私钥对信息生成数字签名
057         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
058         signature.initSign(priKey);
059         signature.update(data);
060  
061         return encryptBASE64(signature.sign());
062     }
063  
064     /**
065      * 校验数字签名
066      
067      * @param data
068      *            加密数据
069      * @param publicKey
070      *            公钥
071      * @param sign
072      *            数字签名
073      
074      * @return 校验成功返回true 失败返回false
075      * @throws Exception
076      
077      */
078     public static boolean verify(byte[] data, String publicKey, String sign)
079             throws Exception {
080  
081         // 解密由base64编码的公钥
082         byte[] keyBytes = decryptBASE64(publicKey);
083  
084         // 构造X509EncodedKeySpec对象
085         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
086  
087         // KEY_ALGORITHM 指定的加密算法
088         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
089  
090         // 取公钥匙对象
091         PublicKey pubKey = keyFactory.generatePublic(keySpec);
092  
093         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
094         signature.initVerify(pubKey);
095         signature.update(data);
096  
097         // 验证签名是否正常
098         return signature.verify(decryptBASE64(sign));
099     }
100  
101     /**
102      * 解密<br>
103      * 用私钥解密
104      
105      * @param data
106      * @param key
107      * @return
108      * @throws Exception
109      */
110     public static byte[] decryptByPrivateKey(byte[] data, String key)
111             throws Exception {
112         // 对密钥解密
113         byte[] keyBytes = decryptBASE64(key);
114  
115         // 取得私钥
116         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
117         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
118         Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
119  
120         // 对数据解密
121         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
122         cipher.init(Cipher.DECRYPT_MODE, privateKey);
123  
124         return cipher.doFinal(data);
125     }
126  
127     /**
128      * 解密<br>
129      * 用私钥解密
130      
131      * @param data
132      * @param key
133      * @return
134      * @throws Exception
135      */
136     public static byte[] decryptByPublicKey(byte[] data, String key)
137             throws Exception {
138         // 对密钥解密
139         byte[] keyBytes = decryptBASE64(key);
140  
141         // 取得公钥
142         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
143         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
144         Key publicKey = keyFactory.generatePublic(x509KeySpec);
145  
146         // 对数据解密
147         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
148         cipher.init(Cipher.DECRYPT_MODE, publicKey);
149  
150         return cipher.doFinal(data);
151     }
152  
153     /**
154      * 加密<br>
155      * 用公钥加密
156      
157      * @param data
158      * @param key
159      * @return
160      * @throws Exception
161      */
162     public static byte[] encryptByPublicKey(byte[] data, String key)
163             throws Exception {
164         // 对公钥解密
165         byte[] keyBytes = decryptBASE64(key);
166  
167         // 取得公钥
168         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
169         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
170         Key publicKey = keyFactory.generatePublic(x509KeySpec);
171  
172         // 对数据加密
173         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
174         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
175  
176         return cipher.doFinal(data);
177     }
178  
179     /**
180      * 加密<br>
181      * 用私钥加密
182      
183      * @param data
184      * @param key
185      * @return
186      * @throws Exception
187      */
188     public static byte[] encryptByPrivateKey(byte[] data, String key)
189             throws Exception {
190         // 对密钥解密
191         byte[] keyBytes = decryptBASE64(key);
192  
193         // 取得私钥
194         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
195         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
196         Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
197  
198         // 对数据加密
199         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
200         cipher.init(Cipher.ENCRYPT_MODE, privateKey);
201  
202         return cipher.doFinal(data);
203     }
204  
205     /**
206      * 取得私钥
207      
208      * @param keyMap
209      * @return
210      * @throws Exception
211      */
212     public static String getPrivateKey(Map<String, Object> keyMap)
213             throws Exception {
214         Key key = (Key) keyMap.get(PRIVATE_KEY);
215  
216         return encryptBASE64(key.getEncoded());
217     }
218  
219     /**
220      * 取得公钥
221      
222      * @param keyMap
223      * @return
224      * @throws Exception
225      */
226     public static String getPublicKey(Map<String, Object> keyMap)
227             throws Exception {
228         Key key = (Key) keyMap.get(PUBLIC_KEY);
229  
230         return encryptBASE64(key.getEncoded());
231     }
232  
233     /**
234      * 初始化密钥
235      
236      * @return
237      * @throws Exception
238      */
239     public static Map<String, Object> initKey() throws Exception {
240         KeyPairGenerator keyPairGen = KeyPairGenerator
241                 .getInstance(KEY_ALGORITHM);
242         keyPairGen.initialize(1024);
243  
244         KeyPair keyPair = keyPairGen.generateKeyPair();
245  
246         // 公钥
247         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
248  
249         // 私钥
250         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
251  
252         Map<String, Object> keyMap = new HashMap<String, Object>(2);
253  
254         keyMap.put(PUBLIC_KEY, publicKey);
255         keyMap.put(PRIVATE_KEY, privateKey);
256         return keyMap;
257     }
258 }

再给出一个测试类:

01 import static org.junit.Assert.*;
02  
03 import org.junit.Before;
04 import org.junit.Test;
05  
06 import java.util.Map;
07  
08 /**
09  
10  * @author 梁栋
11  * @version 1.0
12  * @since 1.0
13  */
14 public class RSACoderTest {
15     private String publicKey;
16     private String privateKey;
17  
18     @Before
19     public void setUp() throws Exception {
20         Map<String, Object> keyMap = RSACoder.initKey();
21  
22         publicKey = RSACoder.getPublicKey(keyMap);
23         privateKey = RSACoder.getPrivateKey(keyMap);
24         System.err.println("公钥: \n\r" + publicKey);
25         System.err.println("私钥: \n\r" + privateKey);
26     }
27  
28     @Test
29     public void test() throws Exception {
30         System.err.println("公钥加密——私钥解密");
31         String inputStr = "abc";
32         byte[] data = inputStr.getBytes();
33  
34         byte[] encodedData = RSACoder.encryptByPublicKey(data, publicKey);
35  
36         byte[] decodedData = RSACoder.decryptByPrivateKey(encodedData,
37                 privateKey);
38  
39         String outputStr = new String(decodedData);
40         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
41         assertEquals(inputStr, outputStr);
42  
43     }
44  
45     @Test
46     public void testSign() throws Exception {
47         System.err.println("私钥加密——公钥解密");
48         String inputStr = "sign";
49         byte[] data = inputStr.getBytes();
50  
51         byte[] encodedData = RSACoder.encryptByPrivateKey(data, privateKey);
52  
53         byte[] decodedData = RSACoder
54                 .decryptByPublicKey(encodedData, publicKey);
55  
56         String outputStr = new String(decodedData);
57         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
58         assertEquals(inputStr, outputStr);
59  
60         System.err.println("私钥签名——公钥验证签名");
61         // 产生签名
62         String sign = RSACoder.sign(encodedData, privateKey);
63         System.err.println("签名:\r" + sign);
64  
65         // 验证签名
66         boolean status = RSACoder.verify(encodedData, publicKey, sign);
67         System.err.println("状态:\r" + status);
68         assertTrue(status);
69  
70     }
71  
72 }

控制台输出:

公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYU/+I0+z1aBl5X6DUUOHQ7FZpmBSDbKTtx89J
EcB64jFCkunELT8qiKly7fzEqD03g8ALlu5XvX+bBqHFy7YPJJP0ekE2X3wjUnh2NxlqpH3/B/xm
1ZdSlCwDIkbijhBVDjA/bu5BObhZqQmDwIxlQInL9oVz+o6FbAZCyHBd7wIDAQAB私钥: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJhT/4jT7PVoGXlfoNRQ4dDsVmmY
FINspO3Hz0kRwHriMUKS6cQtPyqIqXLt/MSoPTeDwAuW7le9f5sGocXLtg8kk/R6QTZffCNSeHY3
GWqkff8H/GbVl1KULAMiRuKOEFUOMD9u7kE5uFmpCYPAjGVAicv2hXP6joVsBkLIcF3vAgMBAAEC
gYBvZHWoZHmS2EZQqKqeuGr58eobG9hcZzWQoJ4nq/CarBAjw/VovUHE490uK3S9ht4FW7Yzg3LV
/MB06Huifh6qf/X9NQA7SeZRRC8gnCQk6JuDIEVJOud5jU+9tyumJakDKodQ3Jf2zQtNr+5ZdEPl
uwWgv9c4kmpjhAdyMuQmYQJBANn6pcgvyYaia52dnu+yBUsGkaFfwXkzFSExIbi0MXTkhEb/ER/D
rLytukkUu5S5ecz/KBa8U4xIslZDYQbLz5ECQQCy5dutt7RsxN4+dxCWn0/1FrkWl2G329Ucewm3
QU9CKu4D+7Kqdj+Ha3lXP8F0Etaaapi7+EfkRUpukn2ItZV/AkEAlk+I0iphxT1rCB0Q5CjWDY5S
Df2B5JmdEG5Y2o0nLXwG2w44OLct/k2uD4cEcuITY5Dvi/4BftMCZwm/dnhEgQJACIktJSnJwxLV
o9dchENPtlsCM9C/Sd2EWpqISSUlmfugZbJBwR5pQ5XeMUqKeXZYpP+HEBj1nS+tMH9u2/IGEwJA
fL8mZiZXan/oBKrblAbplNcKWGRVD/3y65042PAEeghahlJMiYquV5DzZajuuT0wbJ5xQuZB01+X
nfpFpBJ2dw==公钥加密——私钥解密
加密前: abc解密后: abc
公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdOj40yEB48XqWxmPILmJAc7UecIN7F32etSHF
9rwbuEh3+iTPOGSxhoSQpOED0vOb0ZIMkBXZSgsxLaBSin2RZ09YKWRjtpCA0kDkiD11gj4tzTiM
l9qq1kwSK7ZkGAgodEn3yIILVmQDuEImHOXFtulvJ71ka07u3LuwUNdB/wIDAQAB私钥: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN06PjTIQHjxepbGY8guYkBztR5w
g3sXfZ61IcX2vBu4SHf6JM84ZLGGhJCk4QPS85vRkgyQFdlKCzEtoFKKfZFnT1gpZGO2kIDSQOSI
PXWCPi3NOIyX2qrWTBIrtmQYCCh0SffIggtWZAO4QiYc5cW26W8nvWRrTu7cu7BQ10H/AgMBAAEC
gYEAz2JWBizjI31bqhP4XiP9PuY5F3vqBW4T+L9cFbQiyumKJc58yzTWUAUGKIIn3enXLG7dNqGr
mbJro4JeFIJ3CiVDpXR9+FluIgI4SXm7ioGKF2NOMA9LR5Fu82W+pLfpTN2y2SaLYWEDZyp53BxY
j9gUxaxi1MQs+C1ZgDF2xmECQQDy70bQntbRfysP+ppCtd56YRnES1Tyekw0wryS2tr+ivQJl7JF
gp5rPAOXpgrq36xHDwUspQ0sJ0vj0O7ywxr1AkEA6SAaLhrJJrYucC0jxwAhUYyaPN+aOsWymaRh
9jA/Wc0wp29SbGTh5CcMuGpXm1g0M+FKW3dGiHgS3rVUKim4owJAbnxgapUzAgiiHxxMeDaavnHW
9C2GrtjsO7qtZOTgYI/1uT8itvZW8lJTF+9OW8/qXE76fXl7ai9dFnl5kzMk2QJBALfHz/vCsArt
mkRiwY6zApE4Z6tPl1V33ymSVovvUzHnOdD1SKQdD5t+UV/crb3QVi8ED0t2B0u0ZSPfDT/D7kMC
QDpwdj9k2F5aokLHBHUNJPFDAp7a5QMaT64gv/d48ITJ68Co+v5WzLMpzJBYXK6PAtqIhxbuPEc2
I2k1Afmrwyw=私钥加密——公钥解密
加密前: sign解密后: sign
私钥签名——公钥验证签名
签名:
ud1RsIwmSC1pN22I4IXteg1VD2FbiehKUfNxgVSHzvQNIK+d20FCkHCqh9djP3h94iWnIUY0ifU+
mbJkhAl/i5krExOE0hknOnPMcEP+lZV1RbJI2zG2YooSp2XDleqrQk5e/QF2Mx0Zxt8Xsg7ucVpn
i3wwbYWs9wSzIf0UjlM=状态:
true

简要总结一下,使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互!

类似数字签名,数字信封是这样描述的:

数字信封 
        数字信封用加密技术来保证只有特定的收信人才能阅读信的内容。 
流程: 
    信息发送方采用对称密钥来加密信息,然后再用接收方的公钥来加密此对称密钥(这部分称为数字信封),再将它和信息一起发送给接收方;接收方先用相应的私钥打开数字信封,得到对称密钥,然后使用对称密钥再解开信息。

接下来我们分析DH加密算法,一种适基于密钥一致协议的加密算法。 
DH 
Diffie- Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用 户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私 钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥 (SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单 单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理。

流程分析:

1.甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。 
2.甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。 
3.乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。

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

001 import java.security.Key;
002 import java.security.KeyFactory;
003 import java.security.KeyPair;
004 import java.security.KeyPairGenerator;
005 import java.security.PublicKey;
006 import java.security.spec.PKCS8EncodedKeySpec;
007 import java.security.spec.X509EncodedKeySpec;
008 import java.util.HashMap;
009 import java.util.Map;
010  
011 import javax.crypto.Cipher;
012 import javax.crypto.KeyAgreement;
013 import javax.crypto.SecretKey;
014 import javax.crypto.interfaces.DHPrivateKey;
015 import javax.crypto.interfaces.DHPublicKey;
016 import javax.crypto.spec.DHParameterSpec;
017  
018 /**
019  * DH安全编码组件
020  
021  * @author 梁栋
022  * @version 1.0
023  * @since 1.0
024  */
025 public abstract class DHCoder extends Coder {
026     public static final String ALGORITHM = "DH";
027  
028     /**
029      * 默认密钥字节数
030      
031      * <pre>
032      * DH
033      * Default Keysize 1024  
034      * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
035      * </pre>
036      */
037     private static final int KEY_SIZE = 1024;
038  
039     /**
040      * DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。
041      */
042     public static final String SECRET_ALGORITHM = "DES";
043     private static final String PUBLIC_KEY = "DHPublicKey";
044     private static final String PRIVATE_KEY = "DHPrivateKey";
045  
046     /**
047      * 初始化甲方密钥
048      
049      * @return
050      * @throws Exception
051      */
052     public static Map<String, Object> initKey() throws Exception {
053         KeyPairGenerator keyPairGenerator = KeyPairGenerator
054                 .getInstance(ALGORITHM);
055         keyPairGenerator.initialize(KEY_SIZE);
056  
057         KeyPair keyPair = keyPairGenerator.generateKeyPair();
058  
059         // 甲方公钥
060         DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
061  
062         // 甲方私钥
063         DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
064  
065         Map<String, Object> keyMap = new HashMap<String, Object>(2);
066  
067         keyMap.put(PUBLIC_KEY, publicKey);
068         keyMap.put(PRIVATE_KEY, privateKey);
069         return keyMap;
070     }
071  
072     /**
073      * 初始化乙方密钥
074      
075      * @param key
076      *            甲方公钥
077      * @return
078      * @throws Exception
079      */
080     public static Map<String, Object> initKey(String key) throws Exception {
081         // 解析甲方公钥
082         byte[] keyBytes = decryptBASE64(key);
083         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
084         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
085         PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
086  
087         // 由甲方公钥构建乙方密钥
088         DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();
089  
090         KeyPairGenerator keyPairGenerator = KeyPairGenerator
091                 .getInstance(keyFactory.getAlgorithm());
092         keyPairGenerator.initialize(dhParamSpec);
093  
094         KeyPair keyPair = keyPairGenerator.generateKeyPair();
095  
096         // 乙方公钥
097         DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
098  
099         // 乙方私钥
100         DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
101  
102         Map<String, Object> keyMap = new HashMap<String, Object>(2);
103  
104         keyMap.put(PUBLIC_KEY, publicKey);
105         keyMap.put(PRIVATE_KEY, privateKey);
106  
107         return keyMap;
108     }
109  
110     /**
111      * 加密<br>
112      
113      * @param data
114      *            待加密数据
115      * @param publicKey
116      *            甲方公钥
117      * @param privateKey
118      *            乙方私钥
119      * @return
120      * @throws Exception
121      */
122     public static byte[] encrypt(byte[] data, String publicKey,
123             String privateKey) throws Exception {
124  
125         // 生成本地密钥
126         SecretKey secretKey = getSecretKey(publicKey, privateKey);
127  
128         // 数据加密
129         Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
130         cipher.init(Cipher.ENCRYPT_MODE, secretKey);
131  
132         return cipher.doFinal(data);
133     }
134  
135     /**
136      * 解密<br>
137      
138      * @param data
139      *            待解密数据
140      * @param publicKey
141      *            乙方公钥
142      * @param privateKey
143      *            乙方私钥
144      * @return
145      * @throws Exception
146      */
147     public static byte[] decrypt(byte[] data, String publicKey,
148             String privateKey) throws Exception {
149  
150         // 生成本地密钥
151         SecretKey secretKey = getSecretKey(publicKey, privateKey);
152         // 数据解密
153         Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
154         cipher.init(Cipher.DECRYPT_MODE, secretKey);
155  
156         return cipher.doFinal(data);
157     }
158  
159     /**
160      * 构建密钥
161      
162      * @param publicKey
163      *            公钥
164      * @param privateKey
165      *            私钥
166      * @return
167      * @throws Exception
168      */
169     private static SecretKey getSecretKey(String publicKey, String privateKey)
170             throws Exception {
171         // 初始化公钥
172         byte[] pubKeyBytes = decryptBASE64(publicKey);
173  
174         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
175         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyBytes);
176         PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
177  
178         // 初始化私钥
179         byte[] priKeyBytes = decryptBASE64(privateKey);
180  
181         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKeyBytes);
182         Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);
183  
184         KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory
185                 .getAlgorithm());
186         keyAgree.init(priKey);
187         keyAgree.doPhase(pubKey, true);
188  
189         // 生成本地密钥
190         SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
191  
192         return secretKey;
193     }
194  
195     /**
196      * 取得私钥
197      
198      * @param keyMap
199      * @return
200      * @throws Exception
201      */
202     public static String getPrivateKey(Map<String, Object> keyMap)
203             throws Exception {
204         Key key = (Key) keyMap.get(PRIVATE_KEY);
205  
206         return encryptBASE64(key.getEncoded());
207     }
208  
209     /**
210      * 取得公钥
211      
212      * @param keyMap
213      * @return
214      * @throws Exception
215      */
216     public static String getPublicKey(Map<String, Object> keyMap)
217             throws Exception {
218         Key key = (Key) keyMap.get(PUBLIC_KEY);
219  
220         return encryptBASE64(key.getEncoded());
221     }
222 }

再给出一个测试类:

01 import static org.junit.Assert.*;
02  
03 import java.util.Map;
04  
05 import org.junit.Test;
06  
07 /**
08  
09  * @author 梁栋
10  * @version 1.0
11  * @since 1.0
12  */
13 public class DHCoderTest {
14  
15     @Test
16     public void test() throws Exception {
17         // 生成甲方密钥对儿
18         Map<String, Object> aKeyMap = DHCoder.initKey();
19         String aPublicKey = DHCoder.getPublicKey(aKeyMap);
20         String aPrivateKey = DHCoder.getPrivateKey(aKeyMap);
21  
22         System.err.println("甲方公钥:\r" + aPublicKey);
23         System.err.println("甲方私钥:\r" + aPrivateKey);
24          
25         // 由甲方公钥产生本地密钥对儿
26         Map<String, Object> bKeyMap = DHCoder.initKey(aPublicKey);
27         String bPublicKey = DHCoder.getPublicKey(bKeyMap);
28         String bPrivateKey = DHCoder.getPrivateKey(bKeyMap);
29          
30         System.err.println("乙方公钥:\r" + bPublicKey);
31         System.err.println("乙方私钥:\r" + bPrivateKey);
32          
33         String aInput = "abc ";
34         System.err.println("原文: " + aInput);
35  
36         // 由甲方公钥,乙方私钥构建密文
37         byte[] aCode = DHCoder.encrypt(aInput.getBytes(), aPublicKey,
38                 bPrivateKey);
39  
40         // 由乙方公钥,甲方私钥解密
41         byte[] aDecode = DHCoder.decrypt(aCode, bPublicKey, aPrivateKey);
42         String aOutput = (new String(aDecode));
43  
44         System.err.println("解密: " + aOutput);
45  
46         assertEquals(aInput, aOutput);
47  
48         System.err.println(" ===============反过来加密解密================== ");
49         String bInput = "def ";
50         System.err.println("原文: " + bInput);
51  
52         // 由乙方公钥,甲方私钥构建密文
53         byte[] bCode = DHCoder.encrypt(bInput.getBytes(), bPublicKey,
54                 aPrivateKey);
55  
56         // 由甲方公钥,乙方私钥解密
57         byte[] bDecode = DHCoder.decrypt(bCode, aPublicKey, bPrivateKey);
58         String bOutput = (new String(bDecode));
59  
60         System.err.println("解密: " + bOutput);
61  
62         assertEquals(bInput, bOutput);
63     }
64  
65 }

控制台输出:

甲方公钥:
MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAdAWBVmIzqcko
Ej6qFjLDL2+Y3FPq1iRbnOyOpDj71yKaK1K+FhTv04B0zy4DKcvAASV7/Gv0W+bgqdmffRkqrQ==甲方私钥:
MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjACJRfy1LyR
eHyD+4Hfb+xR0uoIGR1oL9i9Nk6g2AAuaDPgEVWHn+QXID13yL/uDos=乙方公钥:
MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAVEYSfBA+I9nr
dWw3OBv475C+eBrWBBYqt0m6/eu4ptuDQHwV4MmUtKAC2wc2nNrdb1wmBhY1X8RnWkJ1XmdDbQ==乙方私钥:
MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAqaZiCdXp
2iNpdBlHRaO9ir70wo2n32xNlIzIX19VLSPCDdeUWkgRv4CEj/8k+/yd原文: abc
解密: abc ===============反过来加密解密==================
原文: def
解密: def

如我所言,甲乙双方在获得对方公钥后可以对发送给对方的数据加密,同时也能对接收到的数据解密,达到了数据安全通信的目的!

接下来我们介绍DSA数字签名,非对称加密的另一种实现。 
DSA 
DSA-Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。简单的说,这是一种更高级的验证方式,用作数字签名。不单单只有公钥、私钥,还有数字签名。私钥加密生成数字签名,公钥验证数据及签 名。如果数据和签名不匹配则认为验证失败!数字签名的作用就是校验数据在传输过程中不被修改。数字签名,是单向加密的升级!

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

001 import java.security.Key;
002 import java.security.KeyFactory;
003 import java.security.KeyPair;
004 import java.security.KeyPairGenerator;
005 import java.security.PrivateKey;
006 import java.security.PublicKey;
007 import java.security.SecureRandom;
008 import java.security.Signature;
009 import java.security.interfaces.DSAPrivateKey;
010 import java.security.interfaces.DSAPublicKey;
011 import java.security.spec.PKCS8EncodedKeySpec;
012 import java.security.spec.X509EncodedKeySpec;
013 import java.util.HashMap;
014 import java.util.Map;
015  
016 /**
017  * DSA安全编码组件
018  
019  * @author 梁栋
020  * @version 1.0
021  * @since 1.0
022  */
023 public abstract class DSACoder extends Coder {
024  
025     public static final String ALGORITHM = "DSA";
026  
027     /**
028      * 默认密钥字节数
029      
030      * <pre>
031      * DSA 
032      * Default Keysize 1024  
033      * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
034      * </pre>
035      */
036     private static final int KEY_SIZE = 1024;
037  
038     /**
039      * 默认种子
040      */
041     private static final String DEFAULT_SEED = "0f22507a10bbddd07d8a3082122966e3";
042  
043     private static final String PUBLIC_KEY = "DSAPublicKey";
044     private static final String PRIVATE_KEY = "DSAPrivateKey";
045  
046     /**
047      * 用私钥对信息生成数字签名
048      
049      * @param data
050      *            加密数据
051      * @param privateKey
052      *            私钥
053      
054      * @return
055      * @throws Exception
056      */
057     public static String sign(byte[] data, String privateKey) throws Exception {
058         // 解密由base64编码的私钥
059         byte[] keyBytes = decryptBASE64(privateKey);
060  
061         // 构造PKCS8EncodedKeySpec对象
062         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
063  
064         // KEY_ALGORITHM 指定的加密算法
065         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
066  
067         // 取私钥匙对象
068         PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
069  
070         // 用私钥对信息生成数字签名
071         Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
072         signature.initSign(priKey);
073         signature.update(data);
074  
075         return encryptBASE64(signature.sign());
076     }
077  
078     /**
079      * 校验数字签名
080      
081      * @param data
082      *            加密数据
083      * @param publicKey
084      *            公钥
085      * @param sign
086      *            数字签名
087      
088      * @return 校验成功返回true 失败返回false
089      * @throws Exception
090      
091      */
092     public static boolean verify(byte[] data, String publicKey, String sign)
093             throws Exception {
094  
095         // 解密由base64编码的公钥
096         byte[] keyBytes = decryptBASE64(publicKey);
097  
098         // 构造X509EncodedKeySpec对象
099         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
100  
101         // ALGORITHM 指定的加密算法
102         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
103  
104         // 取公钥匙对象
105         PublicKey pubKey = keyFactory.generatePublic(keySpec);
106  
107         Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
108         signature.initVerify(pubKey);
109         signature.update(data);
110  
111         // 验证签名是否正常
112         return signature.verify(decryptBASE64(sign));
113     }
114  
115     /**
116      * 生成密钥
117      
118      * @param seed
119      *            种子
120      * @return 密钥对象
121      * @throws Exception
122      */
123     public static Map<String, Object> initKey(String seed) throws Exception {
124         KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM);
125         // 初始化随机产生器
126         SecureRandom secureRandom = new SecureRandom();
127         secureRandom.setSeed(seed.getBytes());
128         keygen.initialize(KEY_SIZE, secureRandom);
129  
130         KeyPair keys = keygen.genKeyPair();
131  
132         DSAPublicKey publicKey = (DSAPublicKey) keys.getPublic();
133         DSAPrivateKey privateKey = (DSAPrivateKey) keys.getPrivate();
134  
135         Map<String, Object> map = new HashMap<String, Object>(2);
136         map.put(PUBLIC_KEY, publicKey);
137         map.put(PRIVATE_KEY, privateKey);
138  
139         return map;
140     }
141  
142     /**
143      * 默认生成密钥
144      
145      * @return 密钥对象
146      * @throws Exception
147      */
148     public static Map<String, Object> initKey() throws Exception {
149         return initKey(DEFAULT_SEED);
150     }
151  
152     /**
153      * 取得私钥
154      
155      * @param keyMap
156      * @return
157      * @throws Exception
158      */
159     public static String getPrivateKey(Map<String, Object> keyMap)
160             throws Exception {
161         Key key = (Key) keyMap.get(PRIVATE_KEY);
162  
163         return encryptBASE64(key.getEncoded());
164     }
165  
166     /**
167      * 取得公钥
168      
169      * @param keyMap
170      * @return
171      * @throws Exception
172      */
173     public static String getPublicKey(Map<String, Object> keyMap)
174             throws Exception {
175         Key key = (Key) keyMap.get(PUBLIC_KEY);
176  
177         return encryptBASE64(key.getEncoded());
178     }
179 }

再给出一个测试类:

01 import static org.junit.Assert.*;
02  
03 import java.util.Map;
04  
05 import org.junit.Test;
06  
07 /**
08  
09  * @author 梁栋
10  * @version 1.0
11  * @since 1.0
12  */
13 public class DSACoderTest {
14  
15     @Test
16     public void test() throws Exception {
17         String inputStr = "abc";
18         byte[] data = inputStr.getBytes();
19  
20         // 构建密钥
21         Map<String, Object> keyMap = DSACoder.initKey();
22  
23         // 获得密钥
24         String publicKey = DSACoder.getPublicKey(keyMap);
25         String privateKey = DSACoder.getPrivateKey(keyMap);
26  
27         System.err.println("公钥:\r" + publicKey);
28         System.err.println("私钥:\r" + privateKey);
29  
30         // 产生签名
31         String sign = DSACoder.sign(data, privateKey);
32         System.err.println("签名:\r" + sign);
33  
34         // 验证签名
35         boolean status = DSACoder.verify(data, publicKey, sign);
36         System.err.println("状态:\r" + status);
37         assertTrue(status);
38  
39     }
40  
41 }

控制台输出:

公钥:
MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZp
RV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fn
xqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuE
C/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJ
FnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo
g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAIu4RUlcQLp49PI0MrbssOY+3uySVnp0TULSv
5T4VaHoKzsLHgGTrwOvsGA+V3yCNl2WDu3D84bSLF7liTWgOj+SMOEaPk4VyRTlLXZWGPsf1Mfd9
21XAbMeVyKDSHHVGbMjBScajf3bXooYQMlyoHiOt/WrCo+mv7efstMM0PGo=私钥:
MIIBTAIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2
USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4
O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCB
gLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR
kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFwIVAIegLUtmm2oQKQJTOiLugHTSjl/q签名:
MC0CFQCMg0J/uZmF8GuRpr3TNq48w60nDwIUJCyYNah+HtbU6NcQfy8Ac6LeLQs=状态:
true

注意状态为true,就验证成功!

ECC 
ECC-Elliptic Curves Cryptography,椭圆曲线密码编码学,是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。在软件注册保护方面起到很大的作用,一般的序列号通常由该算法产生。 
    当我开始整理《Java加密技术(二)》的时候,我就已经在开始研究ECC了,但是关于Java实现ECC算法的资料实在是太少了,无论是国内还是国外的 资料,无论是官方还是非官方的解释,最终只有一种答案——ECC算法在jdk1.5后加入支持,目前仅仅只能完成密钥的生成与解析。 如果想要获得ECC算法实现,需要调用硬件完成加密/解密(ECC算法相当耗费资源,如果单纯使用CPU进行加密/解密,效率低下),涉及到Java Card领域,PKCS#11。 其实,PKCS#11配置很简单,但缺乏硬件设备,无法尝试!

尽管如此,我照旧提供相应的Java实现代码,以供大家参考。

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

001 import java.math.BigInteger;
002 import java.security.Key;
003 import java.security.KeyFactory;
004 import java.security.interfaces.ECPrivateKey;
005 import java.security.interfaces.ECPublicKey;
006 import java.security.spec.ECFieldF2m;
007 import java.security.spec.ECParameterSpec;
008 import java.security.spec.ECPoint;
009 import java.security.spec.ECPrivateKeySpec;
010 import java.security.spec.ECPublicKeySpec;
011 import java.security.spec.EllipticCurve;
012 import java.security.spec.PKCS8EncodedKeySpec;
013 import java.security.spec.X509EncodedKeySpec;
014 import java.util.HashMap;
015 import java.util.Map;
016  
017 import javax.crypto.Cipher;
018 import javax.crypto.NullCipher;
019  
020 import sun.security.ec.ECKeyFactory;
021 import sun.security.ec.ECPrivateKeyImpl;
022 import sun.security.ec.ECPublicKeyImpl;
023  
024 /**
025  * ECC安全编码组件
026  
027  * @author 梁栋
028  * @version 1.0
029  * @since 1.0
030  */
031 public abstract class ECCCoder extends Coder {
032  
033     public static final String ALGORITHM = "EC";
034     private static final String PUBLIC_KEY = "ECCPublicKey";
035     private static final String PRIVATE_KEY = "ECCPrivateKey";
036  
037     /**
038      * 解密<br>
039      * 用私钥解密
040      
041      * @param data
042      * @param key
043      * @return
044      * @throws Exception
045      */
046     public static byte[] decrypt(byte[] data, String key) throws Exception {
047         // 对密钥解密
048         byte[] keyBytes = decryptBASE64(key);
049  
050         // 取得私钥
051         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
052         KeyFactory keyFactory = ECKeyFactory.INSTANCE;
053  
054         ECPrivateKey priKey = (ECPrivateKey) keyFactory
055                 .generatePrivate(pkcs8KeySpec);
056  
057         ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(),
058                 priKey.getParams());
059  
060         // 对数据解密
061         // TODO Chipher不支持EC算法 未能实现
062         Cipher cipher = new NullCipher();
063         // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());
064         cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams());
065  
066         return cipher.doFinal(data);
067     }
068  
069     /**
070      * 加密<br>
071      * 用公钥加密
072      
073      * @param data
074      * @param privateKey
075      * @return
076      * @throws Exception
077      */
078     public static byte[] encrypt(byte[] data, String privateKey)
079             throws Exception {
080         // 对公钥解密
081         byte[] keyBytes = decryptBASE64(privateKey);
082  
083         // 取得公钥
084         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
085         KeyFactory keyFactory = ECKeyFactory.INSTANCE;
086  
087         ECPublicKey pubKey = (ECPublicKey) keyFactory
088                 .generatePublic(x509KeySpec);
089  
090         ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(),
091                 pubKey.getParams());
092  
093         // 对数据加密
094         // TODO Chipher不支持EC算法 未能实现
095         Cipher cipher = new NullCipher();
096         // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());
097         cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams());
098  
099         return cipher.doFinal(data);
100     }
101  
102     /**
103      * 取得私钥
104      
105      * @param keyMap
106      * @return
107      * @throws Exception
108      */
109     public static String getPrivateKey(Map<String, Object> keyMap)
110             throws Exception {
111         Key key = (Key) keyMap.get(PRIVATE_KEY);
112  
113         return encryptBASE64(key.getEncoded());
114     }
115  
116     /**
117      * 取得公钥
118      
119      * @param keyMap
120      * @return
121      * @throws Exception
122      */
123     public static String getPublicKey(Map<String, Object> keyMap)
124             throws Exception {
125         Key key = (Key) keyMap.get(PUBLIC_KEY);
126  
127         return encryptBASE64(key.getEncoded());
128     }
129  
130     /**
131      * 初始化密钥
132      
133      * @return
134      * @throws Exception
135      */
136     public static Map<String, Object> initKey() throws Exception {
137         BigInteger x1 = new BigInteger(
138                 "2fe13c0537bbc11acaa07d793de4e6d5e5c94eee8"16);
139         BigInteger x2 = new BigInteger(
140                 "289070fb05d38ff58321f2e800536d538ccdaa3d9"16);
141  
142         ECPoint g = new ECPoint(x1, x2);
143  
144         // the order of generator
145         BigInteger n = new BigInteger(
146                 "5846006549323611672814741753598448348329118574063"10);
147         // the cofactor
148         int h = 2;
149         int m = 163;
150         int[] ks = { 763 };
151         ECFieldF2m ecField = new ECFieldF2m(m, ks);
152         // y^2+xy=x^3+x^2+1
153         BigInteger a = new BigInteger("1"2);
154         BigInteger b = new BigInteger("1"2);
155  
156         EllipticCurve ellipticCurve = new EllipticCurve(ecField, a, b);
157  
158         ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, g,
159                 n, h);
160         // 公钥
161         ECPublicKey publicKey = new ECPublicKeyImpl(g, ecParameterSpec);
162  
163         BigInteger s = new BigInteger(
164                 "1234006549323611672814741753598448348329118574063"10);
165         // 私钥
166         ECPrivateKey privateKey = new ECPrivateKeyImpl(s, ecParameterSpec);
167  
168         Map<String, Object> keyMap = new HashMap<String, Object>(2);
169  
170         keyMap.put(PUBLIC_KEY, publicKey);
171         keyMap.put(PRIVATE_KEY, privateKey);
172  
173         return keyMap;
174     }
175  
176 }

请注意上述代码中的TODO内容,再次提醒注意,Chipher不支持EC算法 ,以上代码仅供参考。Chipher、Signature、KeyPairGenerator、KeyAgreement、SecretKey均不支持EC算法。为了确保程序能够正常执行,我们使用了NullCipher类,验证程序。

照旧提供一个测试类:

01 import static org.junit.Assert.*;
02  
03 import java.math.BigInteger;
04 import java.security.spec.ECFieldF2m;
05 import java.security.spec.ECParameterSpec;
06 import java.security.spec.ECPoint;
07 import java.security.spec.ECPrivateKeySpec;
08 import java.security.spec.ECPublicKeySpec;
09 import java.security.spec.EllipticCurve;
10 import java.util.Map;
11  
12 import org.junit.Test;
13  
14 /**
15  
16  * @author 梁栋
17  * @version 1.0
18  * @since 1.0
19  */
20 public class ECCCoderTest {
21  
22     @Test
23     public void test() throws Exception {
24         String inputStr = "abc";
25         byte[] data = inputStr.getBytes();
26  
27         Map<String, Object> keyMap = ECCCoder.initKey();
28  
29         String publicKey = ECCCoder.getPublicKey(keyMap);
30         String privateKey = ECCCoder.getPrivateKey(keyMap);
31         System.err.println("公钥: \n" + publicKey);
32         System.err.println("私钥: \n" + privateKey);
33  
34         byte[] encodedData = ECCCoder.encrypt(data, publicKey);
35  
36         byte[] decodedData = ECCCoder.decrypt(encodedData, privateKey);
37  
38         String outputStr = new String(decodedData);
39         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
40         assertEquals(inputStr, outputStr);
41     }
42 }

控制台输出:

公钥:
MEAwEAYHKoZIzj0CAQYFK4EEAAEDLAAEAv4TwFN7vBGsqgfXk95ObV5clO7oAokHD7BdOP9YMh8u
gAU21TjM2qPZ私钥:
MDICAQAwEAYHKoZIzj0CAQYFK4EEAAEEGzAZAgEBBBTYJsR3BN7TFw7JHcAHFkwNmfil7w==加密前: abc解密后: abc

本篇的主要内容为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类见

001 import java.io.FileInputStream;
002 import java.security.KeyStore;
003 import java.security.PrivateKey;
004 import java.security.PublicKey;
005 import java.security.Signature;
006 import java.security.cert.Certificate;
007 import java.security.cert.CertificateFactory;
008 import java.security.cert.X509Certificate;
009 import java.util.Date;
010  
011 import javax.crypto.Cipher;
012  
013 /**
014  * 证书组件
015  
016  * @author 梁栋
017  * @version 1.0
018  * @since 1.0
019  */
020 public abstract class CertificateCoder extends Coder {
021  
022  
023     /**
024      * Java密钥库(Java Key Store,JKS)KEY_STORE
025      */
026     public static final String KEY_STORE = "JKS";
027  
028     public static final String X509 = "X.509";
029  
030     /**
031      * 由KeyStore获得私钥
032      
033      * @param keyStorePath
034      * @param alias
035      * @param password
036      * @return
037      * @throws Exception
038      */
039     private static PrivateKey getPrivateKey(String keyStorePath, String alias,
040             String password) throws Exception {
041         KeyStore ks = getKeyStore(keyStorePath, password);
042         PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
043         return key;
044     }
045  
046     /**
047      * 由Certificate获得公钥
048      
049      * @param certificatePath
050      * @return
051      * @throws Exception
052      */
053     private static PublicKey getPublicKey(String certificatePath)
054             throws Exception {
055         Certificate certificate = getCertificate(certificatePath);
056         PublicKey key = certificate.getPublicKey();
057         return key;
058     }
059  
060     /**
061      * 获得Certificate
062      
063      * @param certificatePath
064      * @return
065      * @throws Exception
066      */
067     private static Certificate getCertificate(String certificatePath)
068             throws Exception {
069         CertificateFactory certificateFactory = CertificateFactory
070                 .getInstance(X509);
071         FileInputStream in = new FileInputStream(certificatePath);
072  
073         Certificate certificate = certificateFactory.generateCertificate(in);
074         in.close();
075  
076         return certificate;
077     }
078  
079     /**
080      * 获得Certificate
081      
082      * @param keyStorePath
083      * @param alias
084      * @param password
085      * @return
086      * @throws Exception
087      */
088     private static Certificate getCertificate(String keyStorePath,
089             String alias, String password) throws Exception {
090         KeyStore ks = getKeyStore(keyStorePath, password);
091         Certificate certificate = ks.getCertificate(alias);
092  
093         return certificate;
094     }
095  
096     /**
097      * 获得KeyStore
098      
099      * @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 }

再给出一个测试类:

01 import static org.junit.Assert.*;
02  
03 import org.junit.Test;
04  
05 /**
06  
07  * @author 梁栋
08  * @version 1.0
09  * @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 + "\n\r" "解密后: " + 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 + "\n\r" "解密后: " + 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("签名:\r" + sign);
62  
63         // 验证签名
64         boolean status = CertificateCoder.verify(encodedData, sign,
65                 certificatePath);
66         System.err.println("状态:\r" + status);
67         assertTrue(status);
68  
69     }
70 }

控制台输出:

公钥加密——私钥解密
加密前: 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.MF532 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.SF889 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.classX.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.classX.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.classX.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.classX.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:6ASHA1: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,最复杂的准备工作已经完成。 
接下来我们将域名www.zlex.org定位到本机上。打开C:\Windows\System32\drivers\etc\hosts文件,将www.zlex.org绑定在本机上。在文件末尾追加127.0.0.1       www.zlex.org。现在通过地址栏访问http://www.zlex.org,或者通过ping命令,如果能够定位到本机,域名映射就搞定了。 
现在,配置tomcat。先将zlex.keystore拷贝到tomcat的conf目录下,然后配置server.xml。将如下内容加入配置文件

<ConnectorSSLEnabled="true"URIEncoding="UTF-8"clientAuth="false"keystoreFile="conf/zlex.keystore"keystorePass="123456"maxThreads="150"port="443"protocol="HTTP/1.1"scheme="https"secure="true"sslProtocol="TLS" />

注意clientAuth="false"测试阶段,置为false,正式使用时建议使用true。现在启动tomcat,访问https://www.zlex.org/。 
显然,证书未能通过认证,这个时候你可以选择安装证书(上文中的zlex.cer文件就是证书),作为受信任的根证书颁发机构导入,再次重启浏览器(IE,其他浏览器对于域名www.zlex.org不支持本地方式访问),访问https://www.zlex.org/,你会看到地址栏中会有个小锁,就说明安装成功。所有的浏览器联网操作已经在RSA加密解密系统的保护之下了。但似乎我们感受不到。 
这个时候很多人开始怀疑,如果我们要手工做一个这样的https的访问是不是需要把浏览器的这些个功能都实现呢?不需要!

接着上篇内容,给出如下代码实现:

001 import java.io.FileInputStream;
002 import java.security.KeyStore;
003 import java.security.PrivateKey;
004 import java.security.PublicKey;
005 import java.security.Signature;
006 import java.security.cert.Certificate;
007 import java.security.cert.CertificateFactory;
008 import java.security.cert.X509Certificate;
009 import java.util.Date;
010  
011 import javax.crypto.Cipher;
012 import javax.net.ssl.HttpsURLConnection;
013 import javax.net.ssl.KeyManagerFactory;
014 import javax.net.ssl.SSLContext;
015 import javax.net.ssl.SSLSocketFactory;
016 import javax.net.ssl.TrustManagerFactory;
017  
018 /**
019  * 证书组件
020  
021  * @author 梁栋
022  * @version 1.0
023  * @since 1.0
024  */
025 public abstract class CertificateCoder extends Coder {
026  
027     /**
028      * Java密钥库(Java Key Store,JKS)KEY_STORE
029      */
030     public static final String KEY_STORE = "JKS";
031  
032     public static final String X509 = "X.509";
033     public static final String SunX509 = "SunX509";
034     public static final String SSL = "SSL";
035  
036     /**
037      * 由KeyStore获得私钥
038      
039      * @param keyStorePath
040      * @param alias
041      * @param password
042      * @return
043      * @throws Exception
044      */
045     private static PrivateKey getPrivateKey(String keyStorePath, String alias,
046             String password) throws Exception {
047         KeyStore ks = getKeyStore(keyStorePath, password);
048         PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
049         return key;
050     }
051  
052     /**
053      * 由Certificate获得公钥
054      
055      * @param certificatePath
056      * @return
057      * @throws Exception
058      */
059     private static PublicKey getPublicKey(String certificatePath)
060             throws Exception {
061         Certificate certificate = getCertificate(certificatePath);
062         PublicKey key = certificate.getPublicKey();
063         return key;
064     }
065  
066     /**
067      * 获得Certificate
068      
069      * @param certificatePath
070      * @return
071      * @throws Exception
072      */
073     private static Certificate getCertificate(String certificatePath)
074             throws Exception {
075         CertificateFactory certificateFactory = CertificateFactory
076                 .getInstance(X509);
077         FileInputStream in = new FileInputStream(certificatePath);
078  
079         Certificate certificate = certificateFactory.generateCertificate(in);
080         in.close();
081  
082         return certificate;
083     }
084  
085     /**
086      * 获得Certificate
087      
088      * @param keyStorePath
089      * @param alias
090      * @param password
091      * @return
092      * @throws Exception
093      */
094     private static Certificate getCertificate(String keyStorePath,
095             String alias, String password) throws Exception {
096         KeyStore ks = getKeyStore(keyStorePath, password);
097         Certificate certificate = ks.getCertificate(alias);
098  
099         return certificate;
100     }
101  
102     /**
103      * 获得KeyStore
104      
105      * @param keyStorePath
106      * @param password
107      * @return
108      * @throws Exception
109      */
110     private static KeyStore getKeyStore(String keyStorePath, String password)
111             throws Exception {
112         FileInputStream is = new FileInputStream(keyStorePath);
113         KeyStore ks = KeyStore.getInstance(KEY_STORE);
114         ks.load(is, password.toCharArray());
115         is.close();
116         return ks;
117     }
118  
119     /**
120      * 私钥加密
121      
122      * @param data
123      * @param keyStorePath
124      * @param alias
125      * @param password
126      * @return
127      * @throws Exception
128      */
129     public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
130             String alias, String password) throws Exception {
131         // 取得私钥
132         PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
133  
134         // 对数据加密
135         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
136         cipher.init(Cipher.ENCRYPT_MODE, privateKey);
137  
138         return cipher.doFinal(data);
139  
140     }
141  
142     /**
143      * 私钥解密
144      
145      * @param data
146      * @param keyStorePath
147      * @param alias
148      * @param password
149      * @return
150      * @throws Exception
151      */
152     public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
153             String alias, String password) throws Exception {
154         // 取得私钥
155         PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
156  
157         // 对数据加密
158         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
159         cipher.init(Cipher.DECRYPT_MODE, privateKey);
160  
161         return cipher.doFinal(data);
162  
163     }
164  
165     /**
166      * 公钥加密
167      
168      * @param data
169      * @param certificatePath
170      * @return
171      * @throws Exception
172      */
173     public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
174             throws Exception {
175  
176         // 取得公钥
177         PublicKey publicKey = getPublicKey(certificatePath);
178         // 对数据加密
179         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
180         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
181  
182         return cipher.doFinal(data);
183  
184     }
185  
186     /**
187      * 公钥解密
188      
189      * @param data
190      * @param certificatePath
191      * @return
192      * @throws Exception
193      */
194     public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
195             throws Exception {
196         // 取得公钥
197         PublicKey publicKey = getPublicKey(certificatePath);
198  
199         // 对数据加密
200         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
201         cipher.init(Cipher.DECRYPT_MODE, publicKey);
202  
203         return cipher.doFinal(data);
204  
205     }
206  
207     /**
208      * 验证Certificate
209      
210      * @param certificatePath
211      * @return
212      */
213     public static boolean verifyCertificate(String certificatePath) {
214         return verifyCertificate(new Date(), certificatePath);
215     }
216  
217     /**
218      * 验证Certificate是否过期或无效
219      
220      * @param date
221      * @param certificatePath
222      * @return
223      */
224     public static boolean verifyCertificate(Date date, String certificatePath) {
225         boolean status = true;
226         try {
227             // 取得证书
228             Certificate certificate = getCertificate(certificatePath);
229             // 验证证书是否过期或无效
230             status = verifyCertificate(date, certificate);
231         catch (Exception e) {
232             status = false;
233         }
234         return status;
235     }
236  
237     /**
238      * 验证证书是否过期或无效
239      
240      * @param date
241      * @param certificate
242      * @return
243      */
244     private static boolean verifyCertificate(Date date, Certificate certificate) {
245         boolean status = true;
246         try {
247             X509Certificate x509Certificate = (X509Certificate) certificate;
248             x509Certificate.checkValidity(date);
249         catch (Exception e) {
250             status = false;
251         }
252         return status;
253     }
254  
255     /**
256      * 签名
257      
258      * @param keyStorePath
259      * @param alias
260      * @param password
261      
262      * @return
263      * @throws Exception
264      */
265     public static String sign(byte[] sign, String keyStorePath, String alias,
266             String password) throws Exception {
267         // 获得证书
268         X509Certificate x509Certificate = (X509Certificate) getCertificate(
269                 keyStorePath, alias, password);
270         // 获取私钥
271         KeyStore ks = getKeyStore(keyStorePath, password);
272         // 取得私钥
273         PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
274                 .toCharArray());
275  
276         // 构建签名
277         Signature signature = Signature.getInstance(x509Certificate
278                 .getSigAlgName());
279         signature.initSign(privateKey);
280         signature.update(sign);
281         return encryptBASE64(signature.sign());
282     }
283  
284     /**
285      * 验证签名
286      
287      * @param data
288      * @param sign
289      * @param certificatePath
290      * @return
291      * @throws Exception
292      */
293     public static boolean verify(byte[] data, String sign,
294             String certificatePath) throws Exception {
295         // 获得证书
296         X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
297         // 获得公钥
298         PublicKey publicKey = x509Certificate.getPublicKey();
299         // 构建签名
300         Signature signature = Signature.getInstance(x509Certificate
301                 .getSigAlgName());
302         signature.initVerify(publicKey);
303         signature.update(data);
304  
305         return signature.verify(decryptBASE64(sign));
306  
307     }
308  
309     /**
310      * 验证Certificate
311      
312      * @param keyStorePath
313      * @param alias
314      * @param password
315      * @return
316      */
317     public static boolean verifyCertificate(Date date, String keyStorePath,
318             String alias, String password) {
319         boolean status = true;
320         try {
321             Certificate certificate = getCertificate(keyStorePath, alias,
322                     password);
323             status = verifyCertificate(date, certificate);
324         catch (Exception e) {
325             status = false;
326         }
327         return status;
328     }
329  
330     /**
331      * 验证Certificate
332      
333      * @param keyStorePath
334      * @param alias
335      * @param password
336      * @return
337      */
338     public static boolean verifyCertificate(String keyStorePath, String alias,
339             String password) {
340         return verifyCertificate(new Date(), keyStorePath, alias, password);
341     }
342  
343     /**
344      * 获得SSLSocektFactory
345      
346      * @param password
347      *            密码
348      * @param keyStorePath
349      *            密钥库路径
350      
351      * @param trustKeyStorePath
352      *            信任库路径
353      * @return
354      * @throws Exception
355      */
356     private static SSLSocketFactory getSSLSocketFactory(String password,
357             String keyStorePath, String trustKeyStorePath) throws Exception {
358         // 初始化密钥库
359         KeyManagerFactory keyManagerFactory = KeyManagerFactory
360                 .getInstance(SunX509);
361         KeyStore keyStore = getKeyStore(keyStorePath, password);
362         keyManagerFactory.init(keyStore, password.toCharArray());
363  
364         // 初始化信任库
365         TrustManagerFactory trustManagerFactory = TrustManagerFactory
366                 .getInstance(SunX509);
367         KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);
368         trustManagerFactory.init(trustkeyStore);
369  
370         // 初始化SSL上下文
371         SSLContext ctx = SSLContext.getInstance(SSL);
372         ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
373                 .getTrustManagers(), null);
374         SSLSocketFactory sf = ctx.getSocketFactory();
375  
376         return sf;
377     }
378  
379     /**
380      * 为HttpsURLConnection配置SSLSocketFactory
381      
382      * @param conn
383      *            HttpsURLConnection
384      * @param password
385      *            密码
386      * @param keyStorePath
387      *            密钥库路径
388      
389      * @param trustKeyStorePath
390      *            信任库路径
391      * @throws Exception
392      */
393     public static void configSSLSocketFactory(HttpsURLConnection conn,
394             String password, String keyStorePath, String trustKeyStorePath)
395             throws Exception {
396         conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,
397                 trustKeyStorePath));
398     }
399 }

增加了configSSLSocketFactory方法供外界调用,该方法为 HttpsURLConnection配置了SSLSocketFactory。当HttpsURLConnection配置了 SSLSocketFactory后,我们就可以通过HttpsURLConnection的getInputStream、 getOutputStream,像往常使用HttpURLConnection做操作了。尤其要说明一点,未配置SSLSocketFactory 前,HttpsURLConnection的getContentLength()获得值永远都是-1

给出相应测试类:

001 import static org.junit.Assert.*;
002  
003 import java.io.DataInputStream;
004 import java.io.InputStream;
005 import java.net.URL;
006  
007 import javax.net.ssl.HttpsURLConnection;
008  
009 import org.junit.Test;
010  
011 /**
012  
013  * @author 梁栋
014  * @version 1.0
015  * @since 1.0
016  */
017 public class CertificateCoderTest {
018     private String password = "123456";
019     private String alias = "www.zlex.org";
020     private String certificatePath = "d:/zlex.cer";
021     private String keyStorePath = "d:/zlex.keystore";
022     private String clientKeyStorePath = "d:/zlex-client.keystore";
023     private String clientPassword = "654321";
024  
025     @Test
026     public void test() throws Exception {
027         System.err.println("公钥加密——私钥解密");
028         String inputStr = "Ceritifcate";
029         byte[] data = inputStr.getBytes();
030  
031         byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
032                 certificatePath);
033  
034         byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
035                 keyStorePath, alias, password);
036         String outputStr = new String(decrypt);
037  
038         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
039  
040         // 验证数据一致
041         assertArrayEquals(data, decrypt);
042  
043         // 验证证书有效
044         assertTrue(CertificateCoder.verifyCertificate(certificatePath));
045  
046     }
047  
048     @Test
049     public void testSign() throws Exception {
050         System.err.println("私钥加密——公钥解密");
051  
052         String inputStr = "sign";
053         byte[] data = inputStr.getBytes();
054  
055         byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
056                 keyStorePath, alias, password);
057  
058         byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
059                 certificatePath);
060  
061         String outputStr = new String(decodedData);
062         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
063         assertEquals(inputStr, outputStr);
064  
065         System.err.println("私钥签名——公钥验证签名");
066         // 产生签名
067         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
068                 password);
069         System.err.println("签名:\r" + sign);
070  
071         // 验证签名
072         boolean status = CertificateCoder.verify(encodedData, sign,
073                 certificatePath);
074         System.err.println("状态:\r" + status);
075         assertTrue(status);
076  
077     }
078  
079     @Test
080     public void testHttps() throws Exception {
081         URL url = new URL("https://www.zlex.org/examples/");
082         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
083  
084         conn.setDoInput(true);
085         conn.setDoOutput(true);
086  
087         CertificateCoder.configSSLSocketFactory(conn, clientPassword,
088                 clientKeyStorePath, clientKeyStorePath);
089  
090         InputStream is = conn.getInputStream();
091  
092         int length = conn.getContentLength();
093  
094         DataInputStream dis = new DataInputStream(is);
095         byte[] data = new byte[length];
096         dis.readFully(data);
097  
098         dis.close();
099         System.err.println(new String(data));
100         conn.disconnect();
101     }
102 }

注意testHttps方法,几乎和我们往常做HTTP访问没有差别,我们来看控制台输出:

<!--Licensed to the Apache Software Foundation (ASF) under one or morecontributor license agreements.  See the NOTICE file distributed withthis work for additional information regarding copyright ownership.The ASF licenses this file to You under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance withthe License.  You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Apache Tomcat Examples</TITLE>
<META http-equiv=Content-Type content="text/html">
</HEAD>
<BODY>
<P>
<H3>Apache Tomcat Examples</H3>
<P></P>
<ul>
<li><a href="http://javaeye.shaduwang.com/?snowolf/blog/servlets">Servlets examples</a></li>
<li><a href="http://javaeye.shaduwang.com/?snowolf/blog/jsp">JSP Examples</a></li>
</ul>
</BODY></HTML>

通过浏览器直接访问https://www.zlex.org/examples/你 也会获得上述内容。也就是说应用甲方作为服务器构建tomcat服务,乙方可以通过上述方式访问甲方受保护的SSL应用,并且不需要考虑具体的加密解密问 题。甲乙双方可以经过相应配置,通过双方的tomcat配置有效的SSL服务,简化上述代码实现,完全通过证书配置完成SSL双向认证!

我们使用自签名证书完成了认证。接下来,我们使用第三方CA签名机构完成证书签名。 
    这里我们使用thawte提供的测试用21天免费ca证书。 
    1.要在该网站上注明你的域名,这里使用www.zlex.org作为测试用域名(请勿使用该域名作为你的域名地址,该域名受法律保护!请使用其他非注册域名!)。 
    2.如果域名有效,你会收到邮件要求你访问https://www.thawte.com/cgi/server/try.exe获得ca证书。 
    3.复述密钥库的创建。

keytool -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 密码相同,按回车):
再次输入新密码:

4.通过如下命令,从zlex.keystore中导出CA证书申请。

keytool -certreq -alias www.zlex.org -file d:\zlex.csr -keystore d:\zlex.keystore -v

你会获得zlex.csr文件,可以用记事本打开,内容如下格式:

-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBnDCCAQUCAQAwXDELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAkJKMQswCQYDVQQHEwJCSjENMAsG
A1UEChMEemxleDENMAsGA1UECxMEemxleDEVMBMGA1UEAxMMd3d3LnpsZXgub3JnMIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQCR6DXU9Mp+mCKO7cv9JPsj0n1Ec/GpM09qvhpgX3FNad/ZWSDc
vU77YXZSoF9hQp3w1LC+eeKgd2MlVpXTvbVwBNVd2HiQPp37ic6BUUjSaX8LHtCl7l0BIEye9qQ2
j8G0kak7e8ZA0s7nb3Ymq/K8BV7v0MQIdhIc1bifK9ZDewIDAQABoAAwDQYJKoZIhvcNAQEFBQAD
gYEAMA1r2fbZPtNx37U9TRwadCH2TZZecwKJS/hskNm6ryPKIAp9APWwAyj8WJHRBz5SpZM4zmYO
oMCI8BcnY2A4JP+R7/SwXTdH/xcg7NVghd9A2SCgqMpF7KMfc5dE3iygdiPu+UhY200Dvpjx8gmJ
1UbH3+nqMUyCrZgURFslOUY=
-----END NEW CERTIFICATE REQUEST-----

5.将上述文件内容拷贝到https://www.thawte.com/cgi/server/try.exe中,点击next,获得回应内容,这里是p7b格式。 
内容如下:

-----BEGIN PKCS7-----
MIIF3AYJKoZIhvcNAQcCoIIFzTCCBckCAQExADALBgkqhkiG9w0BBwGgggWxMIID
EDCCAnmgAwIBAgIQA/mx/pKoaB+KGX2hveFU9zANBgkqhkiG9w0BAQUFADCBhzEL
MAkGA1UEBhMCWkExIjAgBgNVBAgTGUZPUiBURVNUSU5HIFBVUlBPU0VTIE9OTFkx
HTAbBgNVBAoTFFRoYXd0ZSBDZXJ0aWZpY2F0aW9uMRcwFQYDVQQLEw5URVNUIFRF
U1QgVEVTVDEcMBoGA1UEAxMTVGhhd3RlIFRlc3QgQ0EgUm9vdDAeFw0wOTA1Mjgw
MDIxMzlaFw0wOTA2MTgwMDIxMzlaMFwxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJC
SjELMAkGA1UEBxMCQkoxDTALBgNVBAoTBHpsZXgxDTALBgNVBAsTBHpsZXgxFTAT
BgNVBAMTDHd3dy56bGV4Lm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
keg11PTKfpgiju3L/ST7I9J9RHPxqTNPar4aYF9xTWnf2Vkg3L1O+2F2UqBfYUKd
8NSwvnnioHdjJVaV0721cATVXdh4kD6d+4nOgVFI0ml/Cx7Qpe5dASBMnvakNo/B
tJGpO3vGQNLO5292JqvyvAVe79DECHYSHNW4nyvWQ3sCAwEAAaOBpjCBozAMBgNV
HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBABgNVHR8E
OTA3MDWgM6Axhi9odHRwOi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNl
cnZlckNBLmNybDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9v
Y3NwLnRoYXd0ZS5jb20wDQYJKoZIhvcNAQEFBQADgYEATPuxZbtJJSPmXvfrr1yz
xqM06IwTZ6UU0lZRG7I0WufMjNMKdpn8hklUhE17mxAhGSpewLVVeLR7uzBLFkuC
X7wMXxhoYdJZtNai72izU6Rd1oknao7diahvRxPK4IuQ7y2oZ511/4T4vgY6iRAj
q4q76HhPJrVRL/sduaiu+gYwggKZMIICAqADAgECAgEAMA0GCSqGSIb3DQEBBAUA
MIGHMQswCQYDVQQGEwJaQTEiMCAGA1UECBMZRk9SIFRFU1RJTkcgUFVSUE9TRVMg
T05MWTEdMBsGA1UEChMUVGhhd3RlIENlcnRpZmljYXRpb24xFzAVBgNVBAsTDlRF
U1QgVEVTVCBURVNUMRwwGgYDVQQDExNUaGF3dGUgVGVzdCBDQSBSb290MB4XDTk2
MDgwMTAwMDAwMFoXDTIwMTIzMTIxNTk1OVowgYcxCzAJBgNVBAYTAlpBMSIwIAYD
VQQIExlGT1IgVEVTVElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQKExRUaGF3dGUg
Q2VydGlmaWNhdGlvbjEXMBUGA1UECxMOVEVTVCBURVNUIFRFU1QxHDAaBgNVBAMT
E1RoYXd0ZSBUZXN0IENBIFJvb3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
ALV9kG+Os6x/DOhm+tKUQfzVMWGhE95sFmEtkMMTX2Zi4n6i6BvzoReJ5njzt1LF
cqu4EUk9Ji20egKKfmqRzmQFLP7+1niSdfJEUE7cKY40QoI99270PTrLjJeaMcCl
+AYl+kD+RL5BtuKKU3PurYcsCsre6aTvjMcqpTJOGeSPAgMBAAGjEzARMA8GA1Ud
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAgozj7BkD9O8si2V0v+EZ/t7E
fz/LC8y6mD7IBUziHy5/53ymGAGLtyhXHvX+UIE6UWbHro3IqVkrmY5uC93Z2Wew
A/6edK3KFUcUikrLeewM7gmqsiASEKx2mKRKlu12jXyNS5tXrPWRDvUKtFC1uL9a
12rFAQS2BkIk7aU+ghYxAA==
-----END PKCS7-----

将其存储为zlex.p7b 
    6.将由CA签发的证书导入密钥库。

keytool -import -trustcacerts -alias www.zlex.org -file d:\zlex.p7b -keystore d:\zlex.keystore -v

在这里我使用的密码为 123456

控制台输出:

输入keystore密码:回复中的最高级认证:所有者:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FORTESTING PURPOSES ONLY, C=ZA
签发人:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FORTESTING PURPOSES ONLY, C=ZA
序列号:0
有效期: Thu Aug 01 08:00:00 CST 1996 至Fri Jan 01 05:59:59 CST 2021
证书指纹:MD5:5E:E0:0E:1D:17:B7:CA:A5:7D:36:D6:02:DF:4D:26:A4SHA1:39:C6:9D:27:AF:DC:EB:47:D6:33:36:6A:B2:05:F1:47:A9:B4:DA:EA签名算法名称:MD5withRSA版本: 3扩展:#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[CA:truePathLen:2147483647
]... 是不可信的。 还是要安装回复? [否]:  Y
认证回复已安装在 keystore中
[正在存储 d:\zlex.keystore]

7.域名定位 
    将域名www.zlex.org定位到本机上。打开C:\Windows\System32\drivers\etc\hosts文件,将 www.zlex.org绑定在本机上。在文件末尾追加127.0.0.1       www.zlex.org。现在通过地址栏访问http://www.zlex.org,或者通过ping命令,如果能够定位到本机,域名映射就搞定 了。

8.配置server.xml

<ConnectorkeystoreFile="conf/zlex.keystore"keystorePass="123456" truststoreFile="conf/zlex.keystore"    truststorePass="123456"     SSLEnabled="true"URIEncoding="UTF-8"clientAuth="false"         maxThreads="150"port="443"protocol="HTTP/1.1"scheme="https"secure="true"sslProtocol="TLS" />

将文件zlex.keystore拷贝到tomcat的conf目录下,重新启动tomcat。访问https://www.zlex.org/,我们发现联网有些迟钝。大约5秒钟后,网页正常显示,同时有如下图所示: 
 
浏览器验证了该CA机构的有效性。

打开证书,如下图所示: 

调整测试类:

001 import static org.junit.Assert.*;
002  
003 import java.io.DataInputStream;
004 import java.io.InputStream;
005 import java.net.URL;
006  
007 import javax.net.ssl.HttpsURLConnection;
008  
009 import org.junit.Test;
010  
011 /**
012  
013  * @author 梁栋
014  * @version 1.0
015  * @since 1.0
016  */
017 public class CertificateCoderTest {
018     private String password = "123456";
019     private String alias = "www.zlex.org";
020     private String certificatePath = "d:/zlex.cer";
021     private String keyStorePath = "d:/zlex.keystore";
022  
023     @Test
024     public void test() throws Exception {
025         System.err.println("公钥加密——私钥解密");
026         String inputStr = "Ceritifcate";
027         byte[] data = inputStr.getBytes();
028  
029         byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
030                 certificatePath);
031  
032         byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
033                 keyStorePath, alias, password);
034         String outputStr = new String(decrypt);
035  
036         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
037  
038         // 验证数据一致
039         assertArrayEquals(data, decrypt);
040  
041         // 验证证书有效
042         assertTrue(CertificateCoder.verifyCertificate(certificatePath));
043  
044     }
045  
046     @Test
047     public void testSign() throws Exception {
048         System.err.println("私钥加密——公钥解密");
049  
050         String inputStr = "sign";
051         byte[] data = inputStr.getBytes();
052  
053         byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
054                 keyStorePath, alias, password);
055  
056         byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
057                 certificatePath);
058  
059         String outputStr = new String(decodedData);
060         System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);
061         assertEquals(inputStr, outputStr);
062  
063         System.err.println("私钥签名——公钥验证签名");
064         // 产生签名
065         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
066                 password);
067         System.err.println("签名:\r" + sign);
068  
069         // 验证签名
070         boolean status = CertificateCoder.verify(encodedData, sign,
071                 certificatePath);
072         System.err.println("状态:\r" + status);
073         assertTrue(status);
074  
075     }
076  
077     @Test
078     public void testHttps() throws Exception {
079         URL url = new URL("https://www.zlex.org/examples/");
080         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
081  
082         conn.setDoInput(true);
083         conn.setDoOutput(true);
084  
085         CertificateCoder.configSSLSocketFactory(conn, password, keyStorePath,
086                 keyStorePath);
087  
088         InputStream is = conn.getInputStream();
089  
090         int length = conn.getContentLength();
091  
092         DataInputStream dis = new DataInputStream(is);
093         byte[] data = new byte[length];
094         dis.readFully(data);
095  
096         dis.close();
097         conn.disconnect();
098         System.err.println(new String(data));
099     }
100 }

再次执行,验证通过! 
由此,我们了基于SSL协议的认证过程。测试类的testHttps方法模拟了一次浏览器的HTTPS访问。

       
       

各种Java加密算法相关推荐

  1. 对称密钥加密算法 对称轮数_选择Java加密算法第2部分–单密钥对称加密

    对称密钥加密算法 对称轮数 抽象 这是涵盖Java加密算法的三部分博客系列的第2部分. 该系列涵盖如何实现以下功能: 使用SHA–512散列 AES–256 RSA–4096 这第二篇文章详细介绍了如 ...

  2. 非对称加密 公钥私钥_选择Java加密算法第3部分–公钥/私钥非对称加密

    非对称加密 公钥私钥 抽象 这是涵盖Java加密算法的三部分博客系列的第3部分. 该系列涵盖如何实现以下功能: 使用SHA–512散列 使用AES–256的单密钥对称加密 RSA–4096 这第三篇文 ...

  3. 选择Java加密算法第2部分–单密钥对称加密

    抽象 这是涵盖Java加密算法的三部分博客系列的第2部分. 本系列介绍如何实现以下目标: 使用SHA–512散列 AES–256 RSA–4096 这第二篇文章详细介绍了如何实现单密钥对称AES-25 ...

  4. 选择Java加密算法第3部分–公钥/私钥非对称加密

    抽象 这是涵盖Java加密算法的三部分博客系列的第3部分. 本系列介绍如何实现以下目标: 使用SHA–512散列 使用AES–256的单密钥对称加密 RSA–4096 这第三篇文章详细介绍了如何实现非 ...

  5. java加密算法入门(三)-非对称加密详解

    1.简单介绍 这几天一直在看非对称的加密,相比之前的两篇内容,这次看了两倍多的时间还云里雾里的,所以这篇文章相对之前的两篇,概念性的东西多了些,另外是代码的每一步我都做了介绍,方便自己以后翻阅,也方便 ...

  6. Java加密算法(十一)——双向认证

    对于双向认证,做一个简单的描述.  服务器端下发证书,客户端接受证书.证书带有公钥信息,用于验证服务器端.对数据加密/解密,起到OSI五类服务的认证(鉴别)服务和保密性服务. 这只是单向认证,为什么? ...

  7. java 加密算法 base64

    (一)java自带的加密和解密 import sun.misc.BASE64Decoder; public class Base64Utils {    public static String ge ...

  8. [转]Java加密算法

    如基本的单向加密算法: BASE64 严格地说,属于编码格式,而非加密算法 MD5(Message Digest algorithm 5,信息摘要算法) SHA(Secure Hash Algorit ...

  9. JAVA加密算法(DSA)

    DSA  DSA-Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard) ...

最新文章

  1. oracle单行超2499,SP2-0027: Input is too long ( 2499 characters) - line ignored — oracle-tech
  2. Python编程语言学习:列表与字典互转的几大方法集锦、从列表中按顺序循环抽走一个元素输出剩余元素之详细攻略
  3. 从 SPIR-V 到 ISPC:将 GPU 计算转化为 CPU 计算
  4. 【CodeForces - 244B】Undoubtedly Lucky Numbers (dfs打表 + 二分)
  5. 【Python】BMI指数 计算器
  6. 负margin几种用法的总结
  7. 5G与IoT将成为IPv6强大驱动力
  8. 推荐几款程序员值得拥有的写文档工具
  9. 2018网易编程射击游戏
  10. oeasy教您玩转vim - 4 - # 深入帮助
  11. 20162327WJH四则运算第二周总结
  12. [Gym] - 100886K 2015-2016 Petrozavodsk Winter Training Camp, Saratov SU Contest K - Toll Roads
  13. Matlab 直方图绘制
  14. [Unity]摘录笔记UnityShader(解读shader代码构成)
  15. 不用深厚的数学功底也不用深厚的金融知识,用python也能炒股?
  16. C语言中EOF是什么意思? linux 【转载】 2020-11-19
  17. 右键文件或文件夹或空白处弹出菜单包含自己软件快捷方式
  18. C语言实现搬山游戏,附上代码及解析
  19. PCB高速信号布线技巧
  20. 谷歌怕了!ChatGPT狂砸搜索引擎饭碗,CEO开会拉响「红色警报」

热门文章

  1. php7与apache整合,apache集成php7.3.5的详细步骤
  2. java能写复杂的查询么_spring-data-jpa 复杂查询的写法(包含or的查询)
  3. mysql四种事务级别_【MySQL 知识】四种事务隔离级别
  4. 实现页面适配_微信公众号文章页面适配深色模式
  5. 计算机网络原理(第三章) 传输层 课后习题
  6. C++ 对象的初始化和清理
  7. 《深入理解java虚拟机》第1章 走近Java
  8. C语言变量初始化是必须的
  9. 使用JAVA爬取博客里面的所有文章
  10. 分享一篇关于饿了么的需求文档