1.对称加密算法
加密和解密使用同一个密钥,例如WinRAR。
- WinRAR在对文件进行打包的时候,可以设置一个密码,在解压的时候需要使用同样的密码才能正确的解压。
- 加密:encrypt(key,message) -> s
- 解密:decrypt(key,s) -> message
算法 | 密钥长度(决定加密的强度) | 工作模式(参数) | 填充模式(格式的选择) |
---|---|---|---|
DES | 56/64 | ECB, CBC, PCBC, CTR... | NoPadding, PKCS5Padding |
AES | 128/192/256 | ECB,CBC,PCBC,CTR... | NoPadding,PKCS5Padding, PKCS7Padding |
IDEA | 128 | ECB | PKCS5Padding, PKCS7Padding |
JDK提供的算法并没有包括所有的工作模式和填充模式,但我们通常只需要挑选常用的模式使用就可以了。
DES因为密钥过短,可以在短时间内被暴力破解,所以并不安全。
2.AES/ECB
package com.testList;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;public class SplitString {//指定算法为AES,工作模式为ECB,填充模式为PKCS5Paddingstatic final String CIPHER_NAME = "AES/ECB/PKCS5Padding";//加密public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException{//传入算法、工作模式、填充模式,创建Cipher示例Cipher cipher = Cipher.getInstance(CIPHER_NAME);//将一个byte数组,转化为一个AES的keySecretKeySpec secretKeySpec = new SecretKeySpec(key,"AES");//初始化:采用加密模式,并传入keycipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);//通过doFinal传入input数组获取加密后的byte数组return cipher.doFinal(input);}//解密public static byte[] decrypt(byte[] key,byte[] input) throws GeneralSecurityException{//传入算法、工作模式、填充模式,创建Cipher示例Cipher cipher = Cipher.getInstance(CIPHER_NAME);//将byte数组,转化为一个AES的keySecretKeySpec secretKeySpec = new SecretKeySpec(key,"AES");//初始化:采用解密模式,并传入keycipher.init(Cipher.DECRYPT_MODE,secretKeySpec);//通过doFinal传入input数组获取加密后的byte数组return cipher.doFinal(input);}public static void main(String[] args) throws Exception{String message = "Hello,world!encrypted using AES!";System.out.println(message);//密钥为128位,需要传入128/8=16个byte的字符串byte[] key = "1234567890abcdef".getBytes("utf-8");byte[] input = message.getBytes(StandardCharsets.UTF_8);byte[] encrypted = encrypt(key,input);//把秘闻转化为61位编码打印System.out.println("Encrypted data:"+Base64.getEncoder().encodeToString(encrypted));byte[] decrypted = decrypt(key,encrypted);//将解密后的数组还原为字符串System.out.println("Decrypted data:"+new String(decrypted,"utf-8"));}
}
3.AES/CBC
package com.testList;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Base64;public class AES_CBC {//指定算法为为AES,工作模式为CBC,填充模式为PKCS5Paddingstatic final String CIPHER_NAME = "AES/CBC/PKCS5Padding";//加密public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException{//传入算法、工作模式、填充模式,创建Cipher实例Cipher cipher = Cipher.getInstance(CIPHER_NAME);//传入key数组,获取SecretKeySpec的实例SecretKeySpec keySpec = new SecretKeySpec(key,"AES");//创建SecureRandom实例,用于获取随机数SecureRandom sr = SecureRandom.getInstanceStrong();//获取一个16位字节的数组byte[] iv = sr.generateSeed(16);//传入随机数组,获取IVParameterSpec实例IvParameterSpec ivps = new IvParameterSpec(iv);//初始化:指定加密模式,并传入SecretKeySpec实例keySpec、IvParameterSpec实例ivpscipher.init(Cipher.ENCRYPT_MODE,keySpec,ivps);//通过doFinal传入input数组,获取加密后的byte数组byte[] data = cipher.doFinal(input);//将iv,data一并返回return join(iv,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;}public static byte[] decrypt(byte[] key,byte[] input) throws GeneralSecurityException{//将input数组拆分为iv,databyte[] iv = new byte[16];byte[] data = new byte[input.length-16];System.arraycopy(input,0,iv,0,16);System.arraycopy(input,16,data,0,data.length);//传入算法、工作模式、填充模式,创建Cipher实例Cipher cipher = Cipher.getInstance(CIPHER_NAME);//传入key数组,获取AES加密后的SecretKeySpec类型实例SecretKeySpec keySpec = new SecretKeySpec(key,"AES");//获取IvParameter实例ivpsIvParameterSpec ivps = new IvParameterSpec(iv);//初始化:指定解密模式,并传入SecretKeySpec实例,IvParameterSpec实例cipher.init(Cipher.DECRYPT_MODE,keySpec,ivps);//返回解密后的数组return cipher.doFinal(data);}public static void main(String[] args) throws Exception {String message = "Hello,world!encryptd using AES!";System.out.println("Message:"+message);byte[] key = "1234567890abcefg".getBytes("utf-8");byte[] data = message.getBytes(StandardCharsets.UTF_8);byte[] encrypted = encrypt(key,data);System.out.println("Encrypt data:"+Base64.getEncoder().encodeToString(encrypted));byte[] decryptd = decrypt(key,encrypted);System.out.println("Decrypted data:"+new String(decryptd,"utf-8"));}
}
4.AES/ECB使用256位加密
import jdk.nashorn.internal.runtime.ECMAException;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;public class AES256_ECB {static final String CIPHER_NAME = "AES/ECB/PKCS5Padding";public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException {Cipher cipher = Cipher.getInstance(CIPHER_NAME);SecretKeySpec keySpec = new SecretKeySpec(key,"AES");cipher.init(Cipher.ENCRYPT_MODE,keySpec);return cipher.doFinal(input);}public static byte[] decrypt(byte[] key,byte[] input) throws GeneralSecurityException{Cipher cipher = Cipher.getInstance(CIPHER_NAME);SecretKeySpec keySpec = new SecretKeySpec(key,"AES");cipher.init(Cipher.ENCRYPT_MODE,keySpec);return cipher.doFinal(input);}public static void main(String[] args) throws Exception {String message = "Hello world!encrypted using AES!";System.out.println(message);byte[] key = "1234567890abcdef1234567890abcdef".getBytes("utf-8");byte[] data = message.getBytes(StandardCharsets.UTF_8);byte[] encrypted = encrypt(key,data);System.out.println(Base64.getEncoder().encodeToString(encrypted));byte[] decrypted = decrypt(key,encrypted);System.out.println(new String(decrypted,"utf-8"));}
}
问题:256位加密执行失败
搜索jdk jce policy,下载jar包,
window:将下载的jar包复制到jdk/jre/lib/security和jdk/lib/security目录下。
Mac:
#查看Java目录
which java
#寻找jre/lib/security目录
find . -name lcoal_policy.jar
如我的目录是:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/security。将下载的jar包复制到该文件。
再次运行,不再报错
5.总结:
- 对称加密算法使用同一个密钥进行加密和解密
- 常用算法:DES/AES/IDEA等
- 密钥长度由算法设计决定给,AES的密钥长度是128/192/256
- 使用256位加密需要修改JDK的policy文件
- 使用对称加密算法需要指定:算法名称/工作模式/填充模式