加密,是以某種特殊的算法改變原有的信息數據,使得未授權的用戶即使獲得了已加密的信息,但因不知解密的方法,仍然無法了解信息的內容。大體上分為雙向加密和單向加密,而雙向加密又分為對稱加密和非對稱加密(有些資料將加密直接分為對稱加密和非對稱加密)。
雙向加密大體意思就是明文加密后形成密文,可以通過算法還原成明文。而單向加密只是對信息進行了摘要計算,不能通過算法生成明文,單向加密從嚴格意思上說不能算是加密的一種,應該算是摘要算法吧。
具體來說:
系統必須可用,非數學上不可譯碼。
系統不一定要保密,可以輕易落入敵人手中。
密匙必須可以不經書寫的資料交換和記憶,且雙方可以改變密匙。
系統可以用于電訊。
系統可以轉移位置,它的功能必須不用經過幾個人之手才可達到。
系統容易使用,不要求使用者的腦力過份操勞或有很多的規則。
一、主要的加密方式代碼提供方
JDK:代碼在java安裝目錄下的jre\lib\jce.jar包里;
CC:Apache公司提供的org.apache.commons.codec
主頁: http://commons.apache.org/proper/commons-codec/
BC:org.bouncecastle
主頁: http://www.bouncycastle.org/java.html
基本常用的使用JDK就夠了。
二、Base64算法
1、從現在加密算法的復雜性來看Base64這種都不好意思說自己是加密,不過對于完全不懂計算機的人來說也夠用了。采用Base64編碼具有不可讀性,即所編碼的數據不會被人用肉眼所直接看到。
Base64編碼一般用于url的處理,或者說任何你不想讓普通人一眼就知道是啥的東西都可以用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
|
package com.amuro.strategy.base64; import java.util.Base64; import com.amuro.strategy.IStrategy; /** * Base64算法基于64個基本字符,加密后的string中只包含這64個字符 * @author Amuro * */ public class Base64Strategy implements IStrategy { public String encode(String src) { byte [] encodeBytes = Base64.getEncoder().encode(src.getBytes()); return new String(encodeBytes); } public String decode(String src) { byte [] decodeBytes = Base64.getDecoder().decode(src.getBytes()); return new String(decodeBytes); } } |
2、Base64編碼對應關系表
三、消息摘要算法(Message Digest)
消息摘要(Message Digest)又稱為數字摘要(Digital Digest)。它是一個唯一對應一個消息或文本的固定長度的值,它由一個單向Hash加密函數對消息進行作用而產生。HASH函數的抗沖突性使得如果一段明文稍有變化,哪怕只更改該段落的一個字母,通過哈希算法作用后都將產生不同的值。而HASH算法的單向性使得要找到哈希值相同的兩個不同的輸入消息,在計算上是不可能的。所以數據的哈希值,即消息摘要,可以檢驗數據的完整性。
用大白話來說,任何一段數據應該都和人一樣是唯一的,唯一的標識是什么,人類的話目前就是指紋,而數據的指紋是什么呢?沒錯,就是消息摘要算法產生的這一段String。比如我們在注冊網站的時候,客戶端向服務器傳輸的,應該是我們輸入的密碼進行消息摘要處理后的內容,這樣就算服務器被攻破,Hack也無法知道用戶真實的密碼是什么。不過有說現在MD5和SHA已經被攻破了,具體大家可以谷歌。
1、MD5
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
|
package com.amuro.strategy.message_digest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; /** * 消息摘要算法 * @author Amuro * */ public class MD5Strategy implements IStrategy { public String encode(String src) { try { MessageDigest md = MessageDigest.getInstance( "MD5" ); byte [] encodeBytes = md.digest(src.getBytes()); return Hex.encodeHexString(encodeBytes); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null ; } public String decode(String src) { throw new RuntimeException( "MD5 no decode" ); } } |
2、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
35
36
37
38
|
package com.amuro.strategy.message_digest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; /** * 安全散列算法 * @author Amuro * */ public class SHAStrategy implements IStrategy { public String encode(String src) { try { MessageDigest md = MessageDigest.getInstance( "SHA" ); md.update(src.getBytes()); return Hex.encodeHexString(md.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null ; } public String decode(String src) { throw new RuntimeException( "SHA no decode" ); } } |
四、對稱加密
采用單鑰密碼系統的加密方法,同一個密鑰可以同時用作信息的加密和解密,這種加密方法稱為對稱加密,也稱為單密鑰加密。而因為加密和解密都使用同一個密鑰,如何把密鑰安全地傳遞到解密者手上就成了必須要解決的問題。當然,安全性較低帶來的優點就是優計算量小、加密速度快、加密效率高。
然并卵,現代計算機對這種級別的計算量早就不care了,安全才是最重要的。
1、DES
DES,全稱為“Data Encryption Standard”,中文名為“數據加密標準”,是一種使用密鑰加密的塊算法。DES 算法為密碼體制中的對稱密碼體制,又被稱為美國數據加密標準,是 1972 年美國 IBM 公司研制的對稱密碼體制加密算法。 明文按 64 位進行分組,密鑰長 64 位,密鑰事實上是 56 位參與 DES 運算(第8、16、24、32、40、48、56、64 位是校驗位, 使得每個密鑰都有奇數個 1)分組后的明文組和 56 位的密鑰按位替代或交換的方法形成密文組的加密方法。
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
|
package com.amuro.strategy.des; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; /** * * @author Amuro * */ public class DESStrategy implements IStrategy { private Cipher cipher; private SecretKey generateKey; public String encode(String src) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance( "DES" ); keyGenerator.init( 56 ); //size SecretKey secretKey = keyGenerator.generateKey(); byte [] keyBytes = secretKey.getEncoded(); DESKeySpec desKeySpec = new DESKeySpec(keyBytes); SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance( "DES" ); generateKey = secretKeyFactory.generateSecret(desKeySpec); cipher = Cipher.getInstance( "DES/ECB/PKCS5Padding" ); cipher.init(Cipher.ENCRYPT_MODE, generateKey); byte [] resultBytes = cipher.doFinal(src.getBytes()); return Hex.encodeHexString(resultBytes); } catch (Exception e) { e.printStackTrace(); } return null ; } public String decode(String src) { try { cipher.init(Cipher.DECRYPT_MODE, generateKey); byte [] result = Hex.decodeHex(src.toCharArray()); return new String(cipher.doFinal(result)); } catch (Exception e) { e.printStackTrace(); } return null ; } } |
2、3DES3DES,也就是“Triple DES”,中文名“三重數據加密算法”,它相當于是對每個數據塊應用三次 DES 加密算法。由于計算機運算能力的增強,原版 DES 密碼的密鑰長度變得容易被暴力破解;3DES 即是設計用來提供一種相對簡單的方法,即通過增加 DES 的密鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼算法。
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
|
package com.amuro.strategy.des; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; public class _3DESStrategy implements IStrategy { private Cipher cipher; private SecretKey generateKey; public String encode(String src) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance( "DESede" ); keyGenerator.init( 168 ); //size SecretKey secretKey = keyGenerator.generateKey(); byte [] keyBytes = secretKey.getEncoded(); DESedeKeySpec desKeySpec = new DESedeKeySpec(keyBytes); SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance( "DESede" ); generateKey = secretKeyFactory.generateSecret(desKeySpec); cipher = Cipher.getInstance( "DESede/ECB/PKCS5Padding" ); cipher.init(Cipher.ENCRYPT_MODE, generateKey); byte [] resultBytes = cipher.doFinal(src.getBytes()); return Hex.encodeHexString(resultBytes); } catch (Exception e) { e.printStackTrace(); } return null ; } public String decode(String src) { try { cipher.init(Cipher.DECRYPT_MODE, generateKey); byte [] result = Hex.decodeHex(src.toCharArray()); return new String(cipher.doFinal(result)); } catch (Exception e) { e.printStackTrace(); } return null ; } } |
3、AESAES,全稱為“Advanced Encryption Standard”,中文名“高級加密標準”,在密碼學中又稱 Rijndael 加密法,是美國聯邦政府采用的一種區塊加密標準。AES 加密算法作為新一代的數據加密標準匯聚了強安全性、高性能、高效率、易用和靈活等優點。AES 設計有三個密鑰長度:128,192,256 位。相對而言,AES 的 128 密鑰比 DES 的 56 密鑰強了 1021 倍。
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
|
package com.amuro.strategy.des; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; public class AESStrategy implements IStrategy { private Cipher cipher; private SecretKey generateKey; public String encode(String src) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance( "AES" ); keyGenerator.init( 128 ); //size SecretKey secretKey = keyGenerator.generateKey(); byte [] keyBytes = secretKey.getEncoded(); generateKey = new SecretKeySpec(keyBytes, "AES" ); cipher = Cipher.getInstance( "AES/ECB/PKCS5Padding" ); cipher.init(Cipher.ENCRYPT_MODE, generateKey); byte [] resultBytes = cipher.doFinal(src.getBytes()); return Hex.encodeHexString(resultBytes); } catch (Exception e) { e.printStackTrace(); } return null ; } public String decode(String src) { try { cipher.init(Cipher.DECRYPT_MODE, generateKey); byte [] result = Hex.decodeHex(src.toCharArray()); return new String(cipher.doFinal(result)); } catch (Exception e) { e.printStackTrace(); } return null ; } } |
4、PBE
PBE,全稱為“Password Base Encryption”,中文名“基于口令加密”,是一種基于密碼的加密算法,其特點是使用口令代替了密鑰,而口令由用戶自己掌管,采用隨機數雜湊多重加密等方法保證數據的安全性。
PBE算法沒有密鑰的概念,把口令當做密鑰了。因為密鑰長短影響算法安全性,還不方便記憶,這里我們直接換成我們自己常用的口令就大大不同了,便于我們的記憶。但是單純的口令很容易被字典法給窮舉出來,所以我們這里給口令加了點“鹽”,這個鹽和口令組合,想破解就難了。同時我們將鹽和口令合并后用消息摘要算法進行迭代很多次來構建密鑰初始化向量的基本材料,使破譯更加難了。
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
|
package com.amuro.strategy.pbe; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; /** * 基于口令的加密(password),對稱 + 消息摘要 * @author Amuro * */ public class PBEStrategy implements IStrategy { private Cipher cipher; private SecretKey generateKey; private PBEParameterSpec pbeParameterSpec; public String encode(String src) { try { SecureRandom secureRandom = new SecureRandom(); byte [] salt = secureRandom.generateSeed( 8 ); String password = "amuro" ; PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance( "PBEWITHMD5andDES" ); generateKey = secretKeyFactory.generateSecret(pbeKeySpec); pbeParameterSpec = new PBEParameterSpec(salt, 100 ); cipher = Cipher.getInstance( "PBEWITHMD5andDES" ); cipher.init(Cipher.ENCRYPT_MODE, generateKey, pbeParameterSpec); byte [] resultBytes = cipher.doFinal(src.getBytes()); return Hex.encodeHexString(resultBytes); } catch (Exception e) { e.printStackTrace(); } return null ; } public String decode(String src) { try { cipher.init(Cipher.DECRYPT_MODE, generateKey, pbeParameterSpec); byte [] result = Hex.decodeHex(src.toCharArray()); return new String(cipher.doFinal(result)); } catch (Exception e) { e.printStackTrace(); } return null ; } } |
五、非對稱加密
非對稱加密算法需要兩個密鑰來進行加密和解密,分別是公鑰和私鑰。需要注意的一點,這個公鑰和私鑰必須是一對的,如果用公鑰對數據進行加密,那么只有使用對應的私鑰才能解密,反之亦然。由于加密和解密使用的是兩個不同的密鑰,因此,這種算法叫做非對稱加密算法。
1、RSA
其實,在早在 1978 年的時候,RSA就已經出現了,它是第一個既能用于數據加密也能用于數字簽名的算法。它易于理解和操作,也很流行。其原理就如上面的工作過程所述。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
82
83
84
85
86
87
88
89
90
91
92
93
94
|
package com.amuro.strategy.asymmetric; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; public class RSAStrategy implements IStrategy { private RSAPublicKey rsaPublicKey; private RSAPrivateKey rsaPrivateKey; public String encode(String src) { try { //初始化密鑰 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "RSA" ); keyPairGenerator.initialize( 512 ); KeyPair keyPair = keyPairGenerator.generateKeyPair(); rsaPublicKey = (RSAPublicKey)keyPair.getPublic(); rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate(); //私鑰加密 公鑰解密 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance( "RSA" ); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Cipher cipher = Cipher.getInstance( "RSA" ); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte [] resultBytes = cipher.doFinal(src.getBytes()); //私鑰解密 公鑰加密 // X509EncodedKeySpec x509EncodedKeySpec = // new X509EncodedKeySpec(rsaPublicKey.getEncoded()); // KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); // Cipher cipher = Cipher.getInstance("RSA"); // cipher.init(Cipher.ENCRYPT_MODE, publicKey); // byte[] resultBytes = cipher.doFinal(src.getBytes()); return Hex.encodeHexString(resultBytes); } catch (Exception e) { e.printStackTrace(); } return null ; } public String decode(String src) { try { //私鑰加密 公鑰解密 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance( "RSA" ); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); Cipher cipher = Cipher.getInstance( "RSA" ); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte [] resultBytes = cipher.doFinal(Hex.decodeHex(src.toCharArray())); //私鑰解密 公鑰加密 // PKCS8EncodedKeySpec pkcs8EncodedKeySpec // = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); // KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); // Cipher cipher = Cipher.getInstance("RSA"); // cipher.init(Cipher.DECRYPT_MODE, privateKey); // byte[] resultBytes = cipher.doFinal(Hex.decodeHex(src.toCharArray())); return new String(resultBytes); } catch (Exception e) { e.printStackTrace(); } return null ; } } |
2、DH算法
DH,全稱為“Diffie-Hellman”,他是一種確保共享KEY安全穿越不安全網絡的方法,也就是常說的密鑰一致協議。由公開密鑰密碼體制的奠基人Diffie和Hellman所提出的一種思想。簡單的說就是允許兩名用戶在公開媒體上交換信息以生成“一致”的、可以共享的密鑰。也就是由甲方產出一對密鑰(公鑰、私鑰),乙方依照甲方公鑰產生乙方密鑰對(公鑰、私鑰)。
以此為基線,作為數據傳輸保密基礎,同時雙方使用同一種對稱加密算法構建本地密鑰(SecretKey)對數據加密。這樣,在互通了本地密鑰(SecretKey)算法后,甲乙雙方公開自己的公鑰,使用對方的公鑰和剛才產生的私鑰加密數據,同時可以使用對方的公鑰和自己的私鑰對數據解密。不單單是甲乙雙方兩方,可以擴展為多方共享數據通訊,這樣就完成了網絡交互數據的安全通訊!
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
|
package com.amuro.strategy.asymmetric; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Objects; import javax.crypto.Cipher; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import org.apache.commons.codec.binary.Hex; import com.amuro.strategy.IStrategy; public class DHStrategy implements IStrategy { private Cipher cipher; private SecretKey receiverSecretKey; public String encode(String src) { try { //初始化發送方密鑰 KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance( "DH" ); senderKeyPairGenerator.initialize( 512 ); KeyPair senderkeyPair = senderKeyPairGenerator.generateKeyPair(); PrivateKey senderPrivateKey = senderkeyPair.getPrivate(); byte [] senderPublicKeyBytes = senderkeyPair.getPublic().getEncoded(); //發送方的公鑰 //初始化接收方密鑰,用發送方的公鑰 KeyFactory receiverKeyFactory = KeyFactory.getInstance( "DH" ); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyBytes); PublicKey receiverPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec); DHParameterSpec dhParameterSpec = ((DHPublicKey)receiverPublicKey).getParams(); KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance( "DH" ); receiverKeyPairGenerator.initialize(dhParameterSpec); KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair(); PrivateKey receiverPrivateKey = receiverKeyPair.getPrivate(); byte [] receiverPublicKeyBytes = receiverKeyPair.getPublic().getEncoded(); KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance( "DH" ); receiverKeyAgreement.init(receiverPrivateKey); receiverKeyAgreement.doPhase(receiverPublicKey, true ); receiverSecretKey = receiverKeyAgreement.generateSecret( "DES" ); //發送方拿到接收方的public key就可以做加密了 KeyFactory senderKeyFactory = KeyFactory.getInstance( "DH" ); x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyBytes); PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec); KeyAgreement senderKeyAgreement = KeyAgreement.getInstance( "DH" ); senderKeyAgreement.init(senderPrivateKey); senderKeyAgreement.doPhase(senderPublicKey, true ); SecretKey senderSecretKey = senderKeyAgreement.generateSecret( "DES" ); if (Objects.equals(receiverSecretKey, senderSecretKey)) { cipher = Cipher.getInstance( "DES" ); cipher.init(Cipher.ENCRYPT_MODE, senderSecretKey); byte [] result = cipher.doFinal(src.getBytes()); return Hex.encodeHexString(result); } } catch (Exception e) { e.printStackTrace(); } return null ; } public String decode(String src) { try { cipher.init(Cipher.DECRYPT_MODE, receiverSecretKey); byte [] result = Hex.decodeHex(src.toCharArray()); return new String(cipher.doFinal(result)); } catch (Exception e) { e.printStackTrace(); } return null ; } } |
六、數字簽名證書
非對稱加密已經灰常安全了,但是還有一個破綻:
服務器A公布了自己的公鑰,我的電腦是用服務器A的公鑰加密數據后再發給服務器A的;這時候服務器B侵入了我的電腦,把我用來加密的公鑰換成了它的公鑰,于是我發出去的數據就會被服務器B的私鑰破解了。腫么防止公鑰被篡改呢?
對,我們想到了前面的消息摘要,服務器A把公鑰丟給我的時候,同時去CA申請一份數字證書,其實主要就是公鑰的消息摘要,有了這份證書,當我再用公鑰加密的時候,我就可以先驗證一下當前的公鑰是否確定是服務器A發送給我的。
這里就貼一種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
|
package com.amuro.strategy.signature; 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; public class RSASign { public static boolean verifySign(String src) { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "RSA" ); keyPairGenerator.initialize( 512 ); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic(); PrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate(); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance( "RSA" ); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance( "MD5withRSA" ); signature.initSign(privateKey); signature.update(src.getBytes()); //生成簽名bytes byte [] signBytes = signature.sign(); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); keyFactory = KeyFactory.getInstance( "RSA" ); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); signature = Signature.getInstance( "MD5withRSA" ); signature.initVerify(publicKey); signature.update(src.getBytes()); boolean isVerified = signature.verify(signBytes); return isVerified; } catch (Exception e) { e.printStackTrace(); } return false ; } } |
關于數字簽名和非對稱加密算法的使用,還看到一個非常棒的例子,分享給大家:
唉,這個月買了太多的書,到月底揭不開鍋了。正巧在QQ上遇到了Clark:
1-2-3:“Clark,我需要200兩紋銀,能否借給我?”
Clark:“沒問題。我這就給你轉賬。請給我一張借條。”
1-2-3:“太謝謝了,我這就用Word寫一個借條給你。”
然后,我新建一個Word文檔,寫好借條,存盤。然后,然后怎么辦呢?我不能直接把借條發送給Clark,原因有:
1. 我無法保證Clark不會在收到借條后將“紋銀200兩”改為“紋銀2000兩”。
2. 如果我賴賬,Clark無法證明這個借條就是我寫的。
3. 普通的Word文檔不能作為打官司的證據。
好在我早就申請了數字證書。我先用我的私鑰對借條進行加密,然后將加密后的密文用QQ發送給Clark。Clark收到了借條的密文后,在數字證書認證中心的網站上下載我的公鑰,然后使用我的公鑰將密文解密,發現確實寫的是“借紋銀200兩”,Clark就可以把銀子放心的借給我了,我也不會擔心Clark會篡改我的借條,原因是:
1. 由于我發給Clark的是密文,Clark無法進行修改。Clark倒是可以修改解密后的借條,但是Clark沒有我的私鑰,沒法模仿我對借條進行加密。這就叫防篡改。
2. 由于用我的私鑰進行加密的借條,有且只有我的公鑰可以解密。反過來講,能用我的公鑰解密的借條,一定是使用我的私鑰加密的,而只有我才擁有我的私鑰,這樣Clark就可以證明這個借條就是我寫的。這就叫防抵賴。
3. 如果我一直賴著不還錢,Clark把我告上了法庭,這個用我的私鑰加密過的Word文檔就可以當作程堂證供。因為我國已經出臺了《中華人民共和國電子簽名法》,使數字簽名具有了法律效力。
您一定已經注意到了,這個使用我的私鑰進行了加密的借條,具有了防篡改、防抵賴的特性,并且可以作為程堂證供,就跟我對這個借條進行了“簽名”的效果是一樣的。對了,“使用我的私鑰對借條進行加密”的過程就叫做數字簽名。
這是一篇總結類文章,把一些常用的Java加密技術和核心代碼寫在這邊,供給需要朋友參考。