Java AES加密算法总结笔记

加密算法

  • 对称加密算法
    • symmetric-key cryptography
    • 加密和解密使用相同密匙
    • 常用对称加密算法
      • DES
      • AES
  • 非对称加密算法
    • asymmetric-key cryptography
    • 加密和解密使用不同密匙
    • 常用非对称加密算法是RSA算法

AES加密

  • Advanced Encryption Standard 高级加密标准,是一种对称加密算法,取代了DES加密算法,因为AES安全性更高

  • https://zhuanlan.zhihu.com/p/396015712
    
  • AES一些规则

    • AES是一种区块加密算法,加密时会将原始数据按大小拆分成一个个区块进行加密,区块大小固定为128比特(16字节)
    • AES密匙长度可以是128,192,256比特,密匙越长,安全性越高,而性能也就越低
  • AES工作模式

    • 多种工作模式
      • ECB,CBC,OFB,CFB等
      • 核心仍然是AES算法
  • AES填充方式

    • AES 是一种区块加密算法,加密时会将原始数据按大小拆分成一个个 128 比特(即 16 字节)区块进行加密,如果需要加密的原始数据不是 16 字节的整数倍时,就需要对原始数据进行填充,使其达到 16 字节的整数倍
    • 常用填充方式
      • PKCS5Padding、ISO10126Padding
  • Java中AES

    Java类

    • javax.crypto.Cipher
      
    • 加密与解密

    创建一个Cipher

    • Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      
    • 传递参数

      • algorithm/mode/padding 算法名/工作模式/填充方式

ECB

  • Electronic codebook

  • 将待加密数据拆分成块,并对每个块进行独立加密

  • 在这里插入图片描述

  • public static byte[] encryptECB(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
        byte[] result = cipher.doFinal(data);
        return result;
    }
    
    public static byte[] decryptECB(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
        byte[] result = cipher.doFinal(data);
        return result;
    }
    
    public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
        String data = "Hello World"; // 待加密的明文
        String key = "12345678abcdefgh"; // key 长度只能是 16、25 或 32 字节
    
        byte[] ciphertext = encryptECB(data.getBytes(), key.getBytes());
        System.out.println("ECB 模式加密结果(Base64):" + Base64.getEncoder().encodeToString(ciphertext));
    
        byte[] plaintext = decryptECB(ciphertext, key.getBytes());
        System.out.println("解密结果:" + new String(plaintext));
    }
    
  • ECB 模式有一个致命的缺点,由于该模式对每个块进行独立加密,会导致同样的明文块被加密成相同的密文块

  • 在这在这里插入图片描述
里插入图片描述

CBC

  • Cipher-block chaining

  • 密码分组链接

  • 它的出现解决 ECB 同样的明文块会被加密成相同的密文块的问题

  • CBC 引入了初始向量的概念(IV,Initialization Vector),第一个明文块先与 IV 进行异或后再加密,后续每个明文块先与前一个密文块进行异或后再加密

  • 在这里插入图片描述

  • public static byte[] encryptCBC(byte[] data, byte[] key, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
        byte[] result = cipher.doFinal(data);
        return result;
    }
    
    public static byte[] decryptCBC(byte[] data, byte[] key, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
        byte[] result = cipher.doFinal(data);
        return result;
    }
    
    public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
        String data = "Hello World"; // 待加密的原文
        String key = "12345678abcdefgh"; // key 长度只能是 16、25 或 32 字节
        String iv = "iviviviviviviviv"; // CBC 模式需要用到初始向量参数
    
        byte[] ciphertext = encryptCBC(data.getBytes(), key.getBytes(), iv.getBytes());
        System.out.println("CBC 模式加密结果(Base64):" + Base64.getEncoder().encodeToString(ciphertext));
    
        byte[] plaintext = decryptCBC(ciphertext, key.getBytes(), iv.getBytes());
        System.out.println("解密结果:" + new String(plaintext));
    }
    
  • 由于 CBC 每个明文块加密都依赖前一个块的加密结果,所以其主要缺点在于加密过程是串行的,无法被并行化

GCM

  • Galois/Counter Mode

  • 不但提供了加密解密,还提供了数据完整性校验,防止篡改

  • AES-GCM 模式是目前使用最广泛的模式

  • 需要以下参数

    • 待加密的明文
    • 密钥
    • 初始向量 IV
    • additional authenticated data (AAD)
  • public static byte[] encryptGCM(byte[] data, byte[] key, byte[] iv, byte[] aad) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
        cipher.updateAAD(aad);
        byte[] result = cipher.doFinal(data);
        return result;
    }
    
    public static byte[] decryptGCM(byte[] data, byte[] key, byte[] iv, byte[] aad) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
        cipher.updateAAD(aad);
        byte[] result = cipher.doFinal(data);
        return result;
    }
    
    public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
        String data = "Hello World"; // 待加密的原文
        String key = "12345678abcdefgh"; // key 长度只能是 16、25 或 32 字节
        String iv = "iviviviviviviviv";
        String aad = "aad"; // AAD 长度无限制,可为空
    
        byte[] ciphertext = encryptGCM(data.getBytes(), key.getBytes(), iv.getBytes(), aad.getBytes());
        System.out.println("GCM 模式加密结果(Base64):" + Base64.getEncoder().encodeToString(ciphertext));
    
        byte[] plaintext = decryptGCM(ciphertext, key.getBytes(), iv.getBytes(), aad.getBytes());
        System.out.println("解密结果:" + new String(plaintext));
    }
    
    • 是流加密(Stream cipher)算法,所以对应的填充模式为 NoPadding

获取钥匙与IV

  • String 密码 获取 secretKeySpec

    • private static SecretKey getKey(String password) {
              int keyLength = 128;  // 密匙bit长度
              byte[] keyBytes = new byte[keyLength / 8];
              SecretKeySpec key = null;
              try {
                  Arrays.fill(keyBytes, (byte) 0x0);
                  byte[] passwordBytes = password.getBytes("UTF-8");
                  int length = passwordBytes.length < keyBytes.length ? passwordBytes.length : keyBytes.length;
                  System.arraycopy(passwordBytes, 0, keyBytes, 0, length); // copy数组
                  key = new SecretKeySpec(keyBytes, "AES");
              } catch (UnsupportedEncodingException e) {
                  e.printStackTrace();
              }
              return key;
          }
      
  • 获取IV

    • new IvParameterSpec(iv.getBytes())		// CBC模式
      new GCMParameterSpec(128, iv.getBytes())  // GCM模式
      

遇到问题

  • 文件加密后,从文件读取流出现解密错误
    • 面对文件流应该使用CipherInputStream 和 CipherOutputStream
    • 见java包
  • ADD是身份认证,GCM模式下可以选择添加
    • Additianal Authenticated Data

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是Java中使用AES加密算法的示例代码: ```java import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class AESUtil { private static final String AES_ALGORITHM = "AES/ECB/PKCS5Padding"; // 使用AES算法,ECB模式,PKCS5Padding填充方式 /** * 加密方法 * * @param data 需要加密的数据 * @param password 加密密码 * @return 加密后的数据 * @throws Exception */ public static String encrypt(String data, String password) throws Exception { SecretKeySpec key = new SecretKeySpec(password.getBytes("UTF-8"), "AES"); Cipher cipher = Cipher.getInstance(AES_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(encryptedBytes); } /** * 解密方法 * * @param data 需要解密的数据 * @param password 解密密码 * @return 解密后的数据 * @throws Exception */ public static String decrypt(String data, String password) throws Exception { SecretKeySpec key = new SecretKeySpec(password.getBytes("UTF-8"), "AES"); Cipher cipher = Cipher.getInstance(AES_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, key); byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decryptedBytes, "UTF-8"); } } ``` 其中,encrypt方法用于加密数据,decrypt方法用于解密数据。需要注意的是,加密和解密时使用的密码必须一致,否则无法正确解密数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

檀良月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值