直接上代码:
package com.day02;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Formatter;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/*
* 常见的五种算法加密
*
*/
public class EncryptionAlgorithm {
public static void main(String[] args) throws Exception {
String s1 = "6103211996xxxxxxxx"; // 测试身份证号
String data1 = md5Encrypt(s1);
System.out.println("MD5不可逆算法加密的数据:" + data1);
System.out.println("MD5不可逆算法加密的数据长度::" + data1.length());
System.out.println("-------------------------------------------------");
String s2 = "6103211996xxxxxxxx"; // 测试身份证号
String data2 = SHAEncrypt(s2);
System.out.println("SHA不可逆算法加密的数据:" + data2);
System.out.println("SHA512不可逆算法加密的数据长度::" + data2.length());
System.out.println("-------------------------------------------------");
String s3 = "6103211996xxxxxxxx"; // 测试身份证号
String key = "DES12345"; // 密钥,长度必须为8位
String encryptedData1 = DESEncrypt(s3, key);
System.out.println("DES对称可逆算法加密后的数据:" + encryptedData1);
System.out.println("DES对称可逆算法加密后的数据长度::" + encryptedData1.length());
String decryptedData1 = DESDecrypt(encryptedData1, key);
System.out.println("DES对称可逆算法解密后的数据:" + decryptedData1);
System.out.println("-------------------------------------------------");
String s4 = "6103211996xxxxxxxx"; // 测试身份证号
String encryptedData2 = AESEncrypt(s4);
System.out.println("AES对称可逆算法加密后的数据:" + encryptedData2);
System.out.println("AES对称可逆算法加密后的数据长度:" + encryptedData2.length());
String decryptedData2 = AESDecrypt(encryptedData2);
System.out.println("AES对称可逆算法解密后的数据:" + decryptedData2);
System.out.println("-------------------------------------------------");
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String s5 = "6103211996xxxxxxxx"; // 测试身份证号
String encryptedData3 = RSAEncrypt(s5, publicKey);
System.out.println("RSA非对称可逆算法加密后的数据:" + encryptedData3);
System.out.println("RSA非对称可逆算法加密后的数据长度:" + encryptedData3.length());
String decryptedData3 = RSADecrypt(encryptedData3, privateKey);
System.out.println("RSA非对称可逆算法解密后的数据:" + decryptedData3);
System.out.println("-------------------------------------------------");
}
/*
* 不可逆加密算法一:MD5算法加密(MD5算法的输出长度为128位,通常用32个16进制数表示)
* 特点:不可逆(不可逆加密的算法的加密是不可逆的,密文无法被还原成原文),也称为:散列算法;
* 优点:计算速度快、输出长度固定、应用广泛等
* 缺点:不安全
*
*/
private static final String MD5_ALGORITHM = "MD5";
public static String md5Encrypt(String data) throws Exception {
// 获取MD5算法实例
MessageDigest messageDigest = MessageDigest.getInstance(MD5_ALGORITHM);
// 计算散列值
byte[] digest = messageDigest.digest(data.getBytes());
Formatter formatter = new Formatter();
// 补齐前导0,并格式化
for (byte b : digest) {
formatter.format("%02x", b);
}
return formatter.toString();
}
/*
* 不可逆加密算法二:SHA-256(SHA系列算法是一组密码散列函数,用于将任意长度的数据映射为固定长度的散列值)
* 目前共有SHA-1、SHA-2、SHA-3三种版本。
* SHA-2算法包括SHA-224、SHA-256、SHA-384和SHA-512四种散列函数,分别将任意长度的数据映射为224位、256位、384位和512位的散列值。
* 特点:不可逆(不可逆加密的算法的加密是不可逆的,密文无法被还原成原文),但是SHA-2算法安全比MD5强
* 散列值长度更长:例如SHA-256算法的散列值长度为256位,而MD5算法的散列值长度为128位,这就提高了攻击者暴力破解或者彩虹表攻击的难度。
* 更强的碰撞抗性:SHA算法采用了更复杂的运算过程和更多的轮次,使得攻击者更难以通过预计算或巧合找到碰撞。
* 当然,SHA-2也不是绝对安全的,散列算法都有被暴力破解或者彩虹表攻击的风险,所以,在实际的应用中,加盐还是必不可少的。
*
*/
private static final String SHA_512_ALGORITHM = "SHA-512"; // SHA-224/SHA-256/SHA-384/SHA-512
public static String SHAEncrypt(String data) throws Exception {
//获取SHA-256算法实例
MessageDigest messageDigest = MessageDigest.getInstance(SHA_512_ALGORITHM);
//计算散列值
byte[] digest = messageDigest.digest(data.getBytes());
StringBuilder stringBuilder = new StringBuilder();
//将byte数组转换为15进制字符串
for (byte b : digest) {
stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
}
return stringBuilder.toString();
}
/*
* 可逆算法加密一:DES(对称加密算法)
* 特点:DES算法使用56位密钥对数据进行加密,加密过程中使用了置换、替换、异或等运算,具有较高的安全性
* DES的算法速度较快,但是在安全性上面并不是最优选择,因为DES算法的密钥长度比较短,
* 被暴力破解和差分攻击的风险比较高,一般推荐用一些更安全的对称加密算法,比如3DES、AES
*
* @param data 待加密的数据
* @param key 密钥,长度必须为8位
* @return 加密后的数据,使用Base64编码
*
*/
private static final String DES_ALGORITHM = "DES";
public static String DESEncrypt(String data, String key) throws Exception {
// 根据密钥生成密钥规范
KeySpec keySpec = new DESKeySpec(key.getBytes());
// 根据密钥规范生成密钥工厂
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
// 根据密钥工厂和密钥规范生成密钥
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// 根据加密算法获取加密器
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
// 初始化加密器,设置加密模式和密钥
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 加密数据
byte[] encryptedData = cipher.doFinal(data.getBytes());
// 对加密后的数据进行Base64编码
return Base64.getEncoder().encodeToString(encryptedData);
}
/*
* DES解密
*
* @param encryptedData 加密后的数据,使用Base64编码
* @param key 密钥,长度必须为8位
* @return 解密后的数据
*/
public static String DESDecrypt(String encryptedData, String key) throws Exception {
// 根据密钥生成密钥规范
KeySpec keySpec = new DESKeySpec(key.getBytes());
// 根据密钥规范生成密钥工厂
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
// 根据密钥工厂和密钥规范生成密钥
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// 对加密后的数据进行Base64解码
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// 根据加密算法获取解密器
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
// 初始化解密器,设置解密模式和密钥
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 解密数据
byte[] decryptedData = cipher.doFinal(decodedData);
// 将解密后的数据转换为字符串
return new String(decryptedData);
}
/*
* 可逆算法加密二:AES加密(高级加密标准,对称加密算法,AES算法使用的密钥长度为128位、192位或256位,比DES算法的密钥长度更长,安全性更高)
* 特点:ES算法采用的密钥长度更长,密钥空间更大,安全性更高,能够有效地抵抗暴力破解攻击。
当然,因为密钥长度较长,需要的存储也更多。
对于对称加密算法而言,最大的痛点就在于密钥管理困难,相比而言,非对称加密就没有这个担忧
*
* @param data 待加密的数据
* @return 加密后的数据,使用Base64编码
*/
private static final String AES_ALGORITHM = "AES";
// AES加密模式为CBC,填充方式为PKCS5Padding
private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
// AES密钥为16位
private static final String AES_KEY = "1234567890123456";
// AES初始化向量为16位
private static final String AES_IV = "abcdefghijklmnop";
public static String AESEncrypt(String data) throws Exception {
// 将AES密钥转换为SecretKeySpec对象
SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
// 将AES初始化向量转换为IvParameterSpec对象
IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
// 根据加密算法获取加密器
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
// 初始化加密器,设置加密模式、密钥和初始化向量
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// 加密数据
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
// 对加密后的数据使用Base64编码
return Base64.getEncoder().encodeToString(encryptedData);
}
/*
* AES解密
*
* @param encryptedData 加密后的数据,使用Base64编码
* @return 解密后的数据
*/
public static String AESDecrypt(String encryptedData) throws Exception {
// 将AES密钥转换为SecretKeySpec对象
SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
// 将AES初始化向量转换为IvParameterSpec对象
IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
// 根据加密算法获取解密器
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
// 初始化解密器,设置解密模式、密钥和初始化向量
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// 对加密后的数据使用Base64解码
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// 解密数据
byte[] decryptedData = cipher.doFinal(decodedData);
// 返回解密后的数据
return new String(decryptedData, StandardCharsets.UTF_8);
}
/*
* 可逆加密算法三:RSA(非对称加密算法)
* 非对称加密算法需要两个密钥,这两个密钥互不相同,但是相互匹配,一个称为公钥,另一个称为私钥。
* 使用其中的一个加密,则使用另一个进行解密。例如使用公钥加密,则需要使用私钥解密。
* 特点:RSA算法的优点是安全性高,公钥可以公开,私钥必须保密,保证了数据的安全性;可用于数字签名、密钥协商等多种应用场景。
* 缺点是加密、解密速度较慢,密钥长度越长,加密、解密时间越长;密钥长度过短容易被暴力破解,密钥长度过长则会增加计算量和存储空间的开销。
*
* 生成RSA密钥对
*
* @return RSA密钥对
*/
private static final String RSA_ALGORITHM = "RSA";
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
keyPairGenerator.initialize(2048); // 密钥大小为2048位
return keyPairGenerator.generateKeyPair();
}
/*
* 使用公钥加密数据
*
* @param data 待加密的数据
* @param publicKey 公钥
* @return 加密后的数据
*/
public static String RSAEncrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedData);
}
/*
* 使用私钥解密数据
*
* @param encryptedData 加密后的数据
* @param privateKey 私钥
* @return 解密后的数据
*/
public static String RSADecrypt(String encryptedData, PrivateKey privateKey) throws Exception {
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData = cipher.doFinal(decodedData);
return new String(decryptedData, StandardCharsets.UTF_8);
}
}
测试输出:
MD5不可逆算法加密的数据:9ac85b1b9b3aa99bf769ffd9d5eeaabc
MD5不可逆算法加密的数据长度::32
-------------------------------------------------
SHA不可逆算法加密的数据:ab4b60c37f52de81ce28d55604efc42b08e803db25928f1d7ee428bec1b16c57e787a1df4ee438e13a625936e6d591903dd320f04b3e5b6468b039b82ff799b5
SHA512不可逆算法加密的数据长度::128
-------------------------------------------------
DES对称可逆算法加密后的数据:BNMgizZYKuxP+tDUJlZCAcTAxPQj3jjH
DES对称可逆算法加密后的数据长度::32
DES对称可逆算法解密后的数据:6103211996xxxxxxxx
-------------------------------------------------
AES对称可逆算法加密后的数据:cmgyllaA6AAYJBHNS4WMvwd12HhnCzQw9lvrlkP51M8=
AES对称可逆算法加密后的数据长度:44
AES对称可逆算法解密后的数据:6103211996xxxxxxxx
-------------------------------------------------
RSA非对称可逆算法加密后的数据:shrFh9f6DDbtsY0sdIYWqHiAlMn51anoI1COJj6PyLPDOhP0VXduLOsjqCSA9o45DukvpgQg6N2cSQIsPYHr4GXfSIrMNePk4mlzXPD3UZkHZrhY7rzQND/t7kpfyWUCjmgaOBA+5QstD5toIA8RQF27HKiQWOOAaNL42wVGA5KUtGth5gKhyOtFmo+wrdgZ3LHEny8xq4xMEISVc8J/O0n+z6RWbJxQ3Qrn2qWFM2zd4Ui8PHaeRKq1rPfbmn5DJZDWDwUmqpWqWbF8jwtW6XMcz9EqLjqVrgKbsu0/69Ww9mz1bJ1UtqgdACv1Zp032KMaHhtXxeaTfSvZpEJeZw==
RSA非对称可逆算法加密后的数据长度:344
RSA非对称可逆算法解密后的数据:6103211996xxxxxxxx
-------------------------------------------------