非對稱密碼概念
1、與對稱加密算法的主要差別在于,加密和解密的密鑰不相同,一個公開(公鑰),一個保密(私鑰)。主要解決了對稱加密算法密鑰分配管理的問題,提高了算法安全性。
2、非對稱加密算法的加密、解密的效率比較低。在算法設計上,非對稱加密算法對待加密的數據長度有著苛刻的要求。例如RSA算法要求待加密的數據不得大于53個字節。
3、非對稱加密算法主要用于 交換對稱加密算法的密鑰,而非數據交換
4、java6提供實現了DH和RSA兩種算法。Bouncy Castle提供了E1Gamal算法支持。除了上述三種算法還有一個ECC算法,目前沒有相關的開源組件提供支持
需要兩個密鑰進行加密或解密,分為公鑰和私鑰
特點:安全性高,速度慢
用途
【密鑰交換(DH)】
雙方在沒有確定共同密鑰的情況下,生成密鑰,不提供加密工作,加解密還需要其他對稱加密算法實現
DH算法示例
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
|
import javax.crypto.KeyAgreement; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; //1 生成源密鑰 //2 把源公鑰交給目標,目標通過源公鑰,生成目標公鑰和私鑰 //3 把目標公鑰交給源 //4 雙方使用對方的公鑰和和自己的私鑰,生成本地密鑰 //5 如果雙方生成本地密鑰相同則完成密鑰交換 public class DHUtil { public static final String PUBLIC_KEY = "DH_Public_Key" ; public static final String PRIVATE_KEY = "DH_Private_key" ; /** * 生成源密鑰對 * @return * @throws Exception */ public static Map<String,Object> initSourceKey() throws Exception{ //創建KeyPairGenerator的實例,選用DH算法 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "DH" ); //初始化密鑰長度,默認1024,可選范圍512-65536 & 64的倍數 keyPairGenerator.initialize( 1024 ); //生成密鑰對 KeyPair keyPair = keyPairGenerator.generateKeyPair(); DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate(); //將密鑰對放入Map Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, dhPublicKey); keyMap.put(PRIVATE_KEY, dhPrivateKey); return keyMap; } /** * 通過源公鑰 生成 目標密鑰對 * @param sourcePublicKey * @return * @throws Exception */ public static Map<String,Object> initTargetKey( byte [] sourcePublicKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance( "DH" ); //通過源公鑰,生成keySpec,使用KeyFactory生成源PublicKey相關信息 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(sourcePublicKey); DHPublicKey sourcePublic = (DHPublicKey) keyFactory.generatePublic(keySpec); DHParameterSpec dhPublicKeyParams = sourcePublic.getParams(); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "DH" ); keyPairGenerator.initialize(dhPublicKeyParams); KeyPair keyPair = keyPairGenerator.generateKeyPair(); DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate(); //將密鑰對放入Map Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, dhPublicKey); keyMap.put(PRIVATE_KEY, dhPrivateKey); return keyMap; } /** * 使用一方的公鑰和另一方的私鑰,生成本地密鑰 * @return */ public static byte [] generateLocalSecretKey( byte [] aPublicKey, byte [] bPrivateKey) throws Exception{ KeyFactory keyFactory = KeyFactory.getInstance( "DH" ); //通過A公鑰,生成keySpec,使用KeyFactory生成A PublicKey相關信息 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(aPublicKey); PublicKey publicKey = keyFactory.generatePublic(keySpec); //通過B私鑰,生成B PrivateKey相關信息 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bPrivateKey); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //通過KeyAgreement對A的PublicKey和B的PrivateKey進行加密 KeyAgreement keyAgreement = KeyAgreement.getInstance( "DH" ); keyAgreement.init(privateKey); keyAgreement.doPhase(publicKey, true ); return keyAgreement.generateSecret( "AES" ).getEncoded(); //算法使用對稱加密算法(DES,DESede,AES) //return keyAgreement.generateSecret(); // 也可以不選擇算法,使用默認方法計算 } //獲取公鑰字節數組 public static byte [] getPublicKey(Map<String,Object> map){ return ((DHPublicKey) map.get(PUBLIC_KEY)).getEncoded(); } //獲取私鑰字節數組 public static byte [] getPrivateKey(Map<String,Object> map){ return ((DHPrivateKey) map.get(PRIVATE_KEY)).getEncoded(); } public static void main(String[] args) throws Exception { byte [] source_public_key; byte [] source_private_key; byte [] source_local_key; byte [] target_public_key; byte [] target_private_key; byte [] target_local_key; Map<String, Object> sourceKey = initSourceKey(); source_public_key = getPublicKey(sourceKey); source_private_key = getPrivateKey(sourceKey); System.out.println( "源公鑰:" +BytesToHex.fromBytesToHex(source_public_key)); System.out.println( "源私鑰:" +BytesToHex.fromBytesToHex(source_private_key)); Map<String, Object> targetKey = initTargetKey(getPublicKey(sourceKey)); target_public_key = getPublicKey(targetKey); target_private_key = getPrivateKey(targetKey); System.out.println( "目標公鑰:" +BytesToHex.fromBytesToHex(target_public_key)); System.out.println( "目標私鑰:" +BytesToHex.fromBytesToHex(target_private_key)); source_local_key = generateLocalSecretKey(target_public_key, source_private_key); target_local_key = generateLocalSecretKey(source_public_key, target_private_key); System.out.println( "源本地密鑰:" +BytesToHex.fromBytesToHex(source_local_key)); System.out.println( "目標本地密鑰:" +BytesToHex.fromBytesToHex(target_local_key)); } } |
【加密/解密(RSA)】【數字簽名(RSA)】
RSA算法晚于DH算法,這五個字母全都是人名首字母.DH算法是第一個非對稱密碼體系.
RSA算法運算速度慢,不適宜加密大量數據.一種解決方案是,將RSA跟對稱加密方式混合使用,將數據使用對稱加密方式加密,對稱加密的密鑰使用RSA算法加密,因為密鑰很短,所以時間費不了太多.實際上,對稱加密方式唯一的弊端就是密鑰不好傳遞,對稱加密方式也很難破解.
RSA的適用情景一:
(1)服務器生成一個公鑰和一個私鑰,把公鑰公開了.
(2)客戶端使用公鑰把數據進行加密,上交服務器.別人是沒法理解加密后的數據的.
(3)服務器使用私鑰將數據解密,查看用戶提交的數據.
這種情景下,公鑰像是一個信箱,每個人都可以往這個信箱里面放信,但是這個信箱里面的信只有掌握信箱鑰匙的人才能開箱查看.
RSA適用情景二:
(1)皇上生成一個公鑰和一個密鑰,把公鑰公開了.
(2)皇上發布了一封詔書,昭告天下.詔書右下角有兩串數字,第一串數字是一個隨機串,第二串數字是用私鑰加密第一串數字所得的結果.
(3)有人不相信這詔書是皇上寫的,就把第二串數字使用公鑰解密,解密之后發現跟第一串數字一樣,說明確實是皇上寫的,因為一般人沒有密鑰,也就沒法加密那些能夠用公鑰解密的數據.
這種情境下,公鑰用于解密,私鑰用于加密,這可以用于發布公告時,證明這個公告確實是某個人發的.相當于簽名.
實際上,簽名沒有必要特別長,一般情況下,簽名是定長的,要想定長,可以使用MessageDigest算法,如MD5和SHA系列.所以就有了多種簽名算法,如MD5withRSA等.
RSA 加密/解密 示例
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
|
import javax.crypto.Cipher; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.HashMap; import java.util.Map; /** * RSA加密工具 */ public class RSAUtil { public static final String PUBLIC_KEY = "RSA_Public_Key" ; public static final String PRIVATE_KEY = "RSA_Private_Key" ; /** * 初始化密鑰 * @return * @throws Exception */ public static Map<String,Object> initKey() throws Exception{ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "RSA" ); keyPairGenerator.initialize( 1024 ); //512-65536 & 64的倍數 KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } public static RSAPublicKey getPublicKey(Map<String,Object> keyMap) { return (RSAPublicKey) keyMap.get(PUBLIC_KEY); } public static RSAPrivateKey getPrivateKey(Map<String,Object> keyMap){ return (RSAPrivateKey) keyMap.get(PRIVATE_KEY); } /** * 使用公鑰對數據進行加密 * @param data * @param publicKey * @return * @throws Exception */ public static byte [] encrypt( byte [] data, RSAPublicKey publicKey) throws Exception{ Cipher cipher = Cipher.getInstance( "RSA" ); cipher.init(Cipher.ENCRYPT_MODE,publicKey); return cipher.doFinal(data); } /** * 使用私鑰解密 * @param data * @param privateKey * @return * @throws Exception */ public static byte [] decrypt( byte [] data, RSAPrivateKey privateKey) throws Exception{ Cipher cipher = Cipher.getInstance( "RSA" ); cipher.init(Cipher.DECRYPT_MODE,privateKey); return cipher.doFinal(data); } public static void main(String[] args) throws Exception { String data = "周杰倫-東風破" ; Map<String, Object> keyMap = initKey(); byte [] miwen = encrypt(data.getBytes(),getPublicKey(keyMap)); System.out.println( "加密后的內容:" +BytesToHex.fromBytesToHex(miwen)); byte [] plain = decrypt(miwen, getPrivateKey(keyMap)); System.out.println( "解密后的內容:" + new String(plain)); } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。