对称加密算法AES
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对称加密算法AES相关的知识,希望对你有一定的参考价值。
参考技术A AES(Advanced Encryption Standard),高级加密标准,对称算法,是下一代的加密算法标准,速度快,安全级别高,在21世纪AES 标准的一个实现是 Rijndael 算法;AES加密算法是密码学中的高级加密标准,该加密算法采用对称分组密码体制,密钥长度的最少支持为128、192、256,分组长度128位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准,这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
它适用于敏感内容进行加密传输,防止被窃取。
AES对称加密算法
AES加密算法
AES(Advanced Encryption Standard)是一种对称加密算法(也叫共享密钥),对称加密算法的意思是加密和解密都是用同一个密钥(密钥和秘钥是同义词),通常来说,对称加密算法效率要优于非对称加密算法,它用来代替DES(Data Encryption Standard,56位密钥)。AES有三个关键点:密钥、填充、模式。
- 密钥
- 密钥分为128位(16字节)、192位(24字节)、256位(32字节),位数越多,解密和加密的运算量越大,相应的越安全,可以折中使用192位兼顾效率和安全。
- 填充
- 填充,在加密时,会将数据按照128位(16字节)一组分为多个明文块,然后对明文块分别加密;当然了,加密时与解密时的填充必须一致,否则无法解密。
- NoPadding
- 不填充,但要求明文必须是128位的整数倍;如果使用NoPadding,程序要对明文预处理进行填充,以达到16字节整数倍的要求。
- PKCS5Padding(默认)
- 如果明文块少于128位,则补足相应数量的字符,且字符的值等于缺少的字节数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6}
- ISO10126Padding
- 如果明文块少于16字节,则补足相应数量的字符,且最后一个字符的值等于缺少的字节数,其他字符填充随机数;比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
- 模式
- 模式,上边提到过,加密时,会将数据分为一组一组的明文。
- ECB
- ECB(电码本模式 Electronic Codebook Book 默认)是各组分别加密然后拼接起来,各组之间没有关系,可以并行计算;
- CBC
- CBC(密码分组链接模式 Cipher Block Chaining,默认),第二组依赖第一组的结果,第三组依赖第二组的结果,只有等待前一个组加密完成后,再进行下一组加密,以此类推,这种就没法并行计算。与ECB不同的事,CBC有初始向量,初始向量先于明文进行运算,结果再与密钥进行运算。
注意,咱们通常所说的“密钥”并不是真正的密钥,而是产生密钥的“种子”。
举例
好了,我们用java实验一下AES算法,AES算法在javax.crypto包下
ECB模式
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
String key = "aaaaaaaaaaaaaaaa";
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8),"AES");
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
String content = "你好";
byte[] encryptBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec);
byte[] plaintextBytes = cipher.doFinal(encryptBytes);
String plaintext = new String(plaintextBytes, StandardCharsets.UTF_8);
log.info("解密后:{}",plaintext);
CBC模式
CBC模式必须使用初始向量
String seed = "aaaaaaaaaaaaaaaa";
//CBC有偏移量
IvParameterSpec ivspec = new IvParameterSpec(seed.getBytes(StandardCharsets.UTF_8));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(seed.getBytes(StandardCharsets.UTF_8),"AES");
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,ivspec);
String content = "你";
byte[] encryptBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
byte[] encryptedBase64 = Base64.getEncoder().encode(encryptBytes);
log.info("加密后:{}",new String(encryptedBase64, StandardCharsets.UTF_8));
byte[] decode = Base64.getDecoder().decode(encryptedBase64);
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,ivspec);
byte[] plaintextBytes = cipher.doFinal(decode);
String plaintext = new String(plaintextBytes, StandardCharsets.UTF_8);
log.info("解密后:{}",plaintext);
不填充
以上两个例子都使用了填充,如果使用不填充,那么就需要对明文预处理,确保明文是16字节的整数倍,通常做法是将明文转换为字节数组,将字节数组补为16的倍数,补齐的值都是0,0在ASCII中对应的是没有字符,所以在解码时也不需要特殊处理。比如
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes;
try {
dataBytes = data.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
int plaintextLength = dataBytes.length;
//数据长度必须是16的倍数
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
//字节数组补齐为16的倍数,补上的位置都是0,0在ASCII中不对应字符,所以在解码时不需要特殊处理;
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
常见错误
java.security.InvalidKeyException: Illegal key size or default parameters
默认的jdk提供的AES算法只支持128位,如果超过128位就会抛出这个异常。
根据Stack Overflow所说,JDK8 Update 161版本开始,不限制长度,如果遇到这个问题,就升级JDK吧。
参考
以上是关于对称加密算法AES的主要内容,如果未能解决你的问题,请参考以下文章