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

流程分析:

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

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

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

import java.security.Key;

import java.security.KeyFactory;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.Signature;

import java.security.interfaces.RSAPrivateKey;

import java.security.interfaces.RSAPublicKey;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

import javax.crypto.Cipher;

/**

 * RSA安全编码组件

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public abstract class RSACoder extends Coder {

    public static final String KEY_ALGORITHM = "RSA";

    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    private static final String PUBLIC_KEY = "RSAPublicKey";

    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**

     * 用私钥对信息生成数字签名

     

     * @param data

     *            加密数据

     * @param privateKey

     *            私钥

     

     * @return

     * @throws Exception

     */

    public static String sign(byte[] data, String privateKey) throws Exception {

        // 解密由base64编码的私钥

        byte[] keyBytes = decryptBASE64(privateKey);

        // 构造PKCS8EncodedKeySpec对象

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取私钥匙对象

        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 用私钥对信息生成数字签名

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

        signature.initSign(priKey);

        signature.update(data);

        return encryptBASE64(signature.sign());

    }

    /**

     * 校验数字签名

     

     * @param data

     *            加密数据

     * @param publicKey

     *            公钥

     * @param sign

     *            数字签名

     

     * @return 校验成功返回true 失败返回false

     * @throws Exception

     

     */

    public static boolean verify(byte[] data, String publicKey, String sign)

            throws Exception {

        // 解密由base64编码的公钥

        byte[] keyBytes = decryptBASE64(publicKey);

        // 构造X509EncodedKeySpec对象

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取公钥匙对象

        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

        signature.initVerify(pubKey);

        signature.update(data);

        // 验证签名是否正常

        return signature.verify(decryptBASE64(sign));

    }

    /**

     * 解密<br>

     * 用私钥解密

     

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPrivateKey(byte[] data, String key)

            throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据解密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 解密<br>

     * 用私钥解密

     

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPublicKey(byte[] data, String key)

            throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据解密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 加密<br>

     * 用公钥加密

     

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPublicKey(byte[] data, String key)

            throws Exception {

        // 对公钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 加密<br>

     * 用私钥加密

     

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPrivateKey(byte[] data, String key)

            throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 取得私钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPrivateKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 取得公钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPublicKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 初始化密钥

     

     * @return

     * @throws Exception

     */

    public static Map<String, Object> initKey() throws Exception {

        KeyPairGenerator keyPairGen = KeyPairGenerator

                .getInstance(KEY_ALGORITHM);

        keyPairGen.initialize(1024);

        KeyPair keyPair = keyPairGen.generateKeyPair();

        // 公钥

        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

        // 私钥

        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);

        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;

    }

}

再给出一个测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

import static org.junit.Assert.*;

import org.junit.Before;

import org.junit.Test;

import java.util.Map;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class RSACoderTest {

    private String publicKey;

    private String privateKey;

    @Before

    public void setUp() throws Exception {

        Map<String, Object> keyMap = RSACoder.initKey();

        publicKey = RSACoder.getPublicKey(keyMap);

        privateKey = RSACoder.getPrivateKey(keyMap);

        System.err.println("公钥: \n\r" + publicKey);

        System.err.println("私钥: \n\r" + privateKey);

    }

    @Test

    public void test() throws Exception {

        System.err.println("公钥加密——私钥解密");

        String inputStr = "abc";

        byte[] data = inputStr.getBytes();

        byte[] encodedData = RSACoder.encryptByPublicKey(data, publicKey);

        byte[] decodedData = RSACoder.decryptByPrivateKey(encodedData,

                privateKey);

        String outputStr = new String(decodedData);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        assertEquals(inputStr, outputStr);

    }

    @Test

    public void testSign() throws Exception {

        System.err.println("私钥加密——公钥解密");

        String inputStr = "sign";

        byte[] data = inputStr.getBytes();

        byte[] encodedData = RSACoder.encryptByPrivateKey(data, privateKey);

        byte[] decodedData = RSACoder

                .decryptByPublicKey(encodedData, publicKey);

        String outputStr = new String(decodedData);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        assertEquals(inputStr, outputStr);

        System.err.println("私钥签名——公钥验证签名");

        // 产生签名

        String sign = RSACoder.sign(encodedData, privateKey);

        System.err.println("签名:\r" + sign);

        // 验证签名

        boolean status = RSACoder.verify(encodedData, publicKey, sign);

        System.err.println("状态:\r" + status);

        assertTrue(status);

    }

}

控制台输出:

公钥: 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类见

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

import java.security.Key;

import java.security.KeyFactory;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.PublicKey;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

import javax.crypto.Cipher;

import javax.crypto.KeyAgreement;

import javax.crypto.SecretKey;

import javax.crypto.interfaces.DHPrivateKey;

import javax.crypto.interfaces.DHPublicKey;

import javax.crypto.spec.DHParameterSpec;

/**

 * DH安全编码组件

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public abstract class DHCoder extends Coder {

    public static final String ALGORITHM = "DH";

    /**

     * 默认密钥字节数

     

     * <pre>

     * DH

     * Default Keysize 1024  

     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).

     * </pre>

     */

    private static final int KEY_SIZE = 1024;

    /**

     * DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。

     */

    public static final String SECRET_ALGORITHM = "DES";

    private static final String PUBLIC_KEY = "DHPublicKey";

    private static final String PRIVATE_KEY = "DHPrivateKey";

    /**

     * 初始化甲方密钥

     

     * @return

     * @throws Exception

     */

    public static Map<String, Object> initKey() throws Exception {

        KeyPairGenerator keyPairGenerator = KeyPairGenerator

                .getInstance(ALGORITHM);

        keyPairGenerator.initialize(KEY_SIZE);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // 甲方公钥

        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();

        // 甲方私钥

        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);

        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;

    }

    /**

     * 初始化乙方密钥

     

     * @param key

     *            甲方公钥

     * @return

     * @throws Exception

     */

    public static Map<String, Object> initKey(String key) throws Exception {

        // 解析甲方公钥

        byte[] keyBytes = decryptBASE64(key);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        // 由甲方公钥构建乙方密钥

        DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();

        KeyPairGenerator keyPairGenerator = KeyPairGenerator

                .getInstance(keyFactory.getAlgorithm());

        keyPairGenerator.initialize(dhParamSpec);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // 乙方公钥

        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();

        // 乙方私钥

        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);

        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;

    }

    /**

     * 加密<br>

     

     * @param data

     *            待加密数据

     * @param publicKey

     *            甲方公钥

     * @param privateKey

     *            乙方私钥

     * @return

     * @throws Exception

     */

    public static byte[] encrypt(byte[] data, String publicKey,

            String privateKey) throws Exception {

        // 生成本地密钥

        SecretKey secretKey = getSecretKey(publicKey, privateKey);

        // 数据加密

        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        return cipher.doFinal(data);

    }

    /**

     * 解密<br>

     

     * @param data

     *            待解密数据

     * @param publicKey

     *            乙方公钥

     * @param privateKey

     *            乙方私钥

     * @return

     * @throws Exception

     */

    public static byte[] decrypt(byte[] data, String publicKey,

            String privateKey) throws Exception {

        // 生成本地密钥

        SecretKey secretKey = getSecretKey(publicKey, privateKey);

        // 数据解密

        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        return cipher.doFinal(data);

    }

    /**

     * 构建密钥

     

     * @param publicKey

     *            公钥

     * @param privateKey

     *            私钥

     * @return

     * @throws Exception

     */

    private static SecretKey getSecretKey(String publicKey, String privateKey)

            throws Exception {

        // 初始化公钥

        byte[] pubKeyBytes = decryptBASE64(publicKey);

        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyBytes);

        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        // 初始化私钥

        byte[] priKeyBytes = decryptBASE64(privateKey);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKeyBytes);

        Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory

                .getAlgorithm());

        keyAgree.init(priKey);

        keyAgree.doPhase(pubKey, true);

        // 生成本地密钥

        SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);

        return secretKey;

    }

    /**

     * 取得私钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPrivateKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 取得公钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPublicKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());

    }

}

再给出一个测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

import static org.junit.Assert.*;

import java.util.Map;

import org.junit.Test;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class DHCoderTest {

    @Test

    public void test() throws Exception {

        // 生成甲方密钥对儿

        Map<String, Object> aKeyMap = DHCoder.initKey();

        String aPublicKey = DHCoder.getPublicKey(aKeyMap);

        String aPrivateKey = DHCoder.getPrivateKey(aKeyMap);

        System.err.println("甲方公钥:\r" + aPublicKey);

        System.err.println("甲方私钥:\r" + aPrivateKey);

        

        // 由甲方公钥产生本地密钥对儿

        Map<String, Object> bKeyMap = DHCoder.initKey(aPublicKey);

        String bPublicKey = DHCoder.getPublicKey(bKeyMap);

        String bPrivateKey = DHCoder.getPrivateKey(bKeyMap);

        

        System.err.println("乙方公钥:\r" + bPublicKey);

        System.err.println("乙方私钥:\r" + bPrivateKey);

        

        String aInput = "abc ";

        System.err.println("原文: " + aInput);

        // 由甲方公钥,乙方私钥构建密文

        byte[] aCode = DHCoder.encrypt(aInput.getBytes(), aPublicKey,

                bPrivateKey);

        // 由乙方公钥,甲方私钥解密

        byte[] aDecode = DHCoder.decrypt(aCode, bPublicKey, aPrivateKey);

        String aOutput = (new String(aDecode));

        System.err.println("解密: " + aOutput);

        assertEquals(aInput, aOutput);

        System.err.println(" ===============反过来加密解密================== ");

        String bInput = "def ";

        System.err.println("原文: " + bInput);

        // 由乙方公钥,甲方私钥构建密文

        byte[] bCode = DHCoder.encrypt(bInput.getBytes(), bPublicKey,

                aPrivateKey);

        // 由甲方公钥,乙方私钥解密

        byte[] bDecode = DHCoder.decrypt(bCode, aPublicKey, bPrivateKey);

        String bOutput = (new String(bDecode));

        System.err.println("解密: " + bOutput);

        assertEquals(bInput, bOutput);

    }

}

控制台输出:

甲方公钥:
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类见

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

import java.security.Key;

import java.security.KeyFactory;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.SecureRandom;

import java.security.Signature;

import java.security.interfaces.DSAPrivateKey;

import java.security.interfaces.DSAPublicKey;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

/**

 * DSA安全编码组件

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public abstract class DSACoder extends Coder {

    public static final String ALGORITHM = "DSA";

    /**

     * 默认密钥字节数

     

     * <pre>

     * DSA 

     * Default Keysize 1024  

     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).

     * </pre>

     */

    private static final int KEY_SIZE = 1024;

    /**

     * 默认种子

     */

    private static final String DEFAULT_SEED = "0f22507a10bbddd07d8a3082122966e3";

    private static final String PUBLIC_KEY = "DSAPublicKey";

    private static final String PRIVATE_KEY = "DSAPrivateKey";

    /**

     * 用私钥对信息生成数字签名

     

     * @param data

     *            加密数据

     * @param privateKey

     *            私钥

     

     * @return

     * @throws Exception

     */

    public static String sign(byte[] data, String privateKey) throws Exception {

        // 解密由base64编码的私钥

        byte[] keyBytes = decryptBASE64(privateKey);

        // 构造PKCS8EncodedKeySpec对象

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法

        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        // 取私钥匙对象

        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 用私钥对信息生成数字签名

        Signature signature = Signature.getInstance(keyFactory.getAlgorithm());

        signature.initSign(priKey);

        signature.update(data);

        return encryptBASE64(signature.sign());

    }

    /**

     * 校验数字签名

     

     * @param data

     *            加密数据

     * @param publicKey

     *            公钥

     * @param sign

     *            数字签名

     

     * @return 校验成功返回true 失败返回false

     * @throws Exception

     

     */

    public static boolean verify(byte[] data, String publicKey, String sign)

            throws Exception {

        // 解密由base64编码的公钥

        byte[] keyBytes = decryptBASE64(publicKey);

        // 构造X509EncodedKeySpec对象

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // ALGORITHM 指定的加密算法

        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        // 取公钥匙对象

        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance(keyFactory.getAlgorithm());

        signature.initVerify(pubKey);

        signature.update(data);

        // 验证签名是否正常

        return signature.verify(decryptBASE64(sign));

    }

    /**

     * 生成密钥

     

     * @param seed

     *            种子

     * @return 密钥对象

     * @throws Exception

     */

    public static Map<String, Object> initKey(String seed) throws Exception {

        KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM);

        // 初始化随机产生器

        SecureRandom secureRandom = new SecureRandom();

        secureRandom.setSeed(seed.getBytes());

        keygen.initialize(KEY_SIZE, secureRandom);

        KeyPair keys = keygen.genKeyPair();

        DSAPublicKey publicKey = (DSAPublicKey) keys.getPublic();

        DSAPrivateKey privateKey = (DSAPrivateKey) keys.getPrivate();

        Map<String, Object> map = new HashMap<String, Object>(2);

        map.put(PUBLIC_KEY, publicKey);

        map.put(PRIVATE_KEY, privateKey);

        return map;

    }

    /**

     * 默认生成密钥

     

     * @return 密钥对象

     * @throws Exception

     */

    public static Map<String, Object> initKey() throws Exception {

        return initKey(DEFAULT_SEED);

    }

    /**

     * 取得私钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPrivateKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 取得公钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPublicKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());

    }

}

再给出一个测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

import static org.junit.Assert.*;

import java.util.Map;

import org.junit.Test;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class DSACoderTest {

    @Test

    public void test() throws Exception {

        String inputStr = "abc";

        byte[] data = inputStr.getBytes();

        // 构建密钥

        Map<String, Object> keyMap = DSACoder.initKey();

        // 获得密钥

        String publicKey = DSACoder.getPublicKey(keyMap);

        String privateKey = DSACoder.getPrivateKey(keyMap);

        System.err.println("公钥:\r" + publicKey);

        System.err.println("私钥:\r" + privateKey);

        // 产生签名

        String sign = DSACoder.sign(data, privateKey);

        System.err.println("签名:\r" + sign);

        // 验证签名

        boolean status = DSACoder.verify(data, publicKey, sign);

        System.err.println("状态:\r" + status);

        assertTrue(status);

    }

}

控制台输出:

公钥:
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类见

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

import java.math.BigInteger;

import java.security.Key;

import java.security.KeyFactory;

import java.security.interfaces.ECPrivateKey;

import java.security.interfaces.ECPublicKey;

import java.security.spec.ECFieldF2m;

import java.security.spec.ECParameterSpec;

import java.security.spec.ECPoint;

import java.security.spec.ECPrivateKeySpec;

import java.security.spec.ECPublicKeySpec;

import java.security.spec.EllipticCurve;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

import javax.crypto.Cipher;

import javax.crypto.NullCipher;

import sun.security.ec.ECKeyFactory;

import sun.security.ec.ECPrivateKeyImpl;

import sun.security.ec.ECPublicKeyImpl;

/**

 * ECC安全编码组件

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public abstract class ECCCoder extends Coder {

    public static final String ALGORITHM = "EC";

    private static final String PUBLIC_KEY = "ECCPublicKey";

    private static final String PRIVATE_KEY = "ECCPrivateKey";

    /**

     * 解密<br>

     * 用私钥解密

     

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] decrypt(byte[] data, String key) throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = ECKeyFactory.INSTANCE;

        ECPrivateKey priKey = (ECPrivateKey) keyFactory

                .generatePrivate(pkcs8KeySpec);

        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(),

                priKey.getParams());

        // 对数据解密

        // TODO Chipher不支持EC算法 未能实现

        Cipher cipher = new NullCipher();

        // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());

        cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams());

        return cipher.doFinal(data);

    }

    /**

     * 加密<br>

     * 用公钥加密

     

     * @param data

     * @param privateKey

     * @return

     * @throws Exception

     */

    public static byte[] encrypt(byte[] data, String privateKey)

            throws Exception {

        // 对公钥解密

        byte[] keyBytes = decryptBASE64(privateKey);

        // 取得公钥

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = ECKeyFactory.INSTANCE;

        ECPublicKey pubKey = (ECPublicKey) keyFactory

                .generatePublic(x509KeySpec);

        ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(),

                pubKey.getParams());

        // 对数据加密

        // TODO Chipher不支持EC算法 未能实现

        Cipher cipher = new NullCipher();

        // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());

        cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams());

        return cipher.doFinal(data);

    }

    /**

     * 取得私钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPrivateKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 取得公钥

     

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPublicKey(Map<String, Object> keyMap)

            throws Exception {

        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 初始化密钥

     

     * @return

     * @throws Exception

     */

    public static Map<String, Object> initKey() throws Exception {

        BigInteger x1 = new BigInteger(

                "2fe13c0537bbc11acaa07d793de4e6d5e5c94eee8"16);

        BigInteger x2 = new BigInteger(

                "289070fb05d38ff58321f2e800536d538ccdaa3d9"16);

        ECPoint g = new ECPoint(x1, x2);

        // the order of generator

        BigInteger n = new BigInteger(

                "5846006549323611672814741753598448348329118574063"10);

        // the cofactor

        int h = 2;

        int m = 163;

        int[] ks = { 763 };

        ECFieldF2m ecField = new ECFieldF2m(m, ks);

        // y^2+xy=x^3+x^2+1

        BigInteger a = new BigInteger("1"2);

        BigInteger b = new BigInteger("1"2);

        EllipticCurve ellipticCurve = new EllipticCurve(ecField, a, b);

        ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, g,

                n, h);

        // 公钥

        ECPublicKey publicKey = new ECPublicKeyImpl(g, ecParameterSpec);

        BigInteger s = new BigInteger(

                "1234006549323611672814741753598448348329118574063"10);

        // 私钥

        ECPrivateKey privateKey = new ECPrivateKeyImpl(s, ecParameterSpec);

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);

        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;

    }

}

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

照旧提供一个测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

import static org.junit.Assert.*;

import java.math.BigInteger;

import java.security.spec.ECFieldF2m;

import java.security.spec.ECParameterSpec;

import java.security.spec.ECPoint;

import java.security.spec.ECPrivateKeySpec;

import java.security.spec.ECPublicKeySpec;

import java.security.spec.EllipticCurve;

import java.util.Map;

import org.junit.Test;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class ECCCoderTest {

    @Test

    public void test() throws Exception {

        String inputStr = "abc";

        byte[] data = inputStr.getBytes();

        Map<String, Object> keyMap = ECCCoder.initKey();

        String publicKey = ECCCoder.getPublicKey(keyMap);

        String privateKey = ECCCoder.getPrivateKey(keyMap);

        System.err.println("公钥: \n" + publicKey);

        System.err.println("私钥: \n" + privateKey);

        byte[] encodedData = ECCCoder.encrypt(data, publicKey);

        byte[] decodedData = ECCCoder.decrypt(encodedData, privateKey);

        String outputStr = new String(decodedData);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        assertEquals(inputStr, outputStr);

    }

}

控制台输出:

公钥:
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类见

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

import java.io.FileInputStream;

import java.security.KeyStore;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.Signature;

import java.security.cert.Certificate;

import java.security.cert.CertificateFactory;

import java.security.cert.X509Certificate;

import java.util.Date;

import javax.crypto.Cipher;

/**

 * 证书组件

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public abstract class CertificateCoder extends Coder {

    /**

     * Java密钥库(Java Key Store,JKS)KEY_STORE

     */

    public static final String KEY_STORE = "JKS";

    public static final String X509 = "X.509";

    /**

     * 由KeyStore获得私钥

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    private static PrivateKey getPrivateKey(String keyStorePath, String alias,

            String password) throws Exception {

        KeyStore ks = getKeyStore(keyStorePath, password);

        PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());

        return key;

    }

    /**

     * 由Certificate获得公钥

     

     * @param certificatePath

     * @return

     * @throws Exception

     */

    private static PublicKey getPublicKey(String certificatePath)

            throws Exception {

        Certificate certificate = getCertificate(certificatePath);

        PublicKey key = certificate.getPublicKey();

        return key;

    }

    /**

     * 获得Certificate

     

     * @param certificatePath

     * @return

     * @throws Exception

     */

    private static Certificate getCertificate(String certificatePath)

            throws Exception {

        CertificateFactory certificateFactory = CertificateFactory

                .getInstance(X509);

        FileInputStream in = new FileInputStream(certificatePath);

        Certificate certificate = certificateFactory.generateCertificate(in);

        in.close();

        return certificate;

    }

    /**

     * 获得Certificate

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    private static Certificate getCertificate(String keyStorePath,

            String alias, String password) throws Exception {

        KeyStore ks = getKeyStore(keyStorePath, password);

        Certificate certificate = ks.getCertificate(alias);

        return certificate;

    }

    /**

     * 获得KeyStore

     

     * @param keyStorePath

     * @param password

     * @return

     * @throws Exception

     */

    private static KeyStore getKeyStore(String keyStorePath, String password)

            throws Exception {

        FileInputStream is = new FileInputStream(keyStorePath);

        KeyStore ks = KeyStore.getInstance(KEY_STORE);

        ks.load(is, password.toCharArray());

        is.close();

        return ks;

    }

    /**

     * 私钥加密

     

     * @param data

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,

            String alias, String password) throws Exception {

        // 取得私钥

        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 私钥解密

     

     * @param data

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,

            String alias, String password) throws Exception {

        // 取得私钥

        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 公钥加密

     

     * @param data

     * @param certificatePath

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPublicKey(byte[] data, String certificatePath)

            throws Exception {

        // 取得公钥

        PublicKey publicKey = getPublicKey(certificatePath);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 公钥解密

     

     * @param data

     * @param certificatePath

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPublicKey(byte[] data, String certificatePath)

            throws Exception {

        // 取得公钥

        PublicKey publicKey = getPublicKey(certificatePath);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 验证Certificate

     

     * @param certificatePath

     * @return

     */

    public static boolean verifyCertificate(String certificatePath) {

        return verifyCertificate(new Date(), certificatePath);

    }

    /**

     * 验证Certificate是否过期或无效

     

     * @param date

     * @param certificatePath

     * @return

     */

    public static boolean verifyCertificate(Date date, String certificatePath) {

        boolean status = true;

        try {

            // 取得证书

            Certificate certificate = getCertificate(certificatePath);

            // 验证证书是否过期或无效

            status = verifyCertificate(date, certificate);

        catch (Exception e) {

            status = false;

        }

        return status;

    }

    /**

     * 验证证书是否过期或无效

     

     * @param date

     * @param certificate

     * @return

     */

    private static boolean verifyCertificate(Date date, Certificate certificate) {

        boolean status = true;

        try {

            X509Certificate x509Certificate = (X509Certificate) certificate;

            x509Certificate.checkValidity(date);

        catch (Exception e) {

            status = false;

        }

        return status;

    }

    /**

     * 签名

     

     * @param keyStorePath

     * @param alias

     * @param password

     

     * @return

     * @throws Exception

     */

    public static String sign(byte[] sign, String keyStorePath, String alias,

            String password) throws Exception {

        // 获得证书

        X509Certificate x509Certificate = (X509Certificate) getCertificate(

                keyStorePath, alias, password);

        // 获取私钥

        KeyStore ks = getKeyStore(keyStorePath, password);

        // 取得私钥

        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password

                .toCharArray());

        // 构建签名

        Signature signature = Signature.getInstance(x509Certificate

                .getSigAlgName());

        signature.initSign(privateKey);

        signature.update(sign);

        return encryptBASE64(signature.sign());

    }

    /**

     * 验证签名

     

     * @param data

     * @param sign

     * @param certificatePath

     * @return

     * @throws Exception

     */

    public static boolean verify(byte[] data, String sign,

            String certificatePath) throws Exception {

        // 获得证书

        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);

        // 获得公钥

        PublicKey publicKey = x509Certificate.getPublicKey();

        // 构建签名

        Signature signature = Signature.getInstance(x509Certificate

                .getSigAlgName());

        signature.initVerify(publicKey);

        signature.update(data);

        return signature.verify(decryptBASE64(sign));

    }

    /**

     * 验证Certificate

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     */

    public static boolean verifyCertificate(Date date, String keyStorePath,

            String alias, String password) {

        boolean status = true;

        try {

            Certificate certificate = getCertificate(keyStorePath, alias,

                    password);

            status = verifyCertificate(date, certificate);

        catch (Exception e) {

            status = false;

        }

        return status;

    }

    /**

     * 验证Certificate

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     */

    public static boolean verifyCertificate(String keyStorePath, String alias,

            String password) {

        return verifyCertificate(new Date(), keyStorePath, alias, password);

    }

}

再给出一个测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

import static org.junit.Assert.*;

import org.junit.Test;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class CertificateCoderTest {

    private String password = "123456";

    private String alias = "www.zlex.org";

    private String certificatePath = "d:/zlex.cer";

    private String keyStorePath = "d:/zlex.keystore";

    @Test

    public void test() throws Exception {

        System.err.println("公钥加密——私钥解密");

        String inputStr = "Ceritifcate";

        byte[] data = inputStr.getBytes();

        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,

                certificatePath);

        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,

                keyStorePath, alias, password);

        String outputStr = new String(decrypt);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        // 验证数据一致

        assertArrayEquals(data, decrypt);

        // 验证证书有效

        assertTrue(CertificateCoder.verifyCertificate(certificatePath));

    }

    @Test

    public void testSign() throws Exception {

        System.err.println("私钥加密——公钥解密");

        String inputStr = "sign";

        byte[] data = inputStr.getBytes();

        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,

                keyStorePath, alias, password);

        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,

                certificatePath);

        String outputStr = new String(decodedData);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        assertEquals(inputStr, outputStr);

        System.err.println("私钥签名——公钥验证签名");

        // 产生签名

        String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,

                password);

        System.err.println("签名:\r" + sign);

        // 验证签名

        boolean status = CertificateCoder.verify(encodedData, sign,

                certificatePath);

        System.err.println("状态:\r" + status);

        assertTrue(status);

    }

}

控制台输出:

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

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

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

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

控制台输出:

输入密钥库的口令短语:正在更新: META-INF/WWW_ZLEX.SF正在更新: META-INF/WWW_ZLEX.RSA正在签名: org/zlex/security/Security.class正在签名: org/zlex/tool/Main$1.class正在签名: org/zlex/tool/Main$2.class正在签名: org/zlex/tool/Main.class警告:
签名者证书将在六个月内过期。

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

jarsigner -verify -verbose -certs tools.jar

控制台输出:

         402 Sat Jun 20 16:25:14 CST 2009 META-INF/MANIFEST.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的访问是不是需要把浏览器的这些个功能都实现呢?不需要!

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

import java.io.FileInputStream;

import java.security.KeyStore;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.Signature;

import java.security.cert.Certificate;

import java.security.cert.CertificateFactory;

import java.security.cert.X509Certificate;

import java.util.Date;

import javax.crypto.Cipher;

import javax.net.ssl.HttpsURLConnection;

import javax.net.ssl.KeyManagerFactory;

import javax.net.ssl.SSLContext;

import javax.net.ssl.SSLSocketFactory;

import javax.net.ssl.TrustManagerFactory;

/**

 * 证书组件

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public abstract class CertificateCoder extends Coder {

    /**

     * Java密钥库(Java Key Store,JKS)KEY_STORE

     */

    public static final String KEY_STORE = "JKS";

    public static final String X509 = "X.509";

    public static final String SunX509 = "SunX509";

    public static final String SSL = "SSL";

    /**

     * 由KeyStore获得私钥

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    private static PrivateKey getPrivateKey(String keyStorePath, String alias,

            String password) throws Exception {

        KeyStore ks = getKeyStore(keyStorePath, password);

        PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());

        return key;

    }

    /**

     * 由Certificate获得公钥

     

     * @param certificatePath

     * @return

     * @throws Exception

     */

    private static PublicKey getPublicKey(String certificatePath)

            throws Exception {

        Certificate certificate = getCertificate(certificatePath);

        PublicKey key = certificate.getPublicKey();

        return key;

    }

    /**

     * 获得Certificate

     

     * @param certificatePath

     * @return

     * @throws Exception

     */

    private static Certificate getCertificate(String certificatePath)

            throws Exception {

        CertificateFactory certificateFactory = CertificateFactory

                .getInstance(X509);

        FileInputStream in = new FileInputStream(certificatePath);

        Certificate certificate = certificateFactory.generateCertificate(in);

        in.close();

        return certificate;

    }

    /**

     * 获得Certificate

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    private static Certificate getCertificate(String keyStorePath,

            String alias, String password) throws Exception {

        KeyStore ks = getKeyStore(keyStorePath, password);

        Certificate certificate = ks.getCertificate(alias);

        return certificate;

    }

    /**

     * 获得KeyStore

     

     * @param keyStorePath

     * @param password

     * @return

     * @throws Exception

     */

    private static KeyStore getKeyStore(String keyStorePath, String password)

            throws Exception {

        FileInputStream is = new FileInputStream(keyStorePath);

        KeyStore ks = KeyStore.getInstance(KEY_STORE);

        ks.load(is, password.toCharArray());

        is.close();

        return ks;

    }

    /**

     * 私钥加密

     

     * @param data

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,

            String alias, String password) throws Exception {

        // 取得私钥

        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 私钥解密

     

     * @param data

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,

            String alias, String password) throws Exception {

        // 取得私钥

        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 公钥加密

     

     * @param data

     * @param certificatePath

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPublicKey(byte[] data, String certificatePath)

            throws Exception {

        // 取得公钥

        PublicKey publicKey = getPublicKey(certificatePath);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 公钥解密

     

     * @param data

     * @param certificatePath

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPublicKey(byte[] data, String certificatePath)

            throws Exception {

        // 取得公钥

        PublicKey publicKey = getPublicKey(certificatePath);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 验证Certificate

     

     * @param certificatePath

     * @return

     */

    public static boolean verifyCertificate(String certificatePath) {

        return verifyCertificate(new Date(), certificatePath);

    }

    /**

     * 验证Certificate是否过期或无效

     

     * @param date

     * @param certificatePath

     * @return

     */

    public static boolean verifyCertificate(Date date, String certificatePath) {

        boolean status = true;

        try {

            // 取得证书

            Certificate certificate = getCertificate(certificatePath);

            // 验证证书是否过期或无效

            status = verifyCertificate(date, certificate);

        catch (Exception e) {

            status = false;

        }

        return status;

    }

    /**

     * 验证证书是否过期或无效

     

     * @param date

     * @param certificate

     * @return

     */

    private static boolean verifyCertificate(Date date, Certificate certificate) {

        boolean status = true;

        try {

            X509Certificate x509Certificate = (X509Certificate) certificate;

            x509Certificate.checkValidity(date);

        catch (Exception e) {

            status = false;

        }

        return status;

    }

    /**

     * 签名

     

     * @param keyStorePath

     * @param alias

     * @param password

     

     * @return

     * @throws Exception

     */

    public static String sign(byte[] sign, String keyStorePath, String alias,

            String password) throws Exception {

        // 获得证书

        X509Certificate x509Certificate = (X509Certificate) getCertificate(

                keyStorePath, alias, password);

        // 获取私钥

        KeyStore ks = getKeyStore(keyStorePath, password);

        // 取得私钥

        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password

                .toCharArray());

        // 构建签名

        Signature signature = Signature.getInstance(x509Certificate

                .getSigAlgName());

        signature.initSign(privateKey);

        signature.update(sign);

        return encryptBASE64(signature.sign());

    }

    /**

     * 验证签名

     

     * @param data

     * @param sign

     * @param certificatePath

     * @return

     * @throws Exception

     */

    public static boolean verify(byte[] data, String sign,

            String certificatePath) throws Exception {

        // 获得证书

        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);

        // 获得公钥

        PublicKey publicKey = x509Certificate.getPublicKey();

        // 构建签名

        Signature signature = Signature.getInstance(x509Certificate

                .getSigAlgName());

        signature.initVerify(publicKey);

        signature.update(data);

        return signature.verify(decryptBASE64(sign));

    }

    /**

     * 验证Certificate

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     */

    public static boolean verifyCertificate(Date date, String keyStorePath,

            String alias, String password) {

        boolean status = true;

        try {

            Certificate certificate = getCertificate(keyStorePath, alias,

                    password);

            status = verifyCertificate(date, certificate);

        catch (Exception e) {

            status = false;

        }

        return status;

    }

    /**

     * 验证Certificate

     

     * @param keyStorePath

     * @param alias

     * @param password

     * @return

     */

    public static boolean verifyCertificate(String keyStorePath, String alias,

            String password) {

        return verifyCertificate(new Date(), keyStorePath, alias, password);

    }

    /**

     * 获得SSLSocektFactory

     

     * @param password

     *            密码

     * @param keyStorePath

     *            密钥库路径

     

     * @param trustKeyStorePath

     *            信任库路径

     * @return

     * @throws Exception

     */

    private static SSLSocketFactory getSSLSocketFactory(String password,

            String keyStorePath, String trustKeyStorePath) throws Exception {

        // 初始化密钥库

        KeyManagerFactory keyManagerFactory = KeyManagerFactory

                .getInstance(SunX509);

        KeyStore keyStore = getKeyStore(keyStorePath, password);

        keyManagerFactory.init(keyStore, password.toCharArray());

        // 初始化信任库

        TrustManagerFactory trustManagerFactory = TrustManagerFactory

                .getInstance(SunX509);

        KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);

        trustManagerFactory.init(trustkeyStore);

        // 初始化SSL上下文

        SSLContext ctx = SSLContext.getInstance(SSL);

        ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory

                .getTrustManagers(), null);

        SSLSocketFactory sf = ctx.getSocketFactory();

        return sf;

    }

    /**

     * 为HttpsURLConnection配置SSLSocketFactory

     

     * @param conn

     *            HttpsURLConnection

     * @param password

     *            密码

     * @param keyStorePath

     *            密钥库路径

     

     * @param trustKeyStorePath

     *            信任库路径

     * @throws Exception

     */

    public static void configSSLSocketFactory(HttpsURLConnection conn,

            String password, String keyStorePath, String trustKeyStorePath)

            throws Exception {

        conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,

                trustKeyStorePath));

    }

}

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

给出相应测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

import static org.junit.Assert.*;

import java.io.DataInputStream;

import java.io.InputStream;

import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import org.junit.Test;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class CertificateCoderTest {

    private String password = "123456";

    private String alias = "www.zlex.org";

    private String certificatePath = "d:/zlex.cer";

    private String keyStorePath = "d:/zlex.keystore";

    private String clientKeyStorePath = "d:/zlex-client.keystore";

    private String clientPassword = "654321";

    @Test

    public void test() throws Exception {

        System.err.println("公钥加密——私钥解密");

        String inputStr = "Ceritifcate";

        byte[] data = inputStr.getBytes();

        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,

                certificatePath);

        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,

                keyStorePath, alias, password);

        String outputStr = new String(decrypt);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        // 验证数据一致

        assertArrayEquals(data, decrypt);

        // 验证证书有效

        assertTrue(CertificateCoder.verifyCertificate(certificatePath));

    }

    @Test

    public void testSign() throws Exception {

        System.err.println("私钥加密——公钥解密");

        String inputStr = "sign";

        byte[] data = inputStr.getBytes();

        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,

                keyStorePath, alias, password);

        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,

                certificatePath);

        String outputStr = new String(decodedData);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        assertEquals(inputStr, outputStr);

        System.err.println("私钥签名——公钥验证签名");

        // 产生签名

        String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,

                password);

        System.err.println("签名:\r" + sign);

        // 验证签名

        boolean status = CertificateCoder.verify(encodedData, sign,

                certificatePath);

        System.err.println("状态:\r" + status);

        assertTrue(status);

    }

    @Test

    public void testHttps() throws Exception {

        URL url = new URL("https://www.zlex.org/examples/");

        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        conn.setDoInput(true);

        conn.setDoOutput(true);

        CertificateCoder.configSSLSocketFactory(conn, clientPassword,

                clientKeyStorePath, clientKeyStorePath);

        InputStream is = conn.getInputStream();

        int length = conn.getContentLength();

        DataInputStream dis = new DataInputStream(is);

        byte[] data = new byte[length];

        dis.readFully(data);

        dis.close();

        System.err.println(new String(data));

        conn.disconnect();

    }

}

注意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机构的有效性。

打开证书,如下图所示: 

调整测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

import static org.junit.Assert.*;

import java.io.DataInputStream;

import java.io.InputStream;

import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import org.junit.Test;

/**

 

 * @author 梁栋

 * @version 1.0

 * @since 1.0

 */

public class CertificateCoderTest {

    private String password = "123456";

    private String alias = "www.zlex.org";

    private String certificatePath = "d:/zlex.cer";

    private String keyStorePath = "d:/zlex.keystore";

    @Test

    public void test() throws Exception {

        System.err.println("公钥加密——私钥解密");

        String inputStr = "Ceritifcate";

        byte[] data = inputStr.getBytes();

        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,

                certificatePath);

        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,

                keyStorePath, alias, password);

        String outputStr = new String(decrypt);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        // 验证数据一致

        assertArrayEquals(data, decrypt);

        // 验证证书有效

        assertTrue(CertificateCoder.verifyCertificate(certificatePath));

    }

    @Test

    public void testSign() throws Exception {

        System.err.println("私钥加密——公钥解密");

        String inputStr = "sign";

        byte[] data = inputStr.getBytes();

        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,

                keyStorePath, alias, password);

        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,

                certificatePath);

        String outputStr = new String(decodedData);

        System.err.println("加密前: " + inputStr + "\n\r" "解密后: " + outputStr);

        assertEquals(inputStr, outputStr);

        System.err.println("私钥签名——公钥验证签名");

        // 产生签名

        String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,

                password);

        System.err.println("签名:\r" + sign);

        // 验证签名

        boolean status = CertificateCoder.verify(encodedData, sign,

                certificatePath);

        System.err.println("状态:\r" + status);

        assertTrue(status);

    }

    @Test

    public void testHttps() throws Exception {

        URL url = new URL("https://www.zlex.org/examples/");

        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        conn.setDoInput(true);

        conn.setDoOutput(true);

        CertificateCoder.configSSLSocketFactory(conn, password, keyStorePath,

                keyStorePath);

        InputStream is = conn.getInputStream();

        int length = conn.getContentLength();

        DataInputStream dis = new DataInputStream(is);

        byte[] data = new byte[length];

        dis.readFully(data);

        dis.close();

        conn.disconnect();

        System.err.println(new String(data));

    }

}

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

各种Java加密算法-非对称加密相关推荐

  1. Java加密算法—非对称加密

    目录 1.概述 2.对称加密.解密实现 1.概述 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密钥(privatekey),公开密钥和私有密钥是一对,如果用公 ...

  2. java RSA非对称加密详解

    简介 RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年首次公布,当 ...

  3. Java实现非对称加密

    1. 简介 公开密钥密码学(英语:Public-key cryptography)也称非对称式密码学(英语:Asymmetric cryptography)是密码学的一种算法,它需要两个密钥,一个是公 ...

  4. Java笔记-非对称加密RSA的使用

    使用OpenSSL生成对应RSA私钥和RSA公钥: #rsa私钥: genrsa -out rsa_private_key.pem 1024 pkcs8 -topk8 -inform PEM -in ...

  5. Java加密算法—对称加密(DES、AES)

    目录 1.概述 2.加密模式 2.1 ECB 2.2 CBC 3.填充模式 4.对称加密.解密实现 1.概述 对称加密就是采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,也称为单密 ...

  6. go加密算法:非对称加密(三)--Elliptic

    看了2星期的区块链原理与运行机制,加密这里开始变得有些生疏,花了一天时间复习了一些;看到了之前忽略的,也学会了椭圆曲线加密. //基础板:浅显易懂package main import ( " ...

  7. 【Java基础】加密与安全基础

    文章目录 一.编码算法 什么是编码? URL编码 1.什么是URL编码算法 2.Java中使用URL编码算法 Base64编码 1.什么是Base64编码算法 2.Java中使用Base64编码算法 ...

  8. Java中的加密与安全,你了解多少

    文章目录 数据安全 编码算法 摘要算法 MD5算法 SAH-1算法 BouncyCastle算法 Hmac算法 加密算法 对称加密算法 口令加密算法 密钥交换算法 非对称加密算法 数字签名算法 RSA ...

  9. 【加密】对称加密DES和非对称加密AES、数字签名|非对称加密--公钥和私钥的区别

    目录 对称加密DES和非对称加密AES.数字签名 对称加密 1.1 定义 1.2 优缺点 1.3 常用对称加密算法 非对称加密( Asymmetric Cryptography ) 非对称加密(现代加 ...

最新文章

  1. 2020考研公共课_基础精讲课_管理类联考综合能力 联考逻辑(读书笔记)
  2. ASP.NET图象处理详解
  3. ecshop安装linux7,RedHat下如何搭建ecshop?
  4. Android中解决debug.keystore到期的问题
  5. surface pro linux服务器,【如何在surface pro 4上安装linux系统?】-看准网
  6. python 卡方检验 特征选择_结合Scikit-learn介绍几种常用的特征选择方法
  7. [译]GC专家系列5-Java应用性能优化的原则
  8. Css颜色和文本字体
  9. chrome控制台如何把vw显示成px_你可能不知道的chrome调试技巧
  10. Linux中SDIO命令,Linux MMC/SD/SDIO体系结构
  11. webbrowser 百度列表点击_百度信息流推广后台完整的实操流程分享
  12. java中怎样创建线程_java中的线程创建和使用
  13. Linux部署Java环境
  14. 在线图片坐标拾取工具
  15. 阿里云云计算 51 在线实验--安全中心初体验
  16. backtrack3安装使用教程
  17. java支付方法_java实现微信H5支付方法详解
  18. 优盘扩容修复 u盘工具
  19. keil中 如何解决warning L13:Recursive call to Function 及overlay解释
  20. 4.46-47访问控制4/5

热门文章

  1. 为什么没人比程序员更讨厌软件
  2. Chrome常见的好用插件(满分好评)
  3. IDEA 修改单行的注释格式
  4. We're sorry but vue_blog doesn't work properly without JavaScript enabled. Please enable it to.....
  5. 用SNMP协议实现系统监控
  6. 正则表达式 取最后一个 . 然后进行匹配
  7. 看看乔帮主留下的世界
  8. Android-smart-image-view加载网络图片
  9. 亚马逊AVS开发--树莓派3麦克风配置
  10. 删除Windows11中设备与驱动器下的多余图标