代码
密码相关
明文、密文、加密、解密(公钥)、密钥(私钥)、加密和非对称加密、密码算法
加密方式
对称加密、非对称加密、哈希算法、混合加密
对称加密
- 特点: 加密和解密使用同一个密钥(就像用同一把钥匙锁门和开门)。
- 优点: 速度快,效率高,适合加密大量数据。
- 缺点: 密钥如何安全地传输给对方是一个难题(密钥分发问题)
DES加密
目前确认已是不安全的加密方式(64位密钥进行加密,8个字节,实际密钥长度56位,其中8位用于奇偶校验)
早期的标准,因为密钥长度较短(56位),现在已被认为不够安全,容易被暴力破解
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class DesDemo {
public static void main(String[] args) {
try {
// 原文
String plainText = "Hello, DES! 这是一段测试文本。";
// 1. 生成 DES 密钥
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
keyGen.init(56); // 指定密钥长度(实际是56位,加上8位奇偶校验共64位)
SecretKey secretKey = keyGen.generateKey();
// 也可以从字节数组恢复密钥(例如存储的密钥)
// byte[] keyBytes = secretKey.getEncoded();
// SecretKey keyFromBytes = new SecretKeySpec(keyBytes, "DES");
System.out.println("原始文本: " + plainText);
// 2. 加密
byte[] cipherData = encrypt(plainText.getBytes("UTF-8"), secretKey);
System.out.println("加密后 (Base64): " + Base64.getEncoder().encodeToString(cipherData));
System.out.println("加密后 (Hex): " + bytesToHex(cipherData));
// 3. 解密
byte[] decryptedData = decrypt(cipherData, secretKey);
String decryptedText = new String(decryptedData, "UTF-8");
System.out.println("解密后文本: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用 DES 加密数据
* @param data 待加密的字节数组
* @param key DES 密钥
* @return 加密后的字节数组
*/
public static byte[] encrypt(byte[] data, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* 使用 DES 解密数据
* @param encryptedData 密文字节数组
* @param key DES 密钥
* @return 解密后的字节数组
*/
public static byte[] decrypt(byte[] encryptedData, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(encryptedData);
}
/**
* 将字节数组转换为十六进制字符串(用于显示)
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}
3DES加密
为了替代DES,对数据应用三次DES加密,安全性较高但速度较慢,逐渐被AES取代
package com.jysemel.top;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.util.Base64;
public class TripleDesDemo {
public static void main(String[] args) {
try {
// 原文
String plainText = "Hello, 3DES! 这是一段需要加密的文本。";
// 1. 生成 3DES 密钥 (DESede)
KeyGenerator keyGen = KeyGenerator.getInstance("DESede");
// 3DES 密钥长度可选 112 或 168 位,通常使用 168 位(24 字节)
keyGen.init(168);
SecretKey secretKey = keyGen.generateKey();
// 也可以从预先定义的字节数组恢复密钥(例如存储的密钥)
// byte[] keyBytes = secretKey.getEncoded();
// SecretKey keyFromBytes = new SecretKeySpec(keyBytes, "DESede");
System.out.println("原始文本: " + plainText);
// 2. 加密
byte[] cipherData = encrypt(plainText.getBytes("UTF-8"), secretKey);
System.out.println("加密后 (Base64): " + Base64.getEncoder().encodeToString(cipherData));
System.out.println("加密后 (Hex): " + bytesToHex(cipherData));
// 3. 解密
byte[] decryptedData = decrypt(cipherData, secretKey);
String decryptedText = new String(decryptedData, "UTF-8");
System.out.println("解密后文本: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用 3DES 加密数据
* @param data 待加密的字节数组
* @param key 3DES 密钥
* @return 加密后的字节数组
*/
public static byte[] encrypt(byte[] data, SecretKey key) throws Exception {
// 算法/模式/填充:ECB 模式 + PKCS5Padding(可根据需要改为 CBC 等)
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* 使用 3DES 解密数据
* @param encryptedData 密文字节数组
* @param key 3DES 密钥
* @return 解密后的字节数组
*/
public static byte[] decrypt(byte[] encryptedData, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(encryptedData);
}
/**
* 将字节数组转换为十六进制字符串(用于显示)
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}
AES加密
一种分组加密算法,将要加密的数据分成固定大小的数据块处理,每个数据库128位(16字节)
目前最常用的对称加密算法,用于文件加密、Wi-Fi加密(WPA2)、硬盘加密等
package com.jysemel.top;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.SecureRandom;
import java.util.Base64;
public class AesDemo {
public static void main(String[] args) {
try {
// 原文
String plainText = "Hello, AES! 这是一段需要加密的敏感信息。";
// 1. 生成 AES 密钥(128位)
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128); // 也可以使用 192 或 256 位(需要 JCE 无限强度策略文件支持 256)
SecretKey secretKey = keyGen.generateKey();
// 2. 生成随机 IV(初始化向量),长度为 16 字节
byte[] ivBytes = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(ivBytes);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
System.out.println("原始文本: " + plainText);
System.out.println("使用的 IV (Base64): " + Base64.getEncoder().encodeToString(ivBytes));
// 3. 加密
byte[] cipherData = encrypt(plainText.getBytes("UTF-8"), secretKey, ivSpec);
System.out.println("加密后 (Base64): " + Base64.getEncoder().encodeToString(cipherData));
System.out.println("加密后 (Hex): " + bytesToHex(cipherData));
// 4. 解密(使用相同的密钥和 IV)
byte[] decryptedData = decrypt(cipherData, secretKey, ivSpec);
String decryptedText = new String(decryptedData, "UTF-8");
System.out.println("解密后文本: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用 AES/CBC/PKCS5Padding 加密
* @param data 明文数据
* @param key AES 密钥
* @param iv 初始化向量
* @return 密文
*/
public static byte[] encrypt(byte[] data, SecretKey key, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
return cipher.doFinal(data);
}
/**
* 使用 AES/CBC/PKCS5Padding 解密
* @param encryptedData 密文
* @param key AES 密钥
* @param iv 初始化向量
* @return 明文
*/
public static byte[] decrypt(byte[] encryptedData, SecretKey key, IvParameterSpec iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
return cipher.doFinal(encryptedData);
}
/**
* 将字节数组转换为十六进制字符串
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}
非对称加密
- 特点: 加密和解密使用不同的密钥(一对密钥:公钥和私钥)。公钥可以公开给别人,私钥自己秘密保存。
- 优点: 解决了密钥分发问题,安全性极高。
- 缺点: 计算复杂,速度非常慢,通常只用来加密少量数据(如对称加密的密钥)
RSA
RSA算法,RSA算法是公开密钥加密算法,RSA算法的密钥长度可以自己定义
package com.jysemel.top;
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
public class RsaDemo {
public static void main(String[] args) {
try {
// 原文(RSA 加密的明文长度有限,这里使用较短文本)
String plainText = "Hello, RSA! 这是一段测试。";
// 1. 生成 RSA 密钥对(2048位)
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048); // 推荐使用 2048 位或更高
KeyPair keyPair = keyPairGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("原始文本: " + plainText);
System.out.println("公钥 (Base64): " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("私钥 (Base64): " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
// 2. 使用公钥加密
byte[] cipherData = encrypt(plainText.getBytes("UTF-8"), publicKey);
System.out.println("加密后 (Base64): " + Base64.getEncoder().encodeToString(cipherData));
// 3. 使用私钥解密
byte[] decryptedData = decrypt(cipherData, privateKey);
String decryptedText = new String(decryptedData, "UTF-8");
System.out.println("解密后文本: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用公钥加密
* @param data 明文数据
* @param publicKey 公钥
* @return 密文
*/
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 常用填充方式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 使用私钥解密
* @param encryptedData 密文
* @param privateKey 私钥
* @return 明文
*/
public static byte[] decrypt(byte[] encryptedData, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedData);
}
// 签名
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(data);
return sig.sign();
}
// 验签
public static boolean verify(byte[] data, byte[] signature, PublicKey publicKey) throws Exception {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(data);
return sig.verify(signature);
}
}
DSA
DSA算法,DSA算法是数字签名算法,DSA算法的密钥长度可以自己定义
-
DSA 与 RSA 不同,只能用于数字签名,不能用于加密或密钥交换
package com.jysemel.top;
import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.util.Base64;
public class DsaDemo {
public static void main(String[] args) { try { // 待签名的原始消息 String message = "Hello, DSA! 这是一条需要签名的消息。"; // 1. 生成 DSA 密钥对(1024位) KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA"); keyPairGen.initialize(1024); // 也可使用 2048 位(需 JDK 支持) KeyPair keyPair = keyPairGen.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); System.out.println("原始消息: " + message); System.out.println("私钥 (Base64): " + Base64.getEncoder().encodeToString(privateKey.getEncoded())); System.out.println("公钥 (Base64): " + Base64.getEncoder().encodeToString(publicKey.getEncoded())); // 2. 使用私钥对消息进行签名 Signature signer = Signature.getInstance("SHA1withDSA"); // 也可用 SHA256withDSA signer.initSign(privateKey); signer.update(message.getBytes("UTF-8")); byte[] signature = signer.sign(); System.out.println("签名结果 (Base64): " + Base64.getEncoder().encodeToString(signature)); System.out.println("签名结果 (Hex): " + bytesToHex(signature)); // 3. 使用公钥验证签名 Signature verifier = Signature.getInstance("SHA1withDSA"); verifier.initVerify(publicKey); verifier.update(message.getBytes("UTF-8")); boolean isVerified = verifier.verify(signature); System.out.println("签名验证结果: " + (isVerified ? "成功 ✓" : "失败 ✗")); // 4. 模拟篡改消息后的验证 String tamperedMessage = message + "篡改"; verifier.initVerify(publicKey); verifier.update(tamperedMessage.getBytes("UTF-8")); boolean isTamperedVerified = verifier.verify(signature); System.out.println("篡改消息验证结果: " + (isTamperedVerified ? "成功 ✓" : "失败 ✗(符合预期)")); } catch (Exception e) { e.printStackTrace(); } } /** * 将字节数组转换为十六进制字符串 */ private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); }}
ECC
密钥长度较短、但安全性同样高,适合对性能要求高的场景
哈希算法
不可逆加密算法,单向的加密算法、散列算法。相同的明文数据加密之后得到的密文相同,只能暴力破解、撞库攻击
- 特点: 将任意长度的数据,计算成固定长度的唯一字符串(哈希值)。这是一个单向过程,无法从哈希值还原原始数据。
- 用途: 验证数据完整性、存储密码、数字签名
MD5 算法
package com.jysemel.top;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Demo {
public static void main(String[] args) {
String input = "Hello, MD5! 这是一段测试文本。";
try {
// 计算 MD5 哈希
String md5Hash = calculateMD5(input);
System.out.println("原始字符串: " + input);
System.out.println("MD5 哈希值: " + md5Hash);
// 演示空字符串的 MD5
String emptyHash = calculateMD5("");
System.out.println("空字符串 MD5: " + emptyHash);
} catch (NoSuchAlgorithmException e) {
System.err.println("MD5 算法不可用: " + e.getMessage());
}
}
/**
* 计算字符串的 MD5 哈希值(十六进制字符串)
* @param input 输入字符串
* @return 32 位小写十六进制哈希值
* @throws NoSuchAlgorithmException 如果 JDK 不支持 MD5(几乎不会发生)
*/
public static String calculateMD5(String input) throws NoSuchAlgorithmException {
// 获取 MD5 MessageDigest 实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 更新摘要数据(UTF-8 编码)
byte[] messageDigest = md.digest(input.getBytes());
// 将字节数组转换为十六进制字符串
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();
}
}
SHA-1 算法
SHA-1 已被证实存在碰撞攻击,不应用于数字签名、证书或任何安全关键场景。本示例仅供学习或兼容遗留系统使用。实际开发请使用 SHA-256 或更高强度的哈希算法
package com.jysemel.top;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
public class Sha1Demo {
public static void main(String[] args) {
String input = "Hello, SHA-1! 这是一段测试文本。";
try {
// 计算 SHA-1 哈希
String sha1Hash = calculateSHA1(input);
System.out.println("原始字符串: " + input);
System.out.println("SHA-1 哈希值: " + sha1Hash);
// 演示空字符串的 SHA-1
String emptyHash = calculateSHA1("");
System.out.println("空字符串 SHA-1: " + emptyHash);
} catch (NoSuchAlgorithmException e) {
System.err.println("SHA-1 算法不可用: " + e.getMessage());
}
}
/**
* 计算字符串的 SHA-1 哈希值(十六进制字符串)
* @param input 输入字符串
* @return 40 位小写十六进制哈希值
* @throws NoSuchAlgorithmException 如果 JDK 不支持 SHA-1(几乎不会发生)
*/
public static String calculateSHA1(String input) throws NoSuchAlgorithmException {
// 获取 SHA-1 MessageDigest 实例
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 更新摘要数据(指定 UTF-8 编码避免跨平台问题)
byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
// 将字节数组转换为十六进制字符串
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();
}
}
SHA-256 算法
package com.jysemel.top;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
public class Sha256Demo {
public static void main(String[] args) {
String input = "Hello, SHA-256! 这是一段测试文本。";
try {
// 计算 SHA-256 哈希
String sha256Hash = calculateSHA256(input);
System.out.println("原始字符串: " + input);
System.out.println("SHA-256 哈希值: " + sha256Hash);
// 演示空字符串的 SHA-256
String emptyHash = calculateSHA256("");
System.out.println("空字符串 SHA-256: " + emptyHash);
} catch (NoSuchAlgorithmException e) {
System.err.println("SHA-256 算法不可用: " + e.getMessage());
}
}
/**
* 计算字符串的 SHA-256 哈希值(十六进制字符串)
* @param input 输入字符串
* @return 64 位小写十六进制哈希值
* @throws NoSuchAlgorithmException 如果 JDK 不支持 SHA-256(通常都支持)
*/
public static String calculateSHA256(String input) throws NoSuchAlgorithmException {
// 获取 SHA-256 MessageDigest 实例
MessageDigest md = MessageDigest.getInstance("SHA-256");
// 更新摘要数据(指定 UTF-8 编码避免跨平台问题)
byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
// 将字节数组转换为十六进制字符串
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();
}
}
混合加密
在实际应用中(比如你正在使用的HTTPS协议),通常不会只用一种加密方式,而是混合使用:
- 使用非对称加密:安全地传输一个临时生成的对称密钥(解决密钥传递问题)。
- 使用对称加密:用这个协商好的密钥,加密实际传输的大量数据(解决加解密速度问题)。
- 使用哈希函数:验证数据在传输过程中是否被篡改
国密
国密算法是国家密码管理局制定的国产密码标准,主要包括SM2(非对称)、SM3(哈希)和SM4(对称)三种核心算法
-
maven 依赖
org.bouncycastle bcprov-jdk15on 1.70 -
示例
package com.jysemel.top;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher; import java.security.*; import java.security.spec.ECGenParameterSpec;
public class SM2Demo {
static { // 添加 Bouncy Castle 作为安全提供者 Security.addProvider(new BouncyCastleProvider()); } public static void main(String[] args) throws Exception { String plainText = "Hello, SM2! 这是一段需要加密的文本。"; // 1. 生成 SM2 密钥对 (使用 sm2p256v1 曲线) KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC"); ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1"); keyPairGenerator.initialize(sm2Spec, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); System.out.println("原始文本: " + plainText); // 2. 使用公钥加密 Cipher cipher = Cipher.getInstance("SM2", "BC"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] cipherData = cipher.doFinal(plainText.getBytes("UTF-8")); System.out.println("加密后 (Base64): " + java.util.Base64.getEncoder().encodeToString(cipherData)); // 3. 使用私钥解密 cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedData = cipher.doFinal(cipherData); String decryptedText = new String(decryptedData, "UTF-8"); System.out.println("解密后文本: " + decryptedText); }}
package com.jysemel.top;
import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security;
public class SM3Demo {
static { Security.addProvider(new BouncyCastleProvider()); } public static void main(String[] args) { String plainText = "Hello, SM3! 这是一段需要哈希的文本。"; System.out.println("原始文本: " + plainText); // 计算 SM3 哈希值 byte[] hash = sm3Hash(plainText.getBytes()); System.out.println("SM3 哈希值 (Hex): " + bytesToHex(hash)); System.out.println("SM3 哈希值 (Base64): " + java.util.Base64.getEncoder().encodeToString(hash)); } public static byte[] sm3Hash(byte[] input) { SM3Digest digest = new SM3Digest(); digest.update(input, 0, input.length); byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); return hash; } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); }}
package com.jysemel.top;
import org.bouncycastle.crypto.engines.SM4Engine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.SecureRandom; import java.security.Security;
public class SM4Demo {
static { Security.addProvider(new BouncyCastleProvider()); } public static void main(String[] args) throws Exception { String plainText = "Hello, SM4! 这是一段需要加密的文本。"; // 生成一个 128 位的随机密钥和 IV byte[] key = new byte[16]; byte[] iv = new byte[16]; new SecureRandom().nextBytes(key); new SecureRandom().nextBytes(iv); System.out.println("原始文本: " + plainText); // 加密 byte[] cipherData = sm4CbcEncrypt(plainText.getBytes("UTF-8"), key, iv); System.out.println("加密后 (Base64): " + java.util.Base64.getEncoder().encodeToString(cipherData)); // 解密 byte[] decryptedData = sm4CbcDecrypt(cipherData, key, iv); String decryptedText = new String(decryptedData, "UTF-8"); System.out.println("解密后文本: " + decryptedText); } public static byte[] sm4CbcEncrypt(byte[] input, byte[] key, byte[] iv) throws Exception { // 创建 SM4 引擎并包装为 CBC 模式 + PKCS7 填充 PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher( new CBCBlockCipher(new SM4Engine())); cipher.init(true, new ParametersWithIV(new KeyParameter(key), iv)); return process(cipher, input); } public static byte[] sm4CbcDecrypt(byte[] input, byte[] key, byte[] iv) throws Exception { PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher( new CBCBlockCipher(new SM4Engine())); cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv)); return process(cipher, input); } private static byte[] process(PaddedBufferedBlockCipher cipher, byte[] input) throws Exception { byte[] output = new byte[cipher.getOutputSize(input.length)]; int bytesProcessed = cipher.processBytes(input, 0, input.length, output, 0); int bytesFinalized = cipher.doFinal(output, bytesProcessed); byte[] finalOutput = new byte[bytesProcessed + bytesFinalized]; System.arraycopy(output, 0, finalOutput, 0, finalOutput.length); return finalOutput; }}
编码
常见编码方式Base64编码、URL编码等
Base64编码
将任意二进制数据编码为ASCII字符串、将二进制数据存储为文本文件,或者将二进制数据进行网络传输
- 由64个字符组成编码集,26个大写字母、26个小写字母、10个数字、2个特殊字符(+,/),当原始数据不够三个字节时,用=进行填充
- 编码
将二进制数据转为字符
- 解码
将字符转为二进制数据
URL编码
主要将特殊字符串和不可打印的字符转换为百分号(%)加上两位十六进制的形式,以确保字符在URL中可以正确传递和解析
package com.jysemel.top;
import java.util.Base64;
public class Base64Demo {
public static void main(String[] args) {
String original = "Hello, 编码世界!";
// 编码
String encoded = Base64.getEncoder().encodeToString(original.getBytes());
System.out.println("Base64 编码: " + encoded);
// 解码
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes);
System.out.println("解码后: " + decoded);
// URL 安全的 Base64(替换 + 和 / 为 - 和 _)
String urlSafe = Base64.getUrlEncoder().encodeToString(original.getBytes());
System.out.println("URL 安全 Base64: " + urlSafe);
}
}
package com.jysemel.top;
/**
* Hex 将每个字节表示为两个十六进制字符(0-9A-F),常用于查看二进制数据或生成哈希值的字符串表示
*/
public class HexDemo {
public static void main(String[] args) {
String original = "Hello Hex";
// 编码:字节 -> 十六进制字符串
byte[] bytes = original.getBytes();
StringBuilder hex = new StringBuilder();
for (byte b : bytes) {
hex.append(String.format("%02x", b));
}
System.out.println("Hex 编码: " + hex);
// 解码:十六进制字符串 -> 字节
String hexStr = hex.toString();
byte[] decodedBytes = new byte[hexStr.length() / 2];
for (int i = 0; i < decodedBytes.length; i++) {
int index = i * 2;
int val = Integer.parseInt(hexStr.substring(index, index + 2), 16);
decodedBytes[i] = (byte) val;
}
String decoded = new String(decodedBytes);
System.out.println("解码后: " + decoded);
}
}
package com.jysemel.top;
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
public class URLEncodingDemo {
public static void main(String[] args) throws Exception {
String original = "name=张三&age=20";
// 编码
String encoded = URLEncoder.encode(original, String.valueOf(StandardCharsets.UTF_8));
System.out.println("URL 编码: " + encoded); // name%3D%E5%BC%A0%E4%B8%89%26age%3D20
// 解码
String decoded = URLDecoder.decode(encoded, String.valueOf(StandardCharsets.UTF_8));
System.out.println("解码后: " + decoded);
}
}