@ -1,5 +1,7 @@
package cn.org.alan.exam.util ;
import cn.org.alan.exam.util.CryptoUtils.Algorithm.Encryption ;
import cn.org.alan.exam.util.CryptoUtils.Algorithm.Signing ;
import org.apache.commons.lang3.StringUtils ;
@ -9,6 +11,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor ;
import org.springframework.stereotype.Component ;
import javax.crypto.Cipher ;
import javax.crypto.KeyGenerator ;
import javax.crypto.NoSuchPaddingException ;
@ -37,7 +40,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap ;
/ * *
* 支 持 AES 、 DES 、 RSA 加 密 、 数 字 签 名 以 及 生 成 对 称 密 钥 和 非 对 称 密 钥 对 , 该 工 具 类 提 供 了 一 系 列 加 密 、 解 密 、 签 名 、 验 签 以 及 密 钥 生 成 相 关 的 功 能 方 法 , 方 便 在 项 目 中 进 行 安 全 相 关 的 操 作 。
* 支 持 AES 、 DES 、 RSA 加 密 、 数 字 签 名 以 及 生 成 对 称 密 钥 和 非 对 称 密 钥 对
* /
/ * *
@ -48,493 +51,311 @@ import java.util.concurrent.ConcurrentHashMap;
@Component
public class CryptoUtils {
// 定义默认的字符编码格式为UTF-8, 用于处理字符串和字节之间的转换操作, 保证统一的编码标准。
private static final Charset DEFAULT_CHARSET = StandardCharsets . UTF_8 ;
// 获取Base64的编码器实例, 用于将字节数据编码为Base64格式的字符串, 常用于加密后数据的编码传输等场景。
private static final Encoder BASE64_ENCODER = Base64 . getEncoder ( ) ;
// 获取Base64的解码器实例, 用于将Base64格式的字符串解码为原始字节数据, 比如在解密等操作前对密文进行解码。
private static final Decoder BASE64_DECODER = Base64 . getDecoder ( ) ;
// 使用ConcurrentHashMap缓存KeyFactory实例, 以算法( Algorithm类型) 为键, 方便后续快速获取相应算法的KeyFactory, 避免重复创建, 提高性能, 并且支持并发访问。
private static final Map < Algorithm , KeyFactory > KEY_FACTORY_CACHE = new ConcurrentHashMap < > ( ) ;
// 使用HashMap缓存Cipher实例, 同样以算法( Algorithm类型) 为键, 用于存储加密、解密操作时对应的Cipher对象, 减少创建开销, 但需注意非并发安全情况下的使用场景( 此处代码中有相应的同步处理机制保证线程安全) 。
private static final Map < Algorithm , Cipher > CIPHER_CACHE = new HashMap < > ( ) ;
/ * *
* 生 成 对 称 密 钥 , 目 前 支 持 的 算 法 有 AES 、 DES , 根 据 指 定 的 算 法 生 成 相 应 的 对 称 密 钥 , 并 将 其 编 码 为 Base64 格 式 的 字 符 串 返 回 。
*
* @param algorithm 要 生 成 对 称 密 钥 的 算 法 类 型 , 通 过 Algorithm 枚 举 类 型 传 入 , 如 Algorithm . AES_ECB_PKCS5 等 。
* @return 生 成 的 对 称 密 钥 的 Base64 编 码 字 符 串 表 示 形 式 。
* @throws NoSuchAlgorithmException 如 果 指 定 的 算 法 不 存 在 , 则 抛 出 此 异 常 。
* 生 成 对 称 密 钥 , 目 前 支 持 的 算 法 有 AES 、 DES
* @param algorithm
* @return
* @throws NoSuchAlgorithmException
* /
public static String generateSymmetricKey ( Algorithm algorithm ) throws NoSuchAlgorithmException {
// 根据指定的算法名称获取对应的KeyGenerator实例, 用于生成对称密钥。
KeyGenerator generator = KeyGenerator . getInstance ( algorithm . getName ( ) ) ;
// 使用算法对应的默认密钥长度( 通过Algorithm中定义的keySize属性获取) 初始化KeyGenerator, 准备生成密钥。
generator . init ( algorithm . getKeySize ( ) ) ;
// 生成对称密钥, 返回的SecretKey对象包含了实际的密钥数据。
SecretKey secretKey = generator . generateKey ( ) ;
// 将生成的对称密钥转换为字节数组后, 使用Base64编码器将其编码为字符串并返回, 方便存储和传输。
return BASE64_ENCODER . encodeToString ( secretKey . getEncoded ( ) ) ;
}
/ * *
* 生 成 非 对 称 密 钥 对 , 目 前 支 持 的 算 法 有 RSA 、 DSA 。 备 注 : 默 认 生 成 的 密 钥 格 式 为 PKCS8 , 根 据 指 定 的 非 对 称 加 密 算 法 生 成 一 对 公 钥 和 私 钥 , 并 分 别 编 码 为 Base64 格 式 的 字 符 串 , 封 装 在 AsymmetricKeyPair 对 象 中 返 回 。
*
* @param algorithm 要 生 成 非 对 称 密 钥 对 的 算 法 类 型 , 通 过 Algorithm 枚 举 类 型 传 入 , 如 Algorithm . RSA_ECB_PKCS1 等 。
* @return 包 含 生 成 的 公 钥 和 私 钥 的 Base64 编 码 字 符 串 的 AsymmetricKeyPair 对 象 。
* @throws NoSuchAlgorithmException 如 果 指 定 的 算 法 不 存 在 , 则 抛 出 此 异 常 。
* 生 成 非 对 称 密 钥 对 , 目 前 支 持 的 算 法 有 RSA 、 DSA 。 备 注 : 默 认 生 成 的 密 钥 格 式 为 PKCS8
* @param algorithm
* @return
* @throws NoSuchAlgorithmException
* /
public static AsymmetricKeyPair generateAsymmetricKeyPair ( Algorithm algorithm ) throws NoSuchAlgorithmException {
// 根据指定的算法名称获取对应的KeyPairGenerator实例, 用于生成非对称密钥对。
KeyPairGenerator generator = KeyPairGenerator . getInstance ( algorithm . getName ( ) ) ;
// 使用算法对应的默认密钥长度( 通过Algorithm中定义的keySize属性获取) 初始化KeyPairGenerator, 准备生成密钥对。
generator . initialize ( algorithm . getKeySize ( ) ) ;
// 生成非对称密钥对, 返回的KeyPair对象包含了公钥和私钥。
KeyPair keyPair = generator . generateKeyPair ( ) ;
// 将公钥转换为字节数组后, 使用Base64编码器将其编码为字符串, 得到公钥的Base64编码表示形式。
String publicKey = BASE64_ENCODER . encodeToString ( keyPair . getPublic ( ) . getEncoded ( ) ) ;
// 将私钥转换为字节数组后, 使用Base64编码器将其编码为字符串, 得到私钥的Base64编码表示形式。
String privateKey = BASE64_ENCODER . encodeToString ( keyPair . getPrivate ( ) . getEncoded ( ) ) ;
// 创建AsymmetricKeyPair对象, 将公钥和私钥的Base64编码字符串传入, 封装后返回。
return new AsymmetricKeyPair ( publicKey , privateKey ) ;
}
/ * *
* 使 用 RSA 算 法 ( 具 体 为 RSA_ECB_PKCS1 模 式 ) 对 明 文 进 行 加 密 , 调 用 encryptAsymmetrically 方 法 实 现 加 密 逻 辑 , 传 入 公 钥 文 本 和 明 文 数 据 进 行 加 密 操 作 。
*
* @param publicKeyText 公 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 加 密 操 作 。
* @param plainText 要 加 密 的 明 文 内 容 , 即 原 始 未 加 密 的 数 据 。
* @return 加 密 后 的 密 文 , 以 Base64 编 码 字 符 串 形 式 返 回 。
* @throws Exception 如 果 在 加 密 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 加 密 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* /
public static String encryptByRSA ( String publicKeyText , String plainText ) throws Exception {
return encryptAsymmetrically ( publicKeyText , plainText , Encryption . RSA_ECB_PKCS1 ) ;
}
/ * *
* 使 用 RSA 算 法 ( 具 体 为 RSA_ECB_PKCS1 模 式 ) 对 密 文 进 行 解 密 , 调 用 decryptAsymmetrically 方 法 实 现 解 密 逻 辑 , 传 入 私 钥 文 本 和 密 文 数 据 进 行 解 密 操 作 。
*
* @param privateKeyText 私 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 解 密 操 作 。
* @param ciphertext 要 解 密 的 密 文 内 容 , 即 经 过 加 密 后 的 Base64 编 码 字 符 串 数 据 。
* @return 解 密 后 的 明 文 内 容 , 以 字 符 串 形 式 返 回 。
* @throws Exception 如 果 在 解 密 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 解 密 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* /
public static String decryptByRSA ( String privateKeyText , String ciphertext ) throws Exception {
return decryptAsymmetrically ( privateKeyText , ciphertext , Encryption . RSA_ECB_PKCS1 ) ;
}
/ * *
* SHA1 签 名 算 法 和 DSA 加 密 算 法 结 合 使 用 生 成 数 字 签 名 , 调 用 doSign 方 法 , 传 入 私 钥 文 本 、 待 签 名 消 息 以 及 相 应 的 加 密 和 签 名 算 法 类 型 , 实 现 数 字 签 名 的 生 成 逻 辑 。
*
* @param privateKeyText 私 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 数 字 签 名 操 作 。
* @param msg 待 加 签 内 容 , 即 要 进 行 数 字 签 名 的 数 据 , 通 常 是 重 要 的 业 务 信 息 等 。
* @return 生 成 的 数 字 签 名 , 以 Base64 编 码 字 符 串 形 式 返 回 。
* @throws Exception 如 果 在 数 字 签 名 生 成 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 签 名 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* SHA1 签 名 算 法 和 DSA 加 密 算 法 结 合 使 用 生 成 数 字 签 名
* @param privateKeyText
* @param msg
* @return 数 字 签 名
* @throws Exception
* /
public static String signBySHA1WithDSA ( String privateKeyText , String msg ) throws Exception {
return doSign ( privateKeyText , msg , Encryption . DSA , Signing . SHA1WithDSA ) ;
}
/ * *
* SHA1 签 名 算 法 和 RSA 加 密 算 法 结 合 使 用 生 成 数 字 签 名 , 调 用 doSign 方 法 , 传 入 私 钥 文 本 、 待 签 名 消 息 以 及 相 应 的 加 密 和 签 名 算 法 类 型 , 实 现 数 字 签 名 的 生 成 逻 辑 。
*
* @param privateKeyText 私 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 数 字 签 名 操 作 。
* @param msg 待 加 签 内 容 , 即 要 进 行 数 字 签 名 的 数 据 , 通 常 是 重 要 的 业 务 信 息 等 。
* @return 生 成 的 数 字 签 名 , 以 Base64 编 码 字 符 串 形 式 返 回 。
* @throws Exception 如 果 在 数 字 签 名 生 成 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 签 名 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* SHA1 签 名 算 法 和 RSA 加 密 算 法 结 合 使 用 生 成 数 字 签 名
* @param privateKeyText 私 钥
* @param msg 待 加 签 内 容
* @return 数 字 签 名
* @throws Exception
* /
public static String signBySHA1WithRSA ( String privateKeyText , String msg ) throws Exception {
return doSign ( privateKeyText , msg , Encryption . RSA_ECB_PKCS1 , Signing . SHA1WithRSA ) ;
}
/ * *
* SHA256 签 名 算 法 和 RSA 加 密 算 法 结 合 使 用 生 成 数 字 签 名 , 调 用 doSign 方 法 , 传 入 私 钥 文 本 、 待 签 名 消 息 以 及 相 应 的 加 密 和 签 名 算 法 类 型 , 实 现 数 字 签 名 的 生 成 逻 辑 。
*
* @param privateKeyText 私 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 数 字 签 名 操 作 。
* @param msg 待 加 签 内 容 , 即 要 进 行 数 字 签 名 的 数 据 , 通 常 是 重 要 的 业 务 信 息 等 。
* @return 生 成 的 数 字 签 名 , 以 Base64 编 码 字 符 串 形 式 返 回 。
* @throws Exception 如 果 在 数 字 签 名 生 成 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 签 名 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* SHA256 签 名 算 法 和 RSA 加 密 算 法 结 合 使 用 生 成 数 字 签 名
* @param privateKeyText 私 钥
* @param msg 待 加 签 内 容
* @return 数 字 签 名
* @throws Exception
* /
public static String signBySHA256WithRSA ( String privateKeyText , String msg ) throws Exception {
return doSign ( privateKeyText , msg , Encryption . RSA_ECB_PKCS1 , Signing . SHA256WithRSA ) ;
}
/ * *
* SHA1 签 名 算 法 和 DSA 加 密 算 法 检 验 数 字 签 名 , 调 用 doVerify 方 法 , 传 入 公 钥 文 本 、 待 验 签 内 容 、 数 字 签 名 以 及 相 应 的 加 密 和 签 名 算 法 类 型 , 实 现 数 字 签 名 验 证 逻 辑 , 判 断 签 名 是 否 有 效 。
*
* @param publicKeyText 公 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 数 字 签 名 验 证 操 作 。
* @param msg 待 验 签 内 容 , 即 要 验 证 数 字 签 名 对 应 的 原 始 数 据 , 需 与 签 名 时 的 数 据 一 致 。
* @param signatureText 数 字 签 名 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 验 证 是 否 匹 配 。
* @return 检 验 是 否 成 功 , 返 回 true 表 示 数 字 签 名 验 证 通 过 , 即 签 名 有 效 ; 返 回 false 表 示 验 证 失 败 , 签 名 可 能 被 篡 改 或 无 效 。
* @throws Exception 如 果 在 数 字 签 名 验 证 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 验 证 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* SHA1 签 名 算 法 和 DSA 加 密 算 法 检 验 数 字 签 名
* @param publicKeyText 公 钥
* @param msg 待 验 签 内 容
* @param signatureText 数 字
* @return 检 验 是 否 成 功
* @throws Exception
* /
public static boolean verifyBySHA1WithDSA ( String publicKeyText , String msg , String signatureText ) throws Exception {
return doVerify ( publicKeyText , msg , signatureText , Encryption . DSA , Signing . SHA1WithDSA ) ;
}
/ * *
* SHA1 签 名 算 法 和 RSA 加 密 算 法 检 验 数 字 签 名 , 调 用 doVerify 方 法 , 传 入 公 钥 文 本 、 待 验 签 内 容 、 数 字 签 名 以 及 相 应 的 加 密 和 签 名 算 法 类 型 , 实 现 数 字 签 名 验 证 逻 辑 , 判 断 签 名 是 否 有 效 。
*
* @param publicKeyText 公 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 数 字 签 名 验 证 操 作 。
* @param msg 待 验 签 内 容 , 即 要 验 证 数 字 签 名 对 应 的 原 始 数 据 , 需 与 签 名 时 的 数 据 一 致 。
* @param signatureText 签 名 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 验 证 是 否 匹 配 。
* @return 校 验 是 否 成 功 , 返 回 true 表 示 数 字 签 名 验 证 通 过 , 即 签 名 有 效 ; 返 回 false 表 示 验 证 失 败 , 签 名 可 能 被 篡 改 或 无 效 。
* @throws Exception 如 果 在 数 字 签 名 验 证 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 验 证 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* SHA1 签 名 算 法 和 RSA 加 密 算 法 检 验 数 字 签 名
* @param publicKeyText 公 钥
* @param msg 待 验 签 内 容
* @param signatureText 签 名
* @return 校 验 是 否 成 功
* @throws Exception
* /
public static boolean verifyBySHA1WithRSA ( String publicKeyText , String msg , String signatureText ) throws Exception {
return doVerify ( publicKeyText , msg , signatureText , Encryption . RSA_ECB_PKCS1 , Signing . SHA1WithRSA ) ;
}
/ * *
* SHA256 签 名 算 法 和 RSA 加 密 算 法 检 验 数 字 签 名 , 调 用 doVerify 方 法 , 传 入 公 钥 文 本 、 待 验 签 内 容 、 数 字 签 名 以 及 相 应 的 加 密 和 签 名 算 法 类 型 , 实 现 数 字 签 名 验 证 逻 辑 , 判 断 签 名 是 否 有 效 。
*
* @param publicKeyText 公 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 数 字 签 名 验 证 操 作 。
* @param msg 待 验 签 内 容 , 即 要 验 证 数 字 签 名 对 应 的 原 始 数 据 , 需 与 签 名 时 的 数 据 一 致 。
* @param signatureText 签 名 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 验 证 是 否 匹 配 。
* @return 校 验 是 否 成 功 , 返 回 true 表 示 数 字 签 名 验 证 通 过 , 即 签 名 有 效 ; 返 回 false 表 示 验 证 失 败 , 签 名 可 能 被 篡 改 或 无 效 。
* @throws Exception 如 果 在 数 字 签 名 验 证 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 验 证 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* SHA256 签 名 算 法 和 RSA 加 密 算 法 检 验 数 字 签 名
* @param publicKeyText 公 钥
* @param msg 待 验 签 内 容
* @param signatureText 签 名
* @return 校 验 是 否 成 功
* @throws Exception
* /
public static boolean verifyBySHA256WithRSA ( String publicKeyText , String msg , signatureText) throws Exception {
public static boolean verifyBySHA256WithRSA ( String publicKeyText , String msg , String signatureText) throws Exception {
return doVerify ( publicKeyText , msg , signatureText , Encryption . RSA_ECB_PKCS1 , Signing . SHA256WithRSA ) ;
}
/ * *
* 对 称 加 密 , 根 据 传 入 的 对 称 密 钥 、 加 密 向 量 ( 部 分 模 式 需 要 ) 、 明 文 以 及 指 定 的 对 称 加 密 算 法 , 对 明 文 进 行 加 密 操 作 , 并 返 回 加 密 后 的 密 文 ( Base64 编 码 字 符 串 形 式 ) 。
*
* @param secretKey 对 称 密 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 加 密 操 作 。
* @param iv 加 密 向 量 , 只 有 CBC 模 式 才 支 持 , 如 果 是 CBC 则 必 传 , 用 于 增 加 加 密 的 安 全 性 和 随 机 性 ( 不 同 模 式 下 使 用 情 况 不 同 ) 。
* @param plainText 要 加 密 的 明 文 内 容 , 即 原 始 未 加 密 的 数 据 。
* @param algorithm 对 称 加 密 算 法 类 型 , 通 过 Algorithm 枚 举 类 型 传 入 , 如 Algorithm . AES_ECB_PKCS5 等 。
* @return 加 密 后 的 密 文 , 以 Base64 编 码 字 符 串 形 式 返 回 。
* @throws Exception 如 果 在 加 密 过 程 中 出 现 任 何 问 题 ( 如 密 钥 格 式 错 误 、 加 密 算 法 执 行 异 常 等 ) , 则 抛 出 异 常 。
* /
public static String encryptSymmetrically ( String secretKey , String iv , String plainText , Algorithm algorithm ) throws Exception {
// 先将Base64编码的对称密钥解码并重新生成SecretKey实例, 用于后续的加密操作。
SecretKey key = decodeSymmetricKey ( secretKey , algorithm ) ;
// 根据传入的加密向量字符串( 如果非空) 解码生成IvParameterSpec实例, 用于指定加密的初始向量信息( CBC模式等需要) , 若为空则设置为null表示不需要初始向量( 如ECB模式) 。
IvParameterSpec ivParameterSpec = StringUtils . isBlank ( iv ) ? null : decodeIv ( iv ) ;
// 将明文字符串按照默认字符编码格式( UTF-8) 转换为字节数组, 准备进行加密操作。
byte [ ] plainTextInBytes = plainText . getBytes ( DEFAULT_CHARSET ) ;
// 调用transform方法, 传入算法、加密模式、密钥、加密向量以及明文字节数组, 执行实际的加密操作, 得到加密后的字节数组。
byte [ ] ciphertextInBytes = transform ( algorithm , Cipher . ENCRYPT_MODE , key , ivParameterSpec , plainTextInBytes ) ;
// 将加密后的字节数组使用Base64编码器转换为字符串并返回, 作为最终的加密结果( 密文) 。
return BASE64_ENCODER . encodeToString ( ciphertextInBytes ) ;
}
/ * *
* 对 称 解 密 , 根 据 传 入 的 对 称 密 钥 、 加 密 向 量 ( 部 分 模 式 需 要 ) 、 密 文 以 及 指 定 的 对 称 加 密 算 法 , 对 密 文 进 行 解 密 操 作 , 并 返 回 解 密 后 的 明 文 内 容 。
*
* @param secretKey 对 称 密 钥 的 Base64 编 码 字 符 串 表 示 形 式 , 用 于 解 密 操 作 。
* @param iv 加 密 向 量 , 只 有 CBC 模 式 才 支 持 , 如 果 是 CBC 则 必 传 , 用 于 匹 配 加 密 时 的 初 始 向 量 信 息 ( 保 证 解 密 正 确 ) 。
* @param ciphertext 要 解 密 的 密 文 内 容 , 即 经 过 加 密 后 的 Base64 编 码 字 符 串 数 据 。
* @param algorithm 对 称 加 密 算 法 类 型 , 通 过 Algorithm 枚 举 类 型 传 入 , 如 Algorithm . AES_ECB_PKCS5 等 。
* @return 解 密 后 的 明 文 内 容 , 以 字 符 串 形 式 返 回 。
* @throws Exception
* /
public static boolean verifyBySHA256WithRSA ( String publicKeyText , String msg , String signatureText ) throws Exception {
// 调用doVerify方法, 传入公钥文本( publicKeyText) 、待验证的消息( msg) 、数字签名文本( signatureText) 以及指定的加密算法( Encryption.RSA_ECB_PKCS1) 和签名算法( Signing.SHA256WithRSA) ,
// 目的是使用RSA加密算法结合SHA256签名算法来验证给定的数字签名是否与消息匹配, 最终返回验证结果( true表示验证通过, false表示验证失败) 。
return doVerify ( publicKeyText , msg , signatureText , Encryption . RSA_ECB_PKCS1 , Signing . SHA256WithRSA ) ;
}
/ * *
* 对 称 加 密
* @param secretKey 密 钥 , 以 Base64 编 码 字 符 串 形 式 传 入 , 用 于 对 称 加 密 操 作 , 是 对 称 加 密 算 法 中 用 于 加 密 和 解 密 的 关 键 数 据 。
* @param iv 加 密 向 量 , 只 有 CBC 模 式 才 支 持 , 如 果 是 CBC 则 必 传 , 用 于 增 加 加 密 的 随 机 性 和 安 全 性 , 不 同 的 加 密 模 式 下 其 使 用 情 况 不 同 , 在 CBC 模 式 中 与 密 钥 共 同 作 用 来 加 密 数 据 。
* @param plainText 明 文 , 即 需 要 进 行 加 密 的 原 始 文 本 内 容 , 是 未 经 过 加 密 处 理 的 原 始 数 据 。
* @param algorithm 对 称 加 密 算 法 , 如 AES 、 DES , 通 过 Algorithm 枚 举 类 型 传 入 具 体 的 算 法 实 例 , 指 定 使 用 哪 种 对 称 加 密 算 法 来 进 行 加 密 操 作 。
* @return 返 回 经 过 对 称 加 密 后 的 密 文 , 以 Base64 编 码 字 符 串 形 式 返 回 , 方 便 存 储 和 传 输 加 密 后 的 数 据 。
* @throws Exception 如 果 在 加 密 过 程 中 出 现 如 密 钥 格 式 错 误 、 加 密 算 法 执 行 异 常 等 任 何 问 题 , 则 抛 出 异 常 。
* @param secretKey 密 钥
* @param iv 加 密 向 量 , 只 有 CBC 模 式 才 支 持 , 如 果 是 CBC 则 必 传
* @param plainText 明 文
* @param algorithm 对 称 加 密 算 法 , 如 AES 、 DES
* @return
* @throws Exception
* /
public static String encryptSymmetrically ( String secretKey , String iv , String plainText , Algorithm algorithm ) throws Exception {
// 调用decodeSymmetricKey方法, 传入对称密钥( secretKey) 和指定的对称加密算法( algorithm) , 将Base64编码的对称密钥解码并重新生成SecretKey实例, 用于后续的加密操作, 得到实际可用的对称密钥对象, 存储在key变量中。
SecretKey key = decodeSymmetricKey ( secretKey , algorithm ) ;
// 通过StringUtils.isBlank判断传入的加密向量( iv) 是否为空字符串, 如果为空, 则将ivParameterSpec设置为null, 表示不需要加密向量( 例如在ECB等不需要加密向量的加密模式下) ;
// 如果不为空, 则调用decodeIv方法对加密向量进行解码并生成IvParameterSpec实例, 用于指定加密的初始向量信息( 在CBC模式等需要的情况下) , 存储在ivParameterSpec变量中。
IvParameterSpec ivParameterSpec = StringUtils . isBlank ( iv ) ? null : decodeIv ( iv ) ;
// 将明文字符串( plainText) 按照默认字符编码格式( DEFAULT_CHARSET, 即UTF-8) 转换为字节数组, 准备进行加密操作, 得到的字节数组存储在plainTextInBytes变量中, 这是因为加密算法通常操作的是字节数据。
IvParameterSpec ivParameterSpec = StringUtils . isBlank ( iv ) ? null : decodeIv ( iv ) ;
byte [ ] plainTextInBytes = plainText . getBytes ( DEFAULT_CHARSET ) ;
// 调用transform方法, 传入对称加密算法( algorithm) 、加密模式( Cipher.ENCRYPT_MODE表示加密操作) 、生成的对称密钥( key) 、加密向量( ivParameterSpec) 以及明文字节数组( plainTextInBytes) ,
// 执行实际的对称加密操作, 得到加密后的字节数组, 存储在ciphertextInBytes变量中。
byte [ ] ciphertextInBytes = transform ( algorithm , Cipher . ENCRYPT_MODE , key , ivParameterSpec , plainTextInBytes ) ;
// 将加密后的字节数组( ciphertextInBytes) 使用Base64编码器( BASE64_ENCODER) 转换为字符串, 即将二进制的加密数据编码为可方便存储和传输的Base64编码字符串形式, 然后返回该字符串作为最终的加密结果( 密文) 。
return BASE64_ENCODER . encodeToString ( ciphertextInBytes ) ;
}
/ * *
* 对 称 解 密
* @param secretKey 密 钥 , 以 Base64 编 码 字 符 串 形 式 传 入 , 用 于 对 称 解 密 操 作 , 需 要 与 加 密 时 使 用 的 密 钥 一 致 才 能 正 确 解 密 数 据 。
* @param iv 加 密 向 量 , 只 有 CBC 模 式 才 支 持 , 如 果 是 CBC 则 必 传 , 用 于 匹 配 加 密 时 使 用 的 加 密 向 量 , 保 证 解 密 过 程 能 正 确 还 原 出 原 始 明 文 数 据 。
* @param ciphertext 密 文 , 即 经 过 加 密 后 的 Base64 编 码 字 符 串 数 据 , 是 需 要 进 行 解 密 还 原 的 加 密 内 容 。
* @param algorithm 对 称 加 密 算 法 , 如 AES 、 DES , 通 过 Algorithm 枚 举 类 型 传 入 具 体 的 算 法 实 例 , 指 定 使 用 哪 种 对 称 加 密 算 法 来 进 行 解 密 操 作 , 需 要 与 加 密 时 使 用 的 算 法 相 同 。
* @return 返 回 解 密 后 的 明 文 内 容 , 以 字 符 串 形 式 返 回 , 是 经 过 解 密 操 作 还 原 出 的 原 始 未 加 密 文 本 。
* @throws Exception 如 果 在 解 密 过 程 中 出 现 如 密 钥 格 式 错 误 、 解 密 算 法 执 行 异 常 等 任 何 问 题 , 则 抛 出 异 常 。
* @param secretKey 密 钥
* @param iv 加 密 向 量 , 只 有 CBC 模 式 才 支 持 , 如 果 是 CBC 则 必 传
* @param ciphertext 密 文
* @param algorithm 对 称 加 密 算 法 , 如 AES 、 DES
* @return
* @throws Exception
* /
public static String decryptSymmetrically ( String secretKey , String iv , String ciphertext , Algorithm algorithm ) throws Exception {
// 调用decodeSymmetricKey方法, 传入对称密钥( secretKey) 和指定的对称加密算法( algorithm) , 将Base64编码的对称密钥解码并重新生成SecretKey实例, 用于后续的解密操作, 得到实际可用的对称密钥对象, 存储在key变量中。
SecretKey key = decodeSymmetricKey ( secretKey , algorithm ) ;
// 通过StringUtils.isBlank判断传入的加密向量( iv) 是否为空字符串, 如果为空, 则将ivParameterSpec设置为null, 表示不需要加密向量( 对应不需要加密向量的加密模式下的解密情况) ;
// 如果不为空, 则调用decodeIv方法对加密向量进行解码并生成IvParameterSpec实例, 用于指定解密时的初始向量信息( 在CBC模式等需要的情况下) , 存储在ivParameterSpec变量中。
IvParameterSpec ivParameterSpec = StringUtils . isBlank ( iv ) ? null : decodeIv ( iv ) ;
// 使用Base64解码器( BASE64_DECODER) 对传入的密文( ciphertext) 进行解码, 将Base64编码的字符串转换回原始的字节数组, 得到的字节数组存储在ciphertextInBytes变量中, 这是因为后续解密操作需要操作字节数据。
IvParameterSpec ivParameterSpec = StringUtils . isBlank ( iv ) ? null : decodeIv ( iv ) ;
byte [ ] ciphertextInBytes = BASE64_DECODER . decode ( ciphertext ) ;
// 调用transform方法, 传入对称加密算法( algorithm) 、解密模式( Cipher.DECRYPT_MODE表示解密操作) 、生成的对称密钥( key) 、加密向量( ivParameterSpec) 以及密文字节数组( ciphertextInBytes) ,
// 执行实际的对称解密操作, 得到解密后的字节数组, 存储在plainTextInBytes变量中。
byte [ ] plainTextInBytes = transform ( algorithm , Cipher . DECRYPT_MODE , key , ivParameterSpec , ciphertextInBytes ) ;
// 将解密后的字节数组( plainTextInBytes) 按照默认字符编码格式( DEFAULT_CHARSET, 即UTF-8) 转换为字符串, 即将字节数据还原为原始的文本内容, 然后返回该字符串作为最终的解密结果( 明文) 。
return new String ( plainTextInBytes , DEFAULT_CHARSET ) ;
}
/ * *
* 非 对 称 加 密
* @param publicKeyText 公 钥 , 以 Base64 编 码 字 符 串 形 式 传 入 , 用 于 非 对 称 加 密 操 作 , 在 非 对 称 加 密 体 系 中 , 公 钥 用 于 对 数 据 进 行 加 密 , 只 有 对 应 的 私 钥 才 能 解 密 。
* @param plainText 明 文 , 即 需 要 进 行 加 密 的 原 始 文 本 内 容 , 是 未 经 过 加 密 处 理 的 原 始 数 据 。
* @param algorithm 非 对 称 加 密 算 法 , 通 过 Algorithm 枚 举 类 型 传 入 具 体 的 算 法 实 例 , 指 定 使 用 哪 种 非 对 称 加 密 算 法 来 进 行 加 密 操 作 , 例 如 RSA 等 算 法 。
* @return 返 回 经 过 非 对 称 加 密 后 的 密 文 , 以 Base64 编 码 字 符 串 形 式 返 回 , 方 便 存 储 和 传 输 加 密 后 的 数 据 。
* @throws Exception 如 果 在 加 密 过 程 中 出 现 如 密 钥 格 式 错 误 、 加 密 算 法 执 行 异 常 等 任 何 问 题 , 则 抛 出 异 常 。
* @param publicKeyText 公 钥
* @param plainText 明 文
* @param algorithm 非 对 称 加 密 算 法
* @return
* @throws Exception
* /
public static String encryptAsymmetrically ( String publicKeyText , String plainText , Algorithm algorithm ) throws Exception {
// 调用regeneratePublicKey方法, 传入公钥文本( publicKeyText) 和指定的非对称加密算法( algorithm) , 将Base64编码的公钥解码并重新生成PublicKey实例, 用于后续的加密操作, 得到实际可用的公钥对象, 存储在publicKey变量中。
PublicKey publicKey = regeneratePublicKey ( publicKeyText , algorithm ) ;
// 将明文字符串( plainText) 按照默认字符编码格式( DEFAULT_CHARSET, 即UTF-8) 转换为字节数组, 准备进行加密操作, 得到的字节数组存储在plainTextInBytes变量中, 因为加密算法通常是基于字节数据进行操作的。
byte [ ] plainTextInBytes = plainText . getBytes ( DEFAULT_CHARSET ) ;
// 调用transform方法, 传入非对称加密算法( algorithm) 、加密模式( Cipher.ENCRYPT_MODE表示加密操作) 、生成的公钥( publicKey) 以及明文字节数组( plainTextInBytes) ,
// 执行实际的非对称加密操作, 得到加密后的字节数组, 存储在ciphertextInBytes变量中。
byte [ ] ciphertextInBytes = transform ( algorithm , Cipher . ENCRYPT_MODE , publicKey , plainTextInBytes ) ;
// 将加密后的字节数组( ciphertextInBytes) 使用Base64编码器( BASE64_ENCODER) 转换为字符串, 即将二进制的加密数据编码为可方便存储和传输的Base64编码字符串形式, 然后返回该字符串作为最终的加密结果( 密文) 。
return BASE64_ENCODER . encodeToString ( ciphertextInBytes ) ;
}
/ * *
* 非 对 称 解 密
* @param privateKeyText 私 钥
* @param ciphertext 密 文
* @param algorithm 非 对 称 加 密 算 法
* @return
* @throws Exception
* /
public static String decryptAsymmetrically ( String privateKeyText , String ciphertext , Algorithm algorithm ) throws Exception {
// 调用regeneratePrivateKey方法, 传入私钥文本( privateKeyText) 和指定的非对称加密算法( algorithm) ,
// 目的是将Base64编码格式的私钥文本解码并重新生成对应的PrivateKey实例, 以便后续用于解密操作, 生成的私钥对象存储在privateKey变量中。
PrivateKey privateKey = regeneratePrivateKey ( privateKeyText , algorithm ) ;
// 使用Base64解码器( BASE64_DECODER) 对传入的密文( ciphertext) 进行解码操作, 将Base64编码的密文字符串转换为原始的字节数组形式,
// 得到的字节数组存储在ciphertextInBytes变量中, 因为后续的解密操作需要基于字节数据进行处理。
byte [ ] ciphertextInBytes = BASE64_DECODER . decode ( ciphertext ) ;
// 调用transform方法, 传入非对称加密算法( algorithm) 、解密模式( Cipher.DECRYPT_MODE表示进行解密操作) 、刚生成的私钥( privateKey) 以及密文字节数组( ciphertextInBytes) ,
// 执行实际的非对称解密操作, 将密文字节数组还原为原始的明文字节数组, 得到的明文字节数组存储在plainTextInBytes变量中。
byte [ ] plainTextInBytes = transform ( algorithm , Cipher . DECRYPT_MODE , privateKey , ciphertextInBytes ) ;
// 将解密得到的明文字节数组( plainTextInBytes) 按照默认字符编码格式( DEFAULT_CHARSET, 这里通常是UTF-8) 转换为字符串形式,
// 从而将字节数据还原为原始的文本内容,最终返回这个解密后的字符串作为非对称解密的结果,也就是原始的明文信息。
return new String ( plainTextInBytes , DEFAULT_CHARSET ) ;
}
/ * *
* 非 对 称 解 密
* @param privateKeyText 私 钥
* @param ciphertext 密 文
* @param algorithm 非 对 称 加 密 算 法
* @return
* @throws Exception
* /
public static String decryptAsymmetrically ( String privateKeyText , String ciphertext , Algorithm algorithm ) throws Exception {
PrivateKey privateKey = regeneratePrivateKey ( privateKeyText , algorithm ) ;
byte [ ] ciphertextInBytes = BASE64_DECODER . decode ( ciphertext ) ;
byte [ ] plainTextInBytes = transform ( algorithm , Cipher . DECRYPT_MODE , privateKey , ciphertextInBytes ) ;
return new String ( plainTextInBytes , DEFAULT_CHARSET ) ;
}
/ * *
* 生 成 数 字 签 名
* @param privateKeyText 私 钥 , 以 Base64 编 码 字 符 串 形 式 传 入 , 用 于 数 字 签 名 操 作 , 在 数 字 签 名 过 程 中 , 私 钥 用 于 对 要 传 输 的 数 据 生 成 唯 一 的 签 名 标 识 , 以 保 证 数 据 的 完 整 性 和 不 可 抵 赖 性 。
* @param msg 传 输 的 数 据 , 即 需 要 进 行 数 字 签 名 的 原 始 数 据 内 容 , 通 常 是 一 些 重 要 的 业 务 信 息 等 , 签 名 后 接 收 方 可 以 通 过 验 证 签 名 来 确 认 数 据 是 否 被 篡 改 。
* @param encryptionAlgorithm 加 密 算 法 , 见 Algorithm 中 的 加 密 算 法 , 用 于 指 定 在 生 成 数 字 签 名 过 程 中 涉 及 到 的 加 密 相 关 算 法 , 例 如 可 能 是 RSA 等 特 定 的 加 密 算 法 , 需 与 业 务 中 约 定 的 加 密 机 制 相 匹 配 。
* @param signatureAlgorithm 签 名 算 法 , 见 Algorithm 中 的 签 名 算 法 , 用 于 明 确 具 体 采 用 哪 种 签 名 算 法 来 生 成 数 字 签 名 , 例 如 SHA1WithRSA 等 , 不 同 的 签 名 算 法 有 不 同 的 特 性 和 安 全 性 级 别 。
* @return 数 字 签 名 , 以 Base64 编 码 字 符 串 形 式 返 回 生 成 的 数 字 签 名 , 方 便 在 网 络 传 输 等 场 景 中 传 递 该 签 名 信 息 , 接 收 方 可 以 利 用 此 签 名 进 行 验 证 操 作 。
* @throws Exception 如 果 在 生 成 数 字 签 名 的 过 程 中 出 现 诸 如 密 钥 格 式 错 误 、 签 名 算 法 执 行 异 常 等 任 何 问 题 , 则 抛 出 异 常 。
* @param privateKeyText 私 钥
* @param msg 传 输 的 数 据
* @param encryptionAlgorithm 加 密 算 法 , 见 Algorithm 中 的 加 密 算 法
* @param signatureAlgorithm 签 名 算 法 , 见 Algorithm 中 的 签 名 算 法
* @return 数 字 签 名
* @throws Exception
* /
public static String doSign ( String privateKeyText , String msg , Algorithm encryptionAlgorithm , Algorithm signatureAlgorithm )
throws Exception {
// 调用regeneratePrivateKey方法, 传入私钥文本( privateKeyText) 和指定的加密算法( encryptionAlgorithm) ,
// 作用是将Base64编码的私钥解码并重新生成对应的PrivateKey实例, 以便后续利用该私钥进行数字签名操作, 生成的私钥对象存储在privateKey变量中。
PrivateKey privateKey = regeneratePrivateKey ( privateKeyText , encryptionAlgorithm ) ;
// 通过Signature.getInstance方法, 根据传入的签名算法名称( signatureAlgorithm.getName()) 获取对应的Signature实例,
// Signature是Java中用于处理数字签名相关操作的类, 这里获取到的实例用于后续具体的签名生成操作, 因为它只支持签名算法相关功能。
// Signature只支持签名算法
Signature signature = Signature . getInstance ( signatureAlgorithm . getName ( ) ) ;
// 使用获取到的Signature实例, 调用initSign方法并传入私钥( privateKey) 进行初始化操作,
// 此操作是为了告知签名对象后续将使用该私钥来生成数字签名,为签名过程做准备。
signature . initSign ( privateKey ) ;
// 调用signature的update方法, 将需要签名的数据( msg) 按照默认字符编码格式( DEFAULT_CHARSET, 一般为UTF-8) 转换为字节数组后传入,
// 这个操作是将待签名的数据传递给签名对象,以便它基于这些数据和之前初始化的私钥来生成数字签名,类似于告知签名对象要对哪些具体内容进行签名。
signature . update ( msg . getBytes ( DEFAULT_CHARSET ) ) ;
// 调用signature的sign方法执行实际的数字签名生成操作, 该方法会基于前面设置的私钥、待签名数据等信息生成数字签名, 返回的是字节数组形式的签名结果, 存储在signatureInBytes变量中。
byte [ ] signatureInBytes = signature . sign ( ) ;
// 将生成的字节数组形式的数字签名( signatureInBytes) 使用Base64编码器( BASE64_ENCODER) 进行编码, 转换为Base64编码字符串形式,
// 方便在网络传输等场景中传递该数字签名,最终返回这个编码后的字符串作为生成的数字签名结果。
return BASE64_ENCODER . encodeToString ( signatureInBytes ) ;
}
/ * *
* 数 字 签 名 验 证
* @param publicKeyText 公 钥 , 以 Base64 编 码 字 符 串 形 式 传 入 , 用 于 数 字 签 名 验 证 操 作 , 在 验 证 数 字 签 名 时 , 公 钥 与 生 成 签 名 时 使 用 的 私 钥 相 对 应 , 通 过 公 钥 来 验 证 签 名 是 否 是 由 对 应 的 私 钥 生 成 的 , 以 此 确 认 数 据 的 完 整 性 和 来 源 合 法 性 。
* @param msg 传 输 的 数 据 , 即 要 验 证 数 字 签 名 对 应 的 原 始 数 据 内 容 , 需 要 与 生 成 数 字 签 名 时 使 用 的 数 据 完 全 一 致 , 否 则 验 证 会 失 败 , 该 数 据 用 于 和 签 名 一 起 进 行 验 证 比 对 。
* @param signatureText 数 字 签 名 , 以 Base64 编 码 字 符 串 形 式 传 入 , 是 之 前 生 成 的 需 要 进 行 验 证 的 数 字 签 名 信 息 , 接 收 方 获 取 到 此 签 名 后 , 使 用 对 应 的 公 钥 和 原 始 数 据 来 验 证 其 有 效 性 。
* @param encryptionAlgorithm 加 密 算 法 , 见 Algorithm 中 的 加 密 算 法 , 用 于 指 定 在 数 字 签 名 验 证 过 程 中 涉 及 到 的 加 密 相 关 算 法 , 需 要 与 生 成 数 字 签 名 时 使 用 的 加 密 算 法 一 致 , 确 保 验 证 的 准 确 性 。
* @param signatureAlgorithm 签 名 算 法 , 见 Algorithm 中 的 签 名 算 法 , 用 于 明 确 具 体 采 用 哪 种 签 名 算 法 来 验 证 数 字 签 名 , 要 与 生 成 数 字 签 名 时 使 用 的 签 名 算 法 相 同 , 保 证 验 证 逻 辑 的 正 确 性 。
* @return 校 验 是 否 成 功 , 返 回 true 表 示 数 字 签 名 验 证 通 过 , 即 签 名 有 效 , 意 味 着 数 据 的 完 整 性 和 来 源 合 法 性 得 到 确 认 ; 返 回 false 表 示 验 证 失 败 , 签 名 可 能 被 篡 改 或 者 来 源 不 合 法 。
* @throws Exception 如 果 在 数 字 签 名 验 证 的 过 程 中 出 现 诸 如 密 钥 格 式 错 误 、 验 证 算 法 执 行 异 常 等 任 何 问 题 , 则 抛 出 异 常 。
* @param publicKeyText 公 钥
* @param msg 传 输 的 数 据
* @param signatureText 数 字 签 名
* @param encryptionAlgorithm 加 密 算 法 , 见 Algorithm 中 的 加 密 算 法
* @param signatureAlgorithm 签 名 算 法 , 见 Algorithm 中 的 签 名 算 法
* @return 校 验 是 否 成 功
* @throws Exception
* /
public static boolean doVerify ( String publicKeyText , String msg , String signatureText , Algorithm encryptionAlgorithm ,
Algorithm signatureAlgorithm ) throws Exception {
// 调用regeneratePublicKey方法, 传入公钥文本( publicKeyText) 和指定的加密算法( encryptionAlgorithm) ,
// 目的是将Base64编码格式的公钥文本解码并重新生成对应的PublicKey实例, 以便后续利用该公钥进行数字签名验证操作, 生成的公钥对象存储在publicKey变量中。
PublicKey publicKey = regeneratePublicKey ( publicKeyText , encryptionAlgorithm ) ;
// 通过Signature.getInstance方法, 根据传入的签名算法名称( signatureAlgorithm.getName()) 获取对应的Signature实例,
// 用于后续具体的数字签名验证操作,因为它提供了验证签名有效性的相关功能。
Signature signature = Signature . getInstance ( signatureAlgorithm . getName ( ) ) ;
// 使用获取到的Signature实例, 调用initVerify方法并传入公钥( publicKey) 进行初始化操作,
// 此操作是为了告知验证对象后续将使用该公钥来验证数字签名,为验证过程做准备。
signature . initVerify ( publicKey ) ;
// 调用signature的update方法, 将需要验证的数据( msg) 按照默认字符编码格式( DEFAULT_CHARSET, 一般为UTF-8) 转换为字节数组后传入,
// 这个操作是将原始数据传递给验证对象,使其基于这些数据和之前初始化的公钥来进行数字签名验证,类似于告知验证对象要验证的原始数据内容是什么。
signature . update ( msg . getBytes ( DEFAULT_CHARSET ) ) ;
// 调用signature的verify方法执行实际的数字签名验证操作, 传入经过Base64解码后的数字签名( 通过BASE64_DECODER.decode(signatureText)获取原始字节数组形式的签名),
// 该方法会基于前面设置的公钥、原始数据以及传入的数字签名信息进行验证,返回一个布尔值,表示验证是否成功,直接返回这个布尔值作为最终的验证结果。
return signature . verify ( BASE64_DECODER . decode ( signatureText ) ) ;
}
/ * *
* 将 密 钥 进 行 Base64 位 解 码 , 重 新 生 成 SecretKey 实 例
* @param secretKey 密 钥
* @param algorithm 算 法
* @return
* /
private static SecretKey decodeSymmetricKey ( String secretKey , Algorithm algorithm ) {
// 使用BASE64_DECODER( Base64解码器, 在类中前面已定义) 对传入的对称密钥字符串( secretKey) 进行解码操作,
// 将Base64编码格式的密钥字符串转换为原始的字节数组形式, 得到的字节数组存储在key变量中, 以便后续基于字节数据构建SecretKey对象。
byte [ ] key = BASE64_DECODER . decode ( secretKey ) ;
// 使用SecretKeySpec类, 根据解码后的字节数组( key) 和指定的算法名称( algorithm.getName()) 创建一个SecretKey实例,
// SecretKeySpec实现了SecretKey接口, 用于包装字节数组形式的密钥数据, 使其成为符合特定对称加密算法要求的密钥对象, 最终返回这个SecretKey对象, 用于后续的对称加密或解密操作等。
return new SecretKeySpec ( key , algorithm . getName ( ) ) ;
}
/ * *
* 将 密 钥 进 行 Base64 位 解 码 , 重 新 生 成 SecretKey 实 例
* @param secretKey 密 钥
* @param algorithm 算 法
* @return
* /
private static SecretKey decodeSymmetricKey ( String secretKey , Algorithm algorithm ) {
byte [ ] key = BASE64_DECODER . decode ( secretKey ) ;
return new SecretKeySpec ( key , algorithm . getName ( ) ) ;
}
private static IvParameterSpec decodeIv ( String iv ) {
// 使用BASE64_DECODER( Base64解码器) 对传入的加密向量字符串( iv) 进行解码操作,
// 将Base64编码格式的加密向量字符串转换为原始的字节数组形式, 得到的字节数组存储在ivInBytes变量中, 后续将基于此字节数组构建IvParameterSpec对象用于加密或解密操作( 在需要加密向量的模式下) 。
byte [ ] ivInBytes = BASE64_DECODER . decode ( iv ) ;
// 使用IvParameterSpec类, 根据解码后的字节数组( ivInBytes) 创建一个IvParameterSpec实例,
// IvParameterSpec用于指定加密或解密操作中使用的初始向量信息( 在如CBC模式等需要加密向量的情况下) , 最终返回这个IvParameterSpec对象, 用于相关加密或解密流程。
return new IvParameterSpec ( ivInBytes ) ;
}
private static PublicKey regeneratePublicKey ( String publicKeyText , Algorithm algorithm )
throws NoSuchAlgorithmException , InvalidKeySpecException {
// 使用BASE64_DECODER( Base64解码器) 对传入的公钥字符串( publicKeyText) 进行解码操作,
// 将Base64编码格式的公钥字符串转换为原始的字节数组形式, 得到的字节数组存储在keyInBytes变量中, 以便后续基于这些字节数据构建PublicKey对象。
byte [ ] keyInBytes = BASE64_DECODER . decode ( publicKeyText ) ;
// 调用getKeyFactory方法, 传入指定的算法( algorithm) , 获取对应的KeyFactory实例, KeyFactory用于根据特定算法创建密钥相关的对象( 如公钥、私钥等) , 存储在keyFactory变量中。
KeyFactory keyFactory = getKeyFactory ( algorithm ) ;
// 按照Java加密规范要求, 公钥必须使用RSAPublicKeySpec或者X509EncodedKeySpec来构建, 这里使用X509EncodedKeySpec类,
// 根据解码后的字节数组( keyInBytes) 创建一个公钥规范对象( KeySpec) , 用于后续通过KeyFactory生成具体的PublicKey对象, 此规范定义了公钥的格式和数据内容等信息。
// 公钥必须使用RSAPublicKeySpec或者X509EncodedKeySpec
KeySpec publicKeySpec = new X509EncodedKeySpec ( keyInBytes ) ;
// 使用获取到的KeyFactory实例( keyFactory) , 调用其generatePublic方法并传入公钥规范对象( publicKeySpec) ,
// 执行实际的公钥生成操作, 将符合规范的字节数据转换为可用的PublicKey对象, 存储在publicKey变量中, 该PublicKey对象可用于后续的非对称加密、数字签名验证等操作。
PublicKey publicKey = keyFactory . generatePublic ( publicKeySpec ) ;
// 返回生成的PublicKey对象, 供调用者在需要使用公钥的地方( 如加密、验证等操作) 使用。
return publicKey ;
}
private static PrivateKey regeneratePrivateKey ( String key , Algorithm algorithm ) throws Exception {
// 使用BASE64_DECODER( Base64解码器) 对传入的私钥字符串( key) 进行解码操作,
// 将Base64编码格式的私钥字符串转换为原始的字节数组形式, 得到的字节数组存储在keyInBytes变量中, 以便后续基于这些字节数据构建PrivateKey对象。
byte [ ] keyInBytes = BASE64_DECODER . decode ( key ) ;
// 调用getKeyFactory方法, 传入指定的算法( algorithm) , 获取对应的KeyFactory实例, 用于后续创建私钥对象, 存储在keyFactory变量中。
KeyFactory keyFactory = getKeyFactory ( algorithm ) ;
// 按照Java加密规范要求, 私钥必须使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpec来构建, 这里使用PKCS8EncodedKeySpec类,
// 根据解码后的字节数组( keyInBytes) 创建一个私钥规范对象( KeySpec) , 用于定义私钥的格式和数据内容等信息, 为生成私钥做准备。
// 私钥必须使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpec
KeySpec privateKeySpec = new PKCS8EncodedKeySpec ( keyInBytes ) ;
// 使用获取到的KeyFactory实例( keyFactory) , 调用其generatePrivate方法并传入私钥规范对象( privateKeySpec) ,
// 执行实际的私钥生成操作, 将符合规范的字节数据转换为可用的PrivateKey对象, 存储在privateKey变量中, 该PrivateKey对象可用于后续的非对称解密、数字签名生成等操作。
PrivateKey privateKey = keyFactory . generatePrivate ( privateKeySpec ) ;
// 返回生成的PrivateKey对象, 供调用者在需要使用私钥的地方( 如解密、签名等操作) 使用。
return privateKey ;
}
private static KeyFactory getKeyFactory ( Algorithm algorithm ) throws NoSuchAlgorithmException {
// 尝试从KEY_FACTORY_CACHE( 一个以Algorithm为键, 存储KeyFactory实例的缓存Map, 在类中前面已定义) 中获取指定算法( algorithm) 对应的KeyFactory实例,
// 目的是先查看缓存中是否已经存在该算法的KeyFactory, 如果存在则直接复用, 避免重复创建, 提高性能, 获取到的实例存储在keyFactory变量中。
KeyFactory keyFactory = KEY_FACTORY_CACHE . get ( algorithm ) ;
// 判断从缓存中获取到的KeyFactory实例是否为null, 如果是null, 表示缓存中还没有该算法对应的KeyFactory实例, 需要创建新的实例, 执行以下操作。
if ( keyFactory = = null ) {
// 通过KeyFactory.getInstance方法, 根据指定算法的名称( algorithm.getName()) 创建一个新的KeyFactory实例,
// 此方法会根据Java运行环境中支持的加密算法来查找并创建对应的KeyFactory, 用于后续创建密钥相关对象( 公钥、私钥等) 。
keyFactory = KeyFactory . getInstance ( algorithm . getName ( ) ) ;
// 将新创建的KeyFactory实例放入KEY_FACTORY_CACHE缓存中, 以算法( algorithm) 为键进行存储, 方便下次获取时直接使用, 避免再次创建, 提高效率。
KEY_FACTORY_CACHE . put ( algorithm , keyFactory ) ;
}
// 返回获取到( 从缓存中或者新创建的) 的KeyFactory实例, 供调用者使用, 例如用于生成公钥、私钥等操作。
return keyFactory ;
}
private static byte [ ] transform ( Algorithm algorithm , int mode , Key key , byte [ ] msg ) throws Exception {
// 此方法重载了另一个transform方法, 这里直接调用另一个带有更多参数的transform方法, 传入算法( algorithm) 、模式( mode) 、密钥( key) 、null( 表示加密向量为默认值, 具体由内部逻辑处理) 以及消息字节数组( msg) ,
// 目的是统一通过另一个更完整参数的方法来处理字节数据的转换(加密或解密等操作),最终返回转换后的字节数组结果。
return transform ( algorithm , mode , key , null , msg ) ;
}
private static byte [ ] transform ( Algorithm algorithm , int mode , Key key , IvParameterSpec iv , byte [ ] msg ) throws Exception {
// 尝试从CIPHER_CACHE( 一个以Algorithm为键, 存储Cipher实例的缓存Map, 在类中前面已定义) 中获取指定算法( algorithm) 对应的Cipher实例,
// Cipher实例用于执行加密或解密等实际操作, 先查看缓存中是否已经存在该算法对应的Cipher, 如果存在则直接复用, 避免重复创建, 减少开销, 获取到的实例存储在cipher变量中。
Cipher cipher = CIPHER_CACHE . get ( algorithm ) ;
// double check, 减少上下文切换
// 再次检查获取到的Cipher实例是否为null, 这是一种双重检查机制, 因为在多线程环境下, 可能存在多个线程同时发现缓存中没有对应Cipher实例的情况,
// 通过再次检查来确保只有一个线程去创建并放入缓存,避免重复创建和不必要的上下文切换开销,提高并发性能。
if ( cipher = = null ) {
// 使用synchronized关键字对CryptoUtils类进行同步锁控制, 确保在同一时刻只有一个线程能进入以下代码块执行创建Cipher实例并放入缓存的操作, 避免多线程并发冲突。
synchronized ( CryptoUtils . class ) {
// 再次检查( 在进入同步块后) 缓存中是否已经存在该算法对应的Cipher实例, 因为可能在等待进入同步块的过程中, 其他线程已经创建并放入缓存了,
// 如果还是null, 表示确实需要创建新的Cipher实例, 执行以下操作。
if ( ( cipher = CIPHER_CACHE . get ( algorithm ) ) = = null ) {
// 调用determineWhichCipherToUse方法, 传入指定算法( algorithm) , 根据算法相关信息确定并创建对应的Cipher实例,
// 该方法内部会根据算法的具体配置( 如算法名称、转换模式等) 来创建合适的Cipher对象, 用于后续的加密或解密操作。
cipher = determineWhichCipherToUse ( algorithm ) ;
// 将新创建的Cipher实例放入CIPHER_CACHE缓存中, 以算法( algorithm) 为键进行存储, 方便后续获取时直接使用, 避免再次创建, 提高效率。
CIPHER_CACHE . put ( algorithm , cipher ) ;
}
// 使用获取到( 从缓存中或者新创建的) 的Cipher实例, 调用其init方法, 传入操作模式( mode, 如加密模式或解密模式等) 、密钥( key) 以及加密向量( iv, 可能为null, 取决于具体算法和模式需求) ,
// 对Cipher实例进行初始化操作, 使其准备好执行后续的加密或解密操作, 根据传入的模式和密钥等信息来配置其内部状态。
cipher . init ( mode , key , iv ) ;
// 调用Cipher实例的doFinal方法, 传入要处理的消息字节数组( msg) , 执行实际的加密或解密操作( 取决于前面传入的模式是加密还是解密) ,
// 该方法会对消息字节数组进行相应处理,并返回处理后的字节数组结果,也就是加密或解密后的字节数组,最终返回这个结果字节数组供调用者使用。
return cipher . doFinal ( msg ) ;
}
}
// 如果第一次获取到的Cipher实例不为null( 即缓存中已经存在可用的Cipher实例) , 执行以下操作, 同样进行初始化和执行加密或解密操作。
synchronized ( CryptoUtils . class ) {
cipher . init ( mode , key , iv ) ;
return cipher . doFinal ( msg ) ;
}
}
private static Cipher determineWhichCipherToUse ( Algorithm algorithm ) throws NoSuchAlgorithmException , NoSuchPaddingException {
// 声明一个Cipher类型的变量cipher, 用于存储后续创建的Cipher实例, Cipher类用于执行加密或解密操作, 这里先进行变量声明, 后续会根据具体情况创建并赋值。
Cipher cipher ;
// 获取传入的Algorithm对象中定义的转换字符串( transformation) , 这个转换字符串通常遵循algorithm/mode/padding的格式( 例如 "AES/CBC/PKCS5Padding") ,
// 它用于指定加密或解密操作中具体的算法、模式( 如ECB、CBC等加密模式) 以及填充方式( 如PKCS5Padding等) 等信息, 存储在transformation变量中。
String transformation = algorithm . getTransformation ( ) ;
// 官方推荐的transformation使用algorithm/mode/padding组合, SunJCE使用ECB作为默认模式, 使用PKCS5Padding作为默认填充
// 判断获取到的转换字符串( transformation) 是否不为空( 即是否有指定具体的算法、模式和填充相关信息) , 如果不为空, 表示有明确的转换要求, 执行以下操作。
if ( StringUtils . isNotEmpty ( transformation ) ) {
// 通过Cipher.getInstance方法, 传入指定的转换字符串( transformation) , 创建一个对应的Cipher实例,
// 该方法会根据传入的转换字符串所表示的算法、模式和填充等信息, 在Java加密框架中查找并创建合适的Cipher对象, 用于后续的加密或解密操作, 创建的实例赋值给cipher变量。
cipher = Cipher . getInstance ( transformation ) ;
} else {
// 如果转换字符串为空, 表示没有明确指定具体的转换信息, 那么只根据算法名称( algorithm.getName()) 来创建Cipher实例,
// 此时会使用默认的模式和填充方式( 根据具体加密框架的默认设置, 如SunJCE的默认情况) 来创建Cipher对象, 同样将创建的实例赋值给cipher变量。
cipher = Cipher . getInstance ( algorithm . getName ( ) ) ;
}
// 返回创建好的Cipher实例, 供调用者在后续的加密、解密等操作中使用, 例如在transform方法中会利用这个Cipher实例来执行具体的字节数据转换操作。
return cipher ;
}
/ * *
* 算 法 分 为 加 密 算 法 和 签 名 算 法 , 更 多 算 法 实 现 见 : < br / >
* < a href = "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl" > jdk8 中 的 标 准 算 法 < / a >
* 这 里 定 义 了 一 个 内 部 静 态 类 Algorithm , 用 于 封 装 和 管 理 加 密 、 签 名 相 关 的 算 法 信 息 , 包 括 算 法 名 称 、 转 换 字 符 串 ( 用 于 指 定 算 法 模 式 和 填 充 等 ) 以 及 密 钥 长 度 等 属 性 , 方 便 在 整 个 加 密 工 具 类 中 统 一 使 用 和 管 理 各 种 算 法 相 关 配 置 。
* /
public static class Algorithm {
// 定义一个内部接口Encryption, 用于列举各种加密算法相关的常量配置, 这些常量都是Algorithm类型的实例, 每个实例代表一种具体的加密算法及其相关属性。
public interface Encryption {
// 创建一个Algorithm实例表示AES算法在ECB模式下使用PKCS5Padding填充的配置, 算法名称为 "AES",转换字符串为 "AES/ECB/PKCS5Padding", 密钥长度为128位,
// 通过这种方式定义了一种具体的加密算法配置,方便在代码中直接引用这个常量来表示该加密算法,后续在加密操作等场景中可以基于此配置来创建对应的加密对象等。
Algorithm AES_ECB_PKCS5 = new Algorithm ( "AES" , "AES/ECB/PKCS5Padding" , 128 ) ;
Algorithm AES_CBC_PKCS5 = new Algorithm ( "AES" , "AES/CBC/PKCS5Padding" , 128 ) ;
Algorithm DES_ECB_PKCS5 = new Algorithm ( "DES" , "DES/ECB/PKCS5Padding" , 56 ) ;
@ -543,31 +364,23 @@ private static SecretKey decodeSymmetricKey(String secretKey, Algorithm algorith
Algorithm DSA = new Algorithm ( "DSA" , 1024 ) ;
}
// 定义一个内部接口Signing, 用于列举各种签名算法相关的常量配置, 同样每个常量都是Algorithm类型的实例, 代表一种具体的签名算法及其相关属性。
public interface Signing {
Algorithm SHA1WithDSA = new Algorithm ( "SHA1withDSA" , 1024 ) ;
Algorithm SHA1WithRSA = new Algorithm ( "SHA1WithRSA" , 2048 ) ;
Algorithm SHA256WithRSA = new Algorithm ( "SHA256WithRSA" , 2048 ) ;
}
// 使用Lombok的@Getter注解, 自动生成获取name属性的getter方法, name属性用于存储算法的名称, 例如 "AES"、"RSA" 等,方便外部获取该算法的名称信息。
@Getter
private String name ;
// 使用Lombok的@Getter注解, 自动生成获取transformation属性的getter方法, transformation属性用于存储算法对应的转换字符串, 包含算法、模式和填充等相关信息, 便于外部获取该算法的具体转换配置。
@Getter
private String transformation ;
// 使用Lombok的@Getter注解, 自动生成获取keySize属性的getter方法, keySize属性用于存储算法对应的密钥长度( 以位为单位) , 例如128、1024等, 方便外部获取该算法的密钥长度信息。
@Getter
private int keySize ;
// 构造函数, 用于创建Algorithm实例, 接收算法名称( name) 和密钥长度( keySize) 两个参数, 调用另一个构造函数( this(name, null, keySize))并传递相应参数,
// 主要用于在创建算法实例时只明确算法名称和密钥长度,而不指定具体转换字符串(使用默认的转换配置情况)的场景,比如某些算法只需要名称和密钥长度就能确定基本配置的情况。
public Algorithm ( String name , int keySize ) {
this ( name , null , keySize ) ;
}
// 完整的构造函数, 用于创建Algorithm实例, 接收算法名称( name) 、转换字符串( transformation) 和密钥长度( keySize) 三个参数,
// 分别将这些参数赋值给对应的实例属性( this.name、this.transformation、this.keySize) , 用于初始化一个完整的算法配置对象, 在定义各种具体算法常量时会调用此构造函数来明确算法的各项属性。
public Algorithm ( String name , String transformation , int keySize ) {
this . name = name ;
this . transformation = transformation ;
@ -576,18 +389,15 @@ private static SecretKey decodeSymmetricKey(String secretKey, Algorithm algorith
}
// 使用Lombok的@Data注解, 自动生成该类的常用方法, 如getter、setter、toString、hashCode和equals等方法, 方便对类的属性进行操作和对象间的比较等操作。
// 使用Lombok的@NoArgsConstructor注解, 自动生成无参构造函数, 方便在某些场景下创建该类的默认实例, 例如在一些框架进行对象实例化时如果需要无参构造函数的情况。
// 使用Lombok的@AllArgsConstructor注解, 自动生成全参构造函数, 接收两个参数publicKey和privateKey, 用于初始化类的属性, 方便在创建对象时一次性传入所有必要属性值进行初始化。
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class AsymmetricKeyPair {
// 定义一个字符串类型的属性publicKey, 用于存储非对称加密中的公钥信息, 通常是以Base64编码的字符串形式存储公钥内容, 方便在加密、验证等操作中传递和使用公钥。
private String publicKey ;
// 定义一个字符串类型的属性privateKey, 用于存储非对称加密中的私钥信息, 同样一般是以Base64编码的字符串形式存储私钥内容, 用于在解密、签名等操作中传递和使用私钥。
private String privateKey ;
}
}
}