加密和解密时使用相同的密钥,这种加密方法称为对称加密
分类
流加密:按顺序一个一个加密,如文本:123456,则先加密1再加密2,以此类推
块加密:分块分组加密,如文本:123456,若分3组,则先加密12,再加密34,以此类推
常见加密算法
DES
AES
特点
加密速度快, 可以加密大文件
密文可逆, 一旦密钥文件泄漏, 就会导致数据暴露
加密后再ASCII编码表找不到对应字符, 出现乱码
一般结合Base64使用,防止乱码
DES是数据加密标准,是一种使用密钥加密的块算法。
Java的Cipher
类供加密和解密功能,在线文档:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html
public static void main(String[] args) throws Exception {
// 原文
String input = "Hello Word";
// 使用des进行加密,密钥必须是8个字节
String key = "12345678";
// 获取Cipher对象的算法
String transformation = "DES";
// 指定获取密钥的算法
String algorithm = "DES";
String encrypt = encrypt(input, key, transformation, algorithm);
System.out.println("加密:" + encrypt);
String decrypt = dncrypt(encrypt, key, transformation, algorithm);
System.out.println("解密:" + decrypt);
}
/**
* 加密数据
*/
private static String encrypt(String input, String key, String transformation, String algorithm) throws Exception {
// 获取加密对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定秘钥规则:传入密钥的字节数组与指定的算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// 初始化加密对象: 指定加密模式与秘钥规则
cipher.init(Cipher.ENCRYPT_MODE, sks);
// 开始加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 打印密文,由于bytes字节数字中存在负数,即ascii码有负数,解析不出来,将输出乱码
System.out.println("bytes = " + new String(bytes));
// 对字节数字进行Base64编码
return Base64.encode(bytes);
}
/**
* 解密数据
*/
private static String dncrypt(String input, String key, String transformation, String algorithm) throws Exception {
// 获取Cipher对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定秘钥规则:传入密钥的字节数组与指定的算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// 初始化解密对象: 指定解密模式与秘钥规则
cipher.init(Cipher.DECRYPT_MODE, sks);
// 解密
byte[] bytes = cipher.doFinal(Base64.decode(input));
return new String(bytes);
}
bytes = �Rd��ʩ� h��
加密:01Jk6AecyqnqsABousAVIA==
解密:Hello Word
AES是高级加密标准,用来替代DES。
public static void main(String[] args) throws Exception {
// 原文
String input = "Hello Word";
// AES加密算法:密匙必须是16个字节
String key = "1234567891234567";
// 获取Cipher对象的算法
String transformation = "AES";
// 指定获取密钥的算法
String algorithm = "AES";
String encrypt = encrypt(input, key, transformation, algorithm);
System.out.println("加密:" + encrypt);
String decrypt = dncrypt(encrypt, key, transformation, algorithm);
System.out.println("解密:" + decrypt);
}
bytes = ��F�p��Ny�|08�k2
加密:/fZGj3CTnE5503wwONlrMg==
解密:Hello Word
Base64算法不是加密算法,是用于传输8Bit字节码的可读性编码算法之一。
可读性编码不改变信息内容,只改变信息内容的表现形式
Base64是说在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”
构成
26个小写字母: a - z
26个大写字母: A - Z
10 个数字: 0 - 9
2个符号: + /
算法原理
base64是3个字节为一组,一个字节 8位,一共就是24位 ,然后把3个字节转成4组,每组6位(
3 * 8 = 4 * 6 = 24
)。
当每组6位时则缺少2位,在高位进行补0 ,于是控制了base64的取值范围在0-63位,所以就叫base64(
00111 111 = 32 + 16 + 8 + 4 + 2 + 1 =63
)
注意:
由于base64是三个字节一组 ,当一组三个字节位数不够的时候,会使用等号来补齐。
public static void main(String[] args) throws Exception {
System.out.println(Base64.encode("1".getBytes()));
System.out.println(Base64.encode("12".getBytes()));
System.out.println(Base64.encode("123".getBytes()));
// UTF-8编码下:一个汉字站3个字节
System.out.println(Base64.encode("中国".getBytes("UTF-8")));
// GBK编码下:一个汉字站2个字节
System.out.println(Base64.encode("中国".getBytes("GBK")));
}
MQ==
MTI=
MTIz
5Lit5Zu9
1tC5+g==
ECB :
电子密码本, 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密
可以并行处理数据,但同样的原文生成同样的密文, 不能很好的保护数据
CBC
密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块
同样的原文生成的密文不一样,但串行处理数据速度慢
当需要按块处理的数据的数据长度不符合块处理需求时, 会按照一定的方法规则填充满块
NoPadding:不填充
DES加密算法:要求原文长度必须是8byte的整数倍
AES加密算法: 要求原文长度必须是16byte的整数倍
PKCS5Padding:填充
数据块的大小为8位, 不够就补足
注意:
默认情况下, 加密模式和填充模式为 :
ECB/PKCS5Padding
。如果使用CBC模式, 在初始化Cipher对象时, 需要添加初始化向量IV参数 :IvParameterSpec iv = new IvParameterSpec(key.getBytes());
Cipher的加密类型如下:
1.使用默认ECB加密模式与PKCS5Padding填充模式
public static void main(String[] args) throws Exception {
// 原文
String input = "Hello Word";
// 使用des进行加密,密钥必须是8个字节
String key = "12345678";
// 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
String transformation = "DES";
// 指定获取密钥的算法
String algorithm = "DES";
String encrypt = encrypt(input, key, transformation, algorithm);
System.out.println("加密:" + encrypt);
String decrypt = dncrypt(encrypt, key, transformation, algorithm);
System.out.println("解密:" + decrypt);
}
bytes = �Rd��ʩ� h��
加密:01Jk6AecyqnqsABousAVIA==
解密:Hello Word
2.明确指定ECB加密模式和PKCS5Padding填充模式
public static void main(String[] args) throws Exception {
// 原文
String input = "Hello Word";
// 使用des进行加密,密钥必须是8个字节
String key = "12345678";
// 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
String transformation = "DES/ECB/PKCS5Padding";
// 指定获取密钥的算法
String algorithm = "DES";
String encrypt = encrypt(input, key, transformation, algorithm);
System.out.println("加密:" + encrypt);
String decrypt = dncrypt(encrypt, key, transformation, algorithm);
System.out.println("解密:" + decrypt);
}
bytes = �Rd��ʩ� h��
加密:01Jk6AecyqnqsABousAVIA==
解密:Hello Word
3.明确指定ECB加密模式和NoPadding填充模式
此时原文必须为8byte的整数倍,否则报错:
Input length not multiple of 8 bytes
public static void main(String[] args) throws Exception {
// 原文
String input = "Hello Wo";
// 使用des进行加密,密钥必须是8个字节
String key = "12345678";
// 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
String transformation = "DES/ECB/NoPadding";
// 指定获取密钥的算法
String algorithm = "DES";
String encrypt = encrypt(input, key, transformation, algorithm);
System.out.println("加密:" + encrypt);
String decrypt = dncrypt(encrypt, key, transformation, algorithm);
System.out.println("解密:" + decrypt);
}
bytes = �Rd��ʩ
加密:01Jk6Aecyqk=
解密:Hello Wo
4.明确指定CBC加密模式和PKCS5Padding填充模式
public static void main(String[] args) throws Exception {
// 原文
String input = "Hello Word";
// 使用des进行加密,密钥必须是8个字节
String key = "12345678";
// 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
String transformation = "DES/CBC/PKCS5Padding";
// 指定获取密钥的算法
String algorithm = "DES";
String encrypt = encrypt(input, key, transformation, algorithm);
System.out.println("加密:" + encrypt);
String decrypt = dncrypt(encrypt, key, transformation, algorithm);
System.out.println("解密:" + decrypt);
}
/**
* 加密数据
*/
private static String encrypt(String input, String key, String transformation, String algorithm) throws Exception {
// 获取加密对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定秘钥规则:传入密钥的字节数组与指定的算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// 初始向量,参数表示跟谁进行异或,初始向量的长度必须是8位
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
// 初始化加密对象: 指定加密模式与秘钥规则
cipher.init(Cipher.ENCRYPT_MODE, sks, ivParameterSpec);
// 开始加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 打印密文,由于bytes字节数字中存在负数,即ascii码有负数,解析不出来,将输出乱码
System.out.println("bytes = " + new String(bytes));
// 对字节数字进行Base64编码
return Base64.encode(bytes);
}
/**
* 解密数据
*/
private static String dncrypt(String input, String key, String transformation, String algorithm) throws Exception {
// 获取Cipher对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定秘钥规则:传入密钥的字节数组与指定的算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// 初始向量,参数表示跟谁进行异或,初始向量的长度必须是8位
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
// 初始化解密对象: 指定解密模式与秘钥规则
cipher.init(Cipher.DECRYPT_MODE, sks, ivParameterSpec);
// 解密
byte[] bytes = cipher.doFinal(Base64.decode(input));
return new String(bytes);
}
bytes = �uQ�w�AоH~�q
加密:w3VRu3f3QdC+E0h+2gRxfw==
解密:Hello Word