引入:
在我们的博客:http://supercharles888.blog.51cto.com/609344/1313864中可以看到,对于加密解密,最重要的是密码,因为从加密方式上来看,有对称加密和非对称加密,所以我们这里就用java的例子来说明,如何使用java security的API 来创造一个符合我们要求的密码。
实践:
从类角度上来说,因为对称加密,非对称加密都会用到密钥,所以顶层接口是Key(密钥因为经常要传输给对方,所以它一定是可序列化的),而对称加密来说,使用的是SecretKey,它继承自Key接口,而对于非对称加密来说,它会使用到PublicKey接口和PrivateKey接口,而且总是成对出现的,所以他们都封装在KeyPair类中:
其核心接口,类关系如下:
对称加密:
对于对称加密来说,加密的密码和解密的密码是同一个,而比较经典的对称加密算法是DES,我们这里也用DES为例子,一般来说,要生成一个用于对称加密的密钥,我们做以下几步:
(1)实例化SecureRandom对象,让它产生一个安全随机数
(2)实例化KeyGenerator对象,它会负责产生一个半成品密钥
(3)初始化KeyGenerator,并调用generateKey()方法让其产生一个密钥(注意:这里的密钥不是最终的密钥,而是半成品,相当于做钥匙的铜片)
(4)将半成品密钥转为字节数组
(5)获取对称加密的密钥规范XXXKeySpec,比如DES,AES等,它决定密钥最终长什么样子,它相当于配钥匙时候使用的模具
(6)实例化SecureKeyFactory对象,它负责产生一个最终密钥
(7)调用SecureKeyFactory的generateSecret()方法产生一个最终密钥,从参数可以看出来,就是铜片和模具的组合,最终才能产生一个我们需要的纹路的钥匙。
代码如下,可直接使用:
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
|
/*
*/
package com.charles.keystudy;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Map;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
/**
*
* Description:这个工具类专门来生成对称的密钥
*
* @author charles.wang
* @created Oct 24, 2013 5:07:41 PM
*
*/
public
class
SymmetricKeyUtil {
public
static
Key generateSecretKey()
throws
Exception {
//实例化SecureRandom对象,这个对象作为安全的随机数生成器
SecureRandom secureRandom =
new
SecureRandom();
//实例化KeyGenerator对象,这个对象专门用来产生对称的密钥
KeyGenerator kg = KeyGenerator.getInstance(
"DES"
);
//初始化密钥产生器
kg.init(secureRandom);
//产生对称的密钥
SecretKey secretKey = kg.generateKey();
//获得密钥的字节数组
byte
[] secretKeyBytes = secretKey.getEncoded();
//获得密钥规范, 比如说"DES"
DESKeySpec dks =
new
DESKeySpec(secretKeyBytes);
//实例化SecureKeyFactory对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(
"DES"
);
//生成对称的密钥
SecretKey finalSecretKey = keyFactory.generateSecret(dks);
return
finalSecretKey;
}
}
|
非对称加密:
对于非对称加密来说,加密的密码和解密的密码是两个密码(公钥加密则私钥解密,私钥加密则公钥解密),而比较经典的对称加密算法是RSA,我们这里也用RSA为例子,一般来说,要生成一个用于非对称加密的公钥私钥对,我们做以下几步:
(1)实例化KeyPairGenerator对象,它会负责产生一个半成品公钥私钥对
(2)初始化KeyPairGenerator,用希望的密钥长度作为参数
(3)调用KeyPairGenerator的generateKeyPair()方法产生半成品的公钥私钥对
(4)将半成品公钥私钥对转为字节数组
(5)获取非对称加密的密钥规范XXXKeySpec,对于RSA来说,一般公钥用X.509,私钥用PKCS#8。
(6)实例化KeyFactory对象,它负责产生最终公钥私钥对
(7)调用KeyFactory的generatePublic()方法产生最终公钥,generatePrivate()方法产生最终私钥
代码如下,可直接使用:
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
|
package
com.charles.keystudy;
import
java.security.Key;
import
java.security.KeyFactory;
import
java.security.KeyPair;
import
java.security.KeyPairGenerator;
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
sun.misc.BASE64Encoder;
/**
*
* Description: 这个工具类专门来生成非对称的密钥(分为公钥和私钥)
*
* @author charles.wang
* @created Oct 24, 2013 12:02:30 PM
*
*/
public
class
AsymmetricKeyUtil {
/**
*
* @return
* @throws Exception
*/
public
static
Map<String, Key> generatePublicPrivateKeyPair()
throws
Exception {
// KeyPairGenerator这个密钥对生成器是用来生成非对称的公钥的
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
"RSA"
);
// 初始化密钥生成器,用密钥的位数作为参数
keyPairGenerator.initialize(
1024
);
// 产生公钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 甲方公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 甲方私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 获得公钥的字节数组
byte
[] publicKeyBytes = publicKey.getEncoded();
// 获得公钥的密钥规范 ,publicKey是用X.509编码的
X509EncodedKeySpec publicKeySpec =
new
X509EncodedKeySpec(publicKeyBytes);
// 获得私钥的字节数组
byte
[] privateKeyBytes = privateKey.getEncoded();
// 获得私钥的密钥规范,privateKey是用PKCS#8规范编码的
PKCS8EncodedKeySpec privatePKC8ENcodedKeySpec =
new
PKCS8EncodedKeySpec(privateKeyBytes);
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(
"RSA"
);
// 生成公钥,它是通过密钥工厂将公钥字节数组转为公钥对象
Key publicKeyValue = keyFactory.generatePublic(publicKeySpec);
// 生成私钥,它是通过密钥工厂将私钥字节数组转为私钥对象
Key privateKeyValue = keyFactory.generatePrivate(privatePKC8ENcodedKeySpec);
Map<String, Key> finalKeyPair =
new
HashMap<String, Key>();
finalKeyPair.put(
"publicKey"
, publicKeyValue);
finalKeyPair.put(
"privateKey"
, privateKeyValue);
return
finalKeyPair;
}
}
|
最后,交给用户使用的时候,应该是一个经过Base64编码的,我们很容易就可以做到这一点,这里附上我们的测试代码:
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
|
/*
*/
package com.charles.keystudy;
import java.security.Key;
import java.util.Map;
import sun.misc.BASE64Encoder;
/**
*
* Description: 演示类,用于演示用法
*
* @author charles.wang
* @created Oct 24, 2013 5:02:36 PM
*
*/
public class KeyDemo {
/**
* 把产生的密钥转为Base64编码的格式
* @param key
* @return
* @throws Exception
*/
public
static
String getKeyString(Key key)
throws
Exception{
byte
[] keyBytes = key.getEncoded();
String s = (
new
BASE64Encoder()).encode(keyBytes);
return
s;
}
public
static
void
main(String[] args)
throws
Exception{
//演示对称密钥的产生 过程
System.out.println(
"演示对称密钥的产生 过程"
);
Key secretKey = SymmetricKeyUtil.generateSecretKey();
System.out.println(
"Format:"
+secretKey.getFormat());
System.out.println(
"secretKey:"
+getKeyString(secretKey) );
System.out.println();
//演示非对称密钥的产生过程
System.out.println(
"演示非对称密钥的产生过程"
);
Map<String,Key> keyPair = AsymmetricKeyUtil.generatePublicPrivateKeyPair();
for
( String s :keyPair.keySet()){
System.out.println(s+
"Format:"
+keyPair.get(s).getFormat());;
System.out.println(s+
":"
+getKeyString(keyPair.get(s)) );
System.out.println();
}
}
}
|
最后我们执行来观察结果,果然对称加密会生成一个密钥,而非对称加密会生成公钥私钥对: