Java C# 通用AES加密工具类
参考:AES加密(java和C#) 为了解决C#与Java使用AES加密后内容不一致的问题,参考文章已经解决该问题,本篇只是在此基础上进行优化等。
C#:
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
/// <summary>
/// AES工具
/// </summary>
public class AESUtils
{
/// <summary>
/// AES加密(Base64)
/// </summary>
/// <param name="Plaintext">明文(UTF-8字符串)</param>
/// <param name="Key">密钥</param>
/// <param name="IV">向量(16位)</param>
/// <returns>密文(Base64)</returns>
public static string Encrypt_Base64(string Plaintext, string Key, string IV)
{
try
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(Plaintext), GetKeyBySeed(Key), IV));
}
catch
{
return null;
}
}
/// <summary>
/// AES解密(Base64)
/// </summary>
/// <param name="Ciphertext">密文(Base64)</param>
/// <param name="Key">密钥</param>
/// <param name="IV">向量(16位)</param>
/// <returns>明文(UTF-8字符串)</returns>
public static string Decrypt_Base64(string Ciphertext, string Key, string IV)
{
try
{
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(Ciphertext), GetKeyBySeed(Key), IV));
}
catch
{
return null;
}
}
/// <summary>
/// AES加密(16进制)
/// </summary>
/// <param name="Plaintext">明文(UTF-8字符串)</param>
/// <param name="Key">密钥</param>
/// <param name="IV">向量(16位)</param>
/// <returns>密文(16进制)</returns>
public static string Encrypt_Hex(string Plaintext, string Key, string IV)
{
try
{
return BytesToHexStr(Encrypt(Encoding.UTF8.GetBytes(Plaintext), GetKeyBySeed(Key), IV));
}
catch
{
return null;
}
}
/// <summary>
/// AES解密(16进制)
/// </summary>
/// <param name="Ciphertext">密文(16进制)</param>
/// <param name="Key">密钥</param>
/// <param name="IV">向量(16位)</param>
/// <returns>明文(UTF-8字符串)</returns>
public static string Decrypt_Hex(string Ciphertext, string Key, string IV)
{
try
{
return Encoding.UTF8.GetString(Decrypt(HexStrToBytes(Ciphertext), GetKeyBySeed(Key), IV));
}
catch
{
return null;
}
}
/// <summary>
/// 用种子获取密钥
/// </summary>
/// <param name="Seed">种子</param>
/// <param name="KeyLen">密钥长度(默认为16)</param>
/// <returns>密钥Key</returns>
public static byte[] GetKeyBySeed(string Seed, int KeyLen = 16)
{
byte[] bySeed = Encoding.UTF8.GetBytes(Seed);
byte[] byKeyArray = null;
using (var st = new SHA1CryptoServiceProvider())
{
using (var nd = new SHA1CryptoServiceProvider())
{
var rd = nd.ComputeHash(st.ComputeHash(bySeed));
byKeyArray = rd.Take(KeyLen).ToArray();
}
}
return byKeyArray;
}
/// <summary>
/// AES加密
/// </summary>
/// <param name="Bytes">明文(byte[])</param>
/// <param name="Key">密钥(byte[])</param>
/// <param name="Vector">向量</param>
/// <returns>密文(byte[])</returns>
public static byte[] Encrypt(byte[] Bytes, byte[] Key, string Vector)
{
RijndaelManaged aes = new RijndaelManaged();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Key;
aes.IV = Encoding.UTF8.GetBytes(Vector);
ICryptoTransform cTransform = aes.CreateEncryptor();
return cTransform.TransformFinalBlock(Bytes, 0, Bytes.Length);
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="Bytes">密文(byte[])</param>
/// <param name="Key">密钥(byte[])</param>
/// <param name="Vector">向量</param>
/// <returns>明文(byte[])</returns>
public static byte[] Decrypt(byte[] Bytes, byte[] Key, string Vector)
{
RijndaelManaged aes = new RijndaelManaged();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Key;
aes.IV = Encoding.UTF8.GetBytes(Vector);
ICryptoTransform cTransform = aes.CreateDecryptor();
return cTransform.TransformFinalBlock(Bytes, 0, Bytes.Length);
}
/// <summary>
/// 字节数组 -> 十六进制字符串
/// </summary>
/// <param name="Bytes"></param>
/// <returns>十六进制字符串</returns>
public static string BytesToHexStr(byte[] Bytes)
{
// 准备十六进制字符串
string result = "";
// 检查字节数组是否为空
if (Bytes == null)
return null;
// 遍历字节数组
for (int i = 0; i < Bytes.Length; i++)
result += Bytes[i].ToString("X2");
// 返回结果
return result;
}
/// <summary>
/// 十六进制字符串 -> 字节数组
/// </summary>
/// <param name="HexString">十六进制字符串</param>
/// <returns>字节数组</returns>
public static byte[] HexStrToBytes(string HexString)
{
// 检查十六进制字符串是否为奇数
if (HexString.Length % 2 == 1)
{
return null;
}
// 十六进制字符串去重空白符
HexString = Regex.Replace(HexString, @"\s", "");
// 准备字节数组
byte[] result = new byte[HexString.Length / 2];
// 遍历十六进制字符串
for (int i = 0; i < result.Length; i++)
result[i] = Convert.ToByte(HexString.Substring(i * 2, 2), 16);
// 返回结果
return result;
}
}
Java:
package repalce.your.package;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AES工具
*/
public class AESUtils {
/**
* AES加密(16进制)
*
* @param plaintext 明文(UTF-8字符串)
* @param key 密钥
* @param iv 向量(16位)
* @return 密文(16进制)
*/
public static String encryptHex(String plaintext, String key, String iv) {
// 检查参数
if (plaintext == null || "".equals((plaintext = plaintext.trim().replaceAll("\\s", "")))) {
return null;
}
if (key == null || "".equals((key = key.trim().replaceAll("\\s", "")))) {
return null;
}
if (iv == null || "".equals((iv = iv.trim().replaceAll("\\s", ""))) || iv.length() != 16) {
return null;
}
try {
return bytes2HexStr(encrypt(plaintext.getBytes("utf-8"), key.getBytes("utf-8"), iv.getBytes("utf-8")));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* AES解密(16进制)
*
* @param ciphertext 密文(16进制)
* @param key 密钥
* @param iv 向量(16位)
* @return 明文(UTF-8字符串)
*/
public static String decryptHex(String ciphertext, String key, String iv) {
// 检查参数
if (ciphertext == null || "".equals((ciphertext = ciphertext.trim().replaceAll("\\s", "")))) {
return null;
}
if (key == null || "".equals((key = key.trim().replaceAll("\\s", "")))) {
return null;
}
if (iv == null || "".equals((iv = iv.trim().replaceAll("\\s", ""))) || iv.length() != 16) {
return null;
}
try {
return new String(decrypt(hexStr2Bytes(ciphertext), key.getBytes("utf-8"), iv.getBytes("utf-8")), "utf-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* AES加密(Base64)
*
* @param plaintext 明文(UTF-8字符串)
* @param key 密钥
* @param iv 向量(16位)
* @return 密文(Base64)
*/
public static String encryptBase64(String plaintext, String key, String iv) {
// 检查参数
if (plaintext == null || "".equals((plaintext = plaintext.trim().replaceAll("\\s", "")))) {
return null;
}
if (key == null || "".equals((key = key.trim().replaceAll("\\s", "")))) {
return null;
}
if (iv == null || "".equals((iv = iv.trim().replaceAll("\\s", ""))) || iv.length() != 16) {
return null;
}
try {
return Base64.getEncoder().encodeToString(encrypt(plaintext.getBytes("utf-8"), key.getBytes("utf-8"), iv.getBytes("utf-8")));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* AES解密(Base64)
*
* @param ciphertext 密文(Base64)
* @param key 密钥
* @param iv 向量(16位)
* @return 明文(UTF-8字符串)
*/
public static String decryptBase64(String ciphertext, String key, String iv) {
// 检查参数
if (ciphertext == null || "".equals((ciphertext = ciphertext.trim().replaceAll("\\s", "")))) {
return null;
}
if (key == null || "".equals((key = key.trim().replaceAll("\\s", "")))) {
return null;
}
if (iv == null || "".equals((iv = iv.trim().replaceAll("\\s", ""))) || iv.length() != 16) {
return null;
}
try {
return new String(decrypt(Base64.getDecoder().decode(ciphertext), key.getBytes("utf-8"), iv.getBytes("utf-8")), "utf-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* AES加密
*
* @param plaintext 明文
* @param key 密钥
* @param iv 向量
* @return 密文
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static byte[] encrypt(byte[] plaintext, byte[] key, byte[] iv)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
// 构造密钥生成器,指定为 AES 算法,不区分大小写
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 新增下面两行,处理 Linux 操作系统下随机数生成不一致的问题
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key);
kgen.init(128, random);
// 根据字节数组生成AES密钥
SecretKey secretKey = new SecretKeySpec(kgen.generateKey().getEncoded(), "AES");
// 根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 初始化密码器(向量必须是16位)
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
// 返回密文
return cipher.doFinal(plaintext);
}
/**
* AES解密
*
* @param ciphertext 密文
* @param key 密钥
* @param iv 向量
* @return 明文
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static byte[] decrypt(byte[] ciphertext, byte[] key, byte[] iv)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
// 构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 新增下面两行,处理 Linux 操作系统下随机数生成不一致的问题
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key);
kgen.init(128, random);
// 根据字节数组生成AES密钥
SecretKey secretKey = new SecretKeySpec(kgen.generateKey().getEncoded(), "AES");
// 根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 初始化密码器(向量必须是16位)
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
// 返回明文
return cipher.doFinal(ciphertext);
}
/**
* 字节 --> 十六进制字符串
*
* @param bytes 字节
* @return 十六进制字符串
*/
public static String bytes2HexStr(byte[] bytes) {
// 检查字节是否为空
if (bytes.length < 1)
return null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 十六进制字符串 --> 字节
*
* @param hexStr 十六进制字符串
* @return 字节
*/
public static byte[] hexStr2Bytes(String hexStr) {
// 检查十六进制字符串是否为空
if (hexStr == null || "".equals(hexStr.trim()))
return null;
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}