文章目录
- 一 常见加密方式
- 二 对称加密
- 2.1 Cipher类简介
- 2.2 Base算法
- 2.3 补充:Byte&bit
- 2.4 DES加密演示
- 2.5 DES解密
- 2.6 补充:对于IDEA控制台乱码的解决方法
- 2.7 AES加密解密
- 2.8 补充: toString()与new String ()用法区别
- 2.9 加密模式
- 2.9.1 ECB
- 2.9.2 CBC
- 2.10 填充模式
- 2.10.1 NoPadding
- 2.10.2 PKCS5Padding
- 2.10.3 Tips
- 2.11 加密模式和填充模式演示
一 常见加密方式
二 对称加密
- 对称加密:采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密
- 示例:现在有一个原文3要发送给B
- 设置密钥为108, 3 * 108 = 324, 将324作为密文发送给B
- B拿到密文324后, 使用324/108 = 3 得到原文
- 常见加密算法
- DES : Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
- AES : Advanced Encryption Standard, 高级加密标准 .在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
- 特点
- 加密速度快, 可以加密大文件
- 密文可逆, 一旦密钥文件泄漏, 就会导致数据暴露
- 加密后编码表找不到对应字符, 出现乱码
- 一般结合Base64使用
2.1 Cipher类简介
- 该类提供加密和解密的加密密码的功能。 它构成了Java加密扩展(JCE)框架的核心。
- 为了创建一个Cipher对象,应用程序调用Cipher的getInstance方法,并将所请求的转换的名称传递给它。 可选地指定提供者的名称。
- 转换是描述要在给定输入上执行的操作(或操作集)的字符串,以产生一些输出。 转换包括**:加密算法的名称(例如, DES ),并且可以跟随有反馈模式和填充方案。**
- 转换形式如下:
- “ 算法/模式/填充 ”或“ 算法 ”
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
- 在该一种情况下,使用模式和填充方案的提供者特定的默认值
Cipher c = Cipher.getInstance("DES");
2.2 Base算法
- Base64:在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”
- Base64是网络上最常见的用于传输8Bit字节码的可读性编码算法之一
- 可读性编码算法不是为了保护数据的安全性,而是为了可读性。可读性编码不改变信息内容,只改变信息内容的表现形式
- Base58是Bitcoin(比特币)中使用的一种编码方式,主要用于产生Bitcoin的钱包地址。相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"i",以及"+“和”/"符号。
- Base64算法原理
- base64 是 3个字节为一组,一个字节 8位,一共 就是24位 ,然后,把3个字节转成4组,每组6位, 3 ∗ 8 = 4 ∗ 6 = 24 3 * 8 = 4 * 6 = 24 3∗8=4∗6=24 ,每组6位,缺少的2位,会在高位进行补0 ,这样做的好处在于 ,base取的是后面6位,去掉高2位 ,那么base64的取值就可以控制在0-63位了,所以就叫base64,111 111 = 32 + 16 + 8 + 4 + 2 + 1 =64.
- base64是三个字节一组 ,如果当我们的位数不够的时候,会使用等号来补齐
2.3 补充:Byte&bit
- Byte : 字节. 数据存储的基本单位,比如移动硬盘1T , 单位是byte
- bit : 比特/位.。要么是0要么是1. 数据传输的单位 , 比如家里的宽带100Mb,下载速度并没有达到100MB,一般都是12-13MB,那么是因为需要使用 100 / 8 MB
- 关系: 1Byte = 8bit
- 演示
public class ByteBit { public static void main(String[] args) { String a = "a"; byte[] bytes = a.getBytes(); for (byte aByte : bytes) { int c = aByte; System.out.println(c); // byte 字节,对应的bit是多少 String s = Integer.toBinaryString(c); System.out.println(s); } } }
![在这里插入图片描述](https://img-blog.csdnimg.cn/2e86e1293f5b4216bc0fe5c4cf3736fa.png)
- 一个英文字母对应的字节
public static void main(String[] args) throws Exception{
String a = "A";
byte[] bytes = a.getBytes();
for (byte aByte : bytes) {
System.out.println(aByte);
String s = Integer.toBinaryString(aByte);
System.out.println(s);
}
}
- 在utf-8编码格式下,一个中文对应三个字节
- 在GBK编码格式下,一个中文对应两个字节
public static void main(String[] args) throws Exception{
String a = "天";
byte[] bytes = a.getBytes();
for (byte aByte : bytes) {
System.out.println(aByte);
String s = Integer.toBinaryString(aByte);
System.out.println(s);
}
}
public static void main(String[] args) throws Exception{
String a = "天";
byte[] bytes = a.getBytes("GBK");
for (byte aByte : bytes) {
System.out.println(aByte);
String s = Integer.toBinaryString(aByte);
System.out.println(s);
}
}
2.4 DES加密演示
public static void main(String[] args) throws Exception{
// 原文
String input = "天下";
// des加密必须是8位
String key = "12345678";
// 算法
String algorithm = "DES";
String transformation = "DES";
// Cipher:密码,获取加密对象
// transformation:表示使用什么类型加密
Cipher cipher = Cipher.getInstance(transformation);
/* 第一步:指定秘钥规则
第一个参数表示:密钥,key的字节数组
第二个参数表示:算法
*/
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
/*
第二步:对加密进行初始化
第一个参数:表示模式,有加密模式和解密模式
第二个参数:表示秘钥规则
*/
cipher.init(Cipher.ENCRYPT_MODE,sks);
// 第三步:进行加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 打印密文,因为ascii码有负数,解析不出来,所以乱码
System.out.println(new String(bytes));
//
}
- 注意:DES加密算法规定,密匙必须是八个字节,否做会出现以下错误
java.security.InvalidKeyException: Wrong key size
at java.base/com.sun.crypto.provider.DESCrypt.init(DESCrypt.java:536)
at java.base/com.sun.crypto.provider.ElectronicCodeBook.init(ElectronicCodeBook.java:97)
at java.base/com.sun.crypto.provider.CipherCore.init(CipherCore.java:481)
at java.base/com.sun.crypto.provider.CipherCore.init(CipherCore.java:399)
at java.base/com.sun.crypto.provider.DESCipher.engineInit(DESCipher.java:187)
at java.base/javax.crypto.Cipher.implInit(Cipher.java:869)
at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:931)
at java.base/javax.crypto.Cipher.init(Cipher.java:1301)
at java.base/javax.crypto.Cipher.init(Cipher.java:1238)
at DESTest.test1(DESTest.java:31)
- 注意:出现乱码是因为对应的字节出现负数,但负数,没有出现在 ascii 码表里面,所以出现乱码,需要配合base64进行转码
- 注意:导入的包为
org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Base64; //对数据进行Base64编码 String s = Base64.encodeBase64String(bytes); System.out.println(s);
- 注意:导入的包为
2.5 DES解密
import org.junit.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class DESTest {
@Test
public void test() throws Exception {
String input ="天下";
// DES加密算法,key的大小必须是8个字节
String key = "12345678";
String transformation = "DES";
// 指定获取密钥的算法
String algorithm = "DES";
String encryptDES = encryptDES(input, key, transformation, algorithm);
System.out.println("加密:" + encryptDES);
String s = decryptDES(encryptDES, key, transformation, algorithm);
System.out.println("解密:" + s);
}
/**
* 使用DES加密数据
*
* @param input : 原文
* @param key : 密钥(DES,密钥的长度必须是8个字节)
* @param transformation : 获取Cipher对象的算法
* @param algorithm : 获取密钥的算法
* @return : 密文
* @throws Exception
*/
private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
// 获取加密对象
Cipher cipher = Cipher.getInstance(transformation);
// 创建加密规则
// 第一个参数key的字节
// 第二个参数表示加密算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// ENCRYPT_MODE:加密模式
// 初始化加密模式和算法
cipher.init(Cipher.ENCRYPT_MODE,sks);
// 加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 输出加密后的数据
String encode = Base64.encodeBase64String(bytes);
return encode;
}
/**
* 使用DES解密
*
* @param input : 密文
* @param key : 密钥
* @param transformation : 获取Cipher对象的算法
* @param algorithm : 获取密钥的算法
* @throws Exception
* @return: 原文
*/
private static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception {
// 1,获取Cipher对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定密钥规则
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// DECRYPT_MODE: 解密模式
cipher.init(Cipher.DECRYPT_MODE, sks);
// 3. 解密,上面使用的base64编码,下面直接用密文
byte[] bytes = cipher.doFinal(Base64.decodeBase64(input));
// 因为是明文,所以直接返回
return new String(bytes);
}
}
2.6 补充:对于IDEA控制台乱码的解决方法
2.7 AES加密解密
- AES 加密解密和 DES 加密解密代码一样,只需要修改加密算法就行
- AES 加密的密钥key , 需要传入16个字节,否则,会出现以下错误信息
java.security.InvalidKeyException: Invalid AES key length: 8 bytes
import org.junit.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class DESTest {
@Test
public void test() throws Exception {
String input ="天下";
// DES加密算法,key的大小必须是8个字节
String key = "12345678";
String transformation = "AES";
// 指定获取密钥的算法
String algorithm = "AES";
String encryptDES = encryptDES(input, key, transformation, algorithm);
System.out.println("加密:" + encryptDES);
String s = decryptDES(encryptDES, key, transformation, algorithm);
System.out.println("解密:" + s);
}
/**
* 使用DES加密数据
*
* @param input : 原文
* @param key : 密钥(DES,密钥的长度必须是8个字节)
* @param transformation : 获取Cipher对象的算法
* @param algorithm : 获取密钥的算法
* @return : 密文
* @throws Exception
*/
private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
// 获取加密对象
Cipher cipher = Cipher.getInstance(transformation);
// 创建加密规则
// 第一个参数key的字节
// 第二个参数表示加密算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// ENCRYPT_MODE:加密模式
// 初始化加密模式和算法
cipher.init(Cipher.ENCRYPT_MODE,sks);
// 加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 输出加密后的数据
String encode = Base64.encodeBase64String(bytes);
return encode;
}
/**
* 使用DES解密
*
* @param input : 密文
* @param key : 密钥
* @param transformation : 获取Cipher对象的算法
* @param algorithm : 获取密钥的算法
* @throws Exception
* @return: 原文
*/
private static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception {
// 1,获取Cipher对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定密钥规则
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// DECRYPT_MODE: 解密模式
cipher.init(Cipher.DECRYPT_MODE, sks);
// 3. 解密,上面使用的base64编码,下面直接用密文
byte[] bytes = cipher.doFinal(Base64.decodeBase64(input));
// 因为是明文,所以直接返回
return new String(bytes);
}
}
2.8 补充: toString()与new String ()用法区别
public static void main(String[] args) {
// 表示密文
String str="TU0jV0xBTiNVYys5bEdiUjZlNU45aHJ0bTdDQStBPT0jNjQ2NDY1Njk4IzM5OTkwMDAwMzAwMA==";
// 使用base64进行解码
String rlt1=new String(Base64.decodeBase64(str.getBytes()));
// 使用base64进行解码
String rlt2= Base64.decodeBase64(str).toString();
System.out.println("new String===" + rlt1);
System.out.println("toString==" + rlt2);
}
-
哪一个是正确的?为什么?
-
new String()的方法,因为Base64加解密是一种转换编码格式的原理
-
toString()与new String ()用法区别
-
str.toString是调用了这个object对象的类的toString方法。一般是返回这么一个
String:[class name]@[hashCode]
-
new String(str)是根据parameter是一个字节数组,使用java虚拟机默认的编码格式,将这个字节数组decode为对应的字符。若虚拟机默认的编码格式是ISO-8859-1,按照ascii编码表即可得到字节对应的字符。
-
两个方法的使用时机:
-
new String()一般使用字符转码的时候,byte[]数组的时候
-
toString()对象打印的时候使用
2.9 加密模式
2.9.1 ECB
- ECB : Electronic codebook, 电子密码本. 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密
- 优点 : 可以并行处理数据
- 缺点 : 同样的原文生成同样的密文, 不能很好的保护数据
- 同时加密,原文是一样的,加密出来的密文也是一样的
2.9.2 CBC
- CBC : Cipher-block chaining, 密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块
- 优点 : 同样的原文生成的密文不一样
- 缺点 : 串行处理数据.
2.10 填充模式
- 当需要按块处理的数据, 数据长度不符合块处理需求时, 按照一定的方法填充满块长的规则
2.10.1 NoPadding
- 不填充
- 在DES加密算法下, 要求原文长度必须是8byte的整数倍
- 在AES加密算法下, 要求原文长度必须是16byte的整数倍
2.10.2 PKCS5Padding
- 数据块的大小为8位, 不够就补足
2.10.3 Tips
-
默认情况下, 加密模式和填充模式为 : ECB/PKCS5Padding
-
如果使用CBC模式, 在初始化Cipher对象时, 需要增加参数, 初始化向量IV :
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
-
加密模式和填充模式
AES/CBC/NoPadding (128) AES/CBC/PKCS5Padding (128) AES/ECB/NoPadding (128) AES/ECB/PKCS5Padding (128) DES/CBC/NoPadding (56) DES/CBC/PKCS5Padding (56) DES/ECB/NoPadding (56) DES/ECB/PKCS5Padding (56) DESede/CBC/NoPadding (168) DESede/CBC/PKCS5Padding (168) DESede/ECB/NoPadding (168) DESede/ECB/PKCS5Padding (168) RSA/ECB/PKCS1Padding (1024, 2048) RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048) RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
2.11 加密模式和填充模式演示
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public static void main(String[] args) throws Exception{
// 原文 如果使用的是不填充的模式,那么原文必须是8个字节的整数倍
String input = "天下";
// 定义key
// 如果使用des进行加密,那么密钥必须是8个字节
String key = "12345678";
// ECB:表示加密模式
// PKCS5Padding:表示填充模式 qANksk5lvqM=
// 如果默认情况,没有写填充模式和加密模式,那么默认就使用DES/ECB/PKCS5Padding
String transformation = "DES/CBC/PKCS5Padding";
// 加密类型
String algorithm = "DES";
// 指定获取密钥的算法
String encryptDES = encryptDES(input, key, transformation, algorithm);
System.out.println("加密:" + encryptDES);
String s = decryptDES(encryptDES, key, transformation, algorithm);
System.out.println("解密:" + s);
}
/**
* 解密
* @param encryptDES 密文
* @param key 密钥
* @param transformation 加密算法
* @param algorithm 加密类型
* @return
*/
private static String decryptDES(String encryptDES, String key, String transformation, String algorithm) throws Exception{
Cipher cipher = Cipher.getInstance(transformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(),algorithm);
// 创建iv向量
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
//Cipher.DECRYPT_MODE:表示解密
// 解密规则
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,iv);
// 解密,传入密文
byte[] bytes = cipher.doFinal(Base64.decodeBase64(encryptDES));
return new String(bytes);
}
/**
* 使用DES加密数据
*
* @param input : 原文
* @param key : 密钥(DES,密钥的长度必须是8个字节)
* @param transformation : 获取Cipher对象的算法
* @param algorithm : 获取密钥的算法
* @return : 密文
* @throws Exception
*/
private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
// 获取加密对象
Cipher cipher = Cipher.getInstance(transformation);
// 创建加密规则
// 第一个参数key的字节
// 第二个参数表示加密算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// 创建iv向量,iv向量,是使用到CBC加密模式
// 在使用iv向量进行加密的时候,iv的字节也必须是8个字节
IvParameterSpec iv = new IvParameterSpec("12345678".getBytes());
// ENCRYPT_MODE:加密模式
// DECRYPT_MODE: 解密模式
// 初始化加密模式和算法
cipher.init(Cipher.ENCRYPT_MODE,sks,iv);
// 加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 输出加密后的数据
String encode = Base64.encodeBase64String(bytes);
return encode;
}