3

前言

我们数据库中有一条用户信息的数据,需要给到第三方,那么在发送这条数据的时候,我们不能直接把用户的姓名、电话号、身份证号等一些信息发给第三方,不能暴露用户的个人信息,这个时候就需要用到数据加密进行传输。

什么是AES

AES(Advanced Encryption Standard,高级加密标准)是一种用于保护电子数据的对称加密算法。在 HTTPS 协议中使用的 TLS(传输层安全协议)就使用了 AES 加密。具体加密流程如下:

image.png

名词的作用和意义

  • 明文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

希望这篇文章对你有一定帮助。


zZ_jie
411 声望9 粉丝

虚心接受问题,砥砺前行。