前言
我们数据库中有一条用户信息的数据,需要给到第三方,那么在发送这条数据的时候,我们不能直接把用户的姓名、电话号、身份证号等一些信息发给第三方,不能暴露用户的个人信息,这个时候就需要用到数据加密进行传输。
什么是AES
AES(Advanced Encryption Standard,高级加密标准)是一种用于保护电子数据的对称加密算法。在 HTTPS 协议中使用的 TLS(传输层安全协议)就使用了 AES 加密。具体加密流程如下:
名词的作用和意义
- 明文P
没有经过加密的数据。
- 密钥k
用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
- AES加密函数
设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。
- 密文C *
经加密函数处理后的数据
- AES
设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。
为什么要用 AES 而不用其他加密算法?
- 安全性高:AES 使用多轮的替换和排列操作,使得密文在很大程度上脱离了原始数据的特征。
- 灵活性强:AES 支持多种密钥长度(128 位、192 位、256 位)。
相比之下,其他加密算法如 DES(Data Encryption Standard,数据加密标准)已经被认为不够安全,容易被暴力破解;RSA 虽然安全性高,但效率较低且密钥管理复杂,更多用于密钥交换和数字签名。
demo
user实体
@Data
public class User {
String name;
int age;
String contactPhone;
String idCard;
}
实例化后调用AES进行加密。
User user = new User();
user.setName("张三");
user.setAge(18);
user.setContactPhone("1824783xxxx");
user.setIdCard("430626xxxxxxxxxxxxxxx");
String encryptDate = AesService.encrypt(user, "MDEyMzQ1Njc4OWFiY2RlZg==");
System.out.println(encryptDate);
String decryptDate = AesService.decrypt(encryptDate, AesService.base64StringToKey("MDEyMzQ1Njc4OWFiY2RlZg=="));
System.out.println(decryptDate);
最终加密信息为:
TKGywGIVhcLjKil4muBh7ROAp430b7n2TUSKH491PuMwa6Z6RDKQubo9ClNxk+yn5LVTOuPOP9Tt2hGr6/q2X+sxEGqPZvb+Ez4joFKSB/uw5t9AHsAi3BPQlAGSrQJG
解密信息为:
{"name":"张三","age":18,"contactPhone":"1824783xxxx","idCard":"430626xxxxxxxxxxxxxxx"}
encrypt(Object o, String key) 方法。
第一个参数接收一个对象,然后将对象转换成json字符串。
第二个参数接收加密的密钥(以Base64编码的字符串形式)。
public static String encrypt(Object o, String key) {
return AesService.encrypt(new Gson().toJson(o), AesService.base64StringToKey(key));
}
base64StringToKey(String base64Key) 方法。
将一个Base64编码的字符串转换为一个SecretKey对象。
public static SecretKey base64StringToKey(String base64Key) {
try {
// 将base64Key解码为一个字节数组
byte[] data = Base64.getDecoder().decode(base64Key);
return new SecretKeySpec(data, 0, data.length, "AES");
} catch (Exception e) {
throw new KeyFormatException();
}
}
- data:密钥的字节数据。
- 0:偏移量,从数据数组的起始位置开始使用。
- data.length:使用数据数组的全部长度。
"AES":表示加密算法。
encrypt(String input, SecretKey key) 方法。
将base64Key输入字符串input进行加密, key则就是密钥。
public static String encrypt(String input, SecretKey key) { try { //创建Cipher对象,并且指定算法为AES Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); // doFinal执行加密操作 byte[] cipherText = cipher.doFinal(input.getBytes()); // 返回密文 return Base64.getEncoder().encodeToString(cipherText); } catch (Exception e) { throw new RuntimeException(e); } }
ENCRYPT_MODE
表明是此时是加密模式DECRYPT_MODE
表明此时是解密模式
decrypt(String cipherText, SecretKey key)方法。
解密一个用Base64编码的密文字符串cipherText
, key则就是密钥
public static String decrypt(String cipherText, SecretKey key) {
try {
Cipher cipher = Cipher.getInstance("AES");
//初始化解密模式
cipher.init(Cipher.DECRYPT_MODE, key);
//将cipherText解码为字节数组
byte[] plainText = cipher.doFinal(Base64.getDecoder()
.decode(cipherText));
return new String(plainText);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
为什么得到加密数据后,还要使用base64进行编码呢?
- 二进制数据的表示:
AES生成的数据是二进制数据,这些数据通常包含非打印字符和控制字符。这些字符在许多场景下(例如在 JSON、XML、URL 中)不能直接显示或传输,因为这些格式通常只支持文本字符集(如 ASCII 或 UTF-8)。 - 避免数据传输损坏:
许多传输协议(如 HTTP、SMTP 等)是基于文本的,直接发送或存储二进制数据可能会导致数据损坏或被截断,Base64 编码是一种将二进制数据转换为文本字符的编码方式,它只使用 A-Z、a-z、0-9、+、/ 这 64 个字符(以及填充字符 =),所有这些字符都在文本协议和存储系统中是安全的,因此不会被误处理。 - 数据完整性:
一些传输协议可能会对数据做一些自动的修改或处理,例如去掉空格、替换特殊字符等。Base64 编码保证了数据不会因为这些自动处理而被篡改,确保数据完整性。
例如:
一个简单的字符串 "Hello, World!",你对它进行 AES 加密后,得到的二进制数据可能是:
[-66, 77, 127, -15, 70, 58, -7, -100, -44, -37, 78, 124, 82, -117, 122, 35]
这些值是二进制数据,无法以字符串形式表示。通过 Base64 编码后,它们会变成:
vk1/8UY6+ZzU2058Uot6Iw==
这个结果是一个可打印的字符串,可以安全地在各种文本协议和存储中传输和存储。
所以使用 Base64 编码来表示加密后的二进制数据是一种常见的做法,它保证了数据在各种应用场景中的兼容性和完整性,简化了数据的传输和存储。
参考资料:
https://blog.csdn.net/qq_28205153/article/details/55798628
希望这篇文章对你有一定帮助。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。