DES
DES-Data Encryption Standard,即数据加密算法。是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中 Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密 或解密。
DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位。
通过java代码实现如下:Coder类见
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
|
import
java.security.Key;
import
java.security.SecureRandom;
import
javax.crypto.Cipher;
import
javax.crypto.KeyGenerator;
import
javax.crypto.SecretKey;
import
javax.crypto.SecretKeyFactory;
import
javax.crypto.spec.DESKeySpec;
/**
* DES安全编码组件
*
* <pre>
* 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
* DES key size must be equal to 56
* DESede(TripleDES) key size must be equal to 112 or 168
* AES key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
* Blowfish key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
* RC2 key size must be between 40 and 1024 bits
* RC4(ARCFOUR) key size must be between 40 and 1024 bits
* 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
* </pre>
*
* @author 梁栋
* @version 1.0
* @since 1.0
*/
public
abstract
class
DESCoder
extends
Coder {
/**
* ALGORITHM 算法 <br>
* 可替换为以下任意一种算法,同时key值的size相应改变。
*
* <pre>
* DES key size must be equal to 56
* DESede(TripleDES) key size must be equal to 112 or 168
* AES key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
* Blowfish key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
* RC2 key size must be between 40 and 1024 bits
* RC4(ARCFOUR) key size must be between 40 and 1024 bits
* </pre>
*
* 在Key toKey(byte[] key)方法中使用下述代码
* <code>SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);</code> 替换
* <code>
* DESKeySpec dks = new DESKeySpec(key);
* SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
* SecretKey secretKey = keyFactory.generateSecret(dks);
* </code>
*/
public
static
final
String ALGORITHM =
"DES"
;
/**
* 转换密钥<br>
*
* @param key
* @return
* @throws Exception
*/
private
static
Key toKey(
byte
[] key)
throws
Exception {
DESKeySpec dks =
new
DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(dks);
// 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码
// SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
return
secretKey;
}
/**
* 解密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public
static
byte
[] decrypt(
byte
[] data, String key)
throws
Exception {
Key k = toKey(decryptBASE64(key));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, k);
return
cipher.doFinal(data);
}
/**
* 加密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public
static
byte
[] encrypt(
byte
[] data, String key)
throws
Exception {
Key k = toKey(decryptBASE64(key));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, k);
return
cipher.doFinal(data);
}
/**
* 生成密钥
*
* @return
* @throws Exception
*/
public
static
String initKey()
throws
Exception {
return
initKey(
null
);
}
/**
* 生成密钥
*
* @param seed
* @return
* @throws Exception
*/
public
static
String initKey(String seed)
throws
Exception {
SecureRandom secureRandom =
null
;
if
(seed !=
null
) {
secureRandom =
new
SecureRandom(decryptBASE64(seed));
}
else
{
secureRandom =
new
SecureRandom();
}
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
kg.init(secureRandom);
SecretKey secretKey = kg.generateKey();
return
encryptBASE64(secretKey.getEncoded());
}
}
|
延续上一个类的实现,我们通过MD5以及SHA对字符串加密生成密钥,这是比较常见的密钥生成方式。
再给出一个测试类:
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
|
import
static
org.junit.Assert.*;
import
org.junit.Test;
/**
*
* @author 梁栋
* @version 1.0
* @since 1.0
*/
public
class
DESCoderTest {
@Test
public
void
test()
throws
Exception {
String inputStr =
"DES"
;
String key = DESCoder.initKey();
System.err.println(
"原文:\t"
+ inputStr);
System.err.println(
"密钥:\t"
+ key);
byte
[] inputData = inputStr.getBytes();
inputData = DESCoder.encrypt(inputData, key);
System.err.println(
"加密后:\t"
+ DESCoder.encryptBASE64(inputData));
byte
[] outputData = DESCoder.decrypt(inputData, key);
String outputStr =
new
String(outputData);
System.err.println(
"解密后:\t"
+ outputStr);
assertEquals(inputStr, outputStr);
}
}
|
得到的输出内容如下:
原文: DES 密钥: f3wEtRrV6q0= 加密后: C6qe9oNIzRY= 解密后: DES
由控制台得到的输出,我们能够比对加密、解密后结果一致。这是一种简单的加密解密方式,只有一个密钥。
其实DES有很多同胞兄弟,如DESede(TripleDES)、AES、Blowfish、RC2、RC4(ARCFOUR)。这里就不过多阐述了,大同小异,只要换掉ALGORITHM换成对应的值,同时做一个代码替换SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);就可以了,此外就是密钥长度不同了。
1
2
3
4
5
6
7
8
|
/**
* DES key size must be equal to 56
* DESede(TripleDES) key size must be equal to 112 or 168
* AES key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
* Blowfish key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
* RC2 key size must be between 40 and 1024 bits
* RC4(ARCFOUR) key size must be between 40 and 1024 bits
**/
|
除了DES,我们还知道有DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法——PBE
PBE
PBE——Password-based encryption(基于密码加密)。其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。是一种简便的加密方式。
通过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
|
import
java.security.Key;
import
java.util.Random;
import
javax.crypto.Cipher;
import
javax.crypto.SecretKey;
import
javax.crypto.SecretKeyFactory;
import
javax.crypto.spec.PBEKeySpec;
import
javax.crypto.spec.PBEParameterSpec;
/**
* PBE安全编码组件
*
* @author 梁栋
* @version 1.0
* @since 1.0
*/
public
abstract
class
PBECoder
extends
Coder {
/**
* 支持以下任意一种算法
*
* <pre>
* PBEWithMD5AndDES
* PBEWithMD5AndTripleDES
* PBEWithSHA1AndDESede
* PBEWithSHA1AndRC2_40
* </pre>
*/
public
static
final
String ALGORITHM =
"PBEWITHMD5andDES"
;
/**
* 盐初始化
*
* @return
* @throws Exception
*/
public
static
byte
[] initSalt()
throws
Exception {
byte
[] salt =
new
byte
[
8
];
Random random =
new
Random();
random.nextBytes(salt);
return
salt;
}
/**
* 转换密钥<br>
*
* @param password
* @return
* @throws Exception
*/
private
static
Key toKey(String password)
throws
Exception {
PBEKeySpec keySpec =
new
PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(keySpec);
return
secretKey;
}
/**
* 加密
*
* @param data 数据
* @param password 密码
* @param salt 盐
* @return
* @throws Exception
*/
public
static
byte
[] encrypt(
byte
[] data, String password,
byte
[] salt)
throws
Exception {
Key key = toKey(password);
PBEParameterSpec paramSpec =
new
PBEParameterSpec(salt,
100
);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
return
cipher.doFinal(data);
}
/**
* 解密
*
* @param data 数据
* @param password 密码
* @param salt 盐
* @return
* @throws Exception
*/
public
static
byte
[] decrypt(
byte
[] data, String password,
byte
[] salt)
throws
Exception {
Key key = toKey(password);
PBEParameterSpec paramSpec =
new
PBEParameterSpec(salt,
100
);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
return
cipher.doFinal(data);
}
}
|
再给出一个测试类:
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
|
import
static
org.junit.Assert.*;
import
org.junit.Test;
/**
*
* @author 梁栋
* @version 1.0
* @since 1.0
*/
public
class
PBECoderTest {
@Test
public
void
test()
throws
Exception {
String inputStr =
"abc"
;
System.err.println(
"原文: "
+ inputStr);
byte
[] input = inputStr.getBytes();
String pwd =
"efg"
;
System.err.println(
"密码: "
+ pwd);
byte
[] salt = PBECoder.initSalt();
byte
[] data = PBECoder.encrypt(input, pwd, salt);
System.err.println(
"加密后: "
+ PBECoder.encryptBASE64(data));
byte
[] output = PBECoder.decrypt(data, pwd, salt);
String outputStr =
new
String(output);
System.err.println(
"解密后: "
+ outputStr);
assertEquals(inputStr, outputStr);
}
}
|
控制台输出:
原文: abc 密码: efg 加密后: iCZ0uRtaAhE= 解密后: abc