java常見(jiàn)的五種加密算法使用方法舉例
一、BCrypt加密
1.1 BCrypt簡(jiǎn)述
BCrypt是一種密碼散列函數(shù),即單向函數(shù),無(wú)法解密BCrypt哈希
是強(qiáng)哈希算法,結(jié)合了SHA-256、隨機(jī)鹽和密鑰來(lái)增強(qiáng)安全性
特點(diǎn):
唯一性:每次加密生成的鹽不一樣所以密碼的值也不一樣;
不可逆:只能驗(yàn)證兩個(gè)BCrypt哈希值是否相同,從而驗(yàn)證提供的密碼是否與原始密碼匹配
適用的場(chǎng)景:用戶(hù)密碼的加密
加密后的字符由4部分組成:
$2a$10$N9qo8uLOickxx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZmL17lhWy
標(biāo)識(shí)符:BCrypt算法的標(biāo)識(shí)符通常由$2a或$2b開(kāi)頭,2a是加密版本號(hào);
代價(jià)因子:其中10表示代價(jià)因子,這里是2的10次方,也就是1024輪;
鹽:在后面就是22位的鹽;鹽值是一個(gè)16字節(jié)(128位)的隨機(jī)值,經(jīng)過(guò)Base64編碼后變成22個(gè)字符的字符串;
哈希值:最后的31位字符串就是哈希值;通常是24字節(jié)(192位)的原始哈希值,經(jīng)過(guò)Base64編碼后變成31個(gè)字符的字符串;
修改密碼的話,可以向用戶(hù)發(fā)送一次性密碼重置鏈接,使用秘密問(wèn)題或其他一些方式來(lái)確認(rèn)用戶(hù)身份信息,讓他們?cè)O(shè)置新密碼
1.2 代碼示例
BCryptPasswordEncoder是一種使用BCrypt加密算法來(lái)加密密碼的方法
主要目的是為了防止密碼被明文存儲(chǔ)在數(shù)據(jù)庫(kù)中;
是Spring Security中用來(lái)加密用戶(hù)密碼的一個(gè)類(lèi)
在使用時(shí)如果是springBoot項(xiàng)目需要引入依賴(lài):
<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簡(jiǎn)述
MD5(Message-Digest Algorithm 5)是一種廣泛使用的哈希算法,將任意長(zhǎng)度的輸入轉(zhuǎn)換成一個(gè)128位的二進(jìn)制數(shù)
MD5 加密特性:
不可逆
相同的字符串內(nèi)容加密后結(jié)果相同
MD5應(yīng)用:
MD5 容易受到碰撞攻擊,不適用于安全性認(rèn)證;
存在碰撞就是指:在對(duì)兩個(gè)不同的內(nèi)容使用 MD5算法運(yùn)算的時(shí)候,有可能得到一對(duì)相同的結(jié)果值
可以用于消息或文件的完整性校驗(yàn)
2.2 代碼示例
使用 Java 內(nèi)置的 MessageDigest 類(lèi)
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class TestMD5 {
public static String encryptMD5(String input) {
try {
// 創(chuàng)建MD5加密對(duì)象
MessageDigest md = MessageDigest.getInstance("MD5");
// 執(zhí)行加密操作
byte[] messageDigest = md.digest(input.getBytes());
// 將字節(jié)數(shù)組轉(zhuǎn)換為16進(jìn)制字符串
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);
}
}
/**
* 測(cè)試
*/
public static void main(String[] args) {
String str = "test1";
String encrypted = encryptMD5(str);
System.out.println("加密后字符串: " + encrypted);
}
}
三、RSA加密
3.1 RSA簡(jiǎn)述
RSA加密是一種非對(duì)稱(chēng)加密??梢栽诓恢苯觽鬟f密鑰的情況下,完成解密;使用一對(duì)公私秘鑰,公鑰可以對(duì)外公開(kāi),私鑰保密
加密是為了防止信息泄露,保證安全通信
簽名是為了防止信息被篡改,確保消息的完整性和來(lái)源認(rèn)證
?公鑰加密、私鑰解密、私鑰簽名、公鑰驗(yàn)簽;
實(shí)際使用一般情況加密和驗(yàn)簽同時(shí)使用
RSA加密流程:
A和B有自己的公鑰和私鑰;將公鑰給對(duì)方系統(tǒng)
1、A要給B發(fā)送消息時(shí),先用B的公鑰對(duì)消息加密,再對(duì)加密的字符串使用A的私鑰進(jìn)行加簽
2、A將加密后的字符串和加簽后的字符串當(dāng)作參數(shù)傳給B
3、B先用A的公鑰進(jìn)行驗(yàn)簽,沒(méi)問(wèn)題后在使用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;
/**
* 獲取密鑰對(duì)
*
* @return 密鑰對(duì)
*/
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;
// 對(duì)數(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進(jìn)行編碼,并以UTF-8為標(biāo)準(zhǔn)轉(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;
// 對(duì)數(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()));
}
/**
* 驗(yàn)簽
*
* @param srcData 原始字符串
* @param publicKey 公鑰
* @param sign 簽名
* @return 是否驗(yàn)簽通過(guò)
*/
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 {
// 生成密鑰對(duì)
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驗(yàn)簽
boolean result = verify(data, getPublicKey(publicKey), sign);
System.out.print("驗(yàn)簽結(jié)果:" + result);
} catch (Exception e) {
e.printStackTrace();
System.out.print("加解密異常");
}
}
}
// 這部分代碼轉(zhuǎn)自https://www.cnblogs.com/pcheng/p/9629621.html
四、AES加密
4.1 AES簡(jiǎn)述
屬于對(duì)稱(chēng)加密;對(duì)稱(chēng)加密算法中,加密與解密的密鑰是相同的,密鑰為接收方與發(fā)送方協(xié)商產(chǎn)生
AES標(biāo)準(zhǔn)支持三種不同的密鑰長(zhǎng)度:128位、192位和256位
AES加密以16個(gè)字節(jié)為一組進(jìn)行分組加密,要求明文的長(zhǎng)度一定是16個(gè)字節(jié)的整數(shù)倍,如果不夠16個(gè)字節(jié)的倍數(shù),需要按照填充模式進(jìn)行填充
常見(jiàn)的填充模式包括NoPadding、ZeroPadding、PKCS#7
加密模式:ECB、CBC
CBC工作模式使用最廣泛
每一塊的加密依賴(lài)于前一塊的密文,提供了良好的保密性和抗重播攻擊能力
隨機(jī)數(shù)作為IV參數(shù),對(duì)于同一份明文,每次生成的密文都不同
4.2 代碼示例
引入依賴(lài)
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
實(shí)現(xiàn)代碼
@Test
public static void testAes(String data) {
// 密鑰,長(zhǎng)度必須是16、24或32
byte[] key = "1234567898765432".getBytes();
// 初始化向量,CBC模式長(zhǎng)度必須是16
byte[] iv = "1234567898765432".getBytes();
// 創(chuàng)建AES對(duì)象,指定密鑰和初始化向量
SymmetricCrypto aes = new AES(Mode.CBC, Padding.PKCS5Padding, key, iv);
// 加密并進(jìn)行Base轉(zhuǎn)碼
String encrypt = aes.encryptBase64(data);
System.out.println(encrypt);
// 解密為字符串
String decrypt = aes.decryptStr(encrypt);
System.out.println(decrypt);
}
五、商用密碼算法
5.1 算法分類(lèi)
SM1、SM2、SM3、SM4、SM9、ZUC等一系列商用密碼算法構(gòu)成了我國(guó)完整的密碼算法體系
SM1 對(duì)稱(chēng) 電子政務(wù)、硬件等加密
SM2 非對(duì)稱(chēng) 數(shù)字簽名、密鑰交換
SM3 摘要算法 數(shù)字簽名、完整性驗(yàn)證
SM4 對(duì)稱(chēng) 電子政務(wù)、無(wú)線局域網(wǎng)加密
SM9 非對(duì)稱(chēng) 數(shù)據(jù)加密、身份認(rèn)證
5.2 SM4加密算法
5.2.1 SM4簡(jiǎn)述
SM4算法的特點(diǎn)是:
(1)屬于對(duì)稱(chēng)密碼算法,加解密的密鑰相同;
(2)明密文和密鑰均為128比特,分組長(zhǎng)度為128比特;
(3)SM4密碼算法加解密算法的輪數(shù)為32輪,每輪的輪結(jié)構(gòu)相同,只是輪密鑰使用相反
金融行業(yè)國(guó)內(nèi)通用標(biāo)準(zhǔn)為SM4,對(duì)應(yīng)國(guó)際標(biāo)準(zhǔn)SM4
有兩種模式ECB和CBC
區(qū)別是前者只需要一個(gè)key,而后者不僅需要一個(gè)key還需要一個(gè)iv值
SM4的CBC模式和AES的CBC模式類(lèi)似;安全性與AES-128基本一致,但是實(shí)現(xiàn)更簡(jiǎn)單、效率更高
SM4的CBC模式通過(guò)引入鏈?zhǔn)揭蕾?lài)來(lái)提高安全性。它將每個(gè)明文塊與前一個(gè)密文塊進(jìn)行異或后再進(jìn)行加密。在這種方法中,每個(gè)密文塊都依賴(lài)于它前面的所有明文塊。同時(shí),為了保證每條消息的唯一性,在第一個(gè)塊中需要使用初始化向量IV
5.2.2 代碼示例
用工具類(lèi)來(lái)實(shí)現(xiàn)CBC模式
引入依賴(lài)
<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>
代碼實(shí)現(xiàn)
public class TestSm4 {
/**
* 密鑰 長(zhǎng)度必須是16
*/
private static String SECRET_KEY = "";
/**
* IV是初始向量,它的作用是使相同的明文每次加密得到的密文都不同。 長(zhǎng)度必須是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;
}
/**
* 測(cè)試
*/
public static void main(String[] argc){
String originTxt = "加密測(cè)試";
String cipherTxt = encrypt(originTxt);
System.out.println("加密后密文: " + cipherTxt);
String plainTxt = decrypt(cipherTxt);
System.out.println("解密后結(jié)果: " + plainTxt);
}
}
使用SmUtil實(shí)現(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簡(jiǎn)述
SM2算法是一種非對(duì)稱(chēng)加密算法,SM2算法主要用于數(shù)字簽名、密鑰交換和數(shù)據(jù)加密。在使用SM2算法時(shí),需要生成一個(gè)私鑰,一個(gè)公鑰。私鑰用于簽名和解密,公鑰用于驗(yàn)證簽名和加密。是一種更先進(jìn)安全的算法
5.2.2 代碼實(shí)現(xiàn)
引入依賴(lài):
<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>
實(shí)現(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";
// 公鑰;公鑰長(zhǎng)度為64字節(jié)(512位)
String publicKey = "";
// 私鑰;私鑰長(zhǎng)度為32字節(jié)(256位)
String privateKey = "";
// 加密
String encryptedData = encrypt(data, publicKey,privateKey);
// 解密
String decryptedData = decrypt(encryptedData,publicKey, privateKey);
}
5.3 SM3摘要算法
5.3.1 SM3簡(jiǎn)述
SM3算法是中國(guó)國(guó)家密碼管理局發(fā)布的消息摘要算法,用于生成消息的哈希值
SM3算法采用Merkle-Damgård結(jié)構(gòu),消息分組長(zhǎng)度為512位,摘要值長(zhǎng)度為256位(即32字節(jié))。其輸入可以是任意長(zhǎng)度數(shù)據(jù),但加密結(jié)果始終是256位數(shù)據(jù)。
應(yīng)用場(chǎng)景:
數(shù)字簽名:使用SM3算法生成的哈希值作為簽名的一部分,確保簽名的真實(shí)性和完整性。
消息完整性驗(yàn)證:通過(guò)比較消息的哈希值來(lái)驗(yàn)證消息在傳輸過(guò)程中是否被篡改。
流程簡(jiǎn)述:
1、消息填充:
將輸入消息填充至長(zhǎng)度為512位的倍數(shù)。
2、消息分組:
將填充后的消息按512位(64字節(jié))進(jìn)行分組
3、消息擴(kuò)展:
對(duì)每個(gè)512位的分組進(jìn)行擴(kuò)展,每個(gè)分組稱(chēng)為一個(gè)消息塊,對(duì)每個(gè)消息塊進(jìn)行擴(kuò)展,形成132個(gè)字(每個(gè)字為32位)的擴(kuò)展消息
4、迭代壓縮:
將132個(gè)消息字,通過(guò)64輪的迭代壓縮計(jì)算,最終得到256位的哈希值。
在每一輪迭代中,都會(huì)使用8個(gè)32位的寄存器(A、B、C、D、E、F、G、H),這些寄存器在迭代開(kāi)始時(shí)被初始化為固定的常數(shù)值。
通過(guò)一系列操作,更新這些寄存器的值。
在完成64輪迭代后,將8個(gè)寄存器的值進(jìn)行異或運(yùn)算,得到最終的256位哈希值。
5.3.2 代碼實(shí)現(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進(jìn)制字符串
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簡(jiǎn)述
HMAC-SM3是一種基于SM3的帶密鑰的哈希算法認(rèn)證技術(shù),使用SM3算法生成哈希值,引入密鑰來(lái)增強(qiáng)安全性
應(yīng)用場(chǎng)景:
消息認(rèn)證:通過(guò)比較發(fā)送方和接收方生成的消息認(rèn)證碼來(lái)驗(yàn)證消息的真實(shí)性和完整性。
數(shù)據(jù)完整性保護(hù):在數(shù)據(jù)傳輸和存儲(chǔ)過(guò)程中,使用HMAC-SM3算法來(lái)確保數(shù)據(jù)不被篡改。
5.4.2 代碼實(shí)現(xiàn)
引入依賴(lài)
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.69</version> <!-- 使用最新版本 -->
</dependency>
代碼實(shí)現(xiàn)
public static String hmacSM3(byte[] key, byte[] data) {
// 創(chuàng)建一個(gè) SM3Digest 對(duì)象,用于進(jìn)行 SM3 哈希運(yùn)算
SM3Digest sm3Digest = new SM3Digest();
// 創(chuàng)建一個(gè) HMac 對(duì)象,使用 SM3Digest 作為底層哈希算法
HMac hmac = new HMac(sm3Digest);
// 使用密鑰初始化 HMac 對(duì)象
hmac.init(new KeyParameter(key));
// 更新 HMac 對(duì)象的數(shù)據(jù)
hmac.update(data, 0, data.length);
// 計(jì)算 HMAC-SM3 值,并將結(jié)果存儲(chǔ)在 result 數(shù)組中
byte[] result = new byte[hmac.getMacSize()];
// 執(zhí)行最終的哈希運(yùn)算,并將結(jié)果填充到 result 數(shù)組中
hmac.doFinal(result, 0);
return bytesToHex(result);
}
public static void main(String[] args) {
// 示例密鑰
byte[] key = "123456789".getBytes();
byte[] data = "Hello".getBytes();
// 計(jì)算HMAC-SM3值
String hmac = hmacSM3(key, data);
System.out.println("HMAC-SM3: " + hmac);
}
// 轉(zhuǎn)為16進(jìn)制字符串
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
// 將每個(gè)字節(jié)轉(zhuǎn)換為16進(jìn)制字符串,并拼接到 StringBuilder 中
sb.append(String.format("%02x", b));
}
return sb.toString();
}總結(jié)
到此這篇關(guān)于java常見(jiàn)的五種加密算法使用方法的文章就介紹到這了,更多相關(guān)java加密算法使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java calendar 日期實(shí)現(xiàn)不斷加一天的代碼
這篇文章主要介紹了java calendar 日期實(shí)現(xiàn)不斷加一天的代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10
Java中dubbo+zookeeper微服務(wù)架構(gòu)簡(jiǎn)介
Apache Dubbo是一款高性能的 Java RPC 框架,這篇文章主要介紹了Java中dubbo+zookeeper微服務(wù)架構(gòu),需要的朋友可以參考下2021-09-09
Spring中的AOP動(dòng)態(tài)代理源碼詳解
這篇文章主要介紹了Spring中的AOP動(dòng)態(tài)代理源碼詳解,AOP即面向切面編程也稱(chēng)面向方面編程,它是面向?qū)ο缶幊蘋(píng)OP的一種補(bǔ)充,目前已成為一種比較成熟的編程方式,本文就其源碼進(jìn)行解析,需要的朋友可以參考下2023-09-09
java開(kāi)發(fā)ExecutorService監(jiān)控實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了java開(kāi)發(fā)ExecutorService監(jiān)控實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
詳解關(guān)于Windows10 Java環(huán)境變量配置問(wèn)題的解決辦法
這篇文章主要介紹了關(guān)于Windows10 Java環(huán)境變量配置問(wèn)題的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
java學(xué)習(xí)之JVM運(yùn)行時(shí)常量池理解
這篇文章主要介紹了java學(xué)習(xí)之JVM運(yùn)行時(shí)常量池理解,對(duì)常量池的好處以及基本類(lèi)型的包裝類(lèi)常量池等作了簡(jiǎn)要分析,有需要的朋友可以借鑒參考下2021-09-09
Java實(shí)現(xiàn)任務(wù)管理器性能網(wǎng)絡(luò)監(jiān)控?cái)?shù)據(jù)的方法詳解
在現(xiàn)代操作系統(tǒng)中,任務(wù)管理器是一個(gè)非常重要的工具,用于監(jiān)控和管理計(jì)算機(jī)的運(yùn)行狀態(tài),包括CPU使用率、內(nèi)存占用等,對(duì)于開(kāi)發(fā)者和系統(tǒng)管理員來(lái)說(shuō),了解這些性能數(shù)據(jù)有助于優(yōu)化應(yīng)用程序和系統(tǒng)性能,本文將介紹如何使用Java編寫(xiě)一個(gè)簡(jiǎn)單的程序來(lái)監(jiān)控網(wǎng)絡(luò)性能數(shù)據(jù)2025-01-01
MyBatis之一級(jí)緩存和二級(jí)緩存問(wèn)題
這篇文章主要介紹了MyBatis之一級(jí)緩存和二級(jí)緩存問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
ExpressionUtil工具類(lèi)的應(yīng)用實(shí)例
這篇文章主要給大家介紹了關(guān)于ExpressionUtil工具類(lèi)的應(yīng)用實(shí)例,常用的工具類(lèi)有很多,這是其中一個(gè),了解基本的API可以幫助我們更好的開(kāi)發(fā),文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04

