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

用随机密钥加密的字符串如何解密?求安卓Java AES-256加密方案

问题解答与认知纠正
  1. 随机密钥解密逻辑:使用随机密钥加密后,解密时必须使用完全相同的密钥才能完成解密,因此随机密钥需要和密文分开妥善存储。你的密码管理器场景不需要使用随机密钥,密钥由用户主密码派生即可,无需存储密钥。
  2. 你要求的无salt、无IV的AES-256代码存在严重安全缺陷:
  • 无IV意味着只能使用ECB加密模式,该模式下相同明文会生成完全相同的密文,攻击者可以直接通过密文特征推断明文规律,完全不适合存储敏感的账号密码。
  • 无salt直接使用用户主密码作为密钥,会大幅降低暴力破解的难度,即使主密码长度有32位,也存在彩虹表攻击的风险。
  • 用户输入的32/64位字符属于字符串,直接转字节作为AES密钥不符合规范,会出现各类加解密失败的问题,这也是你找到的网上代码无法运行的常见原因。
密码管理器场景的正确实现逻辑

你的场景的加解密流程不需要存储主密码和密钥,符合你的需求:

  1. 首次设置主密码阶段:
    • 生成16字节随机salt、12字节随机IV,二者不属于敏感数据,可直接明文存储在本地
    • 使用PBKDF2密钥派生算法,传入用户主密码、salt、10000次以上迭代次数,派生得到32字节的AES-256密钥
    • 使用AES-GCM认证加密模式,传入密钥、IV加密用户要存储的账号密码,得到密文和16字节认证标签
    • 将salt、IV、认证标签、密文拼接后存储到本地即可
  2. 解密阶段:
    • 用户输入主密码,读取本地存储的salt,用相同的PBKDF2参数派生得到AES密钥
    • 读取本地存储的IV、认证标签、密文,用密钥解密即可得到明文账号密码
代码实现

(强烈不推荐)无IV无salt的AES-256-ECB演示代码

警告:以下代码仅做技术演示,ECB模式安全性极低,禁止在生产环境使用

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

public class InsecureAES {
    // 加密,key需为32位字符串对应AES-256
    public static String encrypt(String plainText, String key) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    // 解密
    public static String decrypt(String cipherText, String key) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}

(推荐生产使用)AES-256-GCM安全实现代码

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;

public class SecureAES {
    private static final int SALT_LENGTH = 16;
    private static final int IV_LENGTH = 12;
    private static final int TAG_LENGTH = 16;
    private static final int ITERATION_COUNT = 10000;
    private static final int KEY_LENGTH = 256;

    // 加密,返回可直接存储的Base64字符串
    public static String encrypt(String plainText, String masterPassword) throws Exception {
        // 生成随机salt和IV
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[SALT_LENGTH];
        random.nextBytes(salt);
        byte[] iv = new byte[IV_LENGTH];
        random.nextBytes(iv);

        // 派生AES密钥
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(masterPassword.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

        // GCM模式加密
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LENGTH * 8, iv));
        byte[] cipherText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        // 拼接salt + iv + 密文,转Base64存储
        ByteBuffer byteBuffer = ByteBuffer.allocate(salt.length + iv.length + cipherText.length);
        byteBuffer.put(salt);
        byteBuffer.put(iv);
        byteBuffer.put(cipherText);
        return Base64.getEncoder().encodeToString(byteBuffer.array());
    }

    // 解密,传入存储的Base64字符串和用户输入的主密码
    public static String decrypt(String storedCipherText, String masterPassword) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(storedCipherText);
        ByteBuffer byteBuffer = ByteBuffer.wrap(decoded);

        // 拆分salt、iv、密文
        byte[] salt = new byte[SALT_LENGTH];
        byteBuffer.get(salt);
        byte[] iv = new byte[IV_LENGTH];
        byteBuffer.get(iv);
        byte[] cipherText = new byte[byteBuffer.remaining()];
        byteBuffer.get(cipherText);

        // 派生相同的密钥
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(masterPassword.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

        // 解密
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LENGTH * 8, iv));
        byte[] plainText = cipher.doFinal(cipherText);
        return new String(plainText, StandardCharsets.UTF_8);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 06:09:00