轉自:http://www.open-open.com/lib/view/open1397274257325.html
如基本的單向加密算法:
BASE64 嚴格地說,屬於編碼格式,而非加密算法
MD5(Message Digest algorithm 5,信息摘要算法)
SHA(Secure Hash Algorithm,安全散列算法)
HMAC(Hash Message Authentication Code,散列消息鑑別碼)
複雜的對稱加密(DES、PBE)、非對稱加密算法:
DES(Data Encryption Standard,數據加密算法)
PBE(Password-based encryption,基於密碼驗證)
RSA(算法的名字以發明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman)
DH(Diffie-Hellman算法,**一致協議)
DSA(Digital Signature Algorithm,數字簽名)
ECC(Elliptic Curves Cryptography,橢圓曲線密碼編碼學)
如基本的單向加密算法:
BASE64 嚴格地說,屬於編碼格式,而非加密算法
MD5(Message Digest algorithm 5,信息摘要算法)
SHA(Secure Hash Algorithm,安全散列算法)
HMAC(Hash Message Authentication Code,散列消息鑑別碼)
複雜的對稱加密(DES、PBE)、非對稱加密算法:
DES(Data Encryption Standard,數據加密算法)
PBE(Password-based encryption,基於密碼驗證)
RSA(算法的名字以發明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman)
DH(Diffie-Hellman算法,**一致協議)
DSA(Digital Signature Algorithm,數字簽名)
ECC(Elliptic Curves Cryptography,橢圓曲線密碼編碼學)
本篇內容簡要介紹BASE64、MD5、SHA、HMAC幾種方法。
MD5、SHA、HMAC這三種加密算法,可謂是非可逆加密,就是不可解密的加密方法。我們通常只把他們作爲加密的基礎。單純的以上三種的加密並不可靠。
BASE64
按 照RFC2045的定義,Base64被定義爲:Base64內容傳送編碼被設計用來把任意序列的8位字節描述爲一種不易被人直接識別的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
常見於郵件、http加密,截取http信息,你就會發現登錄操作的用戶名、密碼字段通過BASE64加密的。
通過java代碼實現如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/**
* BASE64解密
*
* @param key
* @return
* @throws Exception
*/
public
static
byte
[] decryptBASE64(String key)
throws
Exception {
return
(
new
BASE64Decoder()).decodeBuffer(key);
}
/**
* BASE64加密
*
* @param key
* @return
* @throws Exception
*/
public
static
String encryptBASE64(
byte
[] key)
throws
Exception {
return
(
new
BASE64Encoder()).encodeBuffer(key);
}
|
主要就是BASE64Encoder、BASE64Decoder兩個類,我們只需要知道使用對應的方法即可。另,BASE加密後產生的字節位數是8的倍數,如果不夠位數以=符號填充。
MD5
MD5 -- message-digest algorithm 5 (信息-摘要算法)縮寫,廣泛用於加密和解密技術,常用於文件校驗。校驗?不管文件多大,經過MD5後都能生成唯一的MD5值。好比現在的ISO校驗,都 是MD5校驗。怎麼用?當然是把ISO經過MD5後產生MD5的值。一般下載linux-ISO的朋友都見過下載鏈接旁邊放着MD5的串。就是用來驗證文 件是否一致的。
通過java代碼實現如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/**
* MD5加密
*
* @param data
* @return
* @throws Exception
*/
public
static
byte
[] encryptMD5(
byte
[] data)
throws
Exception {
MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
md5.update(data);
return
md5.digest();
}
|
通常我們不直接使用上述MD5加密。通常將MD5產生的字節數組交給BASE64再加密一把,得到相應的字符串。
SHA
SHA(Secure Hash Algorithm,安全散列算法),數字簽名等密碼學應用中重要的工具,被廣泛地應用於電子商務等信息安全領域。雖然,SHA與MD5通過碰撞法都被**了, 但是SHA仍然是公認的安全加密算法,較之MD5更爲安全。
通過java代碼實現如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* SHA加密
*
* @param data
* @return
* @throws Exception
*/
public
static
byte
[] encryptSHA(
byte
[] data)
throws
Exception {
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
sha.update(data);
return
sha.digest();
}
}
|
HMAC
HMAC(Hash Message Authentication Code,散列消息鑑別碼,基於**的Hash算法的認證協議。消息鑑別碼實現鑑別的原理是,用公開函數和**產生一個固定長度的值作爲認證標識,用這個 標識鑑別消息的完整性。使用一個**生成一個固定大小的小數據塊,即MAC,並將其加入到消息中,然後傳輸。接收方利用與發送方共享的**進行鑑別認證 等。
通過java代碼實現如下:
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
|
/**
* 初始化HMAC**
*
* @return
* @throws Exception
*/
public
static
String initMacKey()
throws
Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
SecretKey secretKey = keyGenerator.generateKey();
return
encryptBASE64(secretKey.getEncoded());
}
/**
* HMAC加密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public
static
byte
[] encryptHMAC(
byte
[] data, String key)
throws
Exception {
SecretKey secretKey =
new
SecretKeySpec(decryptBASE64(key), KEY_MAC);
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return
mac.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
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
|
import
java.security.MessageDigest;
import
javax.crypto.KeyGenerator;
import
javax.crypto.Mac;
import
javax.crypto.SecretKey;
import
sun.misc.BASE64Decoder;
import
sun.misc.BASE64Encoder;
/**
* 基礎加密組件
*
* @author 樑棟
* @version 1.0
* @since 1.0
*/
public
abstract
class
Coder {
public
static
final
String KEY_SHA =
"SHA"
;
public
static
final
String KEY_MD5 =
"MD5"
;
/**
* MAC算法可選以下多種算法
*
* <pre>
* HmacMD5
* HmacSHA1
* HmacSHA256
* HmacSHA384
* HmacSHA512
* </pre>
*/
public
static
final
String KEY_MAC =
"HmacMD5"
;
/**
* BASE64解密
*
* @param key
* @return
* @throws Exception
*/
public
static
byte
[] decryptBASE64(String key)
throws
Exception {
return
(
new
BASE64Decoder()).decodeBuffer(key);
}
/**
* BASE64加密
*
* @param key
* @return
* @throws Exception
*/
public
static
String encryptBASE64(
byte
[] key)
throws
Exception {
return
(
new
BASE64Encoder()).encodeBuffer(key);
}
/**
* MD5加密
*
* @param data
* @return
* @throws Exception
*/
public
static
byte
[] encryptMD5(
byte
[] data)
throws
Exception {
MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
md5.update(data);
return
md5.digest();
}
/**
* SHA加密
*
* @param data
* @return
* @throws Exception
*/
public
static
byte
[] encryptSHA(
byte
[] data)
throws
Exception {
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
sha.update(data);
return
sha.digest();
}
/**
* 初始化HMAC**
*
* @return
* @throws Exception
*/
public
static
String initMacKey()
throws
Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
SecretKey secretKey = keyGenerator.generateKey();
return
encryptBASE64(secretKey.getEncoded());
}
/**
* HMAC加密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public
static
byte
[] encryptHMAC(
byte
[] data, String key)
throws
Exception {
SecretKey secretKey =
new
SecretKeySpec(decryptBASE64(key), KEY_MAC);
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return
mac.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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
import
static
org.junit.Assert.*;
import
org.junit.Test;
/**
*
* @author 樑棟
* @version 1.0
* @since 1.0
*/
public
class
CoderTest {
@Test
public
void
test()
throws
Exception {
String inputStr =
"簡單加密"
;
System.err.println(
"原文:\n"
+ inputStr);
byte
[] inputData = inputStr.getBytes();
String code = Coder.encryptBASE64(inputData);
System.err.println(
"BASE64加密後:\n"
+ code);
byte
[] output = Coder.decryptBASE64(code);
String outputStr =
new
String(output);
System.err.println(
"BASE64解密後:\n"
+ outputStr);
// 驗證BASE64加密解密一致性
assertEquals(inputStr, outputStr);
// 驗證MD5對於同一內容加密是否一致
assertArrayEquals(Coder.encryptMD5(inputData), Coder
.encryptMD5(inputData));
// 驗證SHA對於同一內容加密是否一致
assertArrayEquals(Coder.encryptSHA(inputData), Coder
.encryptSHA(inputData));
String key = Coder.initMacKey();
System.err.println(
"Mac**:\n"
+ key);
// 驗證HMAC對於同一內容,同一**加密是否一致
assertArrayEquals(Coder.encryptHMAC(inputData, key), Coder.encryptHMAC(
inputData, key));
BigInteger md5 =
new
BigInteger(Coder.encryptMD5(inputData));
System.err.println(
"MD5:\n"
+ md5.toString(
16
));
BigInteger sha =
new
BigInteger(Coder.encryptSHA(inputData));
System.err.println(
"SHA:\n"
+ sha.toString(
32
));
BigInteger mac =
new
BigInteger(Coder.encryptHMAC(inputData, inputStr));
System.err.println(
"HMAC:\n"
+ mac.toString(
16
));
}
}
|
控制檯輸出:
原文: 簡單加密 BASE64加密後: 566A5Y2V5Yqg5a+G BASE64解密後: 簡單加密 Mac**: uGxdHC+6ylRDaik++leFtGwiMbuYUJ6mqHWyhSgF4trVkVBBSQvY/a22xU8XT1RUemdCWW155Bke pBIpkd7QHg== MD5: -550b4d90349ad4629462113e7934de56 SHA: 91k9vo7p400cjkgfhjh0ia9qthsjagfn HMAC: 2287d192387e95694bdbba2fa941009a
注意
編譯時,可能會看到如下提示:
引用
警告:sun.misc.BASE64Decoder 是 Sun 的專用 API,可能會在未來版本中刪除
import sun.misc.BASE64Decoder;
^
警告:sun.misc.BASE64Encoder 是 Sun 的專用 API,可能會在未來版本中刪除
import sun.misc.BASE64Encoder;
^
BASE64Encoder 和BASE64Decoder是非官方JDK實現類。雖然可以在JDK裏能找到並使用,但是在API裏查不到。JRE 中 sun 和 com.sun 開頭包的類都是未被文檔化的,他們屬於 java, javax 類庫的基礎,其中的實現大多數與底層平臺有關,一般來說是不推薦使用的。
BASE64的加密解密是雙向的,可以求反解。
MD5、SHA以及HMAC是單向加密,任何數據加密後只會產生唯一的一個加密串,通常用來校驗數據在傳輸過程中是否被修改。其中HMAC算法有一個**,增強了數據傳輸過程中的安全性,強化了算法外的不可控因素。
單向加密的用途主要是爲了校驗數據在傳輸過程中是否被修改。
接下來我們介紹對稱加密算法,最常用的莫過於DES數據加密算法。
DES
DES-Data Encryption Standard,即數據加密算法。是IBM公司於1975年研究成功並公開發表的。DES算法的入口參數有三個:Key、Data、Mode。其中 Key爲8個字節共64位,是DES算法的工作**;Data也爲8個字節64位,是要被加密或被解密的數據;Mode爲DES的工作方式,有兩種:加密 或解密。
DES算法把64位的明文輸入塊變爲64位的密文輸出塊,它所使用的**也是64位。
通過java代碼實現如下:Coder類見
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
後續我們會介紹非對稱加密算法,如RSA、DSA、DH、ECC等。
接下來我們介紹典型的非對稱加密算法——RSA
RSA
這種算法1978年就出現了,它是第一個既能用於數據加密也能用於數字簽名的算法。它易於理解和操作,也很流行。算法的名字以發明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。
這種加密算法的特點主要是**的變化,上文我們看到DES只有一個**。相當於只有一把鑰匙,如果這把鑰匙丟了,數據也就不安全了。RSA同時有兩把鑰 匙,公鑰與私鑰。同時支持數字簽名。數字簽名的意義在於,對傳輸過來的數據進行校驗。確保數據在傳輸工程中不被修改。
流程分析:
甲方構建**對兒,將公鑰公佈給乙方,將私鑰保留。
甲方使用私鑰加密數據,然後用私鑰對加密後的數據簽名,發送給乙方簽名以及加密後的數據;乙方使用公鑰、簽名來驗證待解密數據是否有效,如果有效使用公鑰對數據解密。
乙方使用公鑰加密數據,向甲方發送經過加密後的數據;甲方獲得加密數據,通過私鑰解密。
按如上步驟給出序列圖,如下:
通過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/QF2Mx0Zxt8Xsg7ucv*n 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());
}
/**
* 取得公鑰
* </
|