java:AES加密和解密

这篇具有很好参考价值的文章主要介绍了java:AES加密和解密。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java:AES加密和解密

1 前言

对称加密,即单秘钥加密,指加密和解密的过程中,使用相同的秘钥,相比于非对称加密,因仅有一把钥匙,故而速度更快,更适合解密大文件(常见于如视频文件的加密解密中)。AES算法就属于对称加密中的一种。

2 使用

依赖引入:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.6</version>
</dependency>

<!--  spring-boot 3.12.0  -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

AES加密与解密的工具类封装:

package com.xiaoxu.crawler.utils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @author xiaoxu
 * @date 2022-11-06 21:24
 * crawlerJ:com.xiaoxu.crawler.utils.AESUtils
 */
public class AESUtils {

    private static final String AES_ALGORITHM = "AES";

    private static final String UTF8 = StandardCharsets.UTF_8.name();

    /* AES加密 String */
    public static String encryptStrAES(String text, String key){
        if(!StringUtils.hasLength(text)){
            ExcpUtils.throwExp("encode text should not be null or empty.");
        }
        byte[] encodeBytes = encryptByteAES(text.getBytes(StandardCharsets.UTF_8), key);
        return Base64.encodeBase64String(encodeBytes);
    }

    /* AES解密 String*/
    public static String decryptStrAES(String text, String key){
        if(!StringUtils.hasLength(text)){
            ExcpUtils.throwExp("decode text should not be null or empty.");
        }
        byte[] decodeBytes = decryptByteAES(Base64.decodeBase64(text.getBytes(StandardCharsets.UTF_8)), key);
        return new String(decodeBytes, StandardCharsets.UTF_8);
    }

    /* AES加密 originalBytes */
    public static byte[] encryptByteAES(byte[] originalBytes, String key){
        if(ArrayUtils.isEmpty(originalBytes)){
            ExcpUtils.throwExp("encode originalBytes should not be empty.");
        }
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("key :" + key + ", encode key should not be null or empty.");
        }
        Cipher cipher = getAESCipher(key, Cipher.ENCRYPT_MODE);
        byte[] encodeBytes = null;
        try {
            encodeBytes = cipher.doFinal(originalBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            ExcpUtils.throwExp(e.getClass().getName()+": encode byte fail. "+e.getMessage());
        }
        return encodeBytes;
    }

    /* AES解密 encryptedBytes */
    public static byte[] decryptByteAES(byte[] encryptedBytes, String key){
        if(ArrayUtils.isEmpty(encryptedBytes)){
            ExcpUtils.throwExp("decode encryptedBytes should not be empty.");
        }
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("key :" + key + ", decode key should not be null or empty.");
        }
        Cipher cipher = getAESCipher(key, Cipher.DECRYPT_MODE);
        byte[] decodeBytes = null;
        try {
            decodeBytes = cipher.doFinal(encryptedBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            ExcpUtils.throwExp(e.getClass().getName()+": decode byte fail. "+e.getMessage());
        }
        return decodeBytes;
    }

    public static Cipher getAESCipher(String key, int mode){
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("key :" + key + ", should not be null or empty.");
        }
        Cipher cipher = null;
        SecretKey secretKey;
        try {
            cipher = Cipher.getInstance(AES_ALGORITHM);
            byte[] keyBytes = key.getBytes(UTF8);
            secretKey = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            cipher.init(mode, secretKey);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            ExcpUtils.throwExp(e.getClass().getName()+": get cipher instance wrong. "+e.getMessage());
        } catch (UnsupportedEncodingException u){
            ExcpUtils.throwExp(u.getClass().getName()+": key transfer bytes fail. "+u.getMessage());
        } catch (InvalidKeyException i) {
            ExcpUtils.throwExp(i.getClass().getName()+": key is invalid. "+i.getMessage());
        }
        return cipher;
    }

    public static void main(String[] args) {
        String msg = "小徐123testAes!!!";
        String key = "0382f2bcbacfa8be";
//        String key = "0382f2bcbacfa8b";
        System.out.println("AES秘钥长度只能为16、24、32:"+key.getBytes(StandardCharsets.UTF_8).length);
        String s = encryptStrAES(msg, key);
        System.out.println("加密后:"+s);
        String s1 = decryptStrAES(s, key);
        System.out.println("解密后:"+s1);
    }


}

执行如下:

AES秘钥长度只能为162432:16
加密后:ZfZYz9Pk4RcA3QQcv+rKnjM54AQV4s/LjsRiGbkpzw8=
解密后:小徐123testAes!!!

AES的秘钥字节数组长度仅能为16、24、32,修改秘钥长度为15再次执行:

public static void main(String[] args) {
    String msg = "小徐123testAes!!!";
//        String key = "0382f2bcbacfa8be";
    String key = "0382f2bcbacfa8b";
    System.out.println("AES秘钥长度只能为16、24、32:"+key.getBytes(StandardCharsets.UTF_8).length);
    String s = encryptStrAES(msg, key);
    System.out.println("加密后:"+s);
    String s1 = decryptStrAES(s, key);
    System.out.println("解密后:"+s1);
}

结果如下,出现了Invalid AES key length异常:

AES秘钥长度只能为162432:15
Exception in thread "main" com.xiaoxu.crawler.excp.CrawlerForJException: java.security.InvalidKeyException: key is invalid. Invalid AES key length: 15 bytes
	at com.xiaoxu.crawler.utils.ExcpUtils.throwExp(ExcpUtils.java:28)
	at com.xiaoxu.crawler.utils.AESUtils.getAESCipher(AESUtils.java:94)
	at com.xiaoxu.crawler.utils.AESUtils.encryptByteAES(AESUtils.java:50)
	at com.xiaoxu.crawler.utils.AESUtils.encryptStrAES(AESUtils.java:29)
	at com.xiaoxu.crawler.utils.AESUtils.main(AESUtils.java:104)

debug源码可见:

AES使用的秘钥key参数有长度限制,如下可见ElectronicCodeBook的部分源码:

java:AES加密和解密

var2为传入的加密的算法,为AES;var3就是秘钥key转换的字节数组,总共长度为15;调用的是AESCrypt的init方法,如下可见AESCrypt的init源码:

void init(boolean var1, String var2, byte[] var3) throws InvalidKeyException {
    if (!var2.equalsIgnoreCase("AES") && !var2.equalsIgnoreCase("Rijndael")) {
        throw new InvalidKeyException("Wrong algorithm: AES or Rijndael required");
    } else if (!isKeySizeValid(var3.length)) {
        throw new InvalidKeyException("Invalid AES key length: " + var3.length + " bytes");
    } else {
        if (!MessageDigest.isEqual(var3, this.lastKey)) {
            this.makeSessionKey(var3);
            this.lastKey = (byte[])var3.clone();
        }

        this.K = this.sessionK[var1 ? 1 : 0];
    }
}

可见,isKeySizeValid(var3.length)返回false时,即抛出Invalid AES key length异常,如下为isKeySizeValid源码:

AESCrypt部分源码如下:

static final boolean isKeySizeValid(int var0) {
    for(int var1 = 0; var1 < AES_KEYSIZES.length; ++var1) {
        if (var0 == AES_KEYSIZES[var1]) {
            return true;
        }
    }

    return false;
}

其中AES_KEYSIZES为接口中的常量:

interface AESConstants {
    int AES_BLOCK_SIZE = 16;
    int[] AES_KEYSIZES = new int[]{16, 24, 32};
}

即AES的秘钥字节数组长度如果不为16、24、32,将抛出Invalid AES key length异常。

由此可见,AES的秘钥字节数组长度需限制在16、24、32内。

package com.xiaoxu.crawler.utils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xiaoxu
 * @date 2022-11-06 21:24
 * crawlerJ:com.xiaoxu.crawler.utils.AESUtils
 */
public class AESUtils {

    private static final String AES_ALGORITHM = "AES";

    private static final String UTF8 = StandardCharsets.UTF_8.name();

    private static final List<Integer> AES_KEYSIZES = Arrays.asList(16, 24, 32);

    public static String newKey(String key){
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("new key should not be empty");
        }
        boolean fl = false;
        int len = key.getBytes(StandardCharsets.UTF_8).length;
        for (int keySize : AES_KEYSIZES) {
            if(len == keySize){
                fl = true;
                break;
            }
        }
        String newKey = key;
        if(!fl){
            /* 32、24、16倒序排序 */
            List<Integer> new_sizes = AES_KEYSIZES.stream().sorted(new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o2-o1;
                }
            }).collect(Collectors.toList());
            int length = 0;
            for (int var0 = 0; var0 < new_sizes.size(); var0++) {
                if(len > 0 && len < new_sizes.get(new_sizes.size()-1) && var0 == new_sizes.size()-1){
                    length = len;
                }else if(new_sizes.get(var0) <= len){
                    length = new_sizes.get(var0);
                }
                if(new_sizes.get(var0) <= len || (len > 0 && len < new_sizes.get(new_sizes.size()-1)&& var0 == new_sizes.size()-1 ) ){
                    byte[] nKey = new byte[new_sizes.get(var0)];
                    for (int f = 0; f < new_sizes.get(var0); f++) {
	                    /* 不足16位的末尾补0 */
                        nKey[f] = (byte)48;
                    }
                    System.arraycopy(key.getBytes(StandardCharsets.UTF_8),0,nKey,0,length);
                    newKey = new String(nKey, StandardCharsets.UTF_8);
                    break;
                }
            }
        }
        return newKey;
    }

    /* AES加密 String */
    public static String encryptStrAES(String text, String key){
        if(!StringUtils.hasLength(text)){
            ExcpUtils.throwExp("encode text should not be null or empty.");
        }
        byte[] encodeBytes = encryptByteAES(text.getBytes(StandardCharsets.UTF_8), key);
        return Base64.encodeBase64String(encodeBytes);
    }

    /* AES解密 String*/
    public static String decryptStrAES(String text, String key){
        if(!StringUtils.hasLength(text)){
            ExcpUtils.throwExp("decode text should not be null or empty.");
        }
        byte[] decodeBytes = decryptByteAES(Base64.decodeBase64(text.getBytes(StandardCharsets.UTF_8)), key);
        return new String(decodeBytes, StandardCharsets.UTF_8);
    }

    /* AES加密 originalBytes */
    public static byte[] encryptByteAES(byte[] originalBytes, String key){
        if(ArrayUtils.isEmpty(originalBytes)){
            ExcpUtils.throwExp("encode originalBytes should not be empty.");
        }
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("key :" + key + ", encode key should not be null or empty.");
        }

        Cipher cipher = getAESCipher(key, Cipher.ENCRYPT_MODE);
        byte[] encodeBytes = null;
        try {
            encodeBytes = cipher.doFinal(originalBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            ExcpUtils.throwExp(e.getClass().getName()+": encode byte fail. "+e.getMessage());
        }
        return encodeBytes;
    }

    /* AES解密 encryptedBytes */
    public static byte[] decryptByteAES(byte[] encryptedBytes, String key){
        if(ArrayUtils.isEmpty(encryptedBytes)){
            ExcpUtils.throwExp("decode encryptedBytes should not be empty.");
        }
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("key :" + key + ", decode key should not be null or empty.");
        }
        Cipher cipher = getAESCipher(key, Cipher.DECRYPT_MODE);
        byte[] decodeBytes = null;
        try {
            decodeBytes = cipher.doFinal(encryptedBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            ExcpUtils.throwExp(e.getClass().getName()+": decode byte fail. "+e.getMessage());
        }
        return decodeBytes;
    }

    public static Cipher getAESCipher(String key, int mode){
        if(!StringUtils.hasLength(key)){
            ExcpUtils.throwExp("key :" + key + ", should not be null or empty.");
        }
        Cipher cipher = null;
        SecretKey secretKey;
        try {
            cipher = Cipher.getInstance(AES_ALGORITHM);
            byte[] keyBytes = key.getBytes(UTF8);
            secretKey = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            cipher.init(mode, secretKey);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            ExcpUtils.throwExp(e.getClass().getName()+": get cipher instance wrong. "+e.getMessage());
        } catch (UnsupportedEncodingException u){
            ExcpUtils.throwExp(u.getClass().getName()+": key transfer bytes fail. "+u.getMessage());
        } catch (InvalidKeyException i) {
            ExcpUtils.throwExp(i.getClass().getName()+": key is invalid. "+i.getMessage());
        }
        return cipher;
    }

    public static void main(String[] args) {
        String msg = "小徐123testAes!!!";
//        String key = "0382f2bcbacfa8be";
        String key = "0382f2bcbacfa8b";
        System.out.println("转换前的秘钥长度:" + key.getBytes(StandardCharsets.UTF_8).length);
        System.out.println("转换后秘钥:"+newKey(key)+";长度:"+newKey(key).getBytes(StandardCharsets.UTF_8).length);

        System.out.println("AES秘钥长度只能为16、24、32:"+newKey(key).getBytes(StandardCharsets.UTF_8).length);
        String s = encryptStrAES(msg, newKey(key));
        System.out.println("加密后:"+s);
        String s1 = decryptStrAES(s, newKey(key));
        System.out.println("解密后:"+s1);
    }
}

可如上简单对秘钥长度作出填充,执行结果如下:文章来源地址https://www.toymoban.com/news/detail-500731.html

转换前的秘钥长度:15
转换后秘钥:0382f2bcbacfa8b0;长度:16
AES秘钥长度只能为162432:16
加密后:AAz4gPXlduN+l1OX0BV9nWXqJqhXRS3ThRQXJsU0lWM=
解密后:小徐123testAes!!!

到了这里,关于java:AES加密和解密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 国密SM4对称加密Java加解密

    提示:国密SM4对称加密Java加解密 国家密码管理局 参考博文 SM4.0(原名SMS4.0)是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布。相关标准为“GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”。 SM4 代码如下(示例): 在密码学中

    2024年02月11日
    浏览(54)
  • 解决cryptoJS.AES默认参数加密,java无法解密的问题

    有时候我们需要跨编程语言进行加密加密。比如nodejs里面加密,java里面解密,或者反过来java加密,nodejs解密。node可以使用cryptojs,java可以使用javax.crypto.Cipher包。 网上有很多关于这方面的文章。然而如果node使用了默认的参数进行加密(比如现有业务已经生成了一些已经加密

    2024年02月11日
    浏览(105)
  • Java:SpringBoot使用AES对JSON数据加密和解密

    客户端和服务端都可以加密和解密,使用base64进行网络传输 加密方 解密方 2.1、项目结构 2.2、常规业务代码 pom.xml Application.java WebMvcConfig.java CrossConfig.java JsonRequest.java JsonResult.java JsonResultVO.java IndexController.java UserController.java 2.3、加密的实现 application.yml SecretData.java DecryptRequ

    2024年02月11日
    浏览(58)
  • Java RSA加解密-非对称加密-公钥私钥加解密(使用hutool工具)

    之前一篇帖子(https://blog.csdn.net/u014137486/article/details/136413532)展示了使用原生Java进行RSA加解密,本文介绍下使用当下流行的Hutool工具进行RSA加解密的用法。 目录 一、在Linux环境下生成公钥、私钥文件 二、将生成的公私钥文件导入项目中并移除pem文件的前后公私钥标记 三、po

    2024年04月23日
    浏览(105)
  • AES(对称加密)和RSA(非对称加密)使用详情

          待加密的明文以16字节分组进行加密,如果数据字节长度不是16的倍数,最后的一组则需要在有效数据后面进行填充,使得数据长度变为16字节,AES填充方式分为NoPadding、PKCS5(PKCS7)、ISO10126、Zeros。 NoPadding :不填充,那就只能加密长度为16倍数的数据,一般不使用; Zero

    2024年02月08日
    浏览(96)
  • 20.3 OpenSSL 对称AES加解密算法

    AES算法是一种对称加密算法,全称为高级加密标准(Advanced Encryption Standard)。它是一种分组密码,以 128 比特为一个分组进行加密,其密钥长度可以是 128 比特、 192 比特或 256 比特,因此可以提供不同等级的安全性。该算法采用了替代、置换和混淆等技术,以及多轮加密和密

    2024年02月08日
    浏览(41)
  • AES 对称加密算法

    高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。 那么为什么原来的DES会被取代呢,,原因就在于其使用56位密钥,比较容易被破解。而AES可以使用128、192、和256位密钥,并且

    2023年04月17日
    浏览(40)
  • C# 实现对称加密算法(AES)与非对称加密算法(RSA),包含前端加密对应算法实现

    一种既简单速度又快的加密方式,加密与解密使用的都是同一个密钥,别名又叫做:单密钥加密;对称加密有很多公开算法,并且因为它效率很高,所以适用于加密大量数据的场合;但其密钥的传输过程是不安全的,并且容易被破解,密钥管理起来也相对麻烦。 需要两个密钥

    2024年02月09日
    浏览(68)
  • 用java语言写一个AES算法,使用AES(CBC模式)对数据进行加密或解密。加解密用到的密钥(Key)和密钥偏移量(IV),代码实例类编写。

    以下是一个使用Java编写的AES算法实例,使用AES(CBC模式)对数据进行加密和解密。代码中包括了生成随机密钥和密钥偏移量的方法。 java Copy code import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidAlgorithmParameterException; import

    2024年02月07日
    浏览(63)
  • 前端使用AES密码加密、解密,使用详细(crypto加密解密,前后端分离,AES加密解密)

    1、 首先安装 crypto-js插件,安装命令如下:    -S等同于--save,保存在package.json文件中,是在dependencies 下, --save安装包信息将加入到dependencies(生产环境)中,生产阶段的依赖,也就是项目运行时的依赖,就是程序上线后仍然需要依赖; -D等同于--save-dev,也保存在package.j

    2024年02月11日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包