Java 实现 AES 对称加密算法的加解密

前言

文章字数比较多,可直接查看代码:源码地址,文中描述有误的地方欢迎各位大神指导。

一、对称加密算法简介

1.对称加密

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。

对称加密特点:

  • 加密速度快,可以加密大文件。
  • 密文可逆,一旦密钥文件泄漏,就会导致数据暴露。
  • 加密后编码表找不到对应字符会出现乱码。
  • 一般结合Base64使用。

2.加密模式

ECB

ECB(Electronic codebook):电子密码本,需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。

  • 优点 : 可以并行处理数据。
  • 缺点 : 同样的原文生成同样的密文,不能很好的保护数据。

CBC

CBC(Cipher-block chaining):密码块链接,每个明文块先与前一个密文块进行异或,然后再进行加密,在这种方法中,每个密文块都依赖于它前面的所有明文块。

  • 优点 : 同样的原文生成的密文不一样。
  • 缺点 : 串行处理数据。

3.填充模式

当需要按块处理的数据,数据长度不符合块处理需求时,按照一定的方法填充满块长的规则。

NoPadding

  • 不填充,在AES加密算法下,要求原文长度必须是16byte的整数倍。

PKCS5Padding

  • 数据块的大小为8位不够就补足。

二、AES 加解密代码实例

1.生成 AES 密钥

  • AES 密钥长度默认只支持128、192、256 这三种长度,不合法的密钥长度程序会抛出异常。
  • 生成 AES 密钥时会使用到随机数生成器,可以指定不同的随机数算法,也可以在创建随机数生成器时指定 seed。
  • 初始化算法生成器时,如果不指定随机数生成器默认使用 new SecureRandom()。

代码如下:

    public static SecretKey generateSecretKey(int keysize) throws NoSuchAlgorithmException {
        // 校验密钥长度
        if (keysize != 128 && keysize != 192 && keysize != 256) {
            keysize = 128;
        }
        // 创建安全随机数生成器(SHA1PRNG)
        final SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        // 创建 AES 算法生成器(AES)
        final KeyGenerator generator = KeyGenerator.getInstance("AES");
        // 初始化算法生成器
        generator.init(keysize, random);
        return generator.generateKey();
    }

2.AES 加解密

代码如下:

    public static void main(String[] args) throws Exception {
        final String data = "test";
        final SecretKey secretKey = generateSecretKey(128);

        final byte[] encrypt = encrypt(secretKey.getEncoded(), data.getBytes());
        final byte[] decrypt = decrypt(secretKey.getEncoded(), encrypt);
        System.out.println(new String(decrypt));
    }
    
    /**
     * AES 加密
     *
     * @param aseKey 密钥
     * @param plain 加密原文
     * @return 密文
     */
    public static byte[] encrypt(byte[] aseKey, byte[] plain) throws Exception {
        final SecretKey secretKey = new SecretKeySpec(aseKey, "AES");
        final Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(plain);
    }

    /**
     * AES 解密
     *
     * @param aseKey AES 密钥
     * @param encrypted 解密密文
     * @return 原文
     */
    public static byte[] decrypt(byte[] aseKey, byte[] encrypted) throws Exception {
        final SecretKey secretKey = new SecretKeySpec(aseKey, "AES");
        final Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(encrypted);
    }

3.AES + nonce 加解密

注意在使用 nonce 时,nonce 的长度不能超过 128,不然程序会抛出异常。

代码如下:

    public static void main(String[] args) throws Exception {
        final String data = "test";
        final byte[] nonce = generatorNonce(16);
        final SecretKey secretKey = generateSecretKey(128);

        final byte[] encrypt = encrypt(secretKey.getEncoded(), data.getBytes(), nonce);
        final byte[] decrypt = decrypt(secretKey.getEncoded(), encrypt, nonce);
        System.out.println(new String(decrypt));
    }

    /**
     * AES 加密
     *
     * @param aseKey AES 密钥
     * @param plain 加密原文
     * @param nonce 随机值
     * @return 密文
     */
    public static byte[] encrypt(byte[] aseKey, byte[] plain, byte[] nonce) throws Exception {
        final SecretKey secretKeySpec = new SecretKeySpec(aseKey, "AES");
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        final GCMParameterSpec zeroIv = new GCMParameterSpec(128, nonce);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, zeroIv);
        return cipher.doFinal(plain);
    }

    /**
     * AES 解密
     *
     * @param aseKey AES 密钥
     * @param encrypted 解密密文
     * @param nonce 随机值
     * @return 原文
     */
    public static byte[] decrypt(byte[] aseKey, byte[] encrypted, byte[] nonce) throws Exception {
        final SecretKeySpec secretKeySpec = new SecretKeySpec(aseKey, "AES");
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        final GCMParameterSpec zeroIv = new GCMParameterSpec(128, nonce);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, zeroIv);
        return cipher.doFinal(encrypted);
    }

    /**
     * 获取随机值
     *
     * @param len 随机值长度
     */
    public static byte[] generatorNonce(int len) {
        byte[] values = new byte[len];
        final SecureRandom random = new SecureRandom();
        random.nextBytes(values);
        return values;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值