java常見的五種加密算法使用方法舉例
一、BCrypt加密
1.1 BCrypt簡述
BCrypt是一種密碼散列函數(shù),即單向函數(shù),無法解密BCrypt哈希
是強哈希算法,結(jié)合了SHA-256、隨機鹽和密鑰來增強安全性
特點:
唯一性:每次加密生成的鹽不一樣所以密碼的值也不一樣;
不可逆:只能驗證兩個BCrypt哈希值是否相同,從而驗證提供的密碼是否與原始密碼匹配
適用的場景:用戶密碼的加密
加密后的字符由4部分組成:
$2a$10$N9qo8uLOickxx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZmL17lhWy
標識符:BCrypt算法的標識符通常由$2a或$2b開頭,2a是加密版本號;
代價因子:其中10表示代價因子,這里是2的10次方,也就是1024輪;
鹽:在后面就是22位的鹽;鹽值是一個16字節(jié)(128位)的隨機值,經(jīng)過Base64編碼后變成22個字符的字符串;
哈希值:最后的31位字符串就是哈希值;通常是24字節(jié)(192位)的原始哈希值,經(jīng)過Base64編碼后變成31個字符的字符串;
修改密碼的話,可以向用戶發(fā)送一次性密碼重置鏈接,使用秘密問題或其他一些方式來確認用戶身份信息,讓他們設(shè)置新密碼
1.2 代碼示例
BCryptPasswordEncoder是一種使用BCrypt加密算法來加密密碼的方法
主要目的是為了防止密碼被明文存儲在數(shù)據(jù)庫中;
是Spring Security中用來加密用戶密碼的一個類
在使用時如果是springBoot項目需要引入依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐security</artifactId> </dependency>
代碼示例:
BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder(); // 加密;返回加密后字符串 bcryptPasswordEncoder.encoder(password) // 比較;返回true或false // rawPassword 密碼;encodedPassword加密后字符 bcrytPasswordEncoder.matches(rawPassword,encodedPassword)
二、MD5加密
2.1 MD5簡述
MD5(Message-Digest Algorithm 5)是一種廣泛使用的哈希算法,將任意長度的輸入轉(zhuǎn)換成一個128位的二進制數(shù)
MD5 加密特性:
不可逆
相同的字符串內(nèi)容加密后結(jié)果相同
MD5應用:
MD5 容易受到碰撞攻擊,不適用于安全性認證;
存在碰撞就是指:在對兩個不同的內(nèi)容使用 MD5算法運算的時候,有可能得到一對相同的結(jié)果值
可以用于消息或文件的完整性校驗
2.2 代碼示例
使用 Java 內(nèi)置的 MessageDigest 類
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class TestMD5 { public static String encryptMD5(String input) { try { // 創(chuàng)建MD5加密對象 MessageDigest md = MessageDigest.getInstance("MD5"); // 執(zhí)行加密操作 byte[] messageDigest = md.digest(input.getBytes()); // 將字節(jié)數(shù)組轉(zhuǎn)換為16進制字符串 StringBuilder hexString = new StringBuilder(); for (byte b : messageDigest) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } // 返回加密后的字符串 return hexString.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } /** * 測試 */ public static void main(String[] args) { String str = "test1"; String encrypted = encryptMD5(str); System.out.println("加密后字符串: " + encrypted); } }
三、RSA加密
3.1 RSA簡述
RSA加密是一種非對稱加密??梢栽诓恢苯觽鬟f密鑰的情況下,完成解密;使用一對公私秘鑰,公鑰可以對外公開,私鑰保密
加密是為了防止信息泄露,保證安全通信
簽名是為了防止信息被篡改,確保消息的完整性和來源認證
?公鑰加密、私鑰解密、私鑰簽名、公鑰驗簽;
實際使用一般情況加密和驗簽同時使用
RSA加密流程:
A和B有自己的公鑰和私鑰;將公鑰給對方系統(tǒng)
1、A要給B發(fā)送消息時,先用B的公鑰對消息加密,再對加密的字符串使用A的私鑰進行加簽
2、A將加密后的字符串和加簽后的字符串當作參數(shù)傳給B
3、B先用A的公鑰進行驗簽,沒問題后在使用B的私鑰解密
4、B處理完后,返回的參數(shù)用A的公鑰加密
5、A用A的私鑰解密返回參數(shù)
3.2 代碼示例
import java.io.ByteArrayOutputStream; 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.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; public class TestRSA { /** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; /** * 獲取密鑰對 * * @return 密鑰對 */ public static KeyPair getKeyPair() throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(1024); return generator.generateKeyPair(); } /** * 獲取私鑰 * * @param privateKey 私鑰字符串 * @return */ public static PrivateKey getPrivateKey(String privateKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes()); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey); return keyFactory.generatePrivate(keySpec); } /** * 獲取公鑰 * * @param publicKey 公鑰字符串 * @return */ public static PublicKey getPublicKey(String publicKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes()); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey); return keyFactory.generatePublic(keySpec); } /** * RSA加密 * * @param data 待加密數(shù)據(jù) * @param publicKey 公鑰 * @return */ public static String encrypt(String data, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); int inputLen = data.getBytes().length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offset = 0; byte[] cache; int i = 0; // 對數(shù)據(jù)分段加密 while (inputLen - offset > 0) { if (inputLen - offset > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset); } out.write(cache, 0, cache.length); i++; offset = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); // 獲取加密內(nèi)容使用base64進行編碼,并以UTF-8為標準轉(zhuǎn)化成字符串 // 加密后的字符串 return new String(Base64.encodeBase64String(encryptedData)); } /** * RSA解密 * * @param data 待解密數(shù)據(jù) * @param privateKey 私鑰 * @return */ public static String decrypt(String data, PrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] dataBytes = Base64.decodeBase64(data); int inputLen = dataBytes.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offset = 0; byte[] cache; int i = 0; // 對數(shù)據(jù)分段解密 while (inputLen - offset > 0) { if (inputLen - offset > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(dataBytes, offset, inputLen - offset); } out.write(cache, 0, cache.length); i++; offset = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); // 解密后的內(nèi)容 return new String(decryptedData, "UTF-8"); } /** * 簽名 * * @param data 待簽名數(shù)據(jù) * @param privateKey 私鑰 * @return 簽名 */ public static String sign(String data, PrivateKey privateKey) throws Exception { byte[] keyBytes = privateKey.getEncoded(); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey key = keyFactory.generatePrivate(keySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(key); signature.update(data.getBytes()); return new String(Base64.encodeBase64(signature.sign())); } /** * 驗簽 * * @param srcData 原始字符串 * @param publicKey 公鑰 * @param sign 簽名 * @return 是否驗簽通過 */ public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception { byte[] keyBytes = publicKey.getEncoded(); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey key = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initVerify(key); signature.update(srcData.getBytes()); return signature.verify(Base64.decodeBase64(sign.getBytes())); } public static void main(String[] args) { try { // 生成密鑰對 KeyPair keyPair = getKeyPair(); String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded())); String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded())); System.out.println("私鑰:" + privateKey); System.out.println("公鑰:" + publicKey); // RSA加密 String data = "待加密的文字內(nèi)容"; String encryptData = encrypt(data, getPublicKey(publicKey)); System.out.println("加密后內(nèi)容:" + encryptData); // RSA解密 String decryptData = decrypt(encryptData, getPrivateKey(privateKey)); System.out.println("解密后內(nèi)容:" + decryptData); // RSA簽名 String sign = sign(data, getPrivateKey(privateKey)); // RSA驗簽 boolean result = verify(data, getPublicKey(publicKey), sign); System.out.print("驗簽結(jié)果:" + result); } catch (Exception e) { e.printStackTrace(); System.out.print("加解密異常"); } } } // 這部分代碼轉(zhuǎn)自https://www.cnblogs.com/pcheng/p/9629621.html
四、AES加密
4.1 AES簡述
屬于對稱加密;對稱加密算法中,加密與解密的密鑰是相同的,密鑰為接收方與發(fā)送方協(xié)商產(chǎn)生
AES標準支持三種不同的密鑰長度:128位、192位和256位
AES加密以16個字節(jié)為一組進行分組加密,要求明文的長度一定是16個字節(jié)的整數(shù)倍,如果不夠16個字節(jié)的倍數(shù),需要按照填充模式進行填充
常見的填充模式包括NoPadding、ZeroPadding、PKCS#7
加密模式:ECB、CBC
CBC工作模式使用最廣泛
每一塊的加密依賴于前一塊的密文,提供了良好的保密性和抗重播攻擊能力
隨機數(shù)作為IV參數(shù),對于同一份明文,每次生成的密文都不同
4.2 代碼示例
引入依賴
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.26</version> </dependency>
實現(xiàn)代碼
@Test public static void testAes(String data) { // 密鑰,長度必須是16、24或32 byte[] key = "1234567898765432".getBytes(); // 初始化向量,CBC模式長度必須是16 byte[] iv = "1234567898765432".getBytes(); // 創(chuàng)建AES對象,指定密鑰和初始化向量 SymmetricCrypto aes = new AES(Mode.CBC, Padding.PKCS5Padding, key, iv); // 加密并進行Base轉(zhuǎn)碼 String encrypt = aes.encryptBase64(data); System.out.println(encrypt); // 解密為字符串 String decrypt = aes.decryptStr(encrypt); System.out.println(decrypt); }
五、商用密碼算法
5.1 算法分類
SM1、SM2、SM3、SM4、SM9、ZUC等一系列商用密碼算法構(gòu)成了我國完整的密碼算法體系
SM1 對稱 電子政務(wù)、硬件等加密
SM2 非對稱 數(shù)字簽名、密鑰交換
SM3 摘要算法 數(shù)字簽名、完整性驗證
SM4 對稱 電子政務(wù)、無線局域網(wǎng)加密
SM9 非對稱 數(shù)據(jù)加密、身份認證
5.2 SM4加密算法
5.2.1 SM4簡述
SM4算法的特點是:
(1)屬于對稱密碼算法,加解密的密鑰相同;
(2)明密文和密鑰均為128比特,分組長度為128比特;
(3)SM4密碼算法加解密算法的輪數(shù)為32輪,每輪的輪結(jié)構(gòu)相同,只是輪密鑰使用相反
金融行業(yè)國內(nèi)通用標準為SM4,對應國際標準SM4
有兩種模式ECB和CBC
區(qū)別是前者只需要一個key,而后者不僅需要一個key還需要一個iv值
SM4的CBC模式和AES的CBC模式類似;安全性與AES-128基本一致,但是實現(xiàn)更簡單、效率更高
SM4的CBC模式通過引入鏈式依賴來提高安全性。它將每個明文塊與前一個密文塊進行異或后再進行加密。在這種方法中,每個密文塊都依賴于它前面的所有明文塊。同時,為了保證每條消息的唯一性,在第一個塊中需要使用初始化向量IV
5.2.2 代碼示例
用工具類來實現(xiàn)CBC模式
引入依賴
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.26</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.68</version> </dependency>
代碼實現(xiàn)
public class TestSm4 { /** * 密鑰 長度必須是16 */ private static String SECRET_KEY = ""; /** * IV是初始向量,它的作用是使相同的明文每次加密得到的密文都不同。 長度必須是16 */ private static String IV= ""; /** * 加密成base64/字節(jié)數(shù)組 */ public static String encrypt(String plainTxt){ String cipherTxt = ""; SymmetricCrypto sm4Cbc = new SM4(Mode.CBC, Padding.PKCS5Padding, SECRET_KEY.getBytes(CharsetUtil.CHARSET_UTF_8), IV.getBytes(CharsetUtil.CHARSET_UTF_8)); byte[] encrypHex = sm4Cbc.encrypt(plainTxt); cipherTxt = Base64.encode(encrypHex); return cipherTxt; } /** * 解密 */ public static String decrypt(String cipherTxt){ String plainTxt = ""; try { SymmetricCrypto sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, SECRET_KEY.getBytes(CharsetUtil.CHARSET_UTF_8), IV.getBytes(CharsetUtil.CHARSET_UTF_8)); byte[] cipherHex = Base64.decode(cipherTxt); plainTxt = sm4.decryptStr(cipherHex, CharsetUtil.CHARSET_UTF_8); } catch(Exception e) { log.error(e.getMessage()); } return plainTxt; } /** * 測試 */ public static void main(String[] argc){ String originTxt = "加密測試"; String cipherTxt = encrypt(originTxt); System.out.println("加密后密文: " + cipherTxt); String plainTxt = decrypt(cipherTxt); System.out.println("解密后結(jié)果: " + plainTxt); } }
使用SmUtil實現(xiàn)
public void testSm4(String text) { SymmetricCrypto sm4 = SmUtil.sm4(); // 加密后密文 String encryptHex = sm4.encryptHex(text); // 解密后結(jié)果 String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8); }
5.2 SM2簽名算法
5.2.1 SM2簡述
SM2算法是一種非對稱加密算法,SM2算法主要用于數(shù)字簽名、密鑰交換和數(shù)據(jù)加密。在使用SM2算法時,需要生成一個私鑰,一個公鑰。私鑰用于簽名和解密,公鑰用于驗證簽名和加密。是一種更先進安全的算法
5.2.2 代碼實現(xiàn)
引入依賴:
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.26</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.68</version> </dependency>
實現(xiàn):
// 加密 public static String encrypt(String data, String publicKey,String privateKey) { SM2 sm2 = SmUtil.sm2(publicKey,privateKey); return Arrays.toString(sm2.encrypt(data, KeyType.PublicKey)); } // 解密 public static String decrypt(String data, String publicKey,String privateKey) { SM2 sm2 = SmUtil.sm2(publicKey,privateKey); return sm2.decryptStr(data, KeyType.PrivateKey); } public static void main(String[] args) { String data = "text"; // 公鑰;公鑰長度為64字節(jié)(512位) String publicKey = ""; // 私鑰;私鑰長度為32字節(jié)(256位) String privateKey = ""; // 加密 String encryptedData = encrypt(data, publicKey,privateKey); // 解密 String decryptedData = decrypt(encryptedData,publicKey, privateKey); }
5.3 SM3摘要算法
5.3.1 SM3簡述
SM3算法是中國國家密碼管理局發(fā)布的消息摘要算法,用于生成消息的哈希值
SM3算法采用Merkle-Damgård結(jié)構(gòu),消息分組長度為512位,摘要值長度為256位(即32字節(jié))。其輸入可以是任意長度數(shù)據(jù),但加密結(jié)果始終是256位數(shù)據(jù)。
應用場景:
數(shù)字簽名:使用SM3算法生成的哈希值作為簽名的一部分,確保簽名的真實性和完整性。
消息完整性驗證:通過比較消息的哈希值來驗證消息在傳輸過程中是否被篡改。
流程簡述:
1、消息填充:
將輸入消息填充至長度為512位的倍數(shù)。
2、消息分組:
將填充后的消息按512位(64字節(jié))進行分組
3、消息擴展:
對每個512位的分組進行擴展,每個分組稱為一個消息塊,對每個消息塊進行擴展,形成132個字(每個字為32位)的擴展消息
4、迭代壓縮:
將132個消息字,通過64輪的迭代壓縮計算,最終得到256位的哈希值。
在每一輪迭代中,都會使用8個32位的寄存器(A、B、C、D、E、F、G、H),這些寄存器在迭代開始時被初始化為固定的常數(shù)值。
通過一系列操作,更新這些寄存器的值。
在完成64輪迭代后,將8個寄存器的值進行異或運算,得到最終的256位哈希值。
5.3.2 代碼實現(xiàn)
public static void main(String[] args) { String input = "Hello"; String output = sm3Encrypt(input); System.out.println("SM3 Result: " + output); } public static String sm3Encrypt(String input) { try { MessageDigest md = MessageDigest.getInstance("SM3"); byte[] digest = md.digest(input.getBytes()); return bytesToHex(digest); } catch (Exception e) { e.printStackTrace(); return null; } } // 轉(zhuǎn)為16進制字符串 public static String bytesToHex(byte[] bytes) { StringBuilder result = new StringBuilder(); for (byte b : bytes) { result.append(String.format("%02x", b)); } return result.toString(); }
5.4 HMAC-SM3
5.4.1 HMAC-SM3簡述
HMAC-SM3是一種基于SM3的帶密鑰的哈希算法認證技術(shù),使用SM3算法生成哈希值,引入密鑰來增強安全性
應用場景:
消息認證:通過比較發(fā)送方和接收方生成的消息認證碼來驗證消息的真實性和完整性。
數(shù)據(jù)完整性保護:在數(shù)據(jù)傳輸和存儲過程中,使用HMAC-SM3算法來確保數(shù)據(jù)不被篡改。
5.4.2 代碼實現(xiàn)
引入依賴
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.69</version> <!-- 使用最新版本 --> </dependency>
代碼實現(xiàn)
public static String hmacSM3(byte[] key, byte[] data) { // 創(chuàng)建一個 SM3Digest 對象,用于進行 SM3 哈希運算 SM3Digest sm3Digest = new SM3Digest(); // 創(chuàng)建一個 HMac 對象,使用 SM3Digest 作為底層哈希算法 HMac hmac = new HMac(sm3Digest); // 使用密鑰初始化 HMac 對象 hmac.init(new KeyParameter(key)); // 更新 HMac 對象的數(shù)據(jù) hmac.update(data, 0, data.length); // 計算 HMAC-SM3 值,并將結(jié)果存儲在 result 數(shù)組中 byte[] result = new byte[hmac.getMacSize()]; // 執(zhí)行最終的哈希運算,并將結(jié)果填充到 result 數(shù)組中 hmac.doFinal(result, 0); return bytesToHex(result); } public static void main(String[] args) { // 示例密鑰 byte[] key = "123456789".getBytes(); byte[] data = "Hello".getBytes(); // 計算HMAC-SM3值 String hmac = hmacSM3(key, data); System.out.println("HMAC-SM3: " + hmac); } // 轉(zhuǎn)為16進制字符串 public static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { // 將每個字節(jié)轉(zhuǎn)換為16進制字符串,并拼接到 StringBuilder 中 sb.append(String.format("%02x", b)); } return sb.toString(); }
總結(jié)
到此這篇關(guān)于java常見的五種加密算法使用方法的文章就介紹到這了,更多相關(guān)java加密算法使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java calendar 日期實現(xiàn)不斷加一天的代碼
這篇文章主要介紹了java calendar 日期實現(xiàn)不斷加一天的代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10Java中dubbo+zookeeper微服務(wù)架構(gòu)簡介
Apache Dubbo是一款高性能的 Java RPC 框架,這篇文章主要介紹了Java中dubbo+zookeeper微服務(wù)架構(gòu),需要的朋友可以參考下2021-09-09java開發(fā)ExecutorService監(jiān)控實現(xiàn)示例詳解
這篇文章主要為大家介紹了java開發(fā)ExecutorService監(jiān)控實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07詳解關(guān)于Windows10 Java環(huán)境變量配置問題的解決辦法
這篇文章主要介紹了關(guān)于Windows10 Java環(huán)境變量配置問題的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03Java實現(xiàn)任務(wù)管理器性能網(wǎng)絡(luò)監(jiān)控數(shù)據(jù)的方法詳解
在現(xiàn)代操作系統(tǒng)中,任務(wù)管理器是一個非常重要的工具,用于監(jiān)控和管理計算機的運行狀態(tài),包括CPU使用率、內(nèi)存占用等,對于開發(fā)者和系統(tǒng)管理員來說,了解這些性能數(shù)據(jù)有助于優(yōu)化應用程序和系統(tǒng)性能,本文將介紹如何使用Java編寫一個簡單的程序來監(jiān)控網(wǎng)絡(luò)性能數(shù)據(jù)2025-01-01