You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何实现AES静态加密:相同明文生成固定密文?

问题描述

需要将文本加密后存储在Excel表格中,Java代码读取加密文本解密为明文,再用明文请求服务器。使用AES加解密逻辑时,相同明文每次加密得到的密文不同(虽可正常解密),但需求是相同静态明文对应固定密文,以便预存后能正常解密。

示例:

Enter
This is a question
Encrypted Data : mFsue8JGwLcJQTiBzM0HLVvdDXKPNGsG/O7N60joH+Ozgg==
Decrypted Data : This is a question

Enter
This is a question
Encrypted Data : FdBz3cGS4NphK14Fw8Me4daM4lVzdrK47WUMSRiUVe+juQ==
Decrypted Data : This is a question

以下是使用的代码(逻辑一致,可能包含未使用变量和方法):

Method.java

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class Method {

private static SecretKey key;
private final int KEY_SIZE = 128;
private final int DATA_LENGTH = 128;
private Cipher encryptionCipher;

/*
 * public void init() throws Exception { KeyGenerator keyGenerator =
 * KeyGenerator.getInstance("AES"); keyGenerator.init(KEY_SIZE); key =
 * keyGenerator.generateKey();
 * 
 * 
 * }
 */

// String to Key


  public static void getKeyFromPassword(String toEnc, String salt) throws
  NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory
  = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new
  PBEKeySpec(toEnc.toCharArray(), salt.getBytes(), 65536, 128); SecretKey
  originalKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(),"AES"); 
  key= originalKey; }
  
 
/*
 * public static void convertStringToSecretKeyto(String string) {
 * 
 * 
 * byte[] bytesEncoded = Base64.getEncoder().encode(string.getBytes()); byte[]
 * decodedKey = Base64.getDecoder().decode(string); key = new
 * SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
 * System.out.println(bytesEncoded); System.out.println(decodedKey);
 * 
 * }
 */

   public String encrypt(String data) throws Exception {
    byte[] dataInBytes = data.getBytes();
    encryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
    
    encryptionCipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] encryptedBytes = encryptionCipher.doFinal(dataInBytes);
    return encode(encryptedBytes);
   }

    public String decrypt(String encryptedData) throws Exception {
    byte[] dataInBytes = decode(encryptedData);
    Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");

    GCMParameterSpec spec = new GCMParameterSpec(DATA_LENGTH, 
    encryptionCipher.getIV());
    decryptionCipher.init(Cipher.DECRYPT_MODE, key, spec);
    byte[] decryptedBytes = decryptionCipher.doFinal(dataInBytes);
    return new String(decryptedBytes);
    }

    private String encode(byte[] data) {
    return Base64.getEncoder().encodeToString(data);
    }

    private byte[] decode(String data) {
    return Base64.getDecoder().decode(data);
    } 
}

Main.java

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.util.Base64;
import java.util.Scanner;
public class Cypher {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    
    try {
        Method aes_encryption = new Method();
 
        
 //       aes_encryption.init();
       Method.getKeyFromPassword("Texty text","Salty salt");
        
        System.out.println("Enter");
        Scanner sc= new Scanner(System.in);
        String s= sc.nextLine();
        String encryptedData = aes_encryption.encrypt(s);
        String decryptedData = aes_encryption.decrypt(encryptedData);
      

        System.out.println("Encrypted Data : " + encryptedData);
       System.out.println("Decrypted Data : " + decryptedData);
    } catch (Exception ignored) {
    }
}
    
    
}
解决方案

密文不同的核心原因是AES/GCM模式默认会生成随机初始化向量(IV),每次加密的IV不同,导致相同明文和密钥生成的密文也不同。要实现固定密文,需指定固定的IV:

修改思路

  1. 定义一个固定的IV(GCM模式推荐IV长度为12字节,可自行生成固定字节数组)
  2. 加密时手动传入该固定IV初始化Cipher
  3. 解密时使用相同的固定IV进行初始化

修改后的核心代码示例

// 在Method类中添加固定IV(示例值,可自行替换为12字节的固定数组)
private final byte[] FIXED_IV = "abcdefghijkl".getBytes();

public String encrypt(String data) throws Exception {
    byte[] dataInBytes = data.getBytes();
    encryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
    // 使用固定IV初始化加密Cipher
    GCMParameterSpec spec = new GCMParameterSpec(DATA_LENGTH, FIXED_IV);
    encryptionCipher.init(Cipher.ENCRYPT_MODE, key, spec);
    byte[] encryptedBytes = encryptionCipher.doFinal(dataInBytes);
    return encode(encryptedBytes);
}

public String decrypt(String encryptedData) throws Exception {
    byte[] dataInBytes = decode(encryptedData);
    Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
    // 解密时使用相同的固定IV
    GCMParameterSpec spec = new GCMParameterSpec(DATA_LENGTH, FIXED_IV);
    decryptionCipher.init(Cipher.DECRYPT_MODE, key, spec);
    byte[] decryptedBytes = decryptionCipher.doFinal(dataInBytes);
    return new String(decryptedBytes);
}

注意事项

  • 固定IV会让相同明文+密钥的密文固定,但会失去语义安全性,攻击者可通过密文重复判断明文重复,仅适用于预存固定明文的场景,请勿用于动态加密场景
  • 确保密钥和IV的安全性,避免硬编码在代码中,建议通过配置文件等方式管理
  • GCM模式的IV推荐长度为12字节,避免使用过短或过长的IV

内容的提问来源于stack exchange,提问作者Vaibhav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:39:33