You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

AES/CFB/NOPADDING 加密转解密失效问题排查求助

你的AES加密解密失效的核心问题分析与修复方案

嘿,我一眼就瞅出了你的代码里导致加密解密功能罢工的关键问题,咱们一步步拆解来看:

核心问题:加密和解密用了完全不同的密钥

你在encryptdecrypt方法里,每次都调用了generator1.generateKey()——这方法每次执行都会生成一个全新的随机AES密钥啊!AES是对称加密算法,加密和解密必须使用同一个密钥才能正常工作,你加密用密钥A,解密用密钥B,那肯定解不出正确内容。

次要问题:CFB无填充模式的潜在风险

你用了AES/CFB/NOPADDING,虽然CFB属于流模式理论上不需要填充,但如果你的明文转字节后的长度不是16字节(AES块大小)的整数倍,可能会导致解密后出现乱码或截断。不过这个问题和密钥不匹配比起来,属于次要矛盾。

修复后的代码示例

我给你调整了代码,把密钥的生成和加解密逻辑分开,确保加密解密用同一个密钥,同时补上了生产环境需要的安全细节:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;

public class AESHandler {
    // 生成一次性AES密钥,需妥善保存用于后续解密
    public static SecretKey generateAES128Key() throws GeneralSecurityException {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128, new SecureRandom()); // 用SecureRandom生成更安全的密钥
        return keyGen.generateKey();
    }

    public static byte[] encrypt(String plainText, SecretKey secretKey) throws GeneralSecurityException {
        // 生产环境务必用随机IV,这里将IV拼在密文前面,方便解密时取出
        byte[] ivBytes = new byte[16];
        new SecureRandom().nextBytes(ivBytes);
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5Padding"); // 换成带填充的模式更省心
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(Charset.forName("UTF-8")));
        byte[] result = new byte[ivBytes.length + encryptedBytes.length];
        System.arraycopy(ivBytes, 0, result, 0, ivBytes.length);
        System.arraycopy(encryptedBytes, 0, result, ivBytes.length, encryptedBytes.length);
        return result;
    }

    public static String decrypt(byte[] encryptedData, SecretKey secretKey) throws GeneralSecurityException {
        // 先从密文开头取出加密时用的IV
        byte[] ivBytes = new byte[16];
        System.arraycopy(encryptedData, 0, ivBytes, 0, ivBytes.length);
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        // 取出真正的密文部分
        byte[] encryptedBytes = new byte[encryptedData.length - ivBytes.length];
        System.arraycopy(encryptedData, ivBytes.length, encryptedBytes, 0, encryptedBytes.length);

        Cipher cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        byte[] plainBytes = cipher.doFinal(encryptedBytes);
        return new String(plainBytes, Charset.forName("UTF-8"));
    }

    // 测试用例
    public static void main(String[] args) throws GeneralSecurityException {
        String testText = "这是一段测试加密的文本";
        SecretKey key = generateAES128Key();
        
        byte[] encrypted = encrypt(testText, key);
        String decrypted = decrypt(encrypted, key);
        
        System.out.println("原始文本:" + testText);
        System.out.println("解密结果:" + decrypted); // 应该和原始文本完全一致
    }
}

生产环境额外注意事项

  • IV必须随机:固定IV会导致加密安全性大幅降低,我在代码里用SecureRandom生成随机IV并和密文绑定,这是AES安全使用的基本要求。
  • 密钥安全存储:绝对不能把密钥硬编码在代码里,要放在专门的密钥管理服务(KMS)、环境变量或者安全的配置中心里。
  • 选择合适的填充模式:如果没有特殊需求,用PKCS5Padding可以避免明文长度对齐的问题,减少额外的处理逻辑。

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

火山引擎 最新活动