创建加密 log4j appender 时使用什么算法

What algorithm to use when creating an encrypting log4j appender

我创建了一个 RollingFileAppender,它将输出加密到 log4j 日志文件。 目前它使用 AES/ECB/NoPadding,并且工作正常。

下面是我们如何创建密码

public static Cipher getCipher(boolean encrypt) throws Exception {
    //https://en.wikipedia.org/wiki/Stream_cipher       
    byte[] key = ("sometestkey").getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    key = sha.digest(key);
    key = Arrays.copyOf(key, 16); // use only first 128 bit

    Key k = new SecretKeySpec(key,"AES");
    Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
    if (encrypt) {
        cipher.init(Cipher.ENCRYPT_MODE, k);
    } else {
        cipher.init(Cipher.DECRYPT_MODE, k);
    }
    return cipher;
}

以下是我们创建附加程序的方式:

public class EncryptingRollingFileAppender extends RollingFileAppender {
    private CipherOutputStream s;
    private Cipher cipher; 
    public EncryptingRollingFileAppender() {super();}
    public EncryptingRollingFileAppender(Layout layout, String filename, boolean append) throws IOException {super(layout, filename, append);}
    public EncryptingRollingFileAppender(Layout layout, String filename) throws IOException {super(layout, filename);}

    @Override
    protected OutputStreamWriter createWriter(OutputStream outputStream) {
        if (cipher==null) {
            try {
                cipher = DecryptionTools.getCipher(true);
                s = new CipherOutputStream(outputStream, cipher);
            } catch (Throwable t) {
                throw new RuntimeException("failed to initialise encrypting file appender",t);
            }
        }
        OutputStreamWriter out = super.createWriter(s);
        return out;
    }   
}

我们可以使用

解密文件

getCipher(false)

创建适当的解密流。

问题是我们的安全团队正在为密钥管理争论不休。 他们不喜欢使用对称密钥加密,更希望我们使用密钥对而不是我们必须以某种方式管理的简单密码。

有谁知道使用密钥对的非填充 ECB 加密技术,适用于这种流加密和解密?

建议使用混合加密和 PGP 的评论是正确的。
PGP 是文件混合加密的事实标准,它是一种比 ECB 模式 AES 更强大的解决方案。

由于 PGP 的性质,它的工作方式将与您现有的解决方案略有不同。

PGP 消息有页眉和页脚,因此您希望每个文件都单独加密(您不能像使用普通 ECB 模式加密那样只解密单个块)。

看来您使用的是 log4j 1.2,I have created a working implementation of a PGP encrypting RollingFileAppender.

要使用该示例,请生成装甲编码的 PGP public 密钥,运行 主要 class 然后使用任何 PGP 工具解密文件(我使用 GnuPG 创建密钥和解密)。

该示例是针对 log4j:log4j:1.2.17org.bouncycastle:bcpg-jdk15on:1.56

构建的

您已经非常接近您想要实现的目标了。使用 Log4j 1.2(因为你不能在 Log4j 2 中直接继承 RollingFileAppender)你可以为每个日志文件动态生成一个密码,用 RSA 加密密码并存储在它旁边。然后使用密码为日志附加程序生成 AES CipherOutputStream。

public class EncryptingRollingFileAppender extends RollingFileAppender {

    private CipherOutputStream s;

    private Cipher cipher;

    private byte[] secretKey;

    public EncryptingRollingFileAppender(Layout layout, String filename, boolean append) throws IOException {
        super(layout, filename, append);
        writeKeyFile(filename);
    }

    public EncryptingRollingFileAppender(Layout layout, String filename) throws IOException {
        super(layout, filename);
        writeKeyFile(filename);
    }

    private void writeKeyFile(final String logfilename) throws IOException {
        final int dot = logfilename.lastIndexOf('.');
        final String keyfilename = (dot == -1 ? logfilename : logfilename.substring(0, dot)) + ".key";
        try (FileOutputStream out = new FileOutputStream(keyfilename)) {
            out.write(DecryptionTools.encryptPasswordBase64(secretKey).getBytes(ISO_8859_1));
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | KeyStoreException
                | CertificateException e) {
        }
    }

    @Override
    protected OutputStreamWriter createWriter(OutputStream outputStream) {
        System.out.println("createWriter()");
        if (cipher == null) {
            secretKey = DecryptionTools.generateRandomKey(16).getBytes(ISO_8859_1);
            try {
                cipher = DecryptionTools.getCipher(true, secretKey);
            } catch (InvalidKeyException e) {
                System.out.println("InvalidKeyException");
            }
            s = new CipherOutputStream(outputStream, cipher);
        }

        OutputStreamWriter out = super.createWriter(s);
        return out;
    }
}

您需要几个辅助函数来从文件或 Java 密钥库中读取私钥,可以在 here.

中找到

测试文件TestEncryptingRollingFileAppender展示了如何写入加密日志并读回。

import static com.acme.DecryptionTools.getCipher;
import static com.acme.DecryptionTools.decryptPasswordBase64;

public class TestEncryptingRollingFileAppender {

    @SuppressWarnings("deprecation")
    @Test
    public void testAppender() throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, KeyStoreException, CertificateException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {

        final File logfile = File.createTempFile("testlog_", ".log");
        final String logfilename = logfile.getAbsolutePath();

        final Logger lggr = LogManager.getLogger(TestEncryptingRollingFileAppender.class);
        final EncryptingRollingFileAppender appender = new EncryptingRollingFileAppender(new SimpleLayout(), logfilename, true);

        appender.append(new LoggingEvent(lggr.getClass().getName(), lggr, Priority.INFO, "Test Log Line #1", null));
        appender.append(new LoggingEvent(lggr.getClass().getName(), lggr, Priority.INFO, "Test Log Line #1", null));

        final int dot = logfilename.lastIndexOf('.');
        byte[] key = decryptPasswordBase64(new String(Files.readAllBytes(Paths.get(logfilename.substring(0, dot)+".key"))));

        StringBuilder logContent = new StringBuilder();
        try (FileInputStream instrm = new FileInputStream(logfilename);
             CipherInputStream cistrm = new CipherInputStream(instrm, getCipher(false, key))) {
            int c;
            while ((c=cistrm.read())!=-1)
                logContent.append((char) c);
        }

        assertEquals("INFO - Test Log Line #1\r\nINFO - Test Log Line #1", logContent.toString());

    }
}