2017-05-04 18 views
3

当我创建了加密输出到一个log4j的日志文件RollingFileAppender进行使用。 目前它使用AES/ECB/NoPadding,它工作正常。什么算法创建加密Log4j追加

下面是我们如何创建密码

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(假)解密文件

创建一个适当的解密流。

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

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

+0

您可以使用[混合加密](https://en.wikipedia。org/wiki/Hybrid_cryptosystem)与任何非对称和对称加密算法的组合,但您还有其他问题。加密的消息需要某种标题。你如何区分同一个日志文件中的多条消息? –

+0

你正在写一个配置文件?真? – EJP

+0

@ ArtjomB。你有没有Java中的混合加密的例子。更具体地说,我可以让RC4使用异步密钥对吗? – Richard

回答

0

使用混合加密和PGP暗示的意见是正确的。
PGP是文件混合加密的实际标准,它是ECB模式AES更强大的解决方案。

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

PGP消息有一个头和页脚,所以你会希望每个文件进行单独加密(你不会只能够解密各个块像您可以用普通ECB模式加密)。

看起来你正在使用log4j的1.2,I have created a working implementation of a PGP encrypting RollingFileAppender.

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

的例子建对log4j:log4j:1.2.17org.bouncycastle:bcpg-jdk15on:1.56

+0

谢谢你,太棒了。 我不认为我可以使用PGP,因为它不允许我们解密正在写入的文件。此外,PGP之后的文件大小远大于未加密的文件。 我想我需要的是一种使用某种巧妙的密钥对系统的RC4的方式。经过大量的研究,我不相信这是可能的。 相反,我已经解决了使用一个简单的密码来将密钥转换成其他东西。该加密密钥随后用于加密和解密日志。然后我只是混淆了jar来隐藏加密。这是不安全的,但它是向前迈进的一步 – Richard

+0

如果禁用ascii“Armor”编码,文件的大小应该大致相同(文件大小增加时,文件头有一些固定大小的开销变得毫无意义, bouncycastle也有压缩选项)。在编写文件时应该在技术上解密文件,但标准工具可能不会工作,但可以编写一些代码来完成它。我会避免RC4,如果你真的想要一个流密码,你可以在CFB模式下使用AES,那么现在真的没有理由使用它。 – Magnus

+0

但是aes是对称密钥,所以我仍然有隐藏密钥的问题。 – Richard

0

您是非常接近你想要达到的目标。使用Log4j 1.2(因为您无法直接在Log4j 2中继承RollingFileAppender),您可以为每个日志文件实时生成密码,使用RSA加密密码并将其存储在其旁边。然后使用密码为日志appender生成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; 
    } 
} 

You'll需要几个辅助函数用于读取文件或从中可以发现here一个Java密钥存储私钥。

测试文件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()); 

    } 
}