【问题标题】:How to use CipherOutputStream correctly to encrypt and decrypt log created with log4j (RollingFileAppender)如何正确使用 CipherOutputStream 加密和解密使用 log4j (RollingFileAppender) 创建的日志
【发布时间】:2011-07-07 09:35:14
【问题描述】:

我在加密/解密 log4j 的 RollingFileAppender 生成的日志文件时遇到问题。对于我尝试扩展 RollingFileAppender 的加密,只需将其称为 EncryptedRollingFileAppender。我重写了方法

setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)

基本上我使用 CipherOutputStream 和 Base64OutputStream 来加密和编码写入输出流的所有内容。以下是部分代码:

...
setImmediateFlush(true);

FileOutputStream ostream = null;
CipherOutputStream cstream = null;
Base64OutputStream b64stream = null;
try {        
    byte[] keyBytes = "1234123412341234".getBytes();  //example
    final byte[] ivBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; //example

    final SecretKey key = new SecretKeySpec(keyBytes, "AES");
    final IvParameterSpec IV = new IvParameterSpec(ivBytes);
    final Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key, IV);

    ostream = new FileOutputStream(fileName, true);
    b64stream = new Base64OutputStream(ostream);
    cstream = new CipherOutputStream(b64stream, cipher);

    } catch(Exception ex) {
        ex.printStackTrace();
    }

Writer cw = createWriter(cstream);
...

然后我用这个代码解密文件:

private static void decryptFile(String filename) throws Exception {
    FileInputStream fis = null;
    BufferedReader br = new BufferedReader(new FileReader(filename));

    File file = new File(filename + "-decrypted");
    file.createNewFile();
    Writer out = new OutputStreamWriter(new FileOutputStream(filename + "-decrypted"), "UTF-8");

    String line = null;
    try {
         while (( line = br.readLine()) != null){
             line = decrypt(Base64.decodeBase64(line));
             out.write(line);
         }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            br.close();
        }
        if (fis != null) {
            fis.close();
        }
        if (out != null) {
            out.close();
        }
    }
}

public static String decrypt(byte[] line) throws Exception {
    byte[] keyBytes = "1234123412341234".getBytes();
    final byte[] ivBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };

    final SecretKey secretkey = new SecretKeySpec(keyBytes, "AES");
    final IvParameterSpec IV = new IvParameterSpec(ivBytes);
    final Cipher decipher = Cipher.getInstance("AES/CFB8/NoPadding");
    decipher.init(Cipher.DECRYPT_MODE, secretkey, IV);
    final byte[] plainText = decipher.doFinal(line);

    return new String(plainText, "UTF-8").trim();
}

它起作用了,但只是部分起作用。结果文件中的某些文本已正确解密,但其他一些文本未正确解密。如果你很好奇,这就是我所说的部分:

07 Jul 11 13:13:13, DEBUG  MrBean.java:checkUserVal���̥V;��ƃ�˨�� - username: squall,password: 4GROmr95Qcf����v�M�7�y�5�@CGO09 ,active: true 

我也尝试将算法更改为“DESede”,但它仍然被部分解密。然后我尝试在两端都使用“CBC/PKCS5Padding”,但出现异常

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

我假设加密没有正确填充输入,但我想知道为什么......因为当我使用相同的加密和解密算法而没有 CipherOutputStream 时,填充工作得很好。 任何人都可以帮助我完成这项工作吗?任何帮助将不胜感激。

PS:对不起,我的英语不是我的母语。

【问题讨论】:

  • 只是好奇:为什么要使用 Base64OutputStream?通常加密的文件是二进制格式,将它们设为 ascii 没有任何优势。
  • 想一想,解密不需要CipherInputStream吗?

标签: java file log4j encryption


【解决方案1】:

看起来不错。您是否正在为每条消息重置/初始化密码对象?您可能不想这样做,但如果您这样做了,那么您需要仔细考虑密码文件的结构,因为解密器需要知道消息边界在哪里。

【讨论】:

  • 并非针对每条消息,但我认为在某些情况下会重新初始化密码。如果密钥、IV、算法、分组密码模式和填充没有改变,应该不是问题,对吧? (就像上面的示例代码)
  • 这是个问题。为了大大简化,您需要使用的“IV”对于密码流中的不同位置是不同的。详情请见wikipedia page
  • 感谢您的回复。嗯,我认为如果我使用相同的 IV,它会起作用,无论如何它只是用于测试。但是,如果它必须有所不同,那我猜这会使一切变得更加复杂。我必须在文件中写入IV,添加消息分隔符等。无效的填充怎么办?你有什么线索吗?
  • @ordinarydot:我同意,使用单独的消息实体要复杂得多。 NoPadding 工作正常,问题几乎可以肯定完全是由于重置密码实例。
  • 现在已经可以使用了。不过我采取了不同的方法。现在我将所有类扩展到 log4j 的 WriteAppender,然后我简单地将所有加密和编码直接放在编写器中。我想在不知道发生了什么的情况下处理 CipherOutputStream 太多了。现在我使用了 AES/ECB/PKCS5Padding,但我打算将其更改为 CBC。为每条消息使用不同的 IV 并添加必要的更改。好吧,非常感谢 Greg 的所有帮助。
猜你喜欢
  • 1970-01-01
  • 2022-04-07
  • 2011-12-15
  • 2020-12-22
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 2012-02-04
  • 2013-08-13
相关资源
最近更新 更多