總結(jié)Java常用到的六個(gè)加密技術(shù)和代碼
加密,是以某種特殊的算法改變?cè)械男畔?shù)據(jù),使得未授權(quán)的用戶(hù)即使獲得了已加密的信息,但因不知解密的方法,仍然無(wú)法了解信息的內(nèi)容。大體上分為雙向加密和單向加密,而雙向加密又分為對(duì)稱(chēng)加密和非對(duì)稱(chēng)加密(有些資料將加密直接分為對(duì)稱(chēng)加密和非對(duì)稱(chēng)加密)。
雙向加密大體意思就是明文加密后形成密文,可以通過(guò)算法還原成明文。而單向加密只是對(duì)信息進(jìn)行了摘要計(jì)算,不能通過(guò)算法生成明文,單向加密從嚴(yán)格意思上說(shuō)不能算是加密的一種,應(yīng)該算是摘要算法吧。
具體來(lái)說(shuō):
系統(tǒng)必須可用,非數(shù)學(xué)上不可譯碼。
系統(tǒng)不一定要保密,可以輕易落入敵人手中。
密匙必須可以不經(jīng)書(shū)寫(xiě)的資料交換和記憶,且雙方可以改變密匙。
系統(tǒng)可以用于電訊。
系統(tǒng)可以轉(zhuǎn)移位置,它的功能必須不用經(jīng)過(guò)幾個(gè)人之手才可達(dá)到。
系統(tǒng)容易使用,不要求使用者的腦力過(guò)份操勞或有很多的規(guī)則。
一、主要的加密方式代碼提供方
JDK:代碼在java安裝目錄下的jre\lib\jce.jar包里;
CC:Apache公司提供的org.apache.commons.codec
主頁(yè): http://commons.apache.org/proper/commons-codec/
BC:org.bouncecastle
主頁(yè): http://www.bouncycastle.org/java.html
基本常用的使用JDK就夠了。
二、Base64算法
1、從現(xiàn)在加密算法的復(fù)雜性來(lái)看Base64這種都不好意思說(shuō)自己是加密,不過(guò)對(duì)于完全不懂計(jì)算機(jī)的人來(lái)說(shuō)也夠用了。采用Base64編碼具有不可讀性,即所編碼的數(shù)據(jù)不會(huì)被人用肉眼所直接看到。
Base64編碼一般用于url的處理,或者說(shuō)任何你不想讓普通人一眼就知道是啥的東西都可以用Base64編碼處理后再發(fā)布在網(wǎng)絡(luò)上。
package com.amuro.strategy.base64; import java.util.Base64; import com.amuro.strategy.IStrategy; /** * Base64算法基于64個(gè)基本字符,加密后的string中只包含這64個(gè)字符 * @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編碼對(duì)應(yīng)關(guān)系表
三、消息摘要算法(Message Digest)
消息摘要(Message Digest)又稱(chēng)為數(shù)字摘要(Digital Digest)。它是一個(gè)唯一對(duì)應(yīng)一個(gè)消息或文本的固定長(zhǎng)度的值,它由一個(gè)單向Hash加密函數(shù)對(duì)消息進(jìn)行作用而產(chǎn)生。HASH函數(shù)的抗沖突性使得如果一段明文稍有變化,哪怕只更改該段落的一個(gè)字母,通過(guò)哈希算法作用后都將產(chǎn)生不同的值。而HASH算法的單向性使得要找到哈希值相同的兩個(gè)不同的輸入消息,在計(jì)算上是不可能的。所以數(shù)據(jù)的哈希值,即消息摘要,可以檢驗(yàn)數(shù)據(jù)的完整性。
用大白話來(lái)說(shuō),任何一段數(shù)據(jù)應(yīng)該都和人一樣是唯一的,唯一的標(biāo)識(shí)是什么,人類(lèi)的話目前就是指紋,而數(shù)據(jù)的指紋是什么呢?沒(méi)錯(cuò),就是消息摘要算法產(chǎn)生的這一段String。比如我們?cè)谧?cè)網(wǎng)站的時(shí)候,客戶(hù)端向服務(wù)器傳輸?shù)?,?yīng)該是我們輸入的密碼進(jìn)行消息摘要處理后的內(nèi)容,這樣就算服務(wù)器被攻破,Hack也無(wú)法知道用戶(hù)真實(shí)的密碼是什么。不過(guò)有說(shuō)現(xiàn)在MD5和SHA已經(jīng)被攻破了,具體大家可以谷歌。
1、MD5
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
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"); } }
四、對(duì)稱(chēng)加密
采用單鑰密碼系統(tǒng)的加密方法,同一個(gè)密鑰可以同時(shí)用作信息的加密和解密,這種加密方法稱(chēng)為對(duì)稱(chēng)加密,也稱(chēng)為單密鑰加密。而因?yàn)榧用芎徒饷芏际褂猛粋€(gè)密鑰,如何把密鑰安全地傳遞到解密者手上就成了必須要解決的問(wèn)題。當(dāng)然,安全性較低帶來(lái)的優(yōu)點(diǎn)就是優(yōu)計(jì)算量小、加密速度快、加密效率高。
然并卵,現(xiàn)代計(jì)算機(jī)對(duì)這種級(jí)別的計(jì)算量早就不care了,安全才是最重要的。
1、DES
DES,全稱(chēng)為“Data Encryption Standard”,中文名為“數(shù)據(jù)加密標(biāo)準(zhǔn)”,是一種使用密鑰加密的塊算法。DES 算法為密碼體制中的對(duì)稱(chēng)密碼體制,又被稱(chēng)為美國(guó)數(shù)據(jù)加密標(biāo)準(zhǔn),是 1972 年美國(guó) IBM 公司研制的對(duì)稱(chēng)密碼體制加密算法。 明文按 64 位進(jìn)行分組,密鑰長(zhǎng) 64 位,密鑰事實(shí)上是 56 位參與 DES 運(yùn)算(第8、16、24、32、40、48、56、64 位是校驗(yàn)位, 使得每個(gè)密鑰都有奇數(shù)個(gè) 1)分組后的明文組和 56 位的密鑰按位替代或交換的方法形成密文組的加密方法。
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”,中文名“三重?cái)?shù)據(jù)加密算法”,它相當(dāng)于是對(duì)每個(gè)數(shù)據(jù)塊應(yīng)用三次 DES 加密算法。由于計(jì)算機(jī)運(yùn)算能力的增強(qiáng),原版 DES 密碼的密鑰長(zhǎng)度變得容易被暴力破解;3DES 即是設(shè)計(jì)用來(lái)提供一種相對(duì)簡(jiǎn)單的方法,即通過(guò)增加 DES 的密鑰長(zhǎng)度來(lái)避免類(lèi)似的攻擊,而不是設(shè)計(jì)一種全新的塊密碼算法。
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,全稱(chēng)為“Advanced Encryption Standard”,中文名“高級(jí)加密標(biāo)準(zhǔn)”,在密碼學(xué)中又稱(chēng) Rijndael 加密法,是美國(guó)聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)。AES 加密算法作為新一代的數(shù)據(jù)加密標(biāo)準(zhǔn)匯聚了強(qiáng)安全性、高性能、高效率、易用和靈活等優(yōu)點(diǎn)。AES 設(shè)計(jì)有三個(gè)密鑰長(zhǎng)度:128,192,256 位。相對(duì)而言,AES 的 128 密鑰比 DES 的 56 密鑰強(qiáng)了 1021 倍。
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,全稱(chēng)為“Password Base Encryption”,中文名“基于口令加密”,是一種基于密碼的加密算法,其特點(diǎn)是使用口令代替了密鑰,而口令由用戶(hù)自己掌管,采用隨機(jī)數(shù)雜湊多重加密等方法保證數(shù)據(jù)的安全性。
PBE算法沒(méi)有密鑰的概念,把口令當(dāng)做密鑰了。因?yàn)槊荑€長(zhǎng)短影響算法安全性,還不方便記憶,這里我們直接換成我們自己常用的口令就大大不同了,便于我們的記憶。但是單純的口令很容易被字典法給窮舉出來(lái),所以我們這里給口令加了點(diǎn)“鹽”,這個(gè)鹽和口令組合,想破解就難了。同時(shí)我們將鹽和口令合并后用消息摘要算法進(jìn)行迭代很多次來(lái)構(gòu)建密鑰初始化向量的基本材料,使破譯更加難了。
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),對(duì)稱(chēng) + 消息摘要 * @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; } }
五、非對(duì)稱(chēng)加密
非對(duì)稱(chēng)加密算法需要兩個(gè)密鑰來(lái)進(jìn)行加密和解密,分別是公鑰和私鑰。需要注意的一點(diǎn),這個(gè)公鑰和私鑰必須是一對(duì)的,如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,那么只有使用對(duì)應(yīng)的私鑰才能解密,反之亦然。由于加密和解密使用的是兩個(gè)不同的密鑰,因此,這種算法叫做非對(duì)稱(chēng)加密算法。
1、RSA
其實(shí),在早在 1978 年的時(shí)候,RSA就已經(jīng)出現(xiàn)了,它是第一個(gè)既能用于數(shù)據(jù)加密也能用于數(shù)字簽名的算法。它易于理解和操作,也很流行。其原理就如上面的工作過(guò)程所述。RSA 算法基于一個(gè)十分簡(jiǎn)單的數(shù)論事實(shí):將兩個(gè)大素?cái)?shù)相乘十分容易,但是想要對(duì)其乘積進(jìn)行因式分解卻極其困難,因此可以將乘積公開(kāi)作為加密密鑰。
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,全稱(chēng)為“Diffie-Hellman”,他是一種確保共享KEY安全穿越不安全網(wǎng)絡(luò)的方法,也就是常說(shuō)的密鑰一致協(xié)議。由公開(kāi)密鑰密碼體制的奠基人Diffie和Hellman所提出的一種思想。簡(jiǎn)單的說(shuō)就是允許兩名用戶(hù)在公開(kāi)媒體上交換信息以生成“一致”的、可以共享的密鑰。也就是由甲方產(chǎn)出一對(duì)密鑰(公鑰、私鑰),乙方依照甲方公鑰產(chǎn)生乙方密鑰對(duì)(公鑰、私鑰)。
以此為基線,作為數(shù)據(jù)傳輸保密基礎(chǔ),同時(shí)雙方使用同一種對(duì)稱(chēng)加密算法構(gòu)建本地密鑰(SecretKey)對(duì)數(shù)據(jù)加密。這樣,在互通了本地密鑰(SecretKey)算法后,甲乙雙方公開(kāi)自己的公鑰,使用對(duì)方的公鑰和剛才產(chǎn)生的私鑰加密數(shù)據(jù),同時(shí)可以使用對(duì)方的公鑰和自己的私鑰對(duì)數(shù)據(jù)解密。不單單是甲乙雙方兩方,可以擴(kuò)展為多方共享數(shù)據(jù)通訊,這樣就完成了網(wǎng)絡(luò)交互數(shù)據(jù)的安全通訊!
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 { //初始化發(fā)送方密鑰 KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH"); senderKeyPairGenerator.initialize(512); KeyPair senderkeyPair = senderKeyPairGenerator.generateKeyPair(); PrivateKey senderPrivateKey = senderkeyPair.getPrivate(); byte[] senderPublicKeyBytes = senderkeyPair.getPublic().getEncoded();//發(fā)送方的公鑰 //初始化接收方密鑰,用發(fā)送方的公鑰 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"); //發(fā)送方拿到接收方的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; } }
六、數(shù)字簽名證書(shū)
非對(duì)稱(chēng)加密已經(jīng)灰常安全了,但是還有一個(gè)破綻:
服務(wù)器A公布了自己的公鑰,我的電腦是用服務(wù)器A的公鑰加密數(shù)據(jù)后再發(fā)給服務(wù)器A的;這時(shí)候服務(wù)器B侵入了我的電腦,把我用來(lái)加密的公鑰換成了它的公鑰,于是我發(fā)出去的數(shù)據(jù)就會(huì)被服務(wù)器B的私鑰破解了。腫么防止公鑰被篡改呢?
對(duì),我們想到了前面的消息摘要,服務(wù)器A把公鑰丟給我的時(shí)候,同時(shí)去CA申請(qǐng)一份數(shù)字證書(shū),其實(shí)主要就是公鑰的消息摘要,有了這份證書(shū),當(dāng)我再用公鑰加密的時(shí)候,我就可以先驗(yàn)證一下當(dāng)前的公鑰是否確定是服務(wù)器A發(fā)送給我的。
這里就貼一種RSA的:
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; } }
關(guān)于數(shù)字簽名和非對(duì)稱(chēng)加密算法的使用,還看到一個(gè)非常棒的例子,分享給大家:
唉,這個(gè)月買(mǎi)了太多的書(shū),到月底揭不開(kāi)鍋了。正巧在QQ上遇到了Clark:
1-2-3:“Clark,我需要200兩紋銀,能否借給我?”
Clark:“沒(méi)問(wèn)題。我這就給你轉(zhuǎn)賬。請(qǐng)給我一張借條?!?br />
1-2-3:“太謝謝了,我這就用Word寫(xiě)一個(gè)借條給你?!?br />
然后,我新建一個(gè)Word文檔,寫(xiě)好借條,存盤(pán)。然后,然后怎么辦呢?我不能直接把借條發(fā)送給Clark,原因有:
1. 我無(wú)法保證Clark不會(huì)在收到借條后將“紋銀200兩”改為“紋銀2000兩”。
2. 如果我賴(lài)賬,Clark無(wú)法證明這個(gè)借條就是我寫(xiě)的。
3. 普通的Word文檔不能作為打官司的證據(jù)。
好在我早就申請(qǐng)了數(shù)字證書(shū)。我先用我的私鑰對(duì)借條進(jìn)行加密,然后將加密后的密文用QQ發(fā)送給Clark。Clark收到了借條的密文后,在數(shù)字證書(shū)認(rèn)證中心的網(wǎng)站上下載我的公鑰,然后使用我的公鑰將密文解密,發(fā)現(xiàn)確實(shí)寫(xiě)的是“借紋銀200兩”,Clark就可以把銀子放心的借給我了,我也不會(huì)擔(dān)心Clark會(huì)篡改我的借條,原因是:
1. 由于我發(fā)給Clark的是密文,Clark無(wú)法進(jìn)行修改。Clark倒是可以修改解密后的借條,但是Clark沒(méi)有我的私鑰,沒(méi)法模仿我對(duì)借條進(jìn)行加密。這就叫防篡改。
2. 由于用我的私鑰進(jìn)行加密的借條,有且只有我的公鑰可以解密。反過(guò)來(lái)講,能用我的公鑰解密的借條,一定是使用我的私鑰加密的,而只有我才擁有我的私鑰,這樣Clark就可以證明這個(gè)借條就是我寫(xiě)的。這就叫防抵賴(lài)。
3. 如果我一直賴(lài)著不還錢(qián),Clark把我告上了法庭,這個(gè)用我的私鑰加密過(guò)的Word文檔就可以當(dāng)作程堂證供。因?yàn)槲覈?guó)已經(jīng)出臺(tái)了《中華人民共和國(guó)電子簽名法》,使數(shù)字簽名具有了法律效力。
您一定已經(jīng)注意到了,這個(gè)使用我的私鑰進(jìn)行了加密的借條,具有了防篡改、防抵賴(lài)的特性,并且可以作為程堂證供,就跟我對(duì)這個(gè)借條進(jìn)行了“簽名”的效果是一樣的。對(duì)了,“使用我的私鑰對(duì)借條進(jìn)行加密”的過(guò)程就叫做數(shù)字簽名。
這是一篇總結(jié)類(lèi)文章,把一些常用的Java加密技術(shù)和核心代碼寫(xiě)在這邊,供給需要朋友參考。
- java 中RSA的方式實(shí)現(xiàn)非對(duì)稱(chēng)加密的實(shí)例
- java中以DES的方式實(shí)現(xiàn)對(duì)稱(chēng)加密并提供密鑰的實(shí)例
- java 中DH的方式實(shí)現(xiàn)非對(duì)稱(chēng)加密的實(shí)例
- java常用工具類(lèi) Random隨機(jī)數(shù)、MD5加密工具類(lèi)
- Java常用加密算法實(shí)例總結(jié)
- Java中常用加密/解密方法詳解
- Java實(shí)現(xiàn)常用加密算法——單向加密算法MD5和SHA
- 分享Java常用幾種加密算法(四種)
- java中常用工具類(lèi)之字符串操作類(lèi)和MD5加密解密類(lèi)
- java常用工具類(lèi)之DES和Base64加密解密類(lèi)
- 淺析Java 常用的 4 種加密方式(MD5+Base64+SHA+BCrypt)
相關(guān)文章
java 實(shí)現(xiàn)反射 json動(dòng)態(tài)轉(zhuǎn)實(shí)體類(lèi)--fastjson
這篇文章主要介紹了java 實(shí)現(xiàn)反射 json動(dòng)態(tài)轉(zhuǎn)實(shí)體類(lèi)--fastjson,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02Spring事務(wù)事件監(jiān)控的實(shí)現(xiàn)
這篇文章主要介紹了Spring事務(wù)事件監(jiān)控的實(shí)現(xiàn)。本文首先會(huì)使用實(shí)例進(jìn)行講解Spring事務(wù)事件是如何使用的,然后會(huì)講解這種使用方式的實(shí)現(xiàn)原理。感興趣的小伙伴們可以參考一下2018-10-10mybatis-plus saveOrUpdateBatch踩坑記錄
這篇文章主要介紹了mybatis-plus saveOrUpdateBatch踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Spring Security 實(shí)現(xiàn)多種登錄方式(常規(guī)方式外的郵件、手機(jī)驗(yàn)證碼登錄)
本文主要介紹了Spring Security 實(shí)現(xiàn)多種登錄方式(常規(guī)方式外的郵件、手機(jī)驗(yàn)證碼登錄),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01如何使用CountDownLatch同步j(luò)ava多線程
這篇文章主要介紹了如何使用CountDownLatch同步j(luò)ava多線程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08SpringBoot集成本地緩存性能之王Caffeine示例詳解
這篇文章主要為大家介紹了SpringBoot集成本地緩存性能之王Caffeine的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07