项目上传文件需要加密,所以学习一下AES加密算法。
1. AES简介
AES是一个对称密码算法。
AES支持五中模式:ECB,CBC,CFB,OFB,PCBC;支持三种填充:NoPadding,PKCS5Padding,ISO10126Padding。
这章只讲AES加密的使用,不讲具体原理,后面可能会具体讲原理(博主不偷懒的话)。
值得注意的是:NoPadding填充方式只能加密长度为16n的内容
2. 代码示例
2.1代码
package com.tricycle.aes;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import com.tricycle.utils.Log;
public class AES {
static Cipher cipher;
static final String AES_ALGORITHMS = "AES";
static final String ALGORITHMS_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";
static final String ALGORITHMS_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
static final String ALGORITHMS_CBC_NoPadding = "AES/CBC/NoPadding";
static final String ALGORITHMS_ECB_NoPadding = "AES/ECB/NoPadding";
static SecretKey secretKey;
public static void main(String[] args) {
encryptECB(ALGORITHMS_ECB_PKCS5Padding, "0123456789abcde");
encryptECB(ALGORITHMS_ECB_PKCS5Padding, "0123456789abcdef");
encryptECB(ALGORITHMS_ECB_NoPadding, "0123456789abcdef");
encryptECB(ALGORITHMS_ECB_NoPadding, "0123456789abcde");
encryptCBC(ALGORITHMS_CBC_PKCS5Padding, "0123456789abcde");
encryptCBC(ALGORITHMS_CBC_PKCS5Padding, "0123456789abcdef");
encryptCBC(ALGORITHMS_CBC_NoPadding, "0123456789abcdef");
encryptCBC(ALGORITHMS_CBC_NoPadding, "0123456789abcde");
}
private static void encryptECB(String padding, String source) {
try {
cipher = Cipher.getInstance(padding);
secretKey = KeyGenerator.getInstance(AES_ALGORITHMS).generateKey();
Log.print(padding + "; key length: "
+ secretKey.getEncoded().length);
Log.print(Arrays.toString(secretKey.getEncoded()));
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypt = cipher.doFinal(source.getBytes());
Log.print(Arrays.toString(encrypt));
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decrypt = cipher.doFinal(encrypt);
Log.print(new String(decrypt));
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* CBC need an initial vector; IV length must be 16 bytes long
*/
private static byte[] getIV() {
String iv = "1234567812345678";
return iv.getBytes();
}
private static void encryptCBC(String padding, String source) {
try {
cipher = Cipher.getInstance(padding);
secretKey = KeyGenerator.getInstance(AES_ALGORITHMS).generateKey();
Log.print(padding + "; key length: "
+ secretKey.getEncoded().length);
Log.print(Arrays.toString(secretKey.getEncoded()));
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(
getIV()));
byte[] encrypt = cipher.doFinal(source.getBytes());
Log.print(Arrays.toString(encrypt));
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(
getIV()));
byte[] decrypt = cipher.doFinal(encrypt);
Log.print(new String(decrypt));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2输出
AES/ECB/PKCS5Padding; key length: 16
[88, -41, 105, 86, -18, -91, -88, -4, -21, -56, 51, 72, 87, 114, -38, 13]
[-76, 11, -17, 55, 108, -52, -38, -96, -22, -124, -102, 61, 113, 81, 34, -84]
0123456789abcde
AES/ECB/PKCS5Padding; key length: 16
[104, -13, 9, 8, 95, -107, -96, 46, 71, -11, 34, 122, -20, -73, 19, -42]
[45, 118, 127, 84, -18, -122, -4, 105, 105, 56, -59, 94, -115, -108, -12, -8, -62, -71, 55, 13, 63, -82, 78, -5, -65, 10, 30, -9, 54, -9, -39, 70]
0123456789abcdef
AES/ECB/NoPadding; key length: 16
[-62, -48, -55, 82, -83, 115, 17, 122, 89, -25, -19, -31, -84, -111, -11, 16]
[39, 103, 109, 16, -83, 67, 109, 104, -111, -65, -30, -64, 11, -19, 4, 18]
0123456789abcdef
AES/ECB/NoPadding; key length: 16
[-10, 106, 99, -14, 25, 6, -64, -52, 88, 6, 24, 74, -90, 20, -52, 74]
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at com.tricycle.aes.AES.encryptECB(AES.java:57)
at com.tricycle.aes.AES.main(AES.java:37)
AES/CBC/PKCS5Padding; key length: 16
[68, -70, -14, -73, -14, 85, 113, -46, 37, 55, 5, 3, 52, -127, 12, 68]
[94, -18, 6, -27, 10, 97, 61, -69, -50, 0, 30, -49, 125, 106, -114, 20]
0123456789abcde
AES/CBC/PKCS5Padding; key length: 16
[1, -72, -50, 41, -111, 39, -26, -49, 78, -9, -27, -67, 29, 127, 8, 114]
[90, -65, 72, 108, -75, -54, 45, -45, 109, 117, -29, -99, -91, 118, -24, -37, 61, -43, -119, 119, 68, -50, 83, 105, -76, 70, 75, -80, 120, -60, -6, -40]
0123456789abcdef
AES/CBC/NoPadding; key length: 16
[25, -3, 116, -8, -9, 14, 119, 54, -18, -49, 11, -85, -56, 110, 17, -19]
[-114, -123, -43, 55, -85, -98, 24, 125, -45, 43, -3, 65, -98, -104, -34, -30]
0123456789abcdef
AES/CBC/NoPadding; key length: 16
[-79, 28, -10, 43, -50, -108, 7, -59, -116, -110, -42, 38, 56, 75, 71, 32]
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at com.tricycle.aes.AES.encryptCBC(AES.java:88)
at com.tricycle.aes.AES.main(AES.java:42)
2.3分析
1、当加密内容为16n时,NoPadding填充方式加密后长度为16n,PKCS5Padding填充方式加密后长度为16(n+1);
2、当加密内容为16n+m(0<m<16)时,NoPadding填充方式会报异常,PKCS5Padding填充方式加密后长度为16(n+1);
3、CBC加密方式需要一个16位初始向量,以后再说原理。