java 加密技术

Java加密技术(一)
文章分类:Java编程
    加密解密,曾经是我一个毕业设计的重要组件。在工作了多年以后回想当时那个加密、解密算法,实在是太单纯了。  
    言归正传,这里我们主要描述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,椭圆曲线密码编码学)


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

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代码实现如下: 
Java代码   
1.	/** 
2.	 * BASE64解密 
3.	 *  
4.	 * @param key 
5.	 * @return 
6.	 * @throws Exception 
7.	 */  
8.	public static byte[] decryptBASE64(String key) throws Exception {  
9.	    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代码实现如下: 
Java代码   
1.	/** 
2.	 * MD5加密 
3.	 *  
4.	 * @param data 
5.	 * @return 
6.	 * @throws Exception 
7.	 */  
8.	public static byte[] encryptMD5(byte[] data) throws Exception {  
9.	  
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代码实现如下: 
Java代码   
1.	    /** 
2.	     * SHA加密 
3.	     *  
4.	     * @param data 
5.	     * @return 
6.	     * @throws Exception 
7.	     */  
8.	    public static byte[] encryptSHA(byte[] data) throws Exception {  
9.	  
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代码实现如下: 
Java代码   
1.	/** 
2.	 * 初始化HMAC密钥 
3.	 *  
4.	 * @return 
5.	 * @throws Exception 
6.	 */  
7.	public static String initMacKey() throws Exception {  
8.	    KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);  
9.	  
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.	}  


给出一个完整类,如下: 
Java代码   
1.	import java.security.MessageDigest;  
2.	  
3.	import javax.crypto.KeyGenerator;  
4.	import javax.crypto.Mac;  
5.	import javax.crypto.SecretKey;  
6.	  
7.	import sun.misc.BASE64Decoder;  
8.	import sun.misc.BASE64Encoder;  
9.	  
10.	/** 
11.	 * 基础加密组件 
12.	 *  
13.	 * @author 梁栋 
14.	 * @version 1.0 
15.	 * @since 1.0 
16.	 */  
17.	public abstract class Coder {  
18.	    public static final String KEY_SHA = "SHA";  
19.	    public static final String KEY_MD5 = "MD5";  
20.	  
21.	    /** 
22.	     * MAC算法可选以下多种算法 
23.	     *  
24.	     * 
 
25.	     * HmacMD5  
26.	     * HmacSHA1  
27.	     * HmacSHA256  
28.	     * HmacSHA384  
29.	     * HmacSHA512 
30.	     * 
31. */ 32. public static final String KEY_MAC = "HmacMD5"; 33. 34. /** 35. * BASE64解密 36. * 37. * @param key 38. * @return 39. * @throws Exception 40. */ 41. public static byte[] decryptBASE64(String key) throws Exception { 42. return (new BASE64Decoder()).decodeBuffer(key); 43. } 44. 45. /** 46. * BASE64加密 47. * 48. * @param key 49. * @return 50. * @throws Exception 51. */ 52. public static String encryptBASE64(byte[] key) throws Exception { 53. return (new BASE64Encoder()).encodeBuffer(key); 54. } 55. 56. /** 57. * MD5加密 58. * 59. * @param data 60. * @return 61. * @throws Exception 62. */ 63. public static byte[] encryptMD5(byte[] data) throws Exception { 64. 65. MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); 66. md5.update(data); 67. 68. return md5.digest(); 69. 70. } 71. 72. /** 73. * SHA加密 74. * 75. * @param data 76. * @return 77. * @throws Exception 78. */ 79. public static byte[] encryptSHA(byte[] data) throws Exception { 80. 81. MessageDigest sha = MessageDigest.getInstance(KEY_SHA); 82. sha.update(data); 83. 84. return sha.digest(); 85. 86. } 87. 88. /** 89. * 初始化HMAC密钥 90. * 91. * @return 92. * @throws Exception 93. */ 94. public static String initMacKey() throws Exception { 95. KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); 96. 97. SecretKey secretKey = keyGenerator.generateKey(); 98. return encryptBASE64(secretKey.getEncoded()); 99. } 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. } 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import org.junit.Test; 4. 5. /** 6. * 7. * @author 梁栋 8. * @version 1.0 9. * @since 1.0 10. */ 11. public class 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. } 控制台输出: Console代码 1. 原文: 2. 简单加密 3. BASE64加密后: 4. 566A5Y2V5Yqg5a+G 5. 6. BASE64解密后: 7. 简单加密 8. Mac密钥: 9. uGxdHC+6ylRDaik++leFtGwiMbuYUJ6mqHWyhSgF4trVkVBBSQvY/a22xU8XT1RUemdCWW155Bke 10. pBIpkd7QHg== 11. 12. MD5: 13. -550b4d90349ad4629462113e7934de56 14. SHA: 15. 91k9vo7p400cjkgfhjh0ia9qthsjagfn 16. HMAC: 17. 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算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。 单向加密的用途主要是为了校验数据在传输过程中是否被修改。 Java加密技术(二) 文章分类:Java编程 接下来我们介绍对称加密算法,最常用的莫过于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类见 Java加密技术(一) Java代码 1. import java.security.Key; 2. import java.security.SecureRandom; 3. 4. import javax.crypto.Cipher; 5. import javax.crypto.KeyGenerator; 6. import javax.crypto.SecretKey; 7. import javax.crypto.SecretKeyFactory; 8. import javax.crypto.spec.DESKeySpec; 9. 10. 11. /** 12. * DES安全编码组件 13. * 14. *
 
15.	 * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR) 
16.	 * DES                  key size must be equal to 56 
17.	 * DESede(TripleDES)    key size must be equal to 112 or 168 
18.	 * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
19.	 * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
20.	 * RC2                  key size must be between 40 and 1024 bits 
21.	 * RC4(ARCFOUR)         key size must be between 40 and 1024 bits 
22.	 * 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html 
23.	 * 
24. * 25. * @author 梁栋 26. * @version 1.0 27. * @since 1.0 28. */ 29. public abstract class DESCoder extends Coder { 30. /** 31. * ALGORITHM 算法
32. * 可替换为以下任意一种算法,同时key值的size相应改变。 33. * 34. *
 
35.	     * DES                  key size must be equal to 56 
36.	     * DESede(TripleDES)    key size must be equal to 112 or 168 
37.	     * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
38.	     * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
39.	     * RC2                  key size must be between 40 and 1024 bits 
40.	     * RC4(ARCFOUR)         key size must be between 40 and 1024 bits 
41.	     * 
42. * 43. * 在Key toKey(byte[] key)方法中使用下述代码 44. * SecretKey secretKey = new SecretKeySpec(key, ALGORITHM); 替换 45. * 46. * DESKeySpec dks = new DESKeySpec(key); 47. * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); 48. * SecretKey secretKey = keyFactory.generateSecret(dks); 49. * 50. */ 51. public static final String ALGORITHM = "DES"; 52. 53. /** 54. * 转换密钥
55. * 56. * @param key 57. * @return 58. * @throws Exception 59. */ 60. private static Key toKey(byte[] key) throws Exception { 61. DESKeySpec dks = new DESKeySpec(key); 62. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); 63. SecretKey secretKey = keyFactory.generateSecret(dks); 64. 65. // 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码 66. // SecretKey secretKey = new SecretKeySpec(key, ALGORITHM); 67. 68. return secretKey; 69. } 70. 71. /** 72. * 解密 73. * 74. * @param data 75. * @param key 76. * @return 77. * @throws Exception 78. */ 79. public static byte[] decrypt(byte[] data, String key) throws Exception { 80. Key k = toKey(decryptBASE64(key)); 81. 82. Cipher cipher = Cipher.getInstance(ALGORITHM); 83. cipher.init(Cipher.DECRYPT_MODE, k); 84. 85. return cipher.doFinal(data); 86. } 87. 88. /** 89. * 加密 90. * 91. * @param data 92. * @param key 93. * @return 94. * @throws Exception 95. */ 96. public static byte[] encrypt(byte[] data, String key) throws Exception { 97. Key k = toKey(decryptBASE64(key)); 98. Cipher cipher = Cipher.getInstance(ALGORITHM); 99. 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对字符串加密生成密钥,这是比较常见的密钥生成方式。 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. 4. import org.junit.Test; 5. 6. /** 7. * 8. * @author 梁栋 9. * @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. } 得到的输出内容如下: Console代码 1. 原文: DES 2. 密钥: f3wEtRrV6q0= 3. 4. 加密后: C6qe9oNIzRY= 5. 6. 解密后: DES 由控制台得到的输出,我们能够比对加密、解密后结果一致。这是一种简单的加密解密方式,只有一个密钥。 其实DES有很多同胞兄弟,如DESede(TripleDES)、AES、Blowfish、RC2、RC4(ARCFOUR)。这里就不过多阐述了,大同小异,只要换掉ALGORITHM换成对应的值,同时做一个代码替换SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);就可以了,此外就是密钥长度不同了。 Java代码 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. **/ Java加密技术(三) 文章分类:Java编程 除了DES,我们还知道有DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法——PBE PBE PBE——Password-based encryption(基于密码加密)。其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。是一种简便的加密方式。 通过java代码实现如下:Coder类见 Java加密技术(一) Java代码 1. import java.security.Key; 2. import java.util.Random; 3. 4. import javax.crypto.Cipher; 5. import javax.crypto.SecretKey; 6. import javax.crypto.SecretKeyFactory; 7. import javax.crypto.spec.PBEKeySpec; 8. import javax.crypto.spec.PBEParameterSpec; 9. 10. /** 11. * PBE安全编码组件 12. * 13. * @author 梁栋 14. * @version 1.0 15. * @since 1.0 16. */ 17. public abstract class PBECoder extends Coder { 18. /** 19. * 支持以下任意一种算法 20. * 21. *
 
22.	     * PBEWithMD5AndDES  
23.	     * PBEWithMD5AndTripleDES  
24.	     * PBEWithSHA1AndDESede 
25.	     * PBEWithSHA1AndRC2_40 
26.	     * 
27. */ 28. public static final String ALGORITHM = "PBEWITHMD5andDES"; 29. 30. /** 31. * 盐初始化 32. * 33. * @return 34. * @throws Exception 35. */ 36. public static byte[] initSalt() throws Exception { 37. byte[] salt = new byte[8]; 38. Random random = new Random(); 39. random.nextBytes(salt); 40. return salt; 41. } 42. 43. /** 44. * 转换密钥
45. * 46. * @param password 47. * @return 48. * @throws Exception 49. */ 50. private static Key toKey(String password) throws Exception { 51. PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray()); 52. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); 53. SecretKey secretKey = keyFactory.generateSecret(keySpec); 54. 55. return secretKey; 56. } 57. 58. /** 59. * 加密 60. * 61. * @param data 62. * 数据 63. * @param password 64. * 密码 65. * @param salt 66. * 盐 67. * @return 68. * @throws Exception 69. */ 70. public static byte[] encrypt(byte[] data, String password, byte[] salt) 71. throws Exception { 72. 73. Key key = toKey(password); 74. 75. PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100); 76. Cipher cipher = Cipher.getInstance(ALGORITHM); 77. cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 78. 79. return cipher.doFinal(data); 80. 81. } 82. 83. /** 84. * 解密 85. * 86. * @param data 87. * 数据 88. * @param password 89. * 密码 90. * @param salt 91. * 盐 92. * @return 93. * @throws Exception 94. */ 95. public static byte[] decrypt(byte[] data, String password, byte[] salt) 96. throws Exception { 97. 98. Key key = toKey(password); 99. 100. PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100); 101. Cipher cipher = Cipher.getInstance(ALGORITHM); 102. cipher.init(Cipher.DECRYPT_MODE, key, paramSpec); 103. 104. return cipher.doFinal(data); 105. 106. } 107. } 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import org.junit.Test; 4. 5. /** 6. * 7. * @author 梁栋 8. * @version 1.0 9. * @since 1.0 10. */ 11. public class 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. } 控制台输出: Console代码 1. 原文: abc 2. 密码: efg 3. 加密后: iCZ0uRtaAhE= 4. 5. 解密后: abc 后续我们会介绍非对称加密算法,如RSA、DSA、DH、ECC等。 Java加密技术(四) 文章分类:Java编程 接下来我们介绍典型的非对称加密算法——RSA RSA 这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。 这种加密算法的特点主要是密钥的变化,上文我们看到DES只有一个密钥。相当于只有一把钥匙,如果这把钥匙丢了,数据也就不安全了。RSA同时有两把钥匙,公钥与私钥。同时支持数字签名。数字签名的意义在于,对传输过来的数据进行校验。确保数据在传输工程中不被修改。 流程分析: 1. 甲方构建密钥对儿,将公钥公布给乙方,将私钥保留。 2. 甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。 3. 乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。 按如上步骤给出序列图,如下: 1. 2. 3. 通过java代码实现如下:Coder类见 Java加密技术(一) Java代码 1. import java.security.Key; 2. import java.security.KeyFactory; 3. import java.security.KeyPair; 4. import java.security.KeyPairGenerator; 5. import java.security.PrivateKey; 6. import java.security.PublicKey; 7. import java.security.Signature; 8. import java.security.interfaces.RSAPrivateKey; 9. import java.security.interfaces.RSAPublicKey; 10. import java.security.spec.PKCS8EncodedKeySpec; 11. import java.security.spec.X509EncodedKeySpec; 12. 13. import java.util.HashMap; 14. import java.util.Map; 15. 16. import javax.crypto.Cipher; 17. 18. /** 19. * RSA安全编码组件 20. * 21. * @author 梁栋 22. * @version 1.0 23. * @since 1.0 24. */ 25. public abstract class RSACoder extends Coder { 26. public static final String KEY_ALGORITHM = "RSA"; 27. public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; 28. 29. private static final String PUBLIC_KEY = "RSAPublicKey"; 30. private static final String PRIVATE_KEY = "RSAPrivateKey"; 31. 32. /** 33. * 用私钥对信息生成数字签名 34. * 35. * @param data 36. * 加密数据 37. * @param privateKey 38. * 私钥 39. * 40. * @return 41. * @throws Exception 42. */ 43. public static String sign(byte[] data, String privateKey) throws Exception { 44. // 解密由base64编码的私钥 45. byte[] keyBytes = decryptBASE64(privateKey); 46. 47. // 构造PKCS8EncodedKeySpec对象 48. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 49. 50. // KEY_ALGORITHM 指定的加密算法 51. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 52. 53. // 取私钥匙对象 54. PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); 55. 56. // 用私钥对信息生成数字签名 57. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 58. signature.initSign(priKey); 59. signature.update(data); 60. 61. return encryptBASE64(signature.sign()); 62. } 63. 64. /** 65. * 校验数字签名 66. * 67. * @param data 68. * 加密数据 69. * @param publicKey 70. * 公钥 71. * @param sign 72. * 数字签名 73. * 74. * @return 校验成功返回true 失败返回false 75. * @throws Exception 76. * 77. */ 78. public static boolean verify(byte[] data, String publicKey, String sign) 79. throws Exception { 80. 81. // 解密由base64编码的公钥 82. byte[] keyBytes = decryptBASE64(publicKey); 83. 84. // 构造X509EncodedKeySpec对象 85. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 86. 87. // KEY_ALGORITHM 指定的加密算法 88. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 89. 90. // 取公钥匙对象 91. PublicKey pubKey = keyFactory.generatePublic(keySpec); 92. 93. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 94. signature.initVerify(pubKey); 95. signature.update(data); 96. 97. // 验证签名是否正常 98. return signature.verify(decryptBASE64(sign)); 99. } 100. 101. /** 102. * 解密
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. * 解密
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. * 加密
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. * 加密
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 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 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 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 keyMap = new HashMap(2); 253. 254. keyMap.put(PUBLIC_KEY, publicKey); 255. keyMap.put(PRIVATE_KEY, privateKey); 256. return keyMap; 257. } 258. } 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import org.junit.Before; 4. import org.junit.Test; 5. 6. import java.util.Map; 7. 8. /** 9. * 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 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. } 控制台输出: Console代码 1. 公钥: 2. 3. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYU/+I0+z1aBl5X6DUUOHQ7FZpmBSDbKTtx89J 4. EcB64jFCkunELT8qiKly7fzEqD03g8ALlu5XvX+bBqHFy7YPJJP0ekE2X3wjUnh2NxlqpH3/B/xm 5. 1ZdSlCwDIkbijhBVDjA/bu5BObhZqQmDwIxlQInL9oVz+o6FbAZCyHBd7wIDAQAB 6. 7. 私钥: 8. 9. MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJhT/4jT7PVoGXlfoNRQ4dDsVmmY 10. FINspO3Hz0kRwHriMUKS6cQtPyqIqXLt/MSoPTeDwAuW7le9f5sGocXLtg8kk/R6QTZffCNSeHY3 11. GWqkff8H/GbVl1KULAMiRuKOEFUOMD9u7kE5uFmpCYPAjGVAicv2hXP6joVsBkLIcF3vAgMBAAEC 12. gYBvZHWoZHmS2EZQqKqeuGr58eobG9hcZzWQoJ4nq/CarBAjw/VovUHE490uK3S9ht4FW7Yzg3LV 13. /MB06Huifh6qf/X9NQA7SeZRRC8gnCQk6JuDIEVJOud5jU+9tyumJakDKodQ3Jf2zQtNr+5ZdEPl 14. uwWgv9c4kmpjhAdyMuQmYQJBANn6pcgvyYaia52dnu+yBUsGkaFfwXkzFSExIbi0MXTkhEb/ER/D 15. rLytukkUu5S5ecz/KBa8U4xIslZDYQbLz5ECQQCy5dutt7RsxN4+dxCWn0/1FrkWl2G329Ucewm3 16. QU9CKu4D+7Kqdj+Ha3lXP8F0Etaaapi7+EfkRUpukn2ItZV/AkEAlk+I0iphxT1rCB0Q5CjWDY5S 17. Df2B5JmdEG5Y2o0nLXwG2w44OLct/k2uD4cEcuITY5Dvi/4BftMCZwm/dnhEgQJACIktJSnJwxLV 18. o9dchENPtlsCM9C/Sd2EWpqISSUlmfugZbJBwR5pQ5XeMUqKeXZYpP+HEBj1nS+tMH9u2/IGEwJA 19. fL8mZiZXan/oBKrblAbplNcKWGRVD/3y65042PAEeghahlJMiYquV5DzZajuuT0wbJ5xQuZB01+X 20. nfpFpBJ2dw== 21. 22. 公钥加密——私钥解密 23. 加密前: abc 24. 25. 解密后: abc 26. 公钥: 27. 28. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdOj40yEB48XqWxmPILmJAc7UecIN7F32etSHF 29. 9rwbuEh3+iTPOGSxhoSQpOED0vOb0ZIMkBXZSgsxLaBSin2RZ09YKWRjtpCA0kDkiD11gj4tzTiM 30. l9qq1kwSK7ZkGAgodEn3yIILVmQDuEImHOXFtulvJ71ka07u3LuwUNdB/wIDAQAB 31. 32. 私钥: 33. 34. MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN06PjTIQHjxepbGY8guYkBztR5w 35. g3sXfZ61IcX2vBu4SHf6JM84ZLGGhJCk4QPS85vRkgyQFdlKCzEtoFKKfZFnT1gpZGO2kIDSQOSI 36. PXWCPi3NOIyX2qrWTBIrtmQYCCh0SffIggtWZAO4QiYc5cW26W8nvWRrTu7cu7BQ10H/AgMBAAEC 37. gYEAz2JWBizjI31bqhP4XiP9PuY5F3vqBW4T+L9cFbQiyumKJc58yzTWUAUGKIIn3enXLG7dNqGr 38. mbJro4JeFIJ3CiVDpXR9+FluIgI4SXm7ioGKF2NOMA9LR5Fu82W+pLfpTN2y2SaLYWEDZyp53BxY 39. j9gUxaxi1MQs+C1ZgDF2xmECQQDy70bQntbRfysP+ppCtd56YRnES1Tyekw0wryS2tr+ivQJl7JF 40. gp5rPAOXpgrq36xHDwUspQ0sJ0vj0O7ywxr1AkEA6SAaLhrJJrYucC0jxwAhUYyaPN+aOsWymaRh 41. 9jA/Wc0wp29SbGTh5CcMuGpXm1g0M+FKW3dGiHgS3rVUKim4owJAbnxgapUzAgiiHxxMeDaavnHW 42. 9C2GrtjsO7qtZOTgYI/1uT8itvZW8lJTF+9OW8/qXE76fXl7ai9dFnl5kzMk2QJBALfHz/vCsArt 43. mkRiwY6zApE4Z6tPl1V33ymSVovvUzHnOdD1SKQdD5t+UV/crb3QVi8ED0t2B0u0ZSPfDT/D7kMC 44. QDpwdj9k2F5aokLHBHUNJPFDAp7a5QMaT64gv/d48ITJ68Co+v5WzLMpzJBYXK6PAtqIhxbuPEc2 45. I2k1Afmrwyw= 46. 47. 私钥加密——公钥解密 48. 加密前: sign 49. 50. 解密后: sign 51. 私钥签名——公钥验证签名 52. 签名: 53. ud1RsIwmSC1pN22I4IXteg1VD2FbiehKUfNxgVSHzvQNIK+d20FCkHCqh9djP3h94iWnIUY0ifU+ 54. mbJkhAl/i5krExOE0hknOnPMcEP+lZV1RbJI2zG2YooSp2XDleqrQk5e/QF2Mx0Zxt8Xsg7ucVpn 55. i3wwbYWs9wSzIf0UjlM= 56. 57. 状态: 58. true 简要总结一下,使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互! 类似数字签名,数字信封是这样描述的: 数字信封   数字信封用加密技术来保证只有特定的收信人才能阅读信的内容。 流程: 信息发送方采用对称密钥来加密信息,然后再用接收方的公钥来加密此对称密钥(这部分称为数字信封),再将它和信息一起发送给接收方;接收方先用相应的私钥打开数字信封,得到对称密钥,然后使用对称密钥再解开信息。 Java加密技术(五) 文章分类:Java编程 接下来我们分析DH加密算法,一种适基于密钥一致协议的加密算法。 DH Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理。 流程分析: 1.甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。 2.甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。 3.乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。 1. 2. 3. 通过java代码实现如下:Coder类见 Java加密技术(一) Java代码 1. import java.security.Key; 2. import java.security.KeyFactory; 3. import java.security.KeyPair; 4. import java.security.KeyPairGenerator; 5. import java.security.PublicKey; 6. import java.security.spec.PKCS8EncodedKeySpec; 7. import java.security.spec.X509EncodedKeySpec; 8. import java.util.HashMap; 9. import java.util.Map; 10. 11. import javax.crypto.Cipher; 12. import javax.crypto.KeyAgreement; 13. import javax.crypto.SecretKey; 14. import javax.crypto.interfaces.DHPrivateKey; 15. import javax.crypto.interfaces.DHPublicKey; 16. import javax.crypto.spec.DHParameterSpec; 17. 18. /** 19. * DH安全编码组件 20. * 21. * @author 梁栋 22. * @version 1.0 23. * @since 1.0 24. */ 25. public abstract class DHCoder extends Coder { 26. public static final String ALGORITHM = "DH"; 27. 28. /** 29. * 默认密钥字节数 30. * 31. *
 
32.	     * DH 
33.	     * Default Keysize 1024   
34.	     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive). 
35.	     * 
36. */ 37. private static final int KEY_SIZE = 1024; 38. 39. /** 40. * DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。 41. */ 42. public static final String SECRET_ALGORITHM = "DES"; 43. private static final String PUBLIC_KEY = "DHPublicKey"; 44. private static final String PRIVATE_KEY = "DHPrivateKey"; 45. 46. /** 47. * 初始化甲方密钥 48. * 49. * @return 50. * @throws Exception 51. */ 52. public static Map initKey() throws Exception { 53. KeyPairGenerator keyPairGenerator = KeyPairGenerator 54. .getInstance(ALGORITHM); 55. keyPairGenerator.initialize(KEY_SIZE); 56. 57. KeyPair keyPair = keyPairGenerator.generateKeyPair(); 58. 59. // 甲方公钥 60. DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic(); 61. 62. // 甲方私钥 63. DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate(); 64. 65. Map keyMap = new HashMap(2); 66. 67. keyMap.put(PUBLIC_KEY, publicKey); 68. keyMap.put(PRIVATE_KEY, privateKey); 69. return keyMap; 70. } 71. 72. /** 73. * 初始化乙方密钥 74. * 75. * @param key 76. * 甲方公钥 77. * @return 78. * @throws Exception 79. */ 80. public static Map initKey(String key) throws Exception { 81. // 解析甲方公钥 82. byte[] keyBytes = decryptBASE64(key); 83. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 84. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); 85. PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); 86. 87. // 由甲方公钥构建乙方密钥 88. DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams(); 89. 90. KeyPairGenerator keyPairGenerator = KeyPairGenerator 91. .getInstance(keyFactory.getAlgorithm()); 92. keyPairGenerator.initialize(dhParamSpec); 93. 94. KeyPair keyPair = keyPairGenerator.generateKeyPair(); 95. 96. // 乙方公钥 97. DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic(); 98. 99. // 乙方私钥 100. DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate(); 101. 102. Map keyMap = new HashMap(2); 103. 104. keyMap.put(PUBLIC_KEY, publicKey); 105. keyMap.put(PRIVATE_KEY, privateKey); 106. 107. return keyMap; 108. } 109. 110. /** 111. * 加密
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. * 解密
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 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 keyMap) 217. throws Exception { 218. Key key = (Key) keyMap.get(PUBLIC_KEY); 219. 220. return encryptBASE64(key.getEncoded()); 221. } 222. } 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import java.util.Map; 4. 5. import org.junit.Test; 6. 7. /** 8. * 9. * @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 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 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. } 控制台输出: Console代码 1. 甲方公钥: 2. MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz 3. W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG 4. kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAdAWBVmIzqcko 5. Ej6qFjLDL2+Y3FPq1iRbnOyOpDj71yKaK1K+FhTv04B0zy4DKcvAASV7/Gv0W+bgqdmffRkqrQ== 6. 7. 甲方私钥: 8. MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX 9. rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD 10. TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjACJRfy1LyR 11. eHyD+4Hfb+xR0uoIGR1oL9i9Nk6g2AAuaDPgEVWHn+QXID13yL/uDos= 12. 13. 乙方公钥: 14. MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz 15. W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG 16. kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAVEYSfBA+I9nr 17. dWw3OBv475C+eBrWBBYqt0m6/eu4ptuDQHwV4MmUtKAC2wc2nNrdb1wmBhY1X8RnWkJ1XmdDbQ== 18. 19. 乙方私钥: 20. MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX 21. rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD 22. TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAqaZiCdXp 23. 2iNpdBlHRaO9ir70wo2n32xNlIzIX19VLSPCDdeUWkgRv4CEj/8k+/yd 24. 25. 原文: abc 26. 解密: abc 27. ===============反过来加密解密================== 28. 原文: def 29. 解密: def 如我所言,甲乙双方在获得对方公钥后可以对发送给对方的数据加密,同时也能对接收到的数据解密,达到了数据安全通信的目的! Java加密技术(六) 文章分类:Java编程 接下来我们介绍DSA数字签名,非对称加密的另一种实现。 DSA DSA-Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。简单的说,这是一种更高级的验证方式,用作数字签名。不单单只有公钥、私钥,还有数字签名。私钥加密生成数字签名,公钥验证数据及签名。如果数据和签名不匹配则认为验证失败!数字签名的作用就是校验数据在传输过程中不被修改。数字签名,是单向加密的升级! 1. 2. 通过java代码实现如下:Coder类见 Java加密技术(一) Java代码 1. import java.security.Key; 2. import java.security.KeyFactory; 3. import java.security.KeyPair; 4. import java.security.KeyPairGenerator; 5. import java.security.PrivateKey; 6. import java.security.PublicKey; 7. import java.security.SecureRandom; 8. import java.security.Signature; 9. import java.security.interfaces.DSAPrivateKey; 10. import java.security.interfaces.DSAPublicKey; 11. import java.security.spec.PKCS8EncodedKeySpec; 12. import java.security.spec.X509EncodedKeySpec; 13. import java.util.HashMap; 14. import java.util.Map; 15. 16. /** 17. * DSA安全编码组件 18. * 19. * @author 梁栋 20. * @version 1.0 21. * @since 1.0 22. */ 23. public abstract class DSACoder extends Coder { 24. 25. public static final String ALGORITHM = "DSA"; 26. 27. /** 28. * 默认密钥字节数 29. * 30. *
 
31.	     * DSA  
32.	     * Default Keysize 1024   
33.	     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive). 
34.	     * 
35. */ 36. private static final int KEY_SIZE = 1024; 37. 38. /** 39. * 默认种子 40. */ 41. private static final String DEFAULT_SEED = "0f22507a10bbddd07d8a3082122966e3"; 42. 43. private static final String PUBLIC_KEY = "DSAPublicKey"; 44. private static final String PRIVATE_KEY = "DSAPrivateKey"; 45. 46. /** 47. * 用私钥对信息生成数字签名 48. * 49. * @param data 50. * 加密数据 51. * @param privateKey 52. * 私钥 53. * 54. * @return 55. * @throws Exception 56. */ 57. public static String sign(byte[] data, String privateKey) throws Exception { 58. // 解密由base64编码的私钥 59. byte[] keyBytes = decryptBASE64(privateKey); 60. 61. // 构造PKCS8EncodedKeySpec对象 62. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 63. 64. // KEY_ALGORITHM 指定的加密算法 65. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); 66. 67. // 取私钥匙对象 68. PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); 69. 70. // 用私钥对信息生成数字签名 71. Signature signature = Signature.getInstance(keyFactory.getAlgorithm()); 72. signature.initSign(priKey); 73. signature.update(data); 74. 75. return encryptBASE64(signature.sign()); 76. } 77. 78. /** 79. * 校验数字签名 80. * 81. * @param data 82. * 加密数据 83. * @param publicKey 84. * 公钥 85. * @param sign 86. * 数字签名 87. * 88. * @return 校验成功返回true 失败返回false 89. * @throws Exception 90. * 91. */ 92. public static boolean verify(byte[] data, String publicKey, String sign) 93. throws Exception { 94. 95. // 解密由base64编码的公钥 96. byte[] keyBytes = decryptBASE64(publicKey); 97. 98. // 构造X509EncodedKeySpec对象 99. 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 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 map = new HashMap(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 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 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 keyMap) 174. throws Exception { 175. Key key = (Key) keyMap.get(PUBLIC_KEY); 176. 177. return encryptBASE64(key.getEncoded()); 178. } 179. } 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import java.util.Map; 4. 5. import org.junit.Test; 6. 7. /** 8. * 9. * @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 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. } 控制台输出: Console代码 1. 公钥: 2. MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZp 3. RV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fn 4. xqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuE 5. C/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJ 6. FnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo 7. g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAIu4RUlcQLp49PI0MrbssOY+3uySVnp0TULSv 8. 5T4VaHoKzsLHgGTrwOvsGA+V3yCNl2WDu3D84bSLF7liTWgOj+SMOEaPk4VyRTlLXZWGPsf1Mfd9 9. 21XAbMeVyKDSHHVGbMjBScajf3bXooYQMlyoHiOt/WrCo+mv7efstMM0PGo= 10. 11. 私钥: 12. MIIBTAIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2 13. USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4 14. O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC 15. ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCB 16. gLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR 17. kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFwIVAIegLUtmm2oQKQJTOiLugHTSjl/q 18. 19. 签名: 20. MC0CFQCMg0J/uZmF8GuRpr3TNq48w60nDwIUJCyYNah+HtbU6NcQfy8Ac6LeLQs= 21. 22. 状态: 23. true 注意状态为true,就验证成功! Java加密技术(七) 文章分类:Java编程 ECC ECC-Elliptic Curves Cryptography,椭圆曲线密码编码学,是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。在软件注册保护方面起到很大的作用,一般的序列号通常由该算法产生。 当我开始整理《Java加密技术(二)》的时候,我就已经在开始研究ECC了,但是关于Java实现ECC算法的资料实在是太少了,无论是国内还是国外的资料,无论是官方还是非官方的解释,最终只有一种答案——ECC算法在jdk1.5后加入支持,目前仅仅只能完成密钥的生成与解析。 如果想要获得ECC算法实现,需要调用硬件完成加密/解密(ECC算法相当耗费资源,如果单纯使用CPU进行加密/解密,效率低下),涉及到Java Card领域,PKCS#11。 其实,PKCS#11配置很简单,但缺乏硬件设备,无法尝试! 尽管如此,我照旧提供相应的Java实现代码,以供大家参考。 通过java代码实现如下:Coder类见 Java加密技术(一) Java代码 1. import java.math.BigInteger; 2. import java.security.Key; 3. import java.security.KeyFactory; 4. import java.security.interfaces.ECPrivateKey; 5. import java.security.interfaces.ECPublicKey; 6. import java.security.spec.ECFieldF2m; 7. import java.security.spec.ECParameterSpec; 8. import java.security.spec.ECPoint; 9. import java.security.spec.ECPrivateKeySpec; 10. import java.security.spec.ECPublicKeySpec; 11. import java.security.spec.EllipticCurve; 12. import java.security.spec.PKCS8EncodedKeySpec; 13. import java.security.spec.X509EncodedKeySpec; 14. import java.util.HashMap; 15. import java.util.Map; 16. 17. import javax.crypto.Cipher; 18. import javax.crypto.NullCipher; 19. 20. import sun.security.ec.ECKeyFactory; 21. import sun.security.ec.ECPrivateKeyImpl; 22. import sun.security.ec.ECPublicKeyImpl; 23. 24. /** 25. * ECC安全编码组件 26. * 27. * @author 梁栋 28. * @version 1.0 29. * @since 1.0 30. */ 31. public abstract class ECCCoder extends Coder { 32. 33. public static final String ALGORITHM = "EC"; 34. private static final String PUBLIC_KEY = "ECCPublicKey"; 35. private static final String PRIVATE_KEY = "ECCPrivateKey"; 36. 37. /** 38. * 解密
39. * 用私钥解密 40. * 41. * @param data 42. * @param key 43. * @return 44. * @throws Exception 45. */ 46. public static byte[] decrypt(byte[] data, String key) throws Exception { 47. // 对密钥解密 48. byte[] keyBytes = decryptBASE64(key); 49. 50. // 取得私钥 51. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 52. KeyFactory keyFactory = ECKeyFactory.INSTANCE; 53. 54. ECPrivateKey priKey = (ECPrivateKey) keyFactory 55. .generatePrivate(pkcs8KeySpec); 56. 57. ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(), 58. priKey.getParams()); 59. 60. // 对数据解密 61. // TODO Chipher不支持EC算法 未能实现 62. Cipher cipher = new NullCipher(); 63. // Cipher.getInstance(ALGORITHM, keyFactory.getProvider()); 64. cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams()); 65. 66. return cipher.doFinal(data); 67. } 68. 69. /** 70. * 加密
71. * 用公钥加密 72. * 73. * @param data 74. * @param privateKey 75. * @return 76. * @throws Exception 77. */ 78. public static byte[] encrypt(byte[] data, String privateKey) 79. throws Exception { 80. // 对公钥解密 81. byte[] keyBytes = decryptBASE64(privateKey); 82. 83. // 取得公钥 84. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 85. KeyFactory keyFactory = ECKeyFactory.INSTANCE; 86. 87. ECPublicKey pubKey = (ECPublicKey) keyFactory 88. .generatePublic(x509KeySpec); 89. 90. ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(), 91. pubKey.getParams()); 92. 93. // 对数据加密 94. // TODO Chipher不支持EC算法 未能实现 95. Cipher cipher = new NullCipher(); 96. // Cipher.getInstance(ALGORITHM, keyFactory.getProvider()); 97. cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams()); 98. 99. return cipher.doFinal(data); 100. } 101. 102. /** 103. * 取得私钥 104. * 105. * @param keyMap 106. * @return 107. * @throws Exception 108. */ 109. public static String getPrivateKey(Map 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 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 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 = { 7, 6, 3 }; 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 keyMap = new HashMap(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类,验证程序。 照旧提供一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import java.math.BigInteger; 4. import java.security.spec.ECFieldF2m; 5. import java.security.spec.ECParameterSpec; 6. import java.security.spec.ECPoint; 7. import java.security.spec.ECPrivateKeySpec; 8. import java.security.spec.ECPublicKeySpec; 9. 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 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. } 控制台输出: Console代码 1. 公钥: 2. MEAwEAYHKoZIzj0CAQYFK4EEAAEDLAAEAv4TwFN7vBGsqgfXk95ObV5clO7oAokHD7BdOP9YMh8u 3. gAU21TjM2qPZ 4. 5. 私钥: 6. MDICAQAwEAYHKoZIzj0CAQYFK4EEAAEEGzAZAgEBBBTYJsR3BN7TFw7JHcAHFkwNmfil7w== 7. 8. 加密前: abc 9. 10. 解密后: abc Java加密技术(八) 文章分类:Java编程 本篇的主要内容为Java证书体系的实现。 请大家在阅读本篇内容时先阅读 Java加密技术(四),预先了解RSA加密算法。 在构建Java代码实现前,我们需要完成证书的制作。 1.生成keyStroe文件 在命令行下执行以下命令: Shell代码 1. keytool -genkey -validity 36000 -alias www.zlex.org -keyalg RSA -keystore d:\zlex.keystore 其中 -genkey表示生成密钥 -validity指定证书有效期,这里是36000天 -alias指定别名,这里是www.zlex.org -keyalg指定算法,这里是RSA -keystore指定存储位置,这里是d:\zlex.keystore 在这里我使用的密码为 123456 控制台输出: Console代码 1. 输入keystore密码: 2. 再次输入新密码: 3. 您的名字与姓氏是什么? 4. [Unknown]: www.zlex.org 5. 您的组织单位名称是什么? 6. [Unknown]: zlex 7. 您的组织名称是什么? 8. [Unknown]: zlex 9. 您所在的城市或区域名称是什么? 10. [Unknown]: BJ 11. 您所在的州或省份名称是什么? 12. [Unknown]: BJ 13. 该单位的两字母国家代码是什么 14. [Unknown]: CN 15. CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗? 16. [否]: Y 17. 18. 输入的主密码 19. (如果和 keystore 密码相同,按回车): 20. 再次输入新密码: 这时,在D盘下会生成一个zlex.keystore的文件。 2.生成自签名证书 光有keyStore文件是不够的,还需要证书文件,证书才是直接提供给外界使用的公钥凭证。 导出证书: Shell代码 1. keytool -export -keystore d:\zlex.keystore -alias www.zlex.org -file d:\zlex.cer -rfc 其中 -export指定为导出操作 -keystore指定keystore文件 -alias指定导出keystore文件中的别名 -file指向导出路径 -rfc以文本格式输出,也就是以BASE64编码输出 这里的密码是 123456 控制台输出: Console代码 1. 输入keystore密码: 2. 保存在文件中的认证 当然,使用方是需要导入证书的! 可以通过自签名证书完成CAS单点登录系统的构建! Ok,准备工作完成,开始Java实现! 通过java代码实现如下:Coder类见 Java加密技术(一) Java代码 1. import java.io.FileInputStream; 2. import java.security.KeyStore; 3. import java.security.PrivateKey; 4. import java.security.PublicKey; 5. import java.security.Signature; 6. import java.security.cert.Certificate; 7. import java.security.cert.CertificateFactory; 8. import java.security.cert.X509Certificate; 9. import java.util.Date; 10. 11. import javax.crypto.Cipher; 12. 13. /** 14. * 证书组件 15. * 16. * @author 梁栋 17. * @version 1.0 18. * @since 1.0 19. */ 20. public abstract class CertificateCoder extends Coder { 21. 22. 23. /** 24. * Java密钥库(Java Key Store,JKS)KEY_STORE 25. */ 26. public static final String KEY_STORE = "JKS"; 27. 28. public static final String X509 = "X.509"; 29. 30. /** 31. * 由KeyStore获得私钥 32. * 33. * @param keyStorePath 34. * @param alias 35. * @param password 36. * @return 37. * @throws Exception 38. */ 39. private static PrivateKey getPrivateKey(String keyStorePath, String alias, 40. String password) throws Exception { 41. KeyStore ks = getKeyStore(keyStorePath, password); 42. PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray()); 43. return key; 44. } 45. 46. /** 47. * 由Certificate获得公钥 48. * 49. * @param certificatePath 50. * @return 51. * @throws Exception 52. */ 53. private static PublicKey getPublicKey(String certificatePath) 54. throws Exception { 55. Certificate certificate = getCertificate(certificatePath); 56. PublicKey key = certificate.getPublicKey(); 57. return key; 58. } 59. 60. /** 61. * 获得Certificate 62. * 63. * @param certificatePath 64. * @return 65. * @throws Exception 66. */ 67. private static Certificate getCertificate(String certificatePath) 68. throws Exception { 69. CertificateFactory certificateFactory = CertificateFactory 70. .getInstance(X509); 71. FileInputStream in = new FileInputStream(certificatePath); 72. 73. Certificate certificate = certificateFactory.generateCertificate(in); 74. in.close(); 75. 76. return certificate; 77. } 78. 79. /** 80. * 获得Certificate 81. * 82. * @param keyStorePath 83. * @param alias 84. * @param password 85. * @return 86. * @throws Exception 87. */ 88. private static Certificate getCertificate(String keyStorePath, 89. String alias, String password) throws Exception { 90. KeyStore ks = getKeyStore(keyStorePath, password); 91. Certificate certificate = ks.getCertificate(alias); 92. 93. return certificate; 94. } 95. 96. /** 97. * 获得KeyStore 98. * 99. * @param keyStorePath 100. * @param password 101. * @return 102. * @throws Exception 103. */ 104. private static KeyStore getKeyStore(String keyStorePath, String password) 105. throws Exception { 106. FileInputStream is = new FileInputStream(keyStorePath); 107. KeyStore ks = KeyStore.getInstance(KEY_STORE); 108. ks.load(is, password.toCharArray()); 109. is.close(); 110. return ks; 111. } 112. 113. /** 114. * 私钥加密 115. * 116. * @param data 117. * @param keyStorePath 118. * @param alias 119. * @param password 120. * @return 121. * @throws Exception 122. */ 123. public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, 124. String alias, String password) throws Exception { 125. // 取得私钥 126. PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); 127. 128. // 对数据加密 129. Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); 130. cipher.init(Cipher.ENCRYPT_MODE, privateKey); 131. 132. return cipher.doFinal(data); 133. 134. } 135. 136. /** 137. * 私钥解密 138. * 139. * @param data 140. * @param keyStorePath 141. * @param alias 142. * @param password 143. * @return 144. * @throws Exception 145. */ 146. public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath, 147. String alias, String password) throws Exception { 148. // 取得私钥 149. PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); 150. 151. // 对数据加密 152. Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); 153. cipher.init(Cipher.DECRYPT_MODE, privateKey); 154. 155. return cipher.doFinal(data); 156. 157. } 158. 159. /** 160. * 公钥加密 161. * 162. * @param data 163. * @param certificatePath 164. * @return 165. * @throws Exception 166. */ 167. public static byte[] encryptByPublicKey(byte[] data, String certificatePath) 168. throws Exception { 169. 170. // 取得公钥 171. PublicKey publicKey = getPublicKey(certificatePath); 172. // 对数据加密 173. Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); 174. cipher.init(Cipher.ENCRYPT_MODE, publicKey); 175. 176. return cipher.doFinal(data); 177. 178. } 179. 180. /** 181. * 公钥解密 182. * 183. * @param data 184. * @param certificatePath 185. * @return 186. * @throws Exception 187. */ 188. public static byte[] decryptByPublicKey(byte[] data, String certificatePath) 189. throws Exception { 190. // 取得公钥 191. PublicKey publicKey = getPublicKey(certificatePath); 192. 193. // 对数据加密 194. Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); 195. cipher.init(Cipher.DECRYPT_MODE, publicKey); 196. 197. return cipher.doFinal(data); 198. 199. } 200. 201. /** 202. * 验证Certificate 203. * 204. * @param certificatePath 205. * @return 206. */ 207. public static boolean verifyCertificate(String certificatePath) { 208. return verifyCertificate(new Date(), certificatePath); 209. } 210. 211. /** 212. * 验证Certificate是否过期或无效 213. * 214. * @param date 215. * @param certificatePath 216. * @return 217. */ 218. public static boolean verifyCertificate(Date date, String certificatePath) { 219. boolean status = true; 220. try { 221. // 取得证书 222. Certificate certificate = getCertificate(certificatePath); 223. // 验证证书是否过期或无效 224. status = verifyCertificate(date, certificate); 225. } catch (Exception e) { 226. status = false; 227. } 228. return status; 229. } 230. 231. /** 232. * 验证证书是否过期或无效 233. * 234. * @param date 235. * @param certificate 236. * @return 237. */ 238. private static boolean verifyCertificate(Date date, Certificate certificate) { 239. boolean status = true; 240. try { 241. X509Certificate x509Certificate = (X509Certificate) certificate; 242. x509Certificate.checkValidity(date); 243. } catch (Exception e) { 244. status = false; 245. } 246. return status; 247. } 248. 249. /** 250. * 签名 251. * 252. * @param keyStorePath 253. * @param alias 254. * @param password 255. * 256. * @return 257. * @throws Exception 258. */ 259. public static String sign(byte[] sign, String keyStorePath, String alias, 260. String password) throws Exception { 261. // 获得证书 262. X509Certificate x509Certificate = (X509Certificate) getCertificate( 263. keyStorePath, alias, password); 264. // 获取私钥 265. KeyStore ks = getKeyStore(keyStorePath, password); 266. // 取得私钥 267. PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password 268. .toCharArray()); 269. 270. // 构建签名 271. Signature signature = Signature.getInstance(x509Certificate 272. .getSigAlgName()); 273. signature.initSign(privateKey); 274. signature.update(sign); 275. return encryptBASE64(signature.sign()); 276. } 277. 278. /** 279. * 验证签名 280. * 281. * @param data 282. * @param sign 283. * @param certificatePath 284. * @return 285. * @throws Exception 286. */ 287. public static boolean verify(byte[] data, String sign, 288. String certificatePath) throws Exception { 289. // 获得证书 290. X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); 291. // 获得公钥 292. PublicKey publicKey = x509Certificate.getPublicKey(); 293. // 构建签名 294. Signature signature = Signature.getInstance(x509Certificate 295. .getSigAlgName()); 296. signature.initVerify(publicKey); 297. signature.update(data); 298. 299. return signature.verify(decryptBASE64(sign)); 300. 301. } 302. 303. /** 304. * 验证Certificate 305. * 306. * @param keyStorePath 307. * @param alias 308. * @param password 309. * @return 310. */ 311. public static boolean verifyCertificate(Date date, String keyStorePath, 312. String alias, String password) { 313. boolean status = true; 314. try { 315. Certificate certificate = getCertificate(keyStorePath, alias, 316. password); 317. status = verifyCertificate(date, certificate); 318. } catch (Exception e) { 319. status = false; 320. } 321. return status; 322. } 323. 324. /** 325. * 验证Certificate 326. * 327. * @param keyStorePath 328. * @param alias 329. * @param password 330. * @return 331. */ 332. public static boolean verifyCertificate(String keyStorePath, String alias, 333. String password) { 334. return verifyCertificate(new Date(), keyStorePath, alias, password); 335. } 336. } 再给出一个测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import org.junit.Test; 4. 5. /** 6. * 7. * @author 梁栋 8. * @version 1.0 9. * @since 1.0 10. */ 11. public class CertificateCoderTest { 12. private String password = "123456"; 13. private String alias = "www.zlex.org"; 14. private String certificatePath = "d:/zlex.cer"; 15. private String keyStorePath = "d:/zlex.keystore"; 16. 17. @Test 18. public void test() throws Exception { 19. System.err.println("公钥加密——私钥解密"); 20. String inputStr = "Ceritifcate"; 21. byte[] data = inputStr.getBytes(); 22. 23. byte[] encrypt = CertificateCoder.encryptByPublicKey(data, 24. certificatePath); 25. 26. byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt, 27. keyStorePath, alias, password); 28. String outputStr = new String(decrypt); 29. 30. System.err.println("加密前: " + inputStr + "\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. } 控制台输出: Console代码 1. 公钥加密——私钥解密 2. 加密前: Ceritificate 3. 4. 解密后: Ceritificate 5. 6. 私钥加密——公钥解密 7. 加密前: sign 8. 9. 解密后: sign 10. 私钥签名——公钥验证签名 11. 签名: 12. pqBn5m6PJlfOjH0A6U2o2mUmBsfgyEY1NWCbiyA/I5Gc3gaVNVIdj/zkGNZRqTjhf3+J9a9z9EI7 13. 6F2eWYd7punHx5oh6hfNgcKbVb52EfItl4QEN+djbXiPynn07+Lbg1NOjULnpEd6ZhLP1YwrEAuM 14. OfvX0e7/wplxLbySaKQ= 15. 16. 状态: 17. true 由此完成了证书验证体系! 同样,我们可以对代码做签名——代码签名! 通过工具JarSigner可以完成代码签名。 这里我们对tools.jar做代码签名,命令如下: Shell代码 1. jarsigner -storetype jks -keystore zlex.keystore -verbose tools.jar www.zlex.org 控制台输出: Console代码 1. 输入密钥库的口令短语: 2. 正在更新: META-INF/WWW_ZLEX.SF 3. 正在更新: META-INF/WWW_ZLEX.RSA 4. 正在签名: org/zlex/security/Security.class 5. 正在签名: org/zlex/tool/Main$1.class 6. 正在签名: org/zlex/tool/Main$2.class 7. 正在签名: org/zlex/tool/Main.class 8. 9. 警告: 10. 签名者证书将在六个月内过期。 此时,我们可以对签名后的jar做验证! 验证tools.jar,命令如下: Shell代码 1. jarsigner -verify -verbose -certs tools.jar 控制台输出: Console代码 1. 402 Sat Jun 20 16:25:14 CST 2009 META-INF/MANIFEST.MF 2. 532 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.SF 3. 889 Sat Jun 20 16:25:14 CST 2009 META-INF/WWW_ZLEX.RSA 4. sm 590 Wed Dec 10 13:03:42 CST 2008 org/zlex/security/Security.class 5. 6. X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 7. [证书将在 09-9-18 下午3:27 到期] 8. 9. sm 705 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$1.class 10. 11. X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 12. [证书将在 09-9-18 下午3:27 到期] 13. 14. sm 779 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main$2.class 15. 16. X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 17. [证书将在 09-9-18 下午3:27 到期] 18. 19. sm 12672 Tue Dec 16 18:00:56 CST 2008 org/zlex/tool/Main.class 20. 21. X.509, CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 22. [证书将在 09-9-18 下午3:27 到期] 23. 24. 25. s = 已验证签名 26. m = 在清单中列出条目 27. k = 在密钥库中至少找到了一个证书 28. i = 在身份作用域内至少找到了一个证书 29. 30. jar 已验证。 31. 32. 警告: 33. 此 jar 包含签名者证书将在六个月内过期的条目。 代码签名认证的用途主要是对发布的软件做验证,支持 Sun Java .jar (Java Applet) 文件(J2SE)和 J2ME MIDlet Suite 文件。 Java加密技术(九) 文章分类:Java编程 在Java加密技术(八)中,我们模拟了一个基于RSA非对称加密网络的安全通信。现在我们深度了解一下现有的安全网络通信——SSL。 我们需要构建一个由CA机构签发的有效证书,这里我们使用上文中生成的自签名证书zlex.cer 这里,我们将证书导入到我们的密钥库。 Shell代码 1. 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 控制台输出: Console代码 1. 输入keystore密码: 2. 再次输入新密码: 3. 所有者:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 4. 签发人:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 5. 序列号:4a1e48df 6. 有效期: Thu May 28 16:18:39 CST 2009 至Wed Aug 26 16:18:39 CST 2009 7. 证书指纹: 8. MD5:19:CA:E6:36:E2:DF:AD:96:31:97:2F:A9:AD:FC:37:6A 9. SHA1:49:88:30:59:29:45:F1:69:CA:97:A9:6D:8A:CF:08:D2:C3:D5:C0:C4 10. 签名算法名称:SHA1withRSA 11. 版本: 3 12. 信任这个认证? [否]: y 13. 认证已添加至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。将如下内容加入配置文件 Xml代码 1. 注意clientAuth="false"测试阶段,置为false,正式使用时建议使用true。现在启动tomcat,访问https://www.zlex.org/。 显然,证书未能通过认证,这个时候你可以选择安装证书(上文中的zlex.cer文件就是证书),作为受信任的根证书颁发机构导入,再次重启浏览器(IE,其他浏览器对于域名www.zlex.org不支持本地方式访问),访问https://www.zlex.org/,你会看到地址栏中会有个小锁 ,就说明安装成功。所有的浏览器联网操作已经在RSA加密解密系统的保护之下了。但似乎我们感受不到。 这个时候很多人开始怀疑,如果我们要手工做一个这样的https的访问是不是需要把浏览器的这些个功能都实现呢?不需要! 接着上篇内容,给出如下代码实现: Java代码 1. import java.io.FileInputStream; 2. import java.security.KeyStore; 3. import java.security.PrivateKey; 4. import java.security.PublicKey; 5. import java.security.Signature; 6. import java.security.cert.Certificate; 7. import java.security.cert.CertificateFactory; 8. import java.security.cert.X509Certificate; 9. import java.util.Date; 10. 11. import javax.crypto.Cipher; 12. import javax.net.ssl.HttpsURLConnection; 13. import javax.net.ssl.KeyManagerFactory; 14. import javax.net.ssl.SSLContext; 15. import javax.net.ssl.SSLSocketFactory; 16. import javax.net.ssl.TrustManagerFactory; 17. 18. /** 19. * 证书组件 20. * 21. * @author 梁栋 22. * @version 1.0 23. * @since 1.0 24. */ 25. public abstract class CertificateCoder extends Coder { 26. 27. /** 28. * Java密钥库(Java Key Store,JKS)KEY_STORE 29. */ 30. public static final String KEY_STORE = "JKS"; 31. 32. public static final String X509 = "X.509"; 33. public static final String SunX509 = "SunX509"; 34. public static final String SSL = "SSL"; 35. 36. /** 37. * 由KeyStore获得私钥 38. * 39. * @param keyStorePath 40. * @param alias 41. * @param password 42. * @return 43. * @throws Exception 44. */ 45. private static PrivateKey getPrivateKey(String keyStorePath, String alias, 46. String password) throws Exception { 47. KeyStore ks = getKeyStore(keyStorePath, password); 48. PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray()); 49. return key; 50. } 51. 52. /** 53. * 由Certificate获得公钥 54. * 55. * @param certificatePath 56. * @return 57. * @throws Exception 58. */ 59. private static PublicKey getPublicKey(String certificatePath) 60. throws Exception { 61. Certificate certificate = getCertificate(certificatePath); 62. PublicKey key = certificate.getPublicKey(); 63. return key; 64. } 65. 66. /** 67. * 获得Certificate 68. * 69. * @param certificatePath 70. * @return 71. * @throws Exception 72. */ 73. private static Certificate getCertificate(String certificatePath) 74. throws Exception { 75. CertificateFactory certificateFactory = CertificateFactory 76. .getInstance(X509); 77. FileInputStream in = new FileInputStream(certificatePath); 78. 79. Certificate certificate = certificateFactory.generateCertificate(in); 80. in.close(); 81. 82. return certificate; 83. } 84. 85. /** 86. * 获得Certificate 87. * 88. * @param keyStorePath 89. * @param alias 90. * @param password 91. * @return 92. * @throws Exception 93. */ 94. private static Certificate getCertificate(String keyStorePath, 95. String alias, String password) throws Exception { 96. KeyStore ks = getKeyStore(keyStorePath, password); 97. Certificate certificate = ks.getCertificate(alias); 98. 99. 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。 给出相应测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import java.io.DataInputStream; 4. import java.io.InputStream; 5. import java.net.URL; 6. 7. import javax.net.ssl.HttpsURLConnection; 8. 9. import org.junit.Test; 10. 11. /** 12. * 13. * @author 梁栋 14. * @version 1.0 15. * @since 1.0 16. */ 17. public class CertificateCoderTest { 18. private String password = "123456"; 19. private String alias = "www.zlex.org"; 20. private String certificatePath = "d:/zlex.cer"; 21. private String keyStorePath = "d:/zlex.keystore"; 22. private String clientKeyStorePath = "d:/zlex-client.keystore"; 23. private String clientPassword = "654321"; 24. 25. @Test 26. public void test() throws Exception { 27. System.err.println("公钥加密——私钥解密"); 28. String inputStr = "Ceritifcate"; 29. byte[] data = inputStr.getBytes(); 30. 31. byte[] encrypt = CertificateCoder.encryptByPublicKey(data, 32. certificatePath); 33. 34. byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt, 35. keyStorePath, alias, password); 36. String outputStr = new String(decrypt); 37. 38. System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr); 39. 40. // 验证数据一致 41. assertArrayEquals(data, decrypt); 42. 43. // 验证证书有效 44. assertTrue(CertificateCoder.verifyCertificate(certificatePath)); 45. 46. } 47. 48. @Test 49. public void testSign() throws Exception { 50. System.err.println("私钥加密——公钥解密"); 51. 52. String inputStr = "sign"; 53. byte[] data = inputStr.getBytes(); 54. 55. byte[] encodedData = CertificateCoder.encryptByPrivateKey(data, 56. keyStorePath, alias, password); 57. 58. byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData, 59. certificatePath); 60. 61. String outputStr = new String(decodedData); 62. System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr); 63. assertEquals(inputStr, outputStr); 64. 65. System.err.println("私钥签名——公钥验证签名"); 66. // 产生签名 67. String sign = CertificateCoder.sign(encodedData, keyStorePath, alias, 68. password); 69. System.err.println("签名:\r" + sign); 70. 71. // 验证签名 72. boolean status = CertificateCoder.verify(encodedData, sign, 73. certificatePath); 74. System.err.println("状态:\r" + status); 75. assertTrue(status); 76. 77. } 78. 79. @Test 80. public void testHttps() throws Exception { 81. URL url = new URL("https://www.zlex.org/examples/"); 82. HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 83. 84. conn.setDoInput(true); 85. conn.setDoOutput(true); 86. 87. CertificateCoder.configSSLSocketFactory(conn, clientPassword, 88. clientKeyStorePath, clientKeyStorePath); 89. 90. InputStream is = conn.getInputStream(); 91. 92. int length = conn.getContentLength(); 93. 94. DataInputStream dis = new DataInputStream(is); 95. byte[] data = new byte[length]; 96. dis.readFully(data); 97. 98. dis.close(); 99. System.err.println(new String(data)); 100. conn.disconnect(); 101. } 102. } 注意testHttps方法,几乎和我们往常做HTTP访问没有差别,我们来看控制台输出: Console代码 1. 17. 18. Apache Tomcat Examples 19. 20. 21. 22.

23.

Apache Tomcat Examples

24.

25. 29. 通过浏览器直接访问https://www.zlex.org/examples/你也会获得上述内容。也就是说应用甲方作为服务器构建tomcat服务,乙方可以通过上述方式访问甲方受保护的SSL应用,并且不需要考虑具体的加密解密问题。甲乙双方可以经过相应配置,通过双方的tomcat配置有效的SSL服务,简化上述代码实现,完全通过证书配置完成SSL双向认证! Java加密技术(十) 文章分类:Java编程 在Java 加密技术(九)中,我们使用自签名证书完成了认证。接下来,我们使用第三方CA签名机构完成证书签名。 这里我们使用thawte提供的测试用21天免费ca证书。 1.要在该网站上注明你的域名,这里使用www.zlex.org作为测试用域名(请勿使用该域名作为你的域名地址,该域名受法律保护!请使用其他非注册域名!)。 2.如果域名有效,你会收到邮件要求你访问https://www.thawte.com/cgi/server/try.exe获得ca证书。 3.复述密钥库的创建。 Shell代码 1. keytool -genkey -validity 36000 -alias www.zlex.org -keyalg RSA -keystore d:\zlex.keystore 在这里我使用的密码为 123456 控制台输出: Console代码 1. 输入keystore密码: 2. 再次输入新密码: 3. 您的名字与姓氏是什么? 4. [Unknown]: www.zlex.org 5. 您的组织单位名称是什么? 6. [Unknown]: zlex 7. 您的组织名称是什么? 8. [Unknown]: zlex 9. 您所在的城市或区域名称是什么? 10. [Unknown]: BJ 11. 您所在的州或省份名称是什么? 12. [Unknown]: BJ 13. 该单位的两字母国家代码是什么 14. [Unknown]: CN 15. CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗? 16. [否]: Y 17. 18. 输入的主密码 19. (如果和 keystore 密码相同,按回车): 20. 再次输入新密码: 4.通过如下命令,从zlex.keystore中导出CA证书申请。 Shell代码 1. keytool -certreq -alias www.zlex.org -file d:\zlex.csr -keystore d:\zlex.keystore -v 你会获得zlex.csr文件,可以用记事本打开,内容如下格式: Text代码 1. -----BEGIN NEW CERTIFICATE REQUEST----- 2. MIIBnDCCAQUCAQAwXDELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAkJKMQswCQYDVQQHEwJCSjENMAsG 3. A1UEChMEemxleDENMAsGA1UECxMEemxleDEVMBMGA1UEAxMMd3d3LnpsZXgub3JnMIGfMA0GCSqG 4. SIb3DQEBAQUAA4GNADCBiQKBgQCR6DXU9Mp+mCKO7cv9JPsj0n1Ec/GpM09qvhpgX3FNad/ZWSDc 5. vU77YXZSoF9hQp3w1LC+eeKgd2MlVpXTvbVwBNVd2HiQPp37ic6BUUjSaX8LHtCl7l0BIEye9qQ2 6. j8G0kak7e8ZA0s7nb3Ymq/K8BV7v0MQIdhIc1bifK9ZDewIDAQABoAAwDQYJKoZIhvcNAQEFBQAD 7. gYEAMA1r2fbZPtNx37U9TRwadCH2TZZecwKJS/hskNm6ryPKIAp9APWwAyj8WJHRBz5SpZM4zmYO 8. oMCI8BcnY2A4JP+R7/SwXTdH/xcg7NVghd9A2SCgqMpF7KMfc5dE3iygdiPu+UhY200Dvpjx8gmJ 9. 1UbH3+nqMUyCrZgURFslOUY= 10. -----END NEW CERTIFICATE REQUEST----- 5.将上述文件内容拷贝到https://www.thawte.com/cgi/server/try.exe中,点击next,获得回应内容,这里是p7b格式。 内容如下: Text代码 1. -----BEGIN PKCS7----- 2. MIIF3AYJKoZIhvcNAQcCoIIFzTCCBckCAQExADALBgkqhkiG9w0BBwGgggWxMIID 3. EDCCAnmgAwIBAgIQA/mx/pKoaB+KGX2hveFU9zANBgkqhkiG9w0BAQUFADCBhzEL 4. MAkGA1UEBhMCWkExIjAgBgNVBAgTGUZPUiBURVNUSU5HIFBVUlBPU0VTIE9OTFkx 5. HTAbBgNVBAoTFFRoYXd0ZSBDZXJ0aWZpY2F0aW9uMRcwFQYDVQQLEw5URVNUIFRF 6. U1QgVEVTVDEcMBoGA1UEAxMTVGhhd3RlIFRlc3QgQ0EgUm9vdDAeFw0wOTA1Mjgw 7. MDIxMzlaFw0wOTA2MTgwMDIxMzlaMFwxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJC 8. SjELMAkGA1UEBxMCQkoxDTALBgNVBAoTBHpsZXgxDTALBgNVBAsTBHpsZXgxFTAT 9. BgNVBAMTDHd3dy56bGV4Lm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA 10. keg11PTKfpgiju3L/ST7I9J9RHPxqTNPar4aYF9xTWnf2Vkg3L1O+2F2UqBfYUKd 11. 8NSwvnnioHdjJVaV0721cATVXdh4kD6d+4nOgVFI0ml/Cx7Qpe5dASBMnvakNo/B 12. tJGpO3vGQNLO5292JqvyvAVe79DECHYSHNW4nyvWQ3sCAwEAAaOBpjCBozAMBgNV 13. HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBABgNVHR8E 14. OTA3MDWgM6Axhi9odHRwOi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNl 15. cnZlckNBLmNybDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9v 16. Y3NwLnRoYXd0ZS5jb20wDQYJKoZIhvcNAQEFBQADgYEATPuxZbtJJSPmXvfrr1yz 17. xqM06IwTZ6UU0lZRG7I0WufMjNMKdpn8hklUhE17mxAhGSpewLVVeLR7uzBLFkuC 18. X7wMXxhoYdJZtNai72izU6Rd1oknao7diahvRxPK4IuQ7y2oZ511/4T4vgY6iRAj 19. q4q76HhPJrVRL/sduaiu+gYwggKZMIICAqADAgECAgEAMA0GCSqGSIb3DQEBBAUA 20. MIGHMQswCQYDVQQGEwJaQTEiMCAGA1UECBMZRk9SIFRFU1RJTkcgUFVSUE9TRVMg 21. T05MWTEdMBsGA1UEChMUVGhhd3RlIENlcnRpZmljYXRpb24xFzAVBgNVBAsTDlRF 22. U1QgVEVTVCBURVNUMRwwGgYDVQQDExNUaGF3dGUgVGVzdCBDQSBSb290MB4XDTk2 23. MDgwMTAwMDAwMFoXDTIwMTIzMTIxNTk1OVowgYcxCzAJBgNVBAYTAlpBMSIwIAYD 24. VQQIExlGT1IgVEVTVElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQKExRUaGF3dGUg 25. Q2VydGlmaWNhdGlvbjEXMBUGA1UECxMOVEVTVCBURVNUIFRFU1QxHDAaBgNVBAMT 26. E1RoYXd0ZSBUZXN0IENBIFJvb3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB 27. ALV9kG+Os6x/DOhm+tKUQfzVMWGhE95sFmEtkMMTX2Zi4n6i6BvzoReJ5njzt1LF 28. cqu4EUk9Ji20egKKfmqRzmQFLP7+1niSdfJEUE7cKY40QoI99270PTrLjJeaMcCl 29. +AYl+kD+RL5BtuKKU3PurYcsCsre6aTvjMcqpTJOGeSPAgMBAAGjEzARMA8GA1Ud 30. EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAgozj7BkD9O8si2V0v+EZ/t7E 31. fz/LC8y6mD7IBUziHy5/53ymGAGLtyhXHvX+UIE6UWbHro3IqVkrmY5uC93Z2Wew 32. A/6edK3KFUcUikrLeewM7gmqsiASEKx2mKRKlu12jXyNS5tXrPWRDvUKtFC1uL9a 33. 12rFAQS2BkIk7aU+ghYxAA== 34. -----END PKCS7----- 将其存储为zlex.p7b 6.将由CA签发的证书导入密钥库。 Shell代码 1. keytool -import -trustcacerts -alias www.zlex.org -file d:\zlex.p7b -keystore d:\zlex.keystore -v 在这里我使用的密码为 123456 控制台输出: Console代码 1. 输入keystore密码: 2. 3. 回复中的最高级认证: 4. 5. 所有者:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FOR 6. TESTING PURPOSES ONLY, C=ZA 7. 签发人:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FOR 8. TESTING PURPOSES ONLY, C=ZA 9. 序列号:0 10. 有效期: Thu Aug 01 08:00:00 CST 1996 至Fri Jan 01 05:59:59 CST 2021 11. 证书指纹: 12. MD5:5E:E0:0E:1D:17:B7:CA:A5:7D:36:D6:02:DF:4D:26:A4 13. SHA1:39:C6:9D:27:AF:DC:EB:47:D6:33:36:6A:B2:05:F1:47:A9:B4:DA:EA 14. 签名算法名称:MD5withRSA 15. 版本: 3 16. 17. 扩展: 18. 19. #1: ObjectId: 2.5.29.19 Criticality=true 20. BasicConstraints:[ 21. CA:true 22. PathLen:2147483647 23. ] 24. 25. 26. ... 是不可信的。 还是要安装回复? [否]: Y 27. 认证回复已安装在 keystore中 28. [正在存储 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 Xml代码 1. 将文件zlex.keystore拷贝到tomcat的conf目录下,重新启动tomcat。访问https://www.zlex.org/,我们发现联网有些迟钝。大约5秒钟后,网页正常显示,同时有如下图所示: 浏览器验证了该CA机构的有效性。 打开证书,如下图所示: 调整测试类: Java代码 1. import static org.junit.Assert.*; 2. 3. import java.io.DataInputStream; 4. import java.io.InputStream; 5. import java.net.URL; 6. 7. import javax.net.ssl.HttpsURLConnection; 8. 9. import org.junit.Test; 10. 11. /** 12. * 13. * @author 梁栋 14. * @version 1.0 15. * @since 1.0 16. */ 17. public class CertificateCoderTest { 18. private String password = "123456"; 19. private String alias = "www.zlex.org"; 20. private String certificatePath = "d:/zlex.cer"; 21. private String keyStorePath = "d:/zlex.keystore"; 22. 23. @Test 24. public void test() throws Exception { 25. System.err.println("公钥加密——私钥解密"); 26. String inputStr = "Ceritifcate"; 27. byte[] data = inputStr.getBytes(); 28. 29. byte[] encrypt = CertificateCoder.encryptByPublicKey(data, 30. certificatePath); 31. 32. byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt, 33. keyStorePath, alias, password); 34. String outputStr = new String(decrypt); 35. 36. System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr); 37. 38. // 验证数据一致 39. assertArrayEquals(data, decrypt); 40. 41. // 验证证书有效 42. assertTrue(CertificateCoder.verifyCertificate(certificatePath)); 43. 44. } 45. 46. @Test 47. public void testSign() throws Exception { 48. System.err.println("私钥加密——公钥解密"); 49. 50. String inputStr = "sign"; 51. byte[] data = inputStr.getBytes(); 52. 53. byte[] encodedData = CertificateCoder.encryptByPrivateKey(data, 54. keyStorePath, alias, password); 55. 56. byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData, 57. certificatePath); 58. 59. String outputStr = new String(decodedData); 60. System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr); 61. assertEquals(inputStr, outputStr); 62. 63. System.err.println("私钥签名——公钥验证签名"); 64. // 产生签名 65. String sign = CertificateCoder.sign(encodedData, keyStorePath, alias, 66. password); 67. System.err.println("签名:\r" + sign); 68. 69. // 验证签名 70. boolean status = CertificateCoder.verify(encodedData, sign, 71. certificatePath); 72. System.err.println("状态:\r" + status); 73. assertTrue(status); 74. 75. } 76. 77. @Test 78. public void testHttps() throws Exception { 79. URL url = new URL("https://www.zlex.org/examples/"); 80. HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 81. 82. conn.setDoInput(true); 83. conn.setDoOutput(true); 84. 85. CertificateCoder.configSSLSocketFactory(conn, password, keyStorePath, 86. keyStorePath); 87. 88. InputStream is = conn.getInputStream(); 89. 90. int length = conn.getContentLength(); 91. 92. DataInputStream dis = new DataInputStream(is); 93. byte[] data = new byte[length]; 94. dis.readFully(data); 95. 96. dis.close(); 97. conn.disconnect(); 98. System.err.println(new String(data)); 99. } 100. } 再次执行,验证通过! 由此,我们了基于SSL协议的认证过程。测试类的testHttps方法模拟了一次浏览器的HTTPS访问。

你可能感兴趣的:(java加密)