系列文章目录
第一章:Java实现常用加密算法 —— MD5
第二章:Java实现常用加密算法 —— SHA256
前言
本篇主要介绍了各种常用的加密算法在Java(JDK1.8)中如何实现,借助Java标准库或第三方库,非原始实现,较为基础。各个算法的具体介绍或实现方法请参见系列其他文章,本文为汇总,可以照抄作业。
一、各算法对比
根据
是否可逆
和是否对称
对算法进行分类,是否可逆其实就是是否能进行解密操作
是否可逆 | 算法 |
---|---|
不可逆 | MD5、SHA-256、SM3、HMAC |
可逆 | 对称:DES、AES、SM1、SM4,不对称:RSA、SM2 |
二、代码汇总
1、编写代码
1)引入第三方库
<!-- SpringBoot或SpringCloud项目中已有此包,无需再额外引入 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.31</version>
</dependency>
<!-- 建议使用最新版本 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<!-- 建议使用最新版本 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
2)使用Java8在IDEA中实现,示例代码如下:
package com.example.base.util;
//import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
//import org.springframework.util.DigestUtils;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* 加密算法工具类(能用国密就用国密,免得以后因为安全问题让你改)
* <p>
* 1、不可逆:MD5、SHA、HMAC、SM3
* 2.1、可逆对称:DES、AES、SM1(未公开)、SM4
* 2.2、可逆不对称:RSA、SM2
*
* @author 一个不愿意透露姓名的帅比
* @date 2024/7/13 21:01
*/
@SuppressWarnings("unused")
public class EncryptUtils {
static {
// 添加安全提供者(SM2,SM3,SM4等加密算法,CBC、CFB等加密模式,PKCS7Padding等填充方式,不在Java标准库中,由BouncyCastleProvider实现)
Security.addProvider(new BouncyCastleProvider());
}
// -------------------------------------------------------------------------------------- 不可逆加密(无法解密,一般输出为16进制字符串)
/**
* MD5,信息摘要算法(Message-Digest Algorithm5),一种被广泛使用的密码散列函数,可以产生出一个固定长度的散列值。用于确保信息传输完整一致。
* <p>
* 输入:待加密的字符串
* 输出:128位(16字节)或32个16进制字符(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★☆☆☆☆
*
* @param plainString 明文
* @return cipherString 密文
*/
public static String md5(String plainString) {
// 方式1(推荐):使用spring的工具类;org.springframework.util.DigestUtils
// return DigestUtils.md5DigestAsHex(plainString.getBytes(StandardCharsets.UTF_8));
// 方式2:使用apache的工具类;org.apache.commons.codec.digest.DigestUtils
// return DigestUtils.md5Hex(plainString.getBytes(StandardCharsets.UTF_8));
// 方式3:使用Java标准库实现
String cipherString = null;
try {
// 获取实例
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
// 计算摘要
byte[] cipherBytes = messageDigest.digest(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为16进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : cipherBytes) {
sb.append(String.format("%02x", b));
}
cipherString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* SHA256,安全散列算法(Secure Hash Algorithm 256-bit),一种被广泛使用的密码散列函数,可以产生出一个固定长度的散列值。用于确保信息传输完整一致。
* <p>
* 输入:待加密的字符串
* 输出:256位(16字节)或64个16进制字符(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★☆☆☆
*
* @param plainString 明文
* @return cipherString 密文
*/
public static String sha256(String plainString) {
// 方式1:使用apache的org.apache.commons.codec.digest.DigestUtils
// return DigestUtils.sha256Hex(plainString.getBytes(StandardCharsets.UTF_8));
// 方式2:使用Java标准库实现
String cipherString = null;
try {
// 获取实例(SHA-512同理)
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
// 计算摘要
byte[] cipherBytes = messageDigest.digest(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为16进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : cipherBytes) {
sb.append(String.format("%02x", b));
}
cipherString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* SM3,国家商用密码(Shang Mi3)也称国密3,是中华人民共和国政府采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。
* <p>
* 输入:待加密的字符串
* 输出:256位(16字节)或64个16进制字符(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★☆☆☆
*
* @param plainString 明文
* @return cipherString 密文
*/
public static String sm3(String plainString) {
// 方式1(正式项目不推荐):使用三方组件hutool:cn.hutool.crypto.SmUtil.sm3()
// return SmUtil.sm3(plainString);
String cipherString = null;
try {
// 创建SM3Digest对象
SM3Digest sm3Digest = new SM3Digest();
// 初始化SM3计算
sm3Digest.update(plainString.getBytes(StandardCharsets.UTF_8), 0, plainString.length());
// 创建输出缓冲区
byte[] cipherBytes = new byte[sm3Digest.getDigestSize()];
// 计算SM3摘要
sm3Digest.doFinal(cipherBytes, 0);
// 输出16进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : cipherBytes) {
sb.append(String.format("%02x", b));
}
cipherString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* HMAC-MD5,Hash-based Message Authentication Code,是一种基于哈希函数和密钥的消息认证码算法,用于确保消息的完整性和认证。
* <p>
* 输入:待加密的字符串
* 输出:与MD5一致
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★☆☆☆
*
* @param plainString 明文
* @param key 秘钥
* @return cipherString 密文
*/
public static String hmacMD5(String plainString, String key) {
String cipherString = null;
try {
// 指定算法
String algorithm = "HmacMD5";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Mac对象实例
Mac mac = Mac.getInstance(algorithm);
// 初始化mac
mac.init(secretKeySpec);
// 计算mac
byte[] macBytes = mac.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为16进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : macBytes) {
sb.append(String.format("%02x", b));
}
cipherString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* HMAC-SHA256,Hash-based Message Authentication Code,是一种基于哈希函数和密钥的消息认证码算法,用于确保消息的完整性和认证。
* <p>
* 输入:待加密的字符串
* 输出:与SHA256一致
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param plainString 明文
* @param key 秘钥
* @return cipherString 密文
*/
public static String hmacSHA256(String plainString, String key) {
String cipherString = null;
try {
// 指定算法
String algorithm = "HmacSHA256";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Mac对象实例
Mac mac = Mac.getInstance(algorithm);
// 初始化mac
mac.init(secretKeySpec);
// 计算mac
byte[] macBytes = mac.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为16进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : macBytes) {
sb.append(String.format("%02x", b));
}
cipherString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* HMAC-SM3,Hash-based Message Authentication Code,是一种基于哈希函数和密钥的消息认证码算法,用于确保消息的完整性和认证。
* <p>
* 输入:待加密的字符串
* 输出:与SM3一致
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param plainString 明文
* @param key 秘钥
* @return cipherString 密文
*/
public static String hmacSM3(String plainString, String key) {
String cipherString = null;
try {
// 创建KeyParameter对象
KeyParameter keyParameter = new KeyParameter(key.getBytes(StandardCharsets.UTF_8));
// 创建HMac对象
HMac hmac = new HMac(new SM3Digest());
// 初始化hmac
hmac.init(keyParameter);
// 更新hmac
hmac.update(plainString.getBytes(StandardCharsets.UTF_8), 0, plainString.length());
// 创建输出缓冲区
byte[] macBytes = new byte[hmac.getMacSize()];
// 计算hmac
hmac.doFinal(macBytes, 0);
// 输出为16进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : macBytes) {
sb.append(String.format("%02x", b));
}
cipherString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
// -------------------------------------------------------------------------------------- 对称加密(需要解密,一般输出为Base64编码)
/**
* DES,Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法。
* <p>
* 输入:待加密的字符串,8位字符串密码
* 输出:16进制字符串或Base64编码的字符串密文(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param plainString 明文
* @param key 秘钥
* @return cipherString 密文
*/
public static String desEncrypt(String plainString, String key) {
String cipherString = null;
try {
// 指定算法
String algorithm = "DES";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Cipher对象实例(Java8中DES默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
// 初始化Cipher为解密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* DES,Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法。
* <p>
* 输入:密文,8位字符串密码
* 输出:明文字符串
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param cipherString 密文
* @param key 秘钥
* @return plainString 明文
*/
public static String desDecrypt(String cipherString, String key) {
String plainString = null;
try {
// 指定算法
String algorithm = "DES";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Cipher对象实例(Java8中DES默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
// 初始化Cipher为加密模式
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
/**
* AES,Advanced Encryption Standard,即高级数据加密标准。
* <p>
* 输入:待加密的字符串,16或24或32位字符串密码
* 输出:16进制字符串或Base64编码的字符串密文(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★★☆
*
* @param plainString 明文
* @param key 秘钥
* @return cipherString 密文
*/
public static String aesEncrypt(String plainString, String key) {
String cipherString = null;
try {
// 指定算法
String algorithm = "AES";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Cipher对象实例(Java8中AES默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* AES,Advanced Encryption Standard,即高级数据加密标准。
* <p>
* 输入:密文,16或24或32位字符串密码
* 输出:明文
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★★☆
*
* @param cipherString 密文
* @param key 秘钥
* @return plainString 明文
*/
public static String aesDecrypt(String cipherString, String key) {
String plainString = null;
try {
// 指定算法
String algorithm = "AES";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Cipher对象实例(Java8中AES默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
/**
* SM4,商业密码(Shang Mi4)是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布,相关标准为“GM/T 0002-2012《SM4分组密码算法》”。
* <p>
* 输入:待加密的字符串,16或24或32位字符串密码
* 输出:16进制字符串或Base64编码的字符串密文(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★★☆
*
* @param plainString 明文
* @param key 秘钥
* @return cipherString 密文
*/
public static String sm4Encrypt(String plainString, String key) {
String cipherString = null;
try {
// 指定加密算法
String algorithm = "SM4";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Cipher对象实例(BC中SM4默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* SM4,商业密码(Shang Mi4)是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布,相关标准为“GM/T 0002-2012《SM4分组密码算法》”。
* <p>
* 输入:密文,16或24或32位字符串密码
* 输出:明文
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★★☆
*
* @param cipherString 密文
* @param key 秘钥
* @return plainString 明文
*/
public static String sm4Decrypt(String cipherString, String key) {
String plainString = null;
try {
// 指定加密算法
String algorithm = "SM4";
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
// 获取Cipher对象实例(BC中SM4默认使用ECB模式和PKCS5Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
// -------------------------------------------------------------------------------------- 不对称加密(需要解密,一般输出为Base64编码)
/**
* 生成一组RSA的秘钥
*
* @param length 秘钥长度
* @return KeyPair对象
*/
public static KeyPair genRSAKey(int length) {
KeyPair keyPair = null;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(length, new SecureRandom());
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
return keyPair;
}
/**
* RSA,三个作者的姓氏开头字母组合,RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥。
* <p>
* 输入:待加密的字符串,公钥
* 输出:16进制字符串或Base64编码的字符串密文(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param plainString 明文
* @param publicKey 公钥
* @return cipherString 密文
*/
public static String rsaEncrypt(String plainString, PublicKey publicKey) {
String cipherString = null;
try {
// 获取Cipher对象实例(Java8中RSA默认使用ECB模式和PKCS1Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* RSA,三个作者的姓氏开头字母组合,RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥。
* <p>
* 输入:待加密的字符串,公钥
* 输出:16进制字符串或Base64编码的字符串密文(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param plainString 明文
* @param publicKeyString 公钥
* @return cipherString 密文
*/
public static String rsaEncrypt(String plainString, String publicKeyString) {
String cipherString = null;
try {
// 指定算法
String algorithm = "RSA";
// 构造PublicKey对象
publicKeyString = publicKeyString.replaceAll("-----BEGIN PUBLIC KEY-----", "")
.replaceAll("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
// 获取Cipher对象实例(Java8中RSA默认使用ECB模式和PKCS1Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS1Padding");
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* RSA,三个作者的姓氏开头字母组合,RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥。
* <p>
* 输入:16进制字符串或Base64编码的字符串密文,私钥
* 输出:明文字符串
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param cipherString 密文
* @param privateKey 秘钥
* @return plainString 明文
*/
public static String rsaDecrypt(String cipherString, PrivateKey privateKey) {
String plainString = null;
try {
// 获取Cipher对象实例(Java8中RSA默认使用ECB模式和PKCS1Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
/**
* RSA,三个作者的姓氏开头字母组合,RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥。
* <p>
* 输入:16进制字符串或Base64编码的字符串密文,私钥
* 输出:明文字符串
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★☆☆
*
* @param cipherString 密文
* @param privateKeyString 秘钥
* @return plainString 明文
*/
public static String rsaDecrypt(String cipherString, String privateKeyString) {
String plainString = null;
try {
// 指定算法
String algorithm = "RSA";
// 解码Base64字符串(通常秘钥为Base64编码)
privateKeyString = privateKeyString.replaceAll("-----BEGIN RSA PRIVATE KEY-----", "")
.replaceAll("-----END RSA PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(privateKeyString);
// 构造PrivateKey对象
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 获取Cipher对象实例(Java8中RSA默认使用ECB模式和PKCS1Padding填充方式,因此下列模式和填充方式无需指定)
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS1Padding");
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
/**
* 生成一组SM2的秘钥
*
* @return KeyPair秘钥
*/
public static KeyPair genSM2Key() {
KeyPair keyPair = null;
try {
// 创建KeyPairGenerator(指定算法为EC(椭圆曲线),指定提供者为BC(BouncyCastleProvider))
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
// 初始化
keyPairGenerator.initialize(new ECGenParameterSpec("sm2p256v1"));
// 生成密钥
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
return keyPair;
}
/**
* SM2,商业密码(Shang Mi2)是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。详见百科:https://baike.baidu.com/item/SM2
* <p>
* 输入:待加密的字符串,公钥
* 输出:16进制字符串或Base64编码的字符串密文(常用)
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★★☆
*
* @param plainString 明文
* @param publicKey 公钥
* @return cipherString 密文
*/
public static String sm2Encrypt(String plainString, PublicKey publicKey) {
String cipherString = null;
try {
// 获取Cipher对象实例
Cipher cipher = Cipher.getInstance("SM2");
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* SM2,商业密码(Shang Mi2)是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。详见百科:https://baike.baidu.com/item/SM2
* <p>
* 输入:16进制字符串或Base64编码的字符串密文,私钥
* 输出:明文字符串
* 应用:密码管理、数字签名、文件完整性校验
* 安全性:★★★★☆
*
* @param cipherString 密文
* @param privateKey 秘钥
* @return plainString 明文
*/
public static String sm2Decrypt(String cipherString, PrivateKey privateKey) {
String plainString = null;
try {
// 获取Cipher对象实例
Cipher cipher = Cipher.getInstance("SM2");
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
public static void main(String[] args) {
String plainString = "hello world, hello java!";
String md5 = md5(plainString);
System.out.println("--------------------------- md5");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + md5);
String sha256 = sha256(plainString);
System.out.println("--------------------------- sha256");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + sha256);
String sm3 = sm3(plainString);
System.out.println("--------------------------- sm3");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + sm3);
String hmacMD5 = hmacMD5(plainString, "12345678");
System.out.println("--------------------------- hmacMD5");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + hmacMD5);
String hmacSHA256 = hmacSHA256(plainString, "12345678");
System.out.println("--------------------------- hmacSHA256");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + hmacSHA256);
String hmacSM3 = hmacSM3(plainString, "12345678");
System.out.println("--------------------------- hmacSM3");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + hmacSM3);
System.out.println("------------------------------------------------------");
String desEncrypt = desEncrypt(plainString, "12345678");
String desDecrypt = desDecrypt(desEncrypt, "12345678");
System.out.println("--------------------------- des");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + desEncrypt);
System.out.println("解密后: " + desDecrypt);
String aesEncrypt = aesEncrypt(plainString, "1234567812345678");
String aesDecrypt = aesDecrypt(aesEncrypt, "1234567812345678");
System.out.println("--------------------------- aes");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + aesEncrypt);
System.out.println("解密后: " + aesDecrypt);
String sm4Encrypt = sm4Encrypt(plainString, "1234567812345678");
String sm4Decrypt = sm4Decrypt(sm4Encrypt, "1234567812345678");
System.out.println("--------------------------- sm4");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + sm4Encrypt);
System.out.println("解密后: " + sm4Decrypt);
System.out.println("------------------------------------------------------");
KeyPair rsaKey = genRSAKey(2048);
String rsaEncrypt = rsaEncrypt(plainString, rsaKey.getPublic());
String rsaDecrypt = rsaDecrypt(rsaEncrypt, rsaKey.getPrivate());
System.out.println("--------------------------- rsa");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + rsaEncrypt);
System.out.println("解密后: " + rsaDecrypt);
KeyPair sm2Key = genSM2Key();
String sm2Encrypt = sm2Encrypt(plainString, sm2Key.getPublic());
String sm2Decrypt = sm2Decrypt(sm2Encrypt, sm2Key.getPrivate());
System.out.println("--------------------------- sm2");
System.out.println("加密前: " + plainString);
System.out.println("加密后: " + sm2Encrypt);
System.out.println("解密后: " + sm2Decrypt);
System.out.println("------------------------------------------------------");
}
}
2、运行测试
Connected to the target VM, address: '127.0.0.1:62234', transport: 'socket'
--------------------------- md5
加密前: hello world, hello java!
加密后: 0862cb559f83edaeb04e455b413b2c1d
--------------------------- sha256
加密前: hello world, hello java!
加密后: 36fe1f0190a74297bb9f95de3e16a51c252d999895070f0a0a700bab28610254
--------------------------- sm3
加密前: hello world, hello java!
加密后: 1ac1da65f9c28ccac9fa62303d3b325d7bc180bf29e354c70d1b6662939c05d6
--------------------------- hmacMD5
加密前: hello world, hello java!
加密后: ad9f836dad01cfd6dc1e3142b50a8b6e
--------------------------- hmacSHA256
加密前: hello world, hello java!
加密后: 1cb8e22b3a1c04b4164c93b1ef391b7f6a9b5507eda06d8d8454ffc906c035ed
--------------------------- hmacSM3
加密前: hello world, hello java!
加密后: 5d3025d1296e10add5006c795fb93fbba68703521eeb2b8235bbe1fb918e68a1
------------------------------------------------------
--------------------------- des
加密前: hello world, hello java!
加密后: KNugLrX23UcBoieZhlQtpGvdQD8PGIcy/rlZt9RkL8s=
解密后: hello world, hello java!
--------------------------- aes
加密前: hello world, hello java!
加密后: 1xCFNCoW3Z6gZbiXeu1++IrZpliQTk6z3NN10ygOPHc=
解密后: hello world, hello java!
--------------------------- sm4
加密前: hello world, hello java!
加密后: ykzowxeFonA3I4Y4NozLHii3EOUD4r9SMoHw9Sv9DPI=
解密后: hello world, hello java!
------------------------------------------------------
--------------------------- rsa
加密前: hello world, hello java!
加密后: Nd8h8TqBRytMKtQbKr0Rj3XPb4hrW8zHK0rypaMo49pxsdp/o0GNGWyKxV8UETNn3DHcGZCRF0RyiQWVWl3Dz8YD0vjvr8EiznniFtUPXuZ4Tihkyzdj4kl/2aRME26cSYU+F2aJflOUZYLuf6BWEUJy4hI8z+BoxZQ7q4Gaoh1axypU8wi3eOtOu0qD6J+TDxjMQbLgfyDbbxgI+H42QShvi9sWvcMSa7og1UqjuJPBVsR6fjt8c4Ncwu3Za6QgdNGuZuOsMsMU7Fmnplh3fH3PGGRO3RlkzvWAvQG1Br3rbcwVVHUo1Xl6G9SzwqqlzyS4YqgEbuTcL1RQfxi65Q==
解密后: hello world, hello java!
--------------------------- sm2
加密前: hello world, hello java!
加密后: BM3VeU8z1QFpJhAoqRhQm4Wwh4mK6UAzuE2o1ygrBUyl8n+RCNirMTVUvQk3flCH7lIlbU16C0CGPQ1gjKsF5pNT8qe9lJuTg6DXjRFgIYX94losOIWCrmfyrh5Os5Hcya47GIY0YjpBLomTEX0hbSM2PoSPS7aMgg==
解密后: hello world, hello java!
------------------------------------------------------
Disconnected from the target VM, address: '127.0.0.1:62234', transport: 'socket'
Process finished with exit code 0
三、开发总结
1、byte[]
与16进制String
互转
byte[]
转16进制String
代码如下(示例):
// ------------------------------------ 如下为Java标准库
// 方式1:使用String.format
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
// 方式2:使用BigInteger
return new BigInteger(1, bytes).toString(16);
// 方式3:使用DatatypeConverter
return DatatypeConverter.printHexBinary(bytes);
// ------------------------------------ 如下为第三方组件
// 方式4:使用Apache Commons Codec
return Hex.encodeHexString(bytes);
- 16进制
String
转byte[]
// ------------------------------------ 如下为Java标准库
// 方式1:使用BigInteger
return new BigInteger(str, 16).toByteArray();
// 方式2: 使用DatatypeConverter
return DatatypeConverter.parseHexBinary(str);
// ------------------------------------ 如下为第三方组件
// 方式3:使用Apache Commons Codec
return Hex.decodeHex(str.toCharArray());
2、BC包的用处
添加安全提供者,SM2,SM3,SM4等加密算法,CBC、CFB等加密模式,PKCS7Padding等填充方式,不在Java标准库中,由BouncyCastleProvider实现。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了常用的加密算法在Java中的实现方式,水平有限,难免出错,仅供参考,不喜勿喷,感谢!更多内容请百度和ChatGPT!