MST
星途 面试题库

面试题:Java中常见加密算法的实现

请阐述在Java中如何使用对称加密算法(如AES)进行数据加密和解密,要求给出核心代码示例并解释关键步骤。
41.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 引入必要的库

在Java中,进行AES加密和解密需要使用javax.crypto包,这个包在Java的安全库中。一般无需额外引入,因为它是Java标准库的一部分。

2. 生成密钥

AES加密需要一个密钥,密钥长度通常为128位、192位或256位。以下是生成256位密钥的代码:

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;

public class AESExample {
    public static SecretKey generateKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256);
        return keyGenerator.generateKey();
    }
}

这里通过KeyGenerator类的getInstance("AES")方法获取AES密钥生成器实例,然后使用init(256)方法初始化生成器,生成256位长度的密钥。

3. 加密数据

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class AESExample {
    // 省略上面生成密钥的方法

    public static String encrypt(String plainText, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(iv);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        byte[] encryptedIVAndText = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, encryptedIVAndText, 0, iv.length);
        System.arraycopy(encrypted, 0, encryptedIVAndText, iv.length, encrypted.length);
        return Base64.getEncoder().encodeToString(encryptedIVAndText);
    }
}

关键步骤解释:

  • Cipher.getInstance("AES/CBC/PKCS5Padding"):获取AES加密算法实例,使用CBC模式和PKCS5Padding填充方式。
  • 生成16字节的初始向量(IV),IV用于增加加密的安全性,这里通过SecureRandom生成。
  • cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec):初始化Cipher为加密模式,传入密钥和IV。
  • cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)):执行加密操作,将明文转换为密文。
  • 最后将IV和密文拼接,使用Base64编码返回。

4. 解密数据

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AESExample {
    // 省略上面生成密钥和加密的方法

    public static String decrypt(String encryptedText, SecretKey secretKey) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(encryptedText);
        byte[] iv = new byte[16];
        System.arraycopy(decoded, 0, iv, 0, iv.length);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        byte[] encrypted = new byte[decoded.length - iv.length];
        System.arraycopy(decoded, iv.length, encrypted, 0, encrypted.length);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}

关键步骤解释:

  • 使用Base64解码接收到的密文。
  • 从解码后的字节数组中提取出IV。
  • 提取出真正的密文部分。
  • Cipher.getInstance("AES/CBC/PKCS5Padding"):获取AES解密算法实例,同样使用CBC模式和PKCS5Padding填充方式。
  • cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec):初始化Cipher为解密模式,传入密钥和IV。
  • cipher.doFinal(encrypted):执行解密操作,将密文转换为明文,并返回明文的字符串形式。

5. 完整示例及测试

public class AESExample {
    public static void main(String[] args) {
        try {
            SecretKey secretKey = generateKey();
            String plainText = "Hello, AES!";
            String encryptedText = encrypt(plainText, secretKey);
            System.out.println("Encrypted Text: " + encryptedText);
            String decryptedText = decrypt(encryptedText, secretKey);
            System.out.println("Decrypted Text: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SecretKey generateKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256);
        return keyGenerator.generateKey();
    }

    public static String encrypt(String plainText, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(iv);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        byte[] encryptedIVAndText = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, encryptedIVAndText, 0, iv.length);
        System.arraycopy(encrypted, 0, encryptedIVAndText, iv.length, encrypted.length);
        return Base64.getEncoder().encodeToString(encryptedIVAndText);
    }

    public static String decrypt(String encryptedText, SecretKey secretKey) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(encryptedText);
        byte[] iv = new byte[16];
        System.arraycopy(decoded, 0, iv, 0, iv.length);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        byte[] encrypted = new byte[decoded.length - iv.length];
        System.arraycopy(decoded, iv.length, encrypted, 0, encrypted.length);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}

main方法中,生成密钥,对一段明文进行加密,然后再对加密后的密文进行解密,并输出加密和解密后的文本。这样就完成了AES对称加密和解密的整个过程。