内容纲要

背景

在现代信息社会中,数据的安全性至关重要。无论是个人隐私、企业机密,都需要通过加密技术来保护。加密技术通过对数据进行编码,使得未经授权的用户无法读取或篡改数据,从而确保数据的机密性、完整性和可用性。

本文将探讨加密的重要性,并详细介绍几种常见的加密方式,包括 AESRSASHA256RSA + AES 混合加密AES + 时间戳盐值(Salt),分析它们的优缺点及适用场景,并以java代码进行实现。

加密的必要性

1. 保护数据机密性

加密可以防止未经授权的用户访问敏感数据。例如,用户的密码、银行账户信息、医疗记录等都需要加密存储和传输。

2. 确保数据完整性

加密可以防止数据在传输或存储过程中被篡改。通过加密和哈希算法,可以验证数据的完整性。

3. 身份验证

加密技术可以用于验证用户身份,例如通过数字签名和证书确保通信双方的真实性。

4. 合规性要求

许多行业和法规要求对敏感数据进行加密,以确保数据安全和个人隐私数据。

5. 防止数据泄露

加密可以有效防止数据泄露后的滥用,即使数据被窃取,也无法被解密和使用。

常见的加密方式

加密技术主要分为两大类:对称加密非对称加密

对称加密

对称加密算法是指加密和解密使用同一个密钥的加密方式。在通信过程中,双方必须共享这个密钥,使得发送方可以用该密钥加密数据,接收方则用同样的密钥进行解密。

![image-20250302223602200](/Users/yunqi.zhaothoughtworks.com/Library/Application Support/typora-user-images/image-20250302223602200.png)

AES就是一种典型的对称加密算法,使用相同的密钥进行加密和解密。我们以AES来讨论对称算法的实现和优缺点。

实现方式

public class AesUtil {
        //单例模式
    private static final AesUtil INSTANCE = new AesUtil();

    // AES 密钥
    private final SecretKey secretKey;

    // 私有构造函数,防止外部实例化
    private AesUtil() {
        try {
            // 生成 AES 密钥
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(128); // 128位密钥
            secretKey = keyGen.generateKey();
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize AESUtil", e);
        }
    }

    // 获取单例实例
    public static AesUtil getInstance() {
        return INSTANCE;
    }

    /**
     * 加密方法
     *
     * @param plainText 明文
     * @return 加密后的 Base64 编码字符串
     */
    public String encrypt(String plainText) {
        try {
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }
    }

    /**
     * 解密方法
     *
     * @param encryptedText 加密后的 Base64 编码字符串
     * @return 解密后的明文
     */
    public String decrypt(String encryptedText) {
        try {
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
            return new String(decryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("Decryption failed", e);
        }
    }
}

优点

  • 加密速度快:适合加密大量数据。
  • 实现简单:只需一个密钥即可完成加密和解密,管理相对容易。

缺点

  • 密钥安全问题:通信双方需要共享密钥,密钥分发过程可能存在风险。而且密钥需要通信双方共同维护,增加了泄露的风险。

适用场景

  • 文件加密:由于AES适用于大量数据的加密,所以常用语存储文件内容的加密。
  • 数据库加密:对于单个系统来说,加密安全性要求并不高的场景中,密钥的维护也并不困难,所以数据库中敏感字段的加密可以使用AES算法。
  • 网络通信:对于数据安全性要求并不高的场景中,考虑到易用性,通信双方的传输数据的加密也可使用AES加密。

非对称加密

相比与加密算法使用同一个密钥进行加密和解密,非对称加密算法,也称为公钥加密算法,采用了两个密钥:公钥和私钥。公钥用于加密数据,而私钥用于解密数据。公钥是公开的,任何持有公钥的人都可以加密数据,而只有私钥的持有者才能解密数据。

image-20250302223627657

RSA 是一种非对称加密算法,使用一对密钥:公钥和私钥。下面我们以RSA加密算法为例,看一下非对称加密的实现方式和应用场景。

实现方式

public class RsaUtil {
    // 单例实例
    private static final RsaUtil INSTANCE = new RsaUtil();

    // RSA 密钥对
    private final PrivateKey privateKey;
    private final PublicKey publicKey;

    // 私有构造函数,防止外部实例化
    private RsaUtil() {
        try {
            // 生成 RSA 密钥对
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            keyPairGen.initialize(2048); // 2048位密钥
            KeyPair keyPair = keyPairGen.generateKeyPair();
            privateKey = keyPair.getPrivate();
            publicKey = keyPair.getPublic();
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize RSAUtil", e);
        }
    }

    // 获取单例实例
    public static RsaUtil getInstance() {
        return INSTANCE;
    }

    /**
     * 加密方法(使用公钥加密)
     *
     * @param plainText 明文
     * @return 加密后的 Base64 编码字符串
     */
    public String encrypt(String plainText) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }
    }

    /**
     * 解密方法(使用私钥解密)
     *
     * @param encryptedText 加密后的 Base64 编码字符串
     * @return 解密后的明文
     */
    public String decrypt(String encryptedText) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
            return new String(decryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("Decryption failed", e);
        }
    }
}

优点

  • 安全性高:公钥可以公开,私钥保密,解决了密钥分发问题。
  • 支持数字签名:可以用于身份验证和数据完整性验证。

缺点

  • 加密速度慢:适合加密少量数据。
  • 密钥管理复杂:需要管理公钥和私钥。

适用场景

  • 数字签名:验证数据的真实性和完整性。
  • 安全通信:由于非对称加密的安全性比对称加密更高,所以传输敏感数据时可以使用该加密方式。

哈希算法

哈希算法是一种单向加密技术,将任意长度的数据映射为固定长度的哈希值。常见的哈希算法包括 MD5、SHA-1 和 SHA-256。下面我们以SHA-256为例,看一下哈希算法加密解密的实现和应用场景

实现方式

public class Sha256Util {

    public static final Sha256Util INSTANCE = new Sha256Util();

    public String encrypt(String input) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(input.getBytes());
        return Base64.getEncoder().encodeToString(hashBytes);
    }
}

优点

  • 不可逆:无法从哈希值还原原始数据,这意味着就算数据泄露也不会使原始数据泄露,这样可以最大限度保护数据等安全性。

缺点

  • 无法解密:虽然不可逆使得数据更为安全,但同时也使这种算法仅适用于数据完整性验证,不适用于数据加密。

适用场景

  • 密码存储:存储用户密码时将其哈希值存放入数据库,验证密码正确性时只要比较哈希值是否相等即可。
  • 数据完整性验证:验证文件或数据的完整性。

混合加密

混合加密是指使用多种加密方式进行加密,其结合了多种加密方式的优点,同时安全性更高。比如RSA + AES 混合加密、ECC + AES 混合加密和RSA + ChaCha20 混合加密等方式。我们用RSA+AES加密方式为例,使用 RSA 加密 AES 密钥,然后使用 AES 加密数据。

实现方式

//RSA + AES 混合加密
public class MixedUtil {

    private static final MixedUtil INSTANCE = new MixedUtil();

    // RSA 密钥对
    private final KeyPair rsaKeyPair;
    // AES 密钥
    private SecretKey aesKey;

    // 私有构造函数,防止外部实例化
    private MixedUtil() {
        try {
            // 生成 RSA 密钥对
            KeyPairGenerator rsaKeyPairGen = KeyPairGenerator.getInstance("RSA");
            rsaKeyPairGen.initialize(2048);
            rsaKeyPair = rsaKeyPairGen.generateKeyPair();

            // 生成 AES 密钥
            KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
            aesKeyGen.init(128);
            aesKey = aesKeyGen.generateKey();
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize HybridEncryptionUtil", e);
        }
    }

    // 获取单例实例
    public static MixedUtil getInstance() {
        return INSTANCE;
    }

    /**
     * 加密方法
     *
     * @param plainText 明文
     * @return 加密后的 Base64 编码字符串(包含加密的 AES 密钥和加密的数据)
     */
    public String encrypt(String plainText) {
        try {
            // 使用 RSA 加密 AES 密钥
            Cipher rsaCipher = Cipher.getInstance("RSA");
            rsaCipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPublic());
            byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());

            // 使用 AES 加密数据
            Cipher aesCipher = Cipher.getInstance("AES");
            aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
            byte[] encryptedData = aesCipher.doFinal(plainText.getBytes());

            // 将加密的 AES 密钥和数据拼接为字符串
            String encryptedAesKeyBase64 = Base64.getEncoder().encodeToString(encryptedAesKey);
            String encryptedDataBase64 = Base64.getEncoder().encodeToString(encryptedData);
            return encryptedAesKeyBase64 + "|" + encryptedDataBase64;
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }
    }

    /**
     * 解密方法
     *
     * @param encryptedText 加密后的 Base64 编码字符串(包含加密的 AES 密钥和加密的数据)
     * @return 解密后的明文
     */
    public String decrypt(String encryptedText) {
        try {
            // 拆分加密的 AES 密钥和数据
            String[] parts = encryptedText.split("\\|");
            String encryptedAesKeyBase64 = parts[0];
            String encryptedDataBase64 = parts[1];

            // 使用 RSA 解密 AES 密钥
            Cipher rsaCipher = Cipher.getInstance("RSA");
            rsaCipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());
            byte[] decryptedAesKey = rsaCipher.doFinal(Base64.getDecoder().decode(encryptedAesKeyBase64));

            // 使用 AES 解密数据
            SecretKey originalAesKey = new SecretKeySpec(decryptedAesKey, 0, decryptedAesKey.length, "AES");
            Cipher aesCipher = Cipher.getInstance("AES");
            aesCipher.init(Cipher.DECRYPT_MODE, originalAesKey);
            byte[] decryptedData = aesCipher.doFinal(Base64.getDecoder().decode(encryptedDataBase64));

            return new String(decryptedData);
        } catch (Exception e) {
            throw new RuntimeException("Decryption failed", e);
        }
    }
}

优点

  • 安全性高:混合加密通过结合对称加密和非对称加密的优点,既解决了密钥分发问题,又保留了加密的高效性。

缺点

  • 实现复杂:不仅需要同时管理对称和非对称加密的密钥,还需要实现多种加密方式。

适用场景

  • 文件或数据加密:对于安全性要求比非对称加密货对称加密要求更高的场景,可以使用混合加密,比如更高安全性需求的数据库数据加密和文件加密。

加密算法+时间戳

在加密数据时加入时间戳,防止重放攻击。

实现方式

public class AesTimestampUtil {

    private static final AesTimestampUtil INSTANCE = new AesTimestampUtil();

    // AES 密钥
    private final SecretKey secretKey;

    // 私有构造函数,防止外部实例化
    private AesTimestampUtil() {
        try {
            // 生成 AES 密钥
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(128); // 128位密钥
            secretKey = keyGen.generateKey();
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize AESUtil", e);
        }
    }

    // 获取单例实例
    public static AesTimestampUtil getInstance() {
        return INSTANCE;
    }

    /**
     * 加密方法
     *
     * @param plainText 明文
     * @return 加密后的 Base64 编码字符串
     */
    public String encrypt(String plainText) {
        try {
            long timestamp = System.currentTimeMillis();
            String dataWithTimestamp = plainText + "|" + timestamp;
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encryptedBytes = cipher.doFinal(dataWithTimestamp.getBytes());
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }
    }

    /**
     * 解密方法
     *
     * @param encryptedText 加密后的 Base64 编码字符串
     * @return 解密后的明文
     */
    public String decrypt(String encryptedText) {
        try {
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
            String decryptedText = new String(decryptedBytes);

            // 分离数据和时间戳
            String[] parts = decryptedText.split("\\|");
            String originalText = parts[0];
            long originalTimestamp = Long.parseLong(parts[1]);

            // 验证时间戳
            long currentTime = System.currentTimeMillis();
            if (currentTime - originalTimestamp > 600) { // 60秒有效期
                return "Timestamp expired";
            }

            return originalText;
        } catch (Exception e) {
            throw new RuntimeException("Decryption failed", e);
        }
    }
}

优点

  • 防止重放攻击:时间戳确保数据在有效期内使用。重攻击时时间戳失效,可以有效地保证数据的安全性。
  • 增强安全性:结合加密和时间戳,提高数据的安全性。

缺点

  • 时间同步问题:通信双方需要时间同步,否则可能导致验证失败。

适用场景

  • 安全认证:由于时间戳可以防止重放攻击,所以该加密方式可以用于安全性要求较高的认证过程或者数据传输的业务场景中。

盐值(Salt)

实现方式

盐值是一段随机数据,通常与密码一起使用,以增加哈希值的唯一性。

public class SaltUtil {

    public static final SaltUtil INSTANCE = new SaltUtil();

    public String encrypt(String input) throws NoSuchAlgorithmException {
        byte[] salt = generateSalt();

        // 将盐值与密码结合
        String saltedPassword = input + Base64.getEncoder().encodeToString(salt);

        // 计算哈希值
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(saltedPassword.getBytes());
        return Base64.getEncoder().encodeToString(hashBytes);
    }

    private static byte[] generateSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);
        return salt;
    }
}

优点

  • 防止彩虹表攻击:盐值使得每个密码的哈希值唯一。
  • 增强密码安全性:即使两个用户使用相同的密码,由于盐值不同,哈希值也不同。

缺点

  • 需要存储盐值:盐值需要与哈希值一起存储,增加了存储开销。

使用场景

  • 密码存储:存储用户密码的哈希值。但该方式需要另外存储盐值,存储开销更大。
  • 数据完整性验证:验证文件或数据的完整性。

总结

加密技术是保护数据安全的重要手段。不同的加密方式各有优缺点,对称加密适合加密大量数据,非对称加密解决了密钥分发问题,哈希算法用于数据完整性验证,而混合加密结合了两者的优点。基于时间戳的加密方式则进一步增强了数据的安全性,防止重放攻击。

在实际项目中,应根据具体需求选择合适的加密方式,并结合时间戳或盐值等技术提高数据的安全性。

最后修改日期: 2025年3月9日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。