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

Java文件解密遇阻:数字签名未验证+CipherInputStream无输出求助

解决你的文件加密解密程序问题:签名验证失败+解密输出为空

嘿,我看了你的代码和问题描述,发现了几个关键的问题点,帮你一一梳理并给出修复方案:

一、数字签名的逻辑完全搞反了!

你提到“用发送方私钥和接收方公钥生成数字签名”——这是错误的思路哦。数字签名的核心逻辑是:

  • 发送方(Alice):用自己的私钥对要确认的内容(比如原始数据哈希、对称密钥+IV组合)签名,证明“这确实是我发的”
  • 接收方(Bob):用发送方的公钥验证签名,确认内容没被篡改且来自合法发送方

你现在的代码里试图用Bob的公钥参与签名生成,这完全不符合签名的设计逻辑,肯定会导致验证失败。

正确的签名生成(Alice加密时)

// 我们选择对对称密钥+IV的组合签名(确保密钥和IV没被篡改)
byte[] contentToSign = ByteBuffer.allocate(symmetricKey.getEncoded().length + ivByte.length)
        .put(symmetricKey.getEncoded())
        .put(ivByte)
        .array();

// 初始化签名器,用Alice的私钥
Signature signature = Signature.getInstance("SHA256withRSA"); // 推荐用SHA256+RSA,更安全
signature.initSign((PrivateKey) aliceKey);
signature.update(contentToSign);
byte[] signBytes = signature.sign();

// 把签名转成Base64字符串,方便存入配置文件传输
String signatureBase64 = Base64.getEncoder().encodeToString(signBytes);

正确的签名验证(Bob解密时)

// 从配置文件读取签名、加密后的密钥、IV
Properties config = new Properties();
config.load(new FileInputStream("你的配置文件路径"));
String signatureBase64 = config.getProperty("signature");
String encryptedKeyBase64 = config.getProperty("encryptedKey");
String ivBase64 = config.getProperty("iv");

// 从Bob的密钥库获取Alice的公钥(Bob的密钥库必须导入过Alice的证书)
Certificate aliceCert = bobKeystore.getCertificate("alicecert"); // 确保别名正确
PublicKey alicePubKey = aliceCert.getPublicKey();

// 初始化验证器,用Alice的公钥
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(alicePubKey);

// 重构签名时的内容(必须和签名时完全一致)
byte[] encryptedKeyBytes = Base64.getDecoder().decode(encryptedKeyBase64);
byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
byte[] contentToVerify = ByteBuffer.allocate(encryptedKeyBytes.length + ivBytes.length)
        .put(encryptedKeyBytes)
        .put(ivBytes)
        .array();

signature.update(contentToVerify);
boolean isSignValid = signature.verify(Base64.getDecoder().decode(signatureBase64));
if (!isSignValid) {
    throw new SecurityException("数字签名验证失败!数据可能被篡改或来源非法");
}

二、CipherInputStream使用错误+IV处理不当导致输出为空

你的加密代码里有个致命错误:把IV字节数组直接转成String存储——String ivString = new String(curIV);。IV是随机生成的字节,直接用默认字符编码转换会丢失字节信息,导致解密时无法还原正确的IV,自然解不出内容。

另外,解密时的CipherInputStream使用也需要注意正确的流处理方式:

1. 修复IV和密钥的存储方式

加密时必须用Base64编码字节数组,确保字节完整:

// 加密后存储IV和加密后的对称密钥
String ivBase64 = Base64.getEncoder().encodeToString(cipher.getIV());
String encryptedKeyBase64 = Base64.getEncoder().encodeToString(keyCipher.doFinal(symmetricKey.getEncoded()));
// 把这些字符串写入配置文件

2. 正确的解密流实现

这里给你补全正确的decrypt函数:

public static void decrypt(String storePass) throws Exception {
    // 1. 加载配置参数
    Properties config = new Properties();
    config.load(new FileInputStream("C:\\Users\\Victoria\\Desktop\\config.properties"));
    String ivBase64 = config.getProperty("iv");
    String encryptedKeyBase64 = config.getProperty("encryptedKey");
    String signatureBase64 = config.getProperty("signature");

    // 2. 先验证数字签名(参考上面的签名验证代码)
    // ... 这里插入签名验证逻辑 ...

    // 3. 从Bob的密钥库获取私钥,解密对称密钥
    char[] bobStorePassArr = storePass.toCharArray();
    char[] bobKeyPassArr = "bobKey".toCharArray(); // 确保和Bob密钥的密码一致
    FileInputStream bobKsStream = new FileInputStream("C:\\Users\\Victoria\\Desktop\\cryptography\\bobKeystore.jks");
    KeyStore bobKeystore = KeyStore.getInstance("JKS");
    bobKeystore.load(bobKsStream, bobStorePassArr);
    PrivateKey bobPrivateKey = (PrivateKey) bobKeystore.getKey("bob", bobKeyPassArr);

    // 解密对称密钥
    Cipher keyDecryptCipher = Cipher.getInstance("RSA");
    keyDecryptCipher.init(Cipher.DECRYPT_MODE, bobPrivateKey);
    byte[] symmetricKeyBytes = keyDecryptCipher.doFinal(Base64.getDecoder().decode(encryptedKeyBase64));
    SecretKey symmetricKey = new SecretKeySpec(symmetricKeyBytes, "AES");

    // 还原IV
    IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(ivBase64));

    // 4. 初始化文件解密Cipher
    Cipher fileDecryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    fileDecryptCipher.init(Cipher.DECRYPT_MODE, symmetricKey, iv);

    // 5. 使用CipherInputStream解密文件,用try-with-resources自动关流
    File encryptedFile = new File("C:\\Users\\Victoria\\Desktop\\encryptedData.txt");
    File decryptedFile = new File("C:\\Users\\Victoria\\Desktop\\decryptedData.txt");

    try (FileInputStream fis = new FileInputStream(encryptedFile);
         CipherInputStream cis = new CipherInputStream(fis, fileDecryptCipher);
         FileOutputStream fos = new FileOutputStream(decryptedFile)) {

        byte[] buffer = new byte[4096]; // 用4KB缓冲区,提升效率
        int bytesRead;
        // 循环读取直到流结束,不能只读一次!
        while ((bytesRead = cis.read(buffer)) != -1) {
            fos.write(buffer, 0, bytesRead);
        }
        fos.flush(); // 确保所有数据写入文件
    }
}

三、其他需要注意的细节

  1. 代码完整性:你提供的加密代码最后一行keyCipher.init(Ciphe不完整,应该补成keyCipher.init(Cipher.ENCRYPT_MODE, bobPublicKey);,用来用Bob的公钥加密对称密钥。
  2. 异常处理:你的代码几乎没有异常捕获,建议添加try-catch块打印详细异常信息,这样Eclipse就能显示错误,方便你排查问题。
  3. 密钥库别名:确保Bob的密钥库中确实导入了Alice的证书,且别名正确,否则无法获取Alice的公钥验证签名。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:59