AES算法的CBC和ECB两种工作模式

AES算法是一种对称加密算法,加密和解密使用的是同一把密钥。常用的对称算法如下:

AES算法密钥长度是固定的,密钥长度直接决定加密强度,而工作模式和填充模式可以看成是对称加密算法的参数和格式选择。目前比较常见的工作模式是ECB和CBC。

ECB模式

ECB模式是最简单的加密模式,通过固定长度的秘钥,固定的明文会生成固定的密文。ECB模式的密钥长度是128位/16字节。

//AES + ECB
public class Demo01 {
	public static void main(String[] args) throws GeneralSecurityException {
		// 原文:
		String message = "天生我材必有用飞流直下三千尺";
		System.out.println("Message(原始信息): " + message);

		// 128位密钥 = 16 bytes Key:
		byte[] key = "1234567890abcdef".getBytes();

		// 加密:
		byte[] data = message.getBytes();
		byte[] encrypted = encrypt(key, data);
		System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted));

		// 解密:
		byte[] decrypted = decrypt(key, encrypted);
		System.out.println("Decrypted(解密内容): " + new String(decrypted));
	}

	// 加密:
	public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
		// 创建密码对象,需要传入算法/工作模式/填充模式
		Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");//ECB/PKCSSPadding

		// 根据key的字节内容,"恢复"秘钥对象
		SecretKey keySpec=new SecretKeySpec(key, "AES");
		// 初始化秘钥:设置加密模式ENCRYPT_
		cipher.init(Cipher.ENCRYPT_MODE,keySpec);
		// 根据原始内容(字节),进行加密
		return cipher.doFinal(input);
	}

	// 解密:
	public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
		// 创建密码对象,需要传入算法/工作模式/填充模式
		Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
		// 根据key的字节内容,"恢复"秘钥对象
		SecretKey keySpec=new SecretKeySpec(key,"AES");
		// 初始化秘钥:设置解密模式DECRYPT_MODE
		cipher.init(Cipher.DECRYPT_MODE, keySpec);
		// 根据原始内容(字节),进行解密
		return cipher.doFinal(input);
	}
}

无论加密,解密首先要创建Cipher密码对象,并且需要传入算法/工作模式/填充模式 Cipher.getInstance("AES/ECB/PKCS5Padding")。

加密时创建好密码对象,要通过new SecretKeySpec(key, "AES")根据key的字节内容,"恢复"秘钥对象。然后调用init(Cipher.ENCRYPT_MODE,keySpec)初始化密钥,设置加密模式为ENCRYPT_MODE,最后调用doFinal()方法传入原始内容(字节),进行加密。

解密在创建好密码对象后,同样要调用new SecretKeySpec(key,"AES"),根据key的字节内容,"恢复"秘钥“对象。然后初始化密钥,设置解密模式,再调用doFina解密。

 CBC模式

CBC模式加入了一个随机数作为IV参数,同样的明文每次生成的密文都不同。密钥长度为256位/32字节。IV参数是随机生成的16字节,所以每次加密后的密文不同。解密时需要使用同样的IV参数才能得到正确的解密结果。

//AES + CBC
public class Demo02 {
	public static void main(String[] args) throws Exception {
      // 原文:
      String message = "Hello";
      System.out.println("Message(原始信息): " + message);
      
      // 256位密钥 = 32 bytes Key:
      byte[] key = "1234567890abcdef1234567890abcdef".getBytes();
      
      // 加密:
      byte[] data = message.getBytes();
      byte[] encrypted = encrypt(key,data);
      System.out.println("Encrypted(加密内容): " + 
				Base64.getEncoder().encodeToString(encrypted));
      
      // 解密:
      byte[] decrypted = decrypt(key,encrypted);
      System.out.println("Decrypted(解密内容): " + new String(decrypted));
  }

  // 加密:
  public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
      // 设置算法/工作模式CBC/填充
  	  Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
  	  // 恢复秘钥对象
      SecretKey keyScpe=new SecretKeySpec(key, "AES");
      // CBC模式需要生成一个16 bytes的initialization vector:
      SecureRandom sr=SecureRandom.getInstanceStrong();
      byte[] iv=sr.generateSeed(16);//生成16个字节的随机数
      System.out.println("iv字节数组内容"+Arrays.toString(iv));
      System.out.println("iv字节数组长度"+iv.length);
      //随机数封装成IvParameterSpec参数对象
      IvParameterSpec ivps=new IvParameterSpec(iv);
      // 初始化秘钥:操作模式、秘钥、IV参数
      cipher.init(Cipher.ENCRYPT_MODE, keyScpe,ivps);
      // 加密
      byte[] data=cipher.doFinal(input);
      // IV不需要保密,把IV和密文一起返回:
      return join(iv,data);
  }

  // 解密:
  public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
      // 把input分割成IV和密文:
      byte[] iv=new byte[16];
      byte[] data=new byte[input.length-16];
      System.arraycopy(input,0,iv,0,16);//IV
      System.arraycopy(input,16,data,0,data.length);//密文
      // 解密:
      Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
      SecretKey keySpec=new SecretKeySpec(key, "AES");//恢复密钥
      IvParameterSpec ivps=new IvParameterSpec(iv);//恢复iv
      // 初始化秘钥:操作模式、秘钥、IV参数
      cipher.init(Cipher.DECRYPT_MODE, keySpec,ivps);
      // 解密操作
      return cipher.doFinal(data);
  }
  
  // 合并数组
  public static byte[] join(byte[] bs1, byte[] bs2) {
	  byte[] r=new byte[bs1.length+bs2.length];
	  System.arraycopy(bs1, 0, r, 0, bs1.length);
	  System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
      return r;
  }
}

CBC模式比ECB模式多了,IvParameterSpec类,将随机数封装成IvParameterSpec参数对象,IV参数也要初始化。其他步骤与ECB模式一致。

区别:

1.CBC模式多了IV参数,安全程度也更高一些。

2.ECB密钥长度为128位(16字节),CBC密钥长度为256位(32字节)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值