前言
平时的工作中,我们在很多地方用到了加密、解密,比如:用户的密码不能明文存储,要存储加密后的密文,用户的银行卡号、身份证号和数据金额之类的敏感数据,需要加密传输,还有一些重要接口,比如支付,客户端要对请求生成一个签名,服务端要对签名进行验证……
上面提到的这些能力,我们都需要利用加密算法来实现
常见加密算法
算法工具类
我整理了一些常用的算法工具类,具体内容见下
DES
DesUtil
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class DesUtil {
private static final String DES_ALGORITHM = "DES";
public static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.getDecoder().decode(base64Code);
}
/**
* 加密
*
* @param content 待加密内容
* @param encryptKey 加密密钥
* @return 加密后的密文
* @throws Exception
*/
public static byte[] desEncryptToBytes(String content, String encryptKey) throws Exception {
DESKeySpec desKeySpec = new DESKeySpec(encryptKey.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
SecretKey key = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
}
/**
* 解密
*
* @param content 待解密内容
* @param decryptKey 解密密钥
* @return 解密后的明文
* @throws Exception
*/
public static String desDecryptByBytes(byte[] content, String decryptKey) throws Exception {
DESKeySpec desKeySpec = new DESKeySpec(decryptKey.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
SecretKey key = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] result = cipher.doFinal(content);
return new String(result, StandardCharsets.UTF_8);
}
/**
* 加密
*
* @param content 待加密内容
* @param encryptKey 加密密钥
* @return 加密后的密文(Base64编码)
* @throws Exception
*/
public static String desEncrypt(String content, String encryptKey) throws Exception {
byte[] encryptBytes = desEncryptToBytes(content, encryptKey);
return base64Encode(encryptBytes);
}
/**
* 解密
*
* @param content 待解密内容(Base64编码)
* @param decryptKey 解密密钥
* @return 解密后的明文
* @throws Exception
*/
public static String desDecrypt(String content, String decryptKey) throws Exception {
byte[] decryptBytes = base64Decode(content);
return desDecryptByBytes(decryptBytes, decryptKey);
}
}
AES
AesUtil
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class AesUtil {
private static final String AES_ALGORITHM = "AES";
public static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.getDecoder().decode(base64Code);
}
/**
* 加密
*
* @param content 待加密内容
* @param encryptKey 加密密钥
* @return 加密后的密文
* @throws Exception
*/
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
SecretKeySpec key = new SecretKeySpec(encryptKey.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
}
/**
* 解密
*
* @param content 待解密内容
* @param decryptKey 解密密钥
* @return 解密后的明文
* @throws Exception
*/
public static String aesDecryptByBytes(byte[] content, String decryptKey) throws Exception {
SecretKeySpec key = new SecretKeySpec(decryptKey.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] result = cipher.doFinal(content);
return new String(result, StandardCharsets.UTF_8);
}
/**
* 加密
*
* @param content 待加密内容
* @param encryptKey 加密密钥
* @return 加密后的密文(Base64编码)
* @throws Exception
*/
public static String aesEncrypt(String content, String encryptKey) throws Exception {
byte[] encryptBytes = aesEncryptToBytes(content, encryptKey);
return base64Encode(encryptBytes);
}
/**
* 解密
*
* @param content 待解密内容(Base64编码)
* @param decryptKey 解密密钥
* @return 解密后的明文
* @throws Exception
*/
public static String aesDecrypt(String content, String decryptKey) throws Exception {
byte[] decryptBytes = base64Decode(content);
return aesDecryptByBytes(decryptBytes, decryptKey);
}
}
Blowfish
BlowfishUtil
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class BlowfishUtil {
private static final String BLOWFISH_ALGORITHM = "Blowfish";
public static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.getDecoder().decode(base64Code);
}
/**
* 加密
*
* @param content 待加密内容
* @param encryptKey 加密密钥
* @return 加密后的密文
* @throws Exception
*/
public static byte[] blowfishEncryptToBytes(String content, String encryptKey) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(encryptKey.getBytes(StandardCharsets.UTF_8), BLOWFISH_ALGORITHM);
Cipher cipher = Cipher.getInstance(BLOWFISH_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
}
/**
* 解密
*
* @param content 待解密内容
* @param decryptKey 解密密钥
* @return 解密后的明文
* @throws Exception
*/
public static String blowfishDecryptByBytes(byte[] content, String decryptKey) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(decryptKey.getBytes(StandardCharsets.UTF_8), BLOWFISH_ALGORITHM);
Cipher cipher = Cipher.getInstance(BLOWFISH_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] result = cipher.doFinal(content);
return new String(result, StandardCharsets.UTF_8);
}
/**
* 加密
*
* @param content 待加密内容
* @param encryptKey 加密密钥
* @return 加密后的密文(Base64编码)
* @throws Exception
*/
public static String blowfishEncrypt(String content, String encryptKey) throws Exception {
byte[] encryptBytes = blowfishEncryptToBytes(content, encryptKey);
return base64Encode(encryptBytes);
}
/**
* 解密
*
* @param content 待解密内容(Base64编码)
* @param decryptKey 解密密钥
* @return 解密后的明文
* @throws Exception
*/
public static String blowfishDecrypt(String content, String decryptKey) throws Exception {
byte[] decryptBytes = base64Decode(content);
return blowfishDecryptByBytes(decryptBytes, decryptKey);
}
}
RSA
RSAUtil
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import java.util.Base64;
public class RSAUtil {
private static final String RSA_ALGORITHM = "RSA";
public static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.getDecoder().decode(base64Code);
}
/**
* 加密
*
* @param content 待加密内容
* @param publicKey 公钥
* @return 加密后的密文(Base64编码)
* @throws Exception
*/
public static String rsaEncrypt(String content, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return base64Encode(encryptBytes);
}
/**
* 解密
*
* @param content 待解密内容(Base64编码)
* @param privateKey 私钥
* @return 解密后的明文
* @throws Exception
*/
public static String rsaDecrypt(String content, PrivateKey privateKey) throws Exception {
byte[] decryptBytes = base64Decode(content);
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(decryptBytes);
return new String(result, StandardCharsets.UTF_8);
}
/**
* 将Base64编码的公钥字符串转换为PublicKey对象
*
* @param publicKeyStr Base64编码的公钥字符串
* @return PublicKey对象
* @throws Exception
*/
public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
byte[] publicKeyBytes = base64Decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 将Base64编码的私钥字符串转换为PrivateKey对象
*
* @param privateKeyStr Base64编码的私钥字符串
* @return PrivateKey对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception {
byte[] privateKeyBytes = base64Decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
}
DSA
DSAUtil
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class DSAUtil {
private static final String DSA_ALGORITHM = "DSA";
public static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.getDecoder().decode(base64Code);
}
/**
* 使用私钥对内容进行签名
*
* @param content 待签名内容
* @param privateKey 私钥
* @return 签名结果(Base64编码)
* @throws Exception
*/
public static String dsaSign(String content, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance(DSA_ALGORITHM);
signature.initSign(privateKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
byte[] signBytes = signature.sign();
return base64Encode(signBytes);
}
/**
* 使用公钥验证签名
*
* @param content 待验证内容
* @param signatureStr 签名结果(Base64编码)
* @param publicKey 公钥
* @return 验证结果
* @throws Exception
*/
public static boolean dsaVerify(String content, String signatureStr, PublicKey publicKey) throws Exception {
byte[] signatureBytes = base64Decode(signatureStr);
Signature signature = Signature.getInstance(DSA_ALGORITHM);
signature.initVerify(publicKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
return signature.verify(signatureBytes);
}
/**
* 将Base64编码的公钥字符串转换为PublicKey对象
*
* @param publicKeyStr Base64编码的公钥字符串
* @return PublicKey对象
* @throws Exception
*/
public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
byte[] publicKeyBytes = base64Decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(DSA_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 将Base64编码的私钥字符串转换为PrivateKey对象
*
* @param privateKeyStr Base64编码的私钥字符串
* @return PrivateKey对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception {
byte[] privateKeyBytes = base64Decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(DSA_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
}
ECC
ECCUtil
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class ECCUtil {
private static final String ECC_ALGORITHM = "EC";
public static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.getDecoder().decode(base64Code);
}
/**
* 使用私钥对内容进行签名
*
* @param content 待签名内容
* @param privateKey 私钥
* @return 签名结果(Base64编码)
* @throws Exception
*/
public static String eccSign(String content, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(privateKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
byte[] signBytes = signature.sign();
return base64Encode(signBytes);
}
/**
* 使用公钥验证签名
*
* @param content 待验证内容
* @param signatureStr 签名结果(Base64编码)
* @param publicKey 公钥
* @return 验证结果
* @throws Exception
*/
public static boolean eccVerify(String content, String signatureStr, PublicKey publicKey) throws Exception {
byte[] signatureBytes = base64Decode(signatureStr);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(publicKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
return signature.verify(signatureBytes);
}
/**
* 将Base64编码的公钥字符串转换为PublicKey对象
*
* @param publicKeyStr Base64编码的公钥字符串
* @return PublicKey对象
* @throws Exception
*/
public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
byte[] publicKeyBytes = base64Decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ECC_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 将Base64编码的私钥字符串转换为PrivateKey对象
*
* @param privateKeyStr Base64编码的私钥字符串
* @return PrivateKey对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception {
byte[] privateKeyBytes = base64Decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ECC_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
}
MD5
FileMD5Util
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@Slf4j
public class FileMD5Util {
private static final String MD5_ALGORITHM = "MD5";
/**
* 计算文件的MD5哈希值
*
* @param file 文件对象
* @return 计算得到的MD5哈希值的十六进制表示
* @throws NoSuchAlgorithmException 如果MD5算法不可用
* @throws IOException 如果读取文件时发生I/O错误
*/
public static String calculateFileMD5(File file) throws NoSuchAlgorithmException, IOException {
try (InputStream is = new FileInputStream(file)) {
return calculateFileMD5(is);
} catch (IOException e) {
log.error("Failed to calculate MD5 for file: {}", file.getAbsolutePath(), e);
throw e;
}
}
/**
* 计算文件的MD5哈希值
*
* @param filePath 文件路径
* @return 计算得到的MD5哈希值的十六进制表示
* @throws NoSuchAlgorithmException 如果MD5算法不可用
* @throws IOException 如果读取文件时发生I/O错误
*/
public static String calculateFileMD5(String filePath) throws NoSuchAlgorithmException, IOException {
File file = new File(filePath);
return calculateFileMD5(file);
}
/**
* 计算文件的MD5哈希值
*
* @param inputStream 文件输入流
* @return 计算得到的MD5哈希值的十六进制表示
* @throws NoSuchAlgorithmException 如果MD5算法不可用
* @throws IOException 如果读取文件时发生I/O错误
*/
public static String calculateFileMD5(InputStream inputStream) throws NoSuchAlgorithmException, IOException {
MessageDigest md = MessageDigest.getInstance(MD5_ALGORITHM);
try (DigestInputStream dis = new DigestInputStream(inputStream, md)) {
byte[] buffer = new byte[4096];
while (dis.read(buffer) != -1) {
// 读取文件内容,更新消息摘要
md.update(buffer);
}
}
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
/**
* 校验文件的完整性
*
* @param file 文件对象
* @param expectedMD5 预期的MD5哈希值(十六进制表示)
* @return 如果实际的MD5哈希值与预期值相等(忽略大小写),返回true;否则返回false
* @throws NoSuchAlgorithmException 如果MD5算法不可用
* @throws IOException 如果读取文件时发生I/O错误
*/
public static boolean verifyFileIntegrity(File file, String expectedMD5)
throws NoSuchAlgorithmException, IOException {
try (InputStream is = new FileInputStream(file)) {
return verifyFileIntegrity(is, expectedMD5);
} catch (IOException e) {
log.error("Failed to verify file integrity for file: {}", file.getAbsolutePath(), e);
throw e;
}
}
/**
* 校验文件的完整性
*
* @param filePath 文件路径
* @param expectedMD5 预期的MD5哈希值(十六进制表示)
* @return 如果实际的MD5哈希值与预期值相等(忽略大小写),返回true;否则返回false
* @throws NoSuchAlgorithmException 如果MD5算法不可用
* @throws IOException 如果读取文件时发生I/O错误
*/
public static boolean verifyFileIntegrity(String filePath, String expectedMD5)
throws NoSuchAlgorithmException, IOException {
File file = new File(filePath);
return verifyFileIntegrity(file, expectedMD5);
}
/**
* 校验文件的完整性
*
* @param inputStream 文件输入流
* @param expectedMD5 预期的MD5哈希值(十六进制表示)
* @return 如果实际的MD5哈希值与预期值相等(忽略大小写),返回true;否则返回false
* @throws NoSuchAlgorithmException 如果MD5算法不可用
* @throws IOException 如果读取文件时发生I/O错误
*/
public static boolean verifyFileIntegrity(InputStream inputStream, String expectedMD5)
throws NoSuchAlgorithmException, IOException {
String actualMD5 = calculateFileMD5(inputStream);
return actualMD5.equalsIgnoreCase(expectedMD5);
}
}
SHA-1、SHA-256、SHA-384、SHA-512
SHAUtil
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class SHAUtil {
/**
* 计算 SHA-1 哈希值
*
* @param content 待计算的内容
* @return SHA-1 哈希值
* @throws Exception 计算过程中的异常
*/
public static String sha1(String content) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] hashBytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
return bytesToHexString(hashBytes);
}
/**
* 计算 SHA-256 哈希值
*
* @param content 待计算的内容
* @return SHA-256 哈希值
* @throws Exception 计算过程中的异常
*/
public static String sha256(String content) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
return bytesToHexString(hashBytes);
}
/**
* 计算 SHA-384 哈希值
*
* @param content 待计算的内容
* @return SHA-384 哈希值
* @throws Exception 计算过程中的异常
*/
public static String sha384(String content) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-384");
byte[] hashBytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
return bytesToHexString(hashBytes);
}
/**
* 计算 SHA-512 哈希值
*
* @param content 待计算的内容
* @return SHA-512 哈希值
* @throws Exception 计算过程中的异常
*/
public static String sha512(String content) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
byte[] hashBytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
return bytesToHexString(hashBytes);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param bytes 字节数组
* @return 十六进制字符串
*/
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
HMAC
HMACUtil
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class HMACUtil {
private static final String HMAC_ALGORITHM = "HmacSHA256";
private static final String CHARSET = "UTF-8";
/**
* 计算 HMAC 值
*
* @param content 待计算的内容
* @param secretKey 密钥
* @return HMAC 值(Base64 编码)
* @throws Exception 计算过程中的异常
*/
public static String calculateHMAC(String content, String secretKey) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_ALGORITHM);
mac.init(keySpec);
byte[] hmacBytes = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hmacBytes);
}
}
One comment
想想你的文章写的特别好